irframe_tty.c revision 1.8 1 /* $NetBSD: irframe_tty.c,v 1.8 2001/12/05 04:31:02 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 = 0;
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 #if IRFRAMET_DEBUG
444 if (irframetdebug > 1)
445 DPRINTF(("%s: c=0x%02x, inchar=%d state=%d\n", __FUNCTION__, c,
446 sc->sc_inchars, sc->sc_state));
447 #endif
448 if (sc->sc_framestate != FRAME_OUTSIDE) {
449 if (sc->sc_framestate == FRAME_ESCAPE) {
450 sc->sc_framestate = FRAME_INSIDE;
451 c ^= SIR_ESC_BIT;
452 }
453 if (sc->sc_inchars < sc->sc_maxsize + 2) {
454 sc->sc_inbuf[sc->sc_inchars++] = c;
455 sc->sc_inFCS = updateFCS(sc->sc_inFCS, c);
456 } else {
457 sc->sc_framestate = FRAME_OUTSIDE;
458 #ifdef IRFRAMET_DEBUG
459 printf("%s: input frame overrun\n",
460 __FUNCTION__);
461 #endif
462 }
463 }
464 break;
465 }
466
467 #if 1
468 if (sc->sc_framestate != FRAME_OUTSIDE) {
469 callout_reset(&sc->sc_timeout, hz/20, irt_timeout, sc);
470 }
471 #endif
472
473 return (0);
474 }
475
476
477 /*** irframe methods ***/
478
479 int
480 irframet_open(void *h, int flag, int mode, struct proc *p)
481 {
482 struct tty *tp = h;
483 struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
484
485 DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
486
487 sc->sc_speed = 0;
488 sc->sc_ebofs = IRDA_DEFAULT_EBOFS;
489 sc->sc_maxsize = 0;
490 sc->sc_framestate = FRAME_OUTSIDE;
491 sc->sc_nframes = 0;
492 sc->sc_framei = 0;
493 sc->sc_frameo = 0;
494 callout_init(&sc->sc_timeout);
495
496 return (0);
497 }
498
499 int
500 irframet_close(void *h, int flag, int mode, struct proc *p)
501 {
502 struct tty *tp = h;
503 struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
504 int i, s;
505
506 DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
507
508 callout_stop(&sc->sc_timeout);
509 s = splir();
510 if (sc->sc_inbuf != NULL) {
511 free(sc->sc_inbuf, M_DEVBUF);
512 sc->sc_inbuf = NULL;
513 }
514 for (i = 0; i < MAXFRAMES; i++) {
515 if (sc->sc_frames[i].buf != NULL) {
516 free(sc->sc_frames[i].buf, M_DEVBUF);
517 sc->sc_frames[i].buf = NULL;
518 }
519 }
520 splx(s);
521
522 return (0);
523 }
524
525 int
526 irframet_read(void *h, struct uio *uio, int flag)
527 {
528 struct tty *tp = h;
529 struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
530 int error = 0;
531 int s;
532
533 DPRINTF(("%s: resid=%d, iovcnt=%d, offset=%ld\n",
534 __FUNCTION__, uio->uio_resid, uio->uio_iovcnt,
535 (long)uio->uio_offset));
536 DPRINTF(("%s: nframe=%d framei=%d frameo=%d\n",
537 __FUNCTION__, sc->sc_nframes, sc->sc_framei, sc->sc_frameo));
538
539
540 s = splir();
541 while (sc->sc_nframes == 0) {
542 if (flag & IO_NDELAY) {
543 splx(s);
544 return (EWOULDBLOCK);
545 }
546 sc->sc_state |= IRT_RSLP;
547 DPRINTF(("%s: sleep\n", __FUNCTION__));
548 error = tsleep(sc->sc_frames, PZERO | PCATCH, "irtrd", 0);
549 DPRINTF(("%s: woke, error=%d\n", __FUNCTION__, error));
550 if (error) {
551 sc->sc_state &= ~IRT_RSLP;
552 break;
553 }
554 }
555
556 /* Do just one frame transfer per read */
557 if (!error) {
558 if (uio->uio_resid < sc->sc_frames[sc->sc_frameo].len) {
559 DPRINTF(("%s: uio buffer smaller than frame size (%d < %d)\n", __FUNCTION__, uio->uio_resid, sc->sc_frames[sc->sc_frameo].len));
560 error = EINVAL;
561 } else {
562 DPRINTF(("%s: moving %d bytes\n", __FUNCTION__,
563 sc->sc_frames[sc->sc_frameo].len));
564 error = uiomove(sc->sc_frames[sc->sc_frameo].buf,
565 sc->sc_frames[sc->sc_frameo].len, uio);
566 DPRINTF(("%s: error=%d\n", __FUNCTION__, error));
567 }
568 sc->sc_frameo = (sc->sc_frameo+1) % MAXFRAMES;
569 sc->sc_nframes--;
570 }
571 splx(s);
572
573 return (error);
574 }
575
576 int
577 irt_putc(int c, struct tty *tp)
578 {
579 int s;
580 int error;
581
582 if (tp->t_outq.c_cc > tp->t_hiwat) {
583 irframetstart(tp);
584 s = spltty();
585 /*
586 * This can only occur if FLUSHO is set in t_lflag,
587 * or if ttstart/oproc is synchronous (or very fast).
588 */
589 if (tp->t_outq.c_cc <= tp->t_hiwat) {
590 splx(s);
591 goto go;
592 }
593 SET(tp->t_state, TS_ASLEEP);
594 error = ttysleep(tp, &tp->t_outq, TTOPRI | PCATCH, ttyout, 0);
595 splx(s);
596 if (error)
597 return (error);
598 }
599 go:
600 if (putc(c, &tp->t_outq) < 0) {
601 printf("irframe: putc failed\n");
602 return (EIO);
603 }
604 return (0);
605 }
606
607 int
608 irt_putesc(int c, struct tty *tp)
609 {
610 int error;
611
612 if (c == SIR_BOF || c == SIR_EOF || c == SIR_CE) {
613 error = irt_putc(SIR_CE, tp);
614 if (!error)
615 error = irt_putc(SIR_ESC_BIT^c, tp);
616 } else {
617 error = irt_putc(c, tp);
618 }
619 return (error);
620 }
621
622 int
623 irframet_write(void *h, struct uio *uio, int flag)
624 {
625 u_int8_t buf[MAX_IRDA_FRAME];
626 size_t n;
627 int error;
628
629 DPRINTF(("%s: resid=%d, iovcnt=%d, offset=%ld\n",
630 __FUNCTION__, uio->uio_resid, uio->uio_iovcnt,
631 (long)uio->uio_offset));
632
633 n = uio->uio_resid;
634 if (n > MAX_IRDA_FRAME)
635 return (EINVAL);
636 error = uiomove(buf, n, uio);
637 if (error)
638 return (error);
639 return (irt_write_buf(h, buf, n));
640 }
641
642 int
643 irt_write_buf(void *h, void *buf, size_t len)
644 {
645 struct tty *tp = h;
646 struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
647 u_int8_t *cp = buf;
648 int c, error, ofcs, i;
649
650 DPRINTF(("%s: tp=%p len=%d\n", __FUNCTION__, tp, len));
651
652 ofcs = INITFCS;
653 error = 0;
654
655 for (i = 0; i < sc->sc_ebofs; i++)
656 irt_putc(SIR_EXTRA_BOF, tp);
657 irt_putc(SIR_BOF, tp);
658
659 while (len-- > 0) {
660 c = *cp++;
661 ofcs = updateFCS(ofcs, c);
662 error = irt_putesc(c, tp);
663 if (error)
664 return (error);
665 }
666
667 ofcs = ~ofcs;
668 error = irt_putesc(ofcs & 0xff, tp);
669 if (!error)
670 error = irt_putesc((ofcs >> 8) & 0xff, tp);
671 if (!error)
672 error = irt_putc(SIR_EOF, tp);
673
674 irframetstart(tp);
675
676 DPRINTF(("%s: done\n", __FUNCTION__));
677
678 return (error);
679 }
680
681 int
682 irframet_poll(void *h, int events, struct proc *p)
683 {
684 struct tty *tp = h;
685 struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
686 int revents = 0;
687 int s;
688
689 DPRINTF(("%s: sc=%p\n", __FUNCTION__, sc));
690
691 s = splir();
692 /* XXX should check with tty */
693 if (events & (POLLOUT | POLLWRNORM))
694 revents |= events & (POLLOUT | POLLWRNORM);
695 if (events & (POLLIN | POLLRDNORM)) {
696 if (sc->sc_nframes > 0) {
697 DPRINTF(("%s: have data\n", __FUNCTION__));
698 revents |= events & (POLLIN | POLLRDNORM);
699 } else {
700 DPRINTF(("%s: recording select\n", __FUNCTION__));
701 selrecord(p, &sc->sc_rsel);
702 }
703 }
704 splx(s);
705
706 return (revents);
707 }
708
709 int
710 irframet_set_params(void *h, struct irda_params *p)
711 {
712 struct tty *tp = h;
713 struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
714 struct termios tt;
715 int i;
716
717 DPRINTF(("%s: tp=%p speed=%d ebofs=%d maxsize=%d\n",
718 __FUNCTION__, tp, p->speed, p->ebofs, p->maxsize));
719
720 if (p->speed != sc->sc_speed) {
721 switch (p->speed) {
722 case 2400:
723 case 9600:
724 case 19200:
725 case 38400:
726 case 57600:
727 case 115200:
728 break;
729 default: return (EINVAL);
730 }
731 ttioctl(tp, TIOCGETA, (caddr_t)&tt, 0, curproc);
732 sc->sc_speed = tt.c_ispeed = tt.c_ospeed = p->speed;
733 ttioctl(tp, TIOCSETAF, (caddr_t)&tt, 0, curproc);
734 }
735
736 sc->sc_ebofs = p->ebofs;
737 if (sc->sc_maxsize != p->maxsize) {
738 sc->sc_maxsize = p->maxsize;
739 if (sc->sc_inbuf != NULL)
740 free(sc->sc_inbuf, M_DEVBUF);
741 for (i = 0; i < MAXFRAMES; i++)
742 if (sc->sc_frames[i].buf != NULL)
743 free(sc->sc_frames[i].buf, M_DEVBUF);
744 if (sc->sc_maxsize != 0) {
745 sc->sc_inbuf = malloc(sc->sc_maxsize+2, M_DEVBUF,
746 M_WAITOK);
747 for (i = 0; i < MAXFRAMES; i++)
748 sc->sc_frames[i].buf = malloc(sc->sc_maxsize,
749 M_DEVBUF, M_WAITOK);
750 } else {
751 sc->sc_inbuf = NULL;
752 for (i = 0; i < MAXFRAMES; i++)
753 sc->sc_frames[i].buf = NULL;
754 }
755 }
756 sc->sc_framestate = FRAME_OUTSIDE;
757
758 return (0);
759 }
760
761 int
762 irframet_get_speeds(void *h, int *speeds)
763 {
764 struct tty *tp = h;
765
766 tp = tp;
767 DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
768 *speeds = IRDA_SPEEDS_SIR;
769 return (0);
770 }
771
772 int
773 irframet_get_turnarounds(void *h, int *turnarounds)
774 {
775 struct tty *tp = h;
776
777 tp = tp;
778 DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
779 *turnarounds = IRDA_TURNT_10000;
780 return (0);
781 }
782