irframe_tty.c revision 1.6 1 /* $NetBSD: irframe_tty.c,v 1.6 2001/12/05 01:13:58 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=%d\n", __FUNCTION__, tp->t_linesw,
239 tp->t_linesw->l_no));
240 if (tp->t_linesw->l_no == IRFRAMEDISC) {
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 printf("%s attached at tty%02d:", sc->sc_irp.sc_dev.dv_xname,
250 minor(tp->t_dev));
251 tp->t_sc = irframe_alloc(sizeof (struct irframet_softc),
252 &irframet_methods, tp);
253 sc = (struct irframet_softc *)tp->t_sc;
254 sc->sc_tp = tp;
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 if (sc->sc_nframes >= MAXFRAMES) {
364 #ifdef IRFRAMET_DEBUG
365 printf("%s: dropped frame\n", __FUNCTION__);
366 #endif
367 return;
368 }
369 if (sc->sc_frames[sc->sc_framei].buf == NULL)
370 return;
371 memcpy(sc->sc_frames[sc->sc_framei].buf, buf, len);
372 sc->sc_frames[sc->sc_framei].len = len;
373 sc->sc_framei = (sc->sc_framei+1) % MAXFRAMES;
374 sc->sc_nframes++;
375 if (sc->sc_state & IRT_RSLP) {
376 sc->sc_state &= ~IRT_RSLP;
377 DPRINTF(("%s: waking up reader\n", __FUNCTION__));
378 wakeup(sc->sc_frames);
379 }
380 selwakeup(&sc->sc_rsel);
381 }
382
383 void
384 irt_timeout(void *v)
385 {
386 struct irframet_softc *sc = v;
387
388 #ifdef IRFRAMET_DEBUG
389 if (sc->sc_framestate != FRAME_OUTSIDE)
390 printf("%s: input frame timeout\n", __FUNCTION__);
391 #endif
392 sc->sc_framestate = FRAME_OUTSIDE;
393 }
394
395 int
396 irframetinput(int c, struct tty *tp)
397 {
398 struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
399
400 DPRINTF(("%s: tp=%p c=0x%0x\n", __FUNCTION__, tp, c));
401
402 if (sc == NULL || tp != (struct tty *)sc->sc_tp)
403 return (0);
404
405 if (sc->sc_inbuf == NULL)
406 return (0);
407
408 switch (c) {
409 case SIR_BOF:
410 sc->sc_framestate = FRAME_INSIDE;
411 sc->sc_inchars = 0;
412 sc->sc_inFCS = INITFCS;
413 break;
414 case SIR_EOF:
415 if (sc->sc_framestate == FRAME_INSIDE &&
416 sc->sc_inchars >= 4 && sc->sc_inFCS == GOODFCS) {
417 irt_frame(sc, sc->sc_inbuf, sc->sc_inchars - 2);
418 } else if (sc->sc_framestate != FRAME_OUTSIDE) {
419 #ifdef IRFRAMET_DEBUG
420 printf("%s: malformed input frame\n", __FUNCTION__);
421 #endif
422 }
423 sc->sc_framestate = FRAME_OUTSIDE;
424 break;
425 case SIR_CE:
426 if (sc->sc_framestate == FRAME_INSIDE)
427 sc->sc_framestate = FRAME_ESCAPE;
428 break;
429 default:
430 if (sc->sc_framestate != FRAME_OUTSIDE) {
431 if (sc->sc_framestate == FRAME_ESCAPE) {
432 sc->sc_framestate = FRAME_INSIDE;
433 c ^= SIR_ESC_BIT;
434 }
435 if (sc->sc_inchars < sc->sc_maxsize + 2) {
436 sc->sc_inbuf[sc->sc_inchars++] = c;
437 sc->sc_inFCS = updateFCS(sc->sc_inFCS, c);
438 } else {
439 sc->sc_framestate = FRAME_OUTSIDE;
440 #ifdef IRFRAMET_DEBUG
441 printf("%s: input frame overrun\n",
442 __FUNCTION__);
443 #endif
444 }
445 }
446 break;
447 }
448
449 if (sc->sc_framestate != FRAME_OUTSIDE) {
450 callout_reset(&sc->sc_timeout, hz/100, irt_timeout, sc);
451 }
452
453 return (0);
454 }
455
456
457 /*** irframe methods ***/
458
459 int
460 irframet_open(void *h, int flag, int mode, struct proc *p)
461 {
462 struct tty *tp = h;
463 struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
464
465 DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
466
467 sc->sc_speed = 0;
468 sc->sc_ebofs = IRDA_DEFAULT_EBOFS;
469 sc->sc_maxsize = 0;
470 sc->sc_framestate = FRAME_OUTSIDE;
471 sc->sc_nframes = 0;
472 sc->sc_framei = 0;
473 sc->sc_frameo = 0;
474 callout_init(&sc->sc_timeout);
475
476 return (0);
477 }
478
479 int
480 irframet_close(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 int i, s;
485
486 DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
487
488 callout_stop(&sc->sc_timeout);
489 s = splir();
490 if (sc->sc_inbuf != NULL) {
491 free(sc->sc_inbuf, M_DEVBUF);
492 sc->sc_inbuf = NULL;
493 }
494 for (i = 0; i < MAXFRAMES; i++) {
495 if (sc->sc_frames[i].buf != NULL) {
496 free(sc->sc_frames[i].buf, M_DEVBUF);
497 sc->sc_frames[i].buf = NULL;
498 }
499 }
500 splx(s);
501
502 return (0);
503 }
504
505 int
506 irframet_read(void *h, struct uio *uio, int flag)
507 {
508 struct tty *tp = h;
509 struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
510 int error = 0;
511 int s;
512
513 DPRINTF(("%s: resid=%d, iovcnt=%d, offset=%ld\n",
514 __FUNCTION__, uio->uio_resid, uio->uio_iovcnt,
515 (long)uio->uio_offset));
516
517 s = splir();
518 while (sc->sc_nframes == 0) {
519 if (flag & IO_NDELAY) {
520 splx(s);
521 return (EWOULDBLOCK);
522 }
523 sc->sc_state |= IRT_RSLP;
524 DPRINTF(("%s: sleep\n", __FUNCTION__));
525 error = tsleep(sc->sc_frames, PZERO | PCATCH, "irtrd", 0);
526 DPRINTF(("%s: woke, error=%d\n", __FUNCTION__, error));
527 if (error) {
528 sc->sc_state &= ~IRT_RSLP;
529 break;
530 }
531 }
532
533 /* Do just one frame transfer per read */
534 if (!error) {
535 if (uio->uio_resid < sc->sc_frames[sc->sc_frameo].len) {
536 DPRINTF(("%s: uio buffer smaller than frame size (%d < %d)\n", __FUNCTION__, uio->uio_resid, sc->sc_frames[sc->sc_frameo].len));
537 error = EINVAL;
538 } else {
539 DPRINTF(("%s: moving %d bytes\n", __FUNCTION__,
540 sc->sc_frames[sc->sc_frameo].len));
541 error = uiomove(sc->sc_frames[sc->sc_frameo].buf,
542 sc->sc_frames[sc->sc_frameo].len, uio);
543 }
544 sc->sc_frameo++;
545 sc->sc_nframes--;
546 }
547 splx(s);
548
549 return (error);
550 }
551
552 int
553 irt_putc(int c, struct tty *tp)
554 {
555 int s;
556 int error;
557
558 if (tp->t_outq.c_cc > tp->t_hiwat) {
559 irframetstart(tp);
560 s = spltty();
561 /*
562 * This can only occur if FLUSHO is set in t_lflag,
563 * or if ttstart/oproc is synchronous (or very fast).
564 */
565 if (tp->t_outq.c_cc <= tp->t_hiwat) {
566 splx(s);
567 goto go;
568 }
569 SET(tp->t_state, TS_ASLEEP);
570 error = ttysleep(tp, &tp->t_outq, TTOPRI | PCATCH, ttyout, 0);
571 splx(s);
572 if (error)
573 return (error);
574 }
575 go:
576 if (putc(c, &tp->t_rawq) < 0) {
577 printf("irframe: putc failed\n");
578 return (EIO);
579 }
580 return (0);
581 }
582
583 int
584 irt_putesc(int c, struct tty *tp)
585 {
586 int error;
587
588 if (c == SIR_BOF || c == SIR_EOF || c == SIR_CE) {
589 error = irt_putc(SIR_CE, tp);
590 if (!error)
591 error = irt_putc(SIR_ESC_BIT^c, tp);
592 } else {
593 error = irt_putc(c, tp);
594 }
595 return (error);
596 }
597
598 int
599 irframet_write(void *h, struct uio *uio, int flag)
600 {
601 u_int8_t buf[MAX_IRDA_FRAME];
602 size_t n;
603 int error;
604
605 DPRINTF(("%s\n", __FUNCTION__));
606
607 n = uio->uio_resid;
608 if (n > MAX_IRDA_FRAME)
609 return (EINVAL);
610 error = uiomove(buf, n, uio);
611 if (error)
612 return (error);
613 return (irt_write_buf(h, buf, n));
614 }
615
616 int
617 irt_write_buf(void *h, void *buf, size_t len)
618 {
619 struct tty *tp = h;
620 struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
621 u_int8_t *cp = buf;
622 int c, error, ofcs, i;
623
624 DPRINTF(("%s: tp=%p len=%d\n", __FUNCTION__, tp, len));
625
626 ofcs = INITFCS;
627 error = 0;
628
629 for (i = 0; i < sc->sc_ebofs; i++)
630 irt_putc(SIR_EXTRA_BOF, tp);
631 irt_putc(SIR_BOF, tp);
632
633 while (len-- > 0) {
634 c = *cp++;
635 ofcs = updateFCS(ofcs, c);
636 error = irt_putesc(c, tp);
637 if (error)
638 return (error);
639 }
640
641 ofcs = ~ofcs;
642 error = irt_putesc(ofcs & 0xff, tp);
643 if (!error)
644 error = irt_putesc((ofcs >> 8) & 0xff, tp);
645 if (!error)
646 error = irt_putc(SIR_EOF, tp);
647
648 irframetstart(tp);
649
650 return (error);
651 }
652
653 int
654 irframet_poll(void *h, int events, struct proc *p)
655 {
656 struct tty *tp = h;
657 struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
658 int revents = 0;
659 int s;
660
661 DPRINTF(("%s: sc=%p\n", __FUNCTION__, sc));
662
663 s = splir();
664 /* XXX should check with tty */
665 if (events & (POLLOUT | POLLWRNORM))
666 revents |= events & (POLLOUT | POLLWRNORM);
667 if (events & (POLLIN | POLLRDNORM)) {
668 if (sc->sc_nframes > 0) {
669 DPRINTF(("%s: have data\n", __FUNCTION__));
670 revents |= events & (POLLIN | POLLRDNORM);
671 } else {
672 DPRINTF(("%s: recording select", __FUNCTION__));
673 selrecord(p, &sc->sc_rsel);
674 }
675 }
676 splx(s);
677
678 return (revents);
679 }
680
681 int
682 irframet_set_params(void *h, struct irda_params *p)
683 {
684 struct tty *tp = h;
685 struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
686 struct termios tt;
687 int i;
688
689 DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
690
691 if (p->speed != sc->sc_speed) {
692 switch (p->speed) {
693 case 2400:
694 case 9600:
695 case 19200:
696 case 38400:
697 case 57600:
698 case 115200:
699 break;
700 default: return (EINVAL);
701 }
702 ttioctl(tp, TIOCGETA, (caddr_t)&tt, 0, curproc);
703 sc->sc_speed = tt.c_ispeed = tt.c_ospeed = p->speed;
704 ttioctl(tp, TIOCSETAF, (caddr_t)&tt, 0, curproc);
705 }
706
707 sc->sc_ebofs = p->ebofs;
708 if (sc->sc_maxsize != p->maxsize) {
709 sc->sc_maxsize = p->maxsize;
710 if (sc->sc_inbuf != NULL)
711 free(sc->sc_inbuf, M_DEVBUF);
712 for (i = 0; i < MAXFRAMES; i++)
713 if (sc->sc_frames[i].buf != NULL)
714 free(sc->sc_frames[i].buf, M_DEVBUF);
715 if (sc->sc_maxsize != 0) {
716 sc->sc_inbuf = malloc(sc->sc_maxsize+2, M_DEVBUF,
717 M_WAITOK);
718 for (i = 0; i < MAXFRAMES; i++)
719 sc->sc_frames[i].buf = malloc(sc->sc_maxsize,
720 M_DEVBUF, M_WAITOK);
721 } else {
722 sc->sc_inbuf = NULL;
723 for (i = 0; i < MAXFRAMES; i++)
724 sc->sc_frames[i].buf = NULL;
725 }
726 }
727 sc->sc_framestate = FRAME_OUTSIDE;
728
729 return (0);
730 }
731
732 int
733 irframet_get_speeds(void *h, int *speeds)
734 {
735 struct tty *tp = h;
736
737 tp = tp;
738 DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
739 *speeds = IRDA_SPEEDS_SIR;
740 return (0);
741 }
742
743 int
744 irframet_get_turnarounds(void *h, int *turnarounds)
745 {
746 struct tty *tp = h;
747
748 tp = tp;
749 DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
750 *turnarounds = IRDA_TURNT_10000;
751 return (0);
752 }
753