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