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