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