irframe_tty.c revision 1.3 1 /* $NetBSD: irframe_tty.c,v 1.3 2001/12/04 20:53:21 augustss Exp $ */
2
3 /*
4 * Copyright (c) 2001 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Lennart Augustsson (lennart (at) augustsson.net).
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 /*
40 * Loosely based on ppp_tty.c.
41 */
42
43 #include <sys/param.h>
44 #include <sys/proc.h>
45 #include <sys/ioctl.h>
46 #include <sys/tty.h>
47 #include <sys/kernel.h>
48 #include <sys/malloc.h>
49 #include <sys/conf.h>
50 #include <sys/systm.h>
51 #include <sys/device.h>
52 #include <sys/file.h>
53 #include <sys/vnode.h>
54 #include <sys/poll.h>
55
56 #include <dev/ir/ir.h>
57 #include <dev/ir/irdaio.h>
58 #include <dev/ir/irframevar.h>
59
60 /* Macros to clear/set/test flags. */
61 #define SET(t, f) (t) |= (f)
62 #define CLR(t, f) (t) &= ~(f)
63 #define ISSET(t, f) ((t) & (f))
64
65 #ifdef IRFRAMET_DEBUG
66 #define DPRINTF(x) if (irframetdebug) printf x
67 #define Static
68 int irframetdebug = 1;
69 #else
70 #define DPRINTF(x)
71 #define Static static
72 #endif
73
74 /* Protocol constants */
75 #define SIR_EXTRA_BOF 0xff
76 #define SIR_BOF 0xc0
77 #define SIR_CE 0x7d
78 #define SIR_EOF 0xc1
79
80 #define SIR_ESC_BIT 0x20
81 /*****/
82
83 #define MAX_IRDA_FRAME 5000 /* XXX what is it? */
84
85 struct frame {
86 u_char *buf;
87 u_int len;
88 };
89 #define MAXFRAMES 4
90
91 struct irframet_softc {
92 struct irframe_softc sc_irp;
93 struct tty *sc_tp;
94
95 int sc_state;
96 #define IRT_RSLP 0x01 /* waiting for data (read) */
97 #if 0
98 #define IRT_WSLP 0x02 /* waiting for data (write) */
99 #define IRT_CLOSING 0x04 /* waiting for output to drain */
100 #endif
101
102 int sc_ebofs;
103
104 u_char* sc_inbuf;
105 int sc_maxsize;
106 int sc_framestate;
107 #define FRAME_OUTSIDE 0
108 #define FRAME_INSIDE 1
109 #define FRAME_ESCAPE 2
110 int sc_inchars;
111 int sc_inFCS;
112 struct callout sc_timeout;
113
114 u_int sc_nframes;
115 u_int sc_framei;
116 u_int sc_frameo;
117 struct frame sc_frames[MAXFRAMES];
118 struct selinfo sc_rsel;
119 };
120
121 /* line discipline methods */
122 int irframetopen(dev_t dev, struct tty *tp);
123 int irframetclose(struct tty *tp, int flag);
124 int irframetioctl(struct tty *tp, u_long cmd, caddr_t data, int flag,
125 struct proc *);
126 int irframetinput(int c, struct tty *tp);
127 int irframetstart(struct tty *tp);
128
129 /* pseudo device init */
130 void irframettyattach(int);
131
132 /* irframe methods */
133 Static int irframet_open(void *h, int flag, int mode, struct proc *p);
134 Static int irframet_close(void *h, int flag, int mode, struct proc *p);
135 Static int irframet_read(void *h, struct uio *uio, int flag);
136 Static int irframet_write(void *h, struct uio *uio, int flag);
137 Static int irframet_poll(void *h, int events, struct proc *p);
138 Static int irframet_set_params(void *h, struct irda_params *params);
139 Static int irframet_get_speeds(void *h, int *speeds);
140 Static int irframet_get_turnarounds(void *h, int *times);
141
142 /* internal */
143 Static int irt_write_buf(void *h, void *buf, size_t len);
144 Static int irt_putc(int c, struct tty *tp);
145 Static int irt_putesc(int c, struct tty *tp);
146 Static void irt_frame(struct irframet_softc *sc, u_char *buf, u_int len);
147 Static void irt_timeout(void *v);
148
149 Static struct irframe_methods irframet_methods = {
150 irframet_open, irframet_close, irframet_read, irframet_write,
151 irframet_poll, irframet_set_params,
152 irframet_get_speeds, irframet_get_turnarounds
153 };
154
155 void
156 irframettyattach(int n)
157 {
158 }
159
160 /*
161 * CRC
162 */
163
164 static const u_int16_t fcstab[] = {
165 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
166 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
167 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
168 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
169 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
170 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
171 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
172 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
173 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
174 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
175 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
176 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
177 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
178 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
179 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
180 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
181 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
182 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
183 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
184 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
185 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
186 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
187 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
188 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
189 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
190 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
191 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
192 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
193 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
194 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
195 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
196 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
197 };
198
199 static const u_int16_t INITFCS = 0xffff;
200 static const u_int16_t GOODFCS = 0xf0b8;
201
202 static __inline u_int16_t updateFCS(u_int16_t fcs, int c) {
203 return (fcs >> 8) ^ fcstab[(fcs^c) & 0xff];
204 }
205
206
207 /*
208 * Line specific open routine for async tty devices.
209 * Attach the given tty to the first available irframe unit.
210 * Called from device open routine or ttioctl.
211 */
212 /* ARGSUSED */
213 int
214 irframetopen(dev_t dev, struct tty *tp)
215 {
216 struct proc *p = curproc; /* XXX */
217 struct irframet_softc *sc;
218 int error, s;
219
220 DPRINTF(("%s\n", __FUNCTION__));
221
222 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
223 return (error);
224
225 s = spltty();
226
227 DPRINTF(("%s: linesw=%p disc=%d\n", __FUNCTION__, tp->t_linesw,
228 tp->t_linesw->l_no));
229 if (tp->t_linesw->l_no == IRFRAMEDISC) {
230 sc = (struct irframet_softc *)tp->t_sc;
231 DPRINTF(("%s: sc=%p sc_tp=%p\n", __FUNCTION__, sc, sc->sc_tp));
232 if (sc != NULL) {
233 splx(s);
234 return (EBUSY);
235 }
236 }
237
238 printf("%s attached at tty%02d:", sc->sc_irp.sc_dev.dv_xname,
239 minor(tp->t_dev));
240 tp->t_sc = irframe_alloc(sizeof (struct irframet_softc),
241 &irframet_methods, tp);
242 sc = (struct irframet_softc *)tp->t_sc;
243 sc->sc_tp = tp;
244
245 DPRINTF(("%s: set sc=%p\n", __FUNCTION__, sc));
246
247 ttyflush(tp, FREAD | FWRITE);
248
249 splx(s);
250
251 return (0);
252 }
253
254 /*
255 * Line specific close routine, called from device close routine
256 * and from ttioctl.
257 * Detach the tty from the irframe unit.
258 * Mimics part of ttyclose().
259 */
260 int
261 irframetclose(struct tty *tp, int flag)
262 {
263 struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
264 int s;
265
266 DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
267
268 s = spltty();
269 ttyflush(tp, FREAD | FWRITE);
270 tp->t_linesw = linesw[0]; /* default line discipline */
271 if (sc != NULL) {
272 tp->t_sc = NULL;
273 printf("%s detached from tty%02d\n", sc->sc_irp.sc_dev.dv_xname,
274 minor(tp->t_dev));
275
276 if (sc->sc_tp == tp)
277 irframe_dealloc(&sc->sc_irp.sc_dev);
278 }
279 splx(s);
280 return (0);
281 }
282
283 /*
284 * Line specific (tty) ioctl routine.
285 * This discipline requires that tty device drivers call
286 * the line specific l_ioctl routine from their ioctl routines.
287 */
288 /* ARGSUSED */
289 int
290 irframetioctl(struct tty *tp, u_long cmd, caddr_t data, int flag,
291 struct proc *p)
292 {
293 struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
294 int error;
295
296 DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
297
298 if (sc == NULL || tp != sc->sc_tp)
299 return (-1);
300
301 error = 0;
302 switch (cmd) {
303 default:
304 #if 0
305 error = irframeioctl(sc, cmd, data, flag, p);
306 #else
307 error = EINVAL;
308 #endif
309 break;
310 }
311
312 return (error);
313 }
314
315 /*
316 * Start output on async tty interface. If the transmit queue
317 * has drained sufficiently, arrange for irframeasyncstart to be
318 * called later at splsoftnet.
319 * Called at spltty or higher.
320 */
321 int
322 irframetstart(struct tty *tp)
323 {
324 /*struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;*/
325
326 DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
327
328 /*
329 * If there is stuff in the output queue, send it now.
330 * We are being called in lieu of ttstart and must do what it would.
331 */
332 if (tp->t_oproc != NULL)
333 (*tp->t_oproc)(tp);
334
335 return (0);
336 }
337
338 void
339 irt_frame(struct irframet_softc *sc, u_char *buf, u_int len)
340 {
341 if (sc->sc_nframes >= MAXFRAMES) {
342 #ifdef IRFRAMET_DEBUG
343 printf("%s: dropped frame\n", __FUNCTION__);
344 #endif
345 return;
346 }
347 if (sc->sc_frames[sc->sc_framei].buf == NULL)
348 return;
349 memcpy(sc->sc_frames[sc->sc_framei].buf, buf, len);
350 sc->sc_frames[sc->sc_framei].len = len;
351 sc->sc_framei = (sc->sc_framei+1) % MAXFRAMES;
352 sc->sc_nframes++;
353 if (sc->sc_state & IRT_RSLP) {
354 sc->sc_state &= ~IRT_RSLP;
355 DPRINTF(("%s: waking up reader\n", __FUNCTION__));
356 wakeup(sc->sc_frames);
357 }
358 selwakeup(&sc->sc_rsel);
359 }
360
361 void
362 irt_timeout(void *v)
363 {
364 struct irframet_softc *sc = v;
365
366 #ifdef IRFRAMET_DEBUG
367 if (sc->sc_framestate != FRAME_OUTSIDE)
368 printf("%s: input frame timeout\n", __FUNCTION__);
369 #endif
370 sc->sc_framestate = FRAME_OUTSIDE;
371 }
372
373 int
374 irframetinput(int c, struct tty *tp)
375 {
376 struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
377
378 DPRINTF(("%s: tp=%p c=0x%0x\n", __FUNCTION__, tp, c));
379
380 if (sc == NULL || tp != (struct tty *)sc->sc_tp)
381 return (0);
382
383 if (sc->sc_inbuf == NULL)
384 return (0);
385
386 switch (c) {
387 case SIR_BOF:
388 sc->sc_framestate = FRAME_INSIDE;
389 sc->sc_inchars = 0;
390 sc->sc_inFCS = INITFCS;
391 break;
392 case SIR_EOF:
393 if (sc->sc_framestate == FRAME_INSIDE &&
394 sc->sc_inchars >= 4 && sc->sc_inFCS == GOODFCS) {
395 irt_frame(sc, sc->sc_inbuf, sc->sc_inchars - 2);
396 } else if (sc->sc_framestate != FRAME_OUTSIDE) {
397 #ifdef IRFRAMET_DEBUG
398 printf("%s: malformed input frame\n", __FUNCTION__);
399 #endif
400 }
401 sc->sc_framestate = FRAME_OUTSIDE;
402 break;
403 case SIR_CE:
404 if (sc->sc_framestate == FRAME_INSIDE)
405 sc->sc_framestate = FRAME_ESCAPE;
406 break;
407 default:
408 if (sc->sc_framestate != FRAME_OUTSIDE) {
409 if (sc->sc_framestate == FRAME_ESCAPE) {
410 sc->sc_framestate = FRAME_INSIDE;
411 c ^= SIR_ESC_BIT;
412 }
413 if (sc->sc_inchars < sc->sc_maxsize + 2) {
414 sc->sc_inbuf[sc->sc_inchars++] = c;
415 sc->sc_inFCS = updateFCS(sc->sc_inFCS, c);
416 } else {
417 sc->sc_framestate = FRAME_OUTSIDE;
418 #ifdef IRFRAMET_DEBUG
419 printf("%s: input frame overrun\n",
420 __FUNCTION__);
421 #endif
422 }
423 }
424 break;
425 }
426
427 if (sc->sc_framestate != FRAME_OUTSIDE) {
428 callout_reset(&sc->sc_timeout, hz/100, irt_timeout, sc);
429 }
430
431 return (0);
432 }
433
434
435 /*** irframe methods ***/
436
437 int
438 irframet_open(void *h, int flag, int mode, struct proc *p)
439 {
440 struct tty *tp = h;
441 struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
442
443 DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
444
445 sc->sc_ebofs = IRDA_DEFAULT_EBOFS;
446 sc->sc_maxsize = 0;
447 sc->sc_framestate = FRAME_OUTSIDE;
448 sc->sc_nframes = 0;
449 sc->sc_framei = 0;
450 sc->sc_frameo = 0;
451 callout_init(&sc->sc_timeout);
452
453 return (0);
454 }
455
456 int
457 irframet_close(void *h, int flag, int mode, struct proc *p)
458 {
459 struct tty *tp = h;
460 struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
461 int i, s;
462
463 DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
464
465 callout_stop(&sc->sc_timeout);
466 s = splir();
467 if (sc->sc_inbuf != NULL) {
468 free(sc->sc_inbuf, M_DEVBUF);
469 sc->sc_inbuf = NULL;
470 }
471 for (i = 0; i < MAXFRAMES; i++) {
472 if (sc->sc_frames[i].buf != NULL) {
473 free(sc->sc_frames[i].buf, M_DEVBUF);
474 sc->sc_frames[i].buf = NULL;
475 }
476 }
477 splx(s);
478
479 return (0);
480 }
481
482 int
483 irframet_read(void *h, struct uio *uio, int flag)
484 {
485 struct tty *tp = h;
486 struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
487 int error = 0;
488 int s;
489
490 DPRINTF(("%s: resid=%d, iovcnt=%d, offset=%ld\n",
491 __FUNCTION__, uio->uio_resid, uio->uio_iovcnt,
492 (long)uio->uio_offset));
493
494 s = splir();
495 while (sc->sc_nframes == 0) {
496 if (flag & IO_NDELAY) {
497 splx(s);
498 return (EWOULDBLOCK);
499 }
500 sc->sc_state |= IRT_RSLP;
501 DPRINTF(("%s: sleep\n", __FUNCTION__));
502 error = tsleep(sc->sc_frames, PZERO | PCATCH, "irtrd", 0);
503 DPRINTF(("%s: woke, error=%d\n", __FUNCTION__, error));
504 if (error) {
505 sc->sc_state &= ~IRT_RSLP;
506 break;
507 }
508 }
509
510 /* Do just one frame transfer per read */
511 if (!error) {
512 if (uio->uio_resid < sc->sc_frames[sc->sc_frameo].len) {
513 DPRINTF(("%s: uio buffer smaller than frame size (%d < %d)\n", __FUNCTION__, uio->uio_resid, sc->sc_frames[sc->sc_frameo].len));
514 error = EINVAL;
515 } else {
516 DPRINTF(("%s: moving %d bytes\n", __FUNCTION__,
517 sc->sc_frames[sc->sc_frameo].len));
518 error = uiomove(sc->sc_frames[sc->sc_frameo].buf,
519 sc->sc_frames[sc->sc_frameo].len, uio);
520 }
521 sc->sc_frameo++;
522 sc->sc_nframes--;
523 }
524 splx(s);
525
526 return (error);
527 }
528
529 int
530 irt_putc(int c, struct tty *tp)
531 {
532 int s;
533 int error;
534
535 if (tp->t_outq.c_cc > tp->t_hiwat) {
536 irframetstart(tp);
537 s = spltty();
538 /*
539 * This can only occur if FLUSHO is set in t_lflag,
540 * or if ttstart/oproc is synchronous (or very fast).
541 */
542 if (tp->t_outq.c_cc <= tp->t_hiwat) {
543 splx(s);
544 goto go;
545 }
546 SET(tp->t_state, TS_ASLEEP);
547 error = ttysleep(tp, &tp->t_outq, TTOPRI | PCATCH, ttyout, 0);
548 splx(s);
549 if (error)
550 return (error);
551 }
552 go:
553 if (putc(c, &tp->t_rawq) < 0) {
554 printf("irframe: putc failed\n");
555 return (EIO);
556 }
557 return (0);
558 }
559
560 int
561 irt_putesc(int c, struct tty *tp)
562 {
563 int error;
564
565 if (c == SIR_BOF || c == SIR_EOF || c == SIR_CE) {
566 error = irt_putc(SIR_CE, tp);
567 if (!error)
568 error = irt_putc(SIR_ESC_BIT^c, tp);
569 } else {
570 error = irt_putc(c, tp);
571 }
572 return (error);
573 }
574
575 int
576 irframet_write(void *h, struct uio *uio, int flag)
577 {
578 u_int8_t buf[MAX_IRDA_FRAME];
579 size_t n;
580 int error;
581
582 DPRINTF(("%s\n", __FUNCTION__));
583
584 n = uio->uio_resid;
585 if (n > MAX_IRDA_FRAME)
586 return (EINVAL);
587 error = uiomove(buf, n, uio);
588 if (error)
589 return (error);
590 return (irt_write_buf(h, buf, n));
591 }
592
593 int
594 irt_write_buf(void *h, void *buf, size_t len)
595 {
596 struct tty *tp = h;
597 struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
598 u_int8_t *cp = buf;
599 int c, error, ofcs, i;
600
601 DPRINTF(("%s: tp=%p len=%d\n", __FUNCTION__, tp, len));
602
603 ofcs = INITFCS;
604 error = 0;
605
606 for (i = 0; i < sc->sc_ebofs; i++)
607 irt_putc(SIR_EXTRA_BOF, tp);
608 irt_putc(SIR_BOF, tp);
609
610 while (len-- > 0) {
611 c = *cp++;
612 ofcs = updateFCS(ofcs, c);
613 error = irt_putesc(c, tp);
614 if (error)
615 return (error);
616 }
617
618 ofcs = ~ofcs;
619 error = irt_putesc(ofcs & 0xff, tp);
620 if (!error)
621 error = irt_putesc((ofcs >> 8) & 0xff, tp);
622 if (!error)
623 error = irt_putc(SIR_EOF, tp);
624
625 irframetstart(tp);
626
627 return (error);
628 }
629
630 int
631 irframet_poll(void *h, int events, struct proc *p)
632 {
633 struct tty *tp = h;
634 struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
635 int revents = 0;
636 int s;
637
638 DPRINTF(("%s: sc=%p\n", __FUNCTION__, sc));
639
640 s = splir();
641 /* XXX should check with tty */
642 if (events & (POLLOUT | POLLWRNORM))
643 revents |= events & (POLLOUT | POLLWRNORM);
644 if (events & (POLLIN | POLLRDNORM)) {
645 if (sc->sc_nframes > 0) {
646 DPRINTF(("%s: have data\n", __FUNCTION__));
647 revents |= events & (POLLIN | POLLRDNORM);
648 } else {
649 DPRINTF(("%s: recording select", __FUNCTION__));
650 selrecord(p, &sc->sc_rsel);
651 }
652 }
653 splx(s);
654
655 return (revents);
656 }
657
658 int
659 irframet_set_params(void *h, struct irda_params *p)
660 {
661 struct tty *tp = h;
662 struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
663 struct termios tt;
664 int i;
665
666 DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
667
668 switch (p->speed) {
669 case 2400:
670 case 9600:
671 case 19200:
672 case 38400:
673 case 57600:
674 case 115200:
675 break;
676 default: return (EINVAL);
677 }
678 ttioctl(tp, TIOCGETA, (caddr_t)&tt, 0, curproc);
679 tt.c_ispeed = tt.c_ospeed = p->speed;
680 ttioctl(tp, TIOCSETAF, (caddr_t)&tt, 0, curproc);
681
682 sc->sc_ebofs = p->ebofs;
683 if (sc->sc_maxsize != p->maxsize) {
684 sc->sc_maxsize = p->maxsize;
685 if (sc->sc_inbuf != NULL)
686 free(sc->sc_inbuf, M_DEVBUF);
687 for (i = 0; i < MAXFRAMES; i++)
688 if (sc->sc_frames[i].buf != NULL)
689 free(sc->sc_frames[i].buf, M_DEVBUF);
690 if (sc->sc_maxsize != 0) {
691 sc->sc_inbuf = malloc(sc->sc_maxsize+2, M_DEVBUF,
692 M_WAITOK);
693 for (i = 0; i < MAXFRAMES; i++)
694 sc->sc_frames[i].buf = malloc(sc->sc_maxsize,
695 M_DEVBUF, M_WAITOK);
696 } else {
697 sc->sc_inbuf = NULL;
698 for (i = 0; i < MAXFRAMES; i++)
699 sc->sc_frames[i].buf = NULL;
700 }
701 }
702 sc->sc_framestate = FRAME_OUTSIDE;
703
704 return (0);
705 }
706
707 int
708 irframet_get_speeds(void *h, int *speeds)
709 {
710 struct tty *tp = h;
711
712 tp = tp;
713 DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
714 *speeds = IRDA_SPEEDS_SIR;
715 return (0);
716 }
717
718 int
719 irframet_get_turnarounds(void *h, int *turnarounds)
720 {
721 struct tty *tp = h;
722
723 tp = tp;
724 DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
725 *turnarounds = IRDA_TURNT_10000;
726 return (0);
727 }
728