irframe_tty.c revision 1.1 1 /* $NetBSD: irframe_tty.c,v 1.1 2001/12/03 23:32:32 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/conf.h>
49 #include <sys/systm.h>
50 #include <sys/device.h>
51 #include <sys/file.h>
52 #include <sys/poll.h>
53
54 #include <dev/ir/ir.h>
55 #include <dev/ir/irdaio.h>
56 #include <dev/ir/irframevar.h>
57
58 /* Macros to clear/set/test flags. */
59 #define SET(t, f) (t) |= (f)
60 #define CLR(t, f) (t) &= ~((unsigned)(f))
61 #define ISSET(t, f) ((t) & (f))
62
63 #ifdef IRFRAMET_DEBUG
64 #define DPRINTF(x) if (irframetdebug) printf x
65 int irframetdebug = 1;
66 #else
67 #define DPRINTF(x)
68 #endif
69
70 /* Protocol constants */
71 #define SIR_EXTRA_BOF 0xff
72 #define SIR_BOF 0xc0
73 #define SIR_CE 0x7d
74 #define SIR_EOF 0xc1
75
76 #define SIR_ESC_BIT 0x20
77 /*****/
78
79 #define MAX_IRDA_FRAME 5000 /* XXX what is it? */
80
81 struct irframet_softc {
82 struct irframe_softc sc_irp;
83 struct tty *sc_tp;
84 int sc_ebofs;
85 };
86
87 /* line discipline methods */
88 int irframetopen(dev_t dev, struct tty *tp);
89 int irframetclose(struct tty *tp, int flag);
90 int irframetioctl(struct tty *tp, u_long cmd, caddr_t data, int flag,
91 struct proc *);
92 int irframetinput(int c, struct tty *tp);
93 int irframetstart(struct tty *tp);
94
95 /* irframe methods */
96 int irframet_open(void *h, int flag, int mode, struct proc *p);
97 int irframet_close(void *h, int flag, int mode, struct proc *p);
98 int irframet_read(void *h, struct uio *uio, int flag);
99 int irframet_write(void *h, struct uio *uio, int flag);
100 int irframet_poll(void *h, int events, struct proc *p);
101 int irframet_set_params(void *h, struct irda_params *params);
102 int irframet_reset_params(void *h);
103 int irframet_get_speeds(void *h, int *speeds);
104 int irframet_get_turnarounds(void *h, int *times);
105
106 int irframet_write_buf(void *h, void *buf, size_t len);
107
108 void irframettyattach(int);
109
110 struct irframe_methods irframet_methods = {
111 irframet_open, irframet_close, irframet_read, irframet_write,
112 irframet_poll, irframet_set_params, irframet_reset_params,
113 irframet_get_speeds, irframet_get_speeds
114 };
115
116 void
117 irframettyattach(int n)
118 {
119 }
120
121 /*
122 * Line specific open routine for async tty devices.
123 * Attach the given tty to the first available irframe unit.
124 * Called from device open routine or ttioctl.
125 */
126 /* ARGSUSED */
127 int
128 irframetopen(dev_t dev, struct tty *tp)
129 {
130 struct proc *p = curproc; /* XXX */
131 struct irframet_softc *sc;
132 int error, s;
133
134 DPRINTF(("%s\n", __FUNCTION__));
135
136 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
137 return (error);
138
139 s = spltty();
140
141 DPRINTF(("%s: linesw=%p disc=%d\n", __FUNCTION__, tp->t_linesw,
142 tp->t_linesw->l_no));
143 if (tp->t_linesw->l_no == IRFRAMEDISC) {
144 sc = (struct irframet_softc *)tp->t_sc;
145 DPRINTF(("%s: sc=%p sc_tp=%p\n", __FUNCTION__, sc, sc->sc_tp));
146 if (sc != NULL) {
147 splx(s);
148 return (EBUSY);
149 }
150 }
151
152 printf("%s attached at tty%d:", sc->sc_irp.sc_dev.dv_xname,
153 minor(tp->t_dev));
154 tp->t_sc = irframe_alloc(sizeof (struct irframet_softc),
155 &irframet_methods, tp);
156 sc = (struct irframet_softc *)tp->t_sc;
157 sc->sc_tp = tp;
158
159 DPRINTF(("%s: set sc=%p\n", __FUNCTION__, sc));
160
161 ttyflush(tp, FREAD | FWRITE);
162
163 splx(s);
164 return (0);
165 }
166
167 /*
168 * Line specific close routine, called from device close routine
169 * and from ttioctl.
170 * Detach the tty from the irframe unit.
171 * Mimics part of ttyclose().
172 */
173 int
174 irframetclose(struct tty *tp, int flag)
175 {
176 struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
177 int s;
178
179 DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
180
181 s = spltty();
182 ttyflush(tp, FREAD | FWRITE);
183 tp->t_linesw = linesw[0]; /* default line discipline */
184 if (sc != NULL) {
185 tp->t_sc = NULL;
186 printf("%s detached from tty%d\n", sc->sc_irp.sc_dev.dv_xname,
187 minor(tp->t_dev));
188
189 if (sc->sc_tp == tp)
190 irframe_dealloc(&sc->sc_irp.sc_dev);
191 }
192 splx(s);
193 return (0);
194 }
195
196 /*
197 * Line specific (tty) ioctl routine.
198 * This discipline requires that tty device drivers call
199 * the line specific l_ioctl routine from their ioctl routines.
200 */
201 /* ARGSUSED */
202 int
203 irframetioctl(struct tty *tp, u_long cmd, caddr_t data, int flag,
204 struct proc *p)
205 {
206 struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
207 int error;
208
209 DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
210
211 if (sc == NULL || tp != sc->sc_tp)
212 return (-1);
213
214 error = 0;
215 switch (cmd) {
216 default:
217 #if 0
218 error = irframeioctl(sc, cmd, data, flag, p);
219 #else
220 error = EINVAL;
221 #endif
222 break;
223 }
224
225 return (error);
226 }
227
228 /*
229 * Start output on async tty interface. If the transmit queue
230 * has drained sufficiently, arrange for irframeasyncstart to be
231 * called later at splsoftnet.
232 * Called at spltty or higher.
233 */
234 int
235 irframetstart(struct tty *tp)
236 {
237 /*struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;*/
238
239 DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
240
241 /*
242 * If there is stuff in the output queue, send it now.
243 * We are being called in lieu of ttstart and must do what it would.
244 */
245 if (tp->t_oproc != NULL)
246 (*tp->t_oproc)(tp);
247
248 return (0);
249 }
250
251 int
252 irframetinput(int c, struct tty *tp)
253 {
254 struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
255
256 DPRINTF(("%s: tp=%p c=0x%0x\n", __FUNCTION__, tp, c));
257
258 if (sc == NULL || tp != (struct tty *)sc->sc_tp)
259 return (0);
260 #if 0
261
262
263 ++tk_nin;
264 ++sc->sc_stats.irframe_ibytes;
265
266 if (c & TTY_FE) {
267 /* framing error or overrun on this char - abort packet */
268 if (sc->sc_flags & SC_DEBUG)
269 printf("%s: bad char %x\n", sc->sc_if.if_xname, c);
270 goto flush;
271 }
272
273 c &= 0xff;
274
275 /*
276 * Handle software flow control of output.
277 */
278 if (tp->t_iflag & IXON) {
279 if (c == tp->t_cc[VSTOP] && tp->t_cc[VSTOP] != _POSIX_VDISABLE) {
280 if ((tp->t_state & TS_TTSTOP) == 0) {
281 tp->t_state |= TS_TTSTOP;
282 (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
283 }
284 return 0;
285 }
286 if (c == tp->t_cc[VSTART] && tp->t_cc[VSTART] != _POSIX_VDISABLE) {
287 tp->t_state &= ~TS_TTSTOP;
288 if (tp->t_oproc != NULL)
289 (*tp->t_oproc)(tp);
290 return 0;
291 }
292 }
293
294 s = spltty();
295 if (c & 0x80)
296 sc->sc_flags |= SC_RCV_B7_1;
297 else
298 sc->sc_flags |= SC_RCV_B7_0;
299 if (paritytab[c >> 5] & (1 << (c & 0x1F)))
300 sc->sc_flags |= SC_RCV_ODDP;
301 else
302 sc->sc_flags |= SC_RCV_EVNP;
303 splx(s);
304
305 if (sc->sc_flags & SC_LOG_RAWIN)
306 irframelogchar(sc, c);
307
308 if (c == IRFRAME_FLAG) {
309 ilen = sc->sc_ilen;
310 sc->sc_ilen = 0;
311
312 if (sc->sc_rawin_count > 0)
313 irframelogchar(sc, -1);
314
315 /*
316 * If SC_ESCAPED is set, then we've seen the packet
317 * abort sequence "}~".
318 */
319 if (sc->sc_flags & (SC_FLUSH | SC_ESCAPED)
320 || (ilen > 0 && sc->sc_fcs != IRFRAME_GOODFCS)) {
321 s = spltty();
322 sc->sc_flags |= SC_PKTLOST; /* note the dropped packet */
323 if ((sc->sc_flags & (SC_FLUSH | SC_ESCAPED)) == 0){
324 if (sc->sc_flags & SC_DEBUG)
325 printf("%s: bad fcs %x\n", sc->sc_if.if_xname,
326 sc->sc_fcs);
327 sc->sc_if.if_ierrors++;
328 sc->sc_stats.irframe_ierrors++;
329 } else
330 sc->sc_flags &= ~(SC_FLUSH | SC_ESCAPED);
331 splx(s);
332 return 0;
333 }
334
335 if (ilen < IRFRAME_HDRLEN + IRFRAME_FCSLEN) {
336 if (ilen) {
337 if (sc->sc_flags & SC_DEBUG)
338 printf("%s: too short (%d)\n", sc->sc_if.if_xname, ilen);
339 s = spltty();
340 sc->sc_if.if_ierrors++;
341 sc->sc_stats.irframe_ierrors++;
342 sc->sc_flags |= SC_PKTLOST;
343 splx(s);
344 }
345 return 0;
346 }
347
348 /*
349 * Remove FCS trailer. Somewhat painful...
350 */
351 ilen -= 2;
352 if (--sc->sc_mc->m_len == 0) {
353 for (m = sc->sc_m; m->m_next != sc->sc_mc; m = m->m_next)
354 ;
355 sc->sc_mc = m;
356 }
357 sc->sc_mc->m_len--;
358
359 /* excise this mbuf chain */
360 m = sc->sc_m;
361 sc->sc_m = sc->sc_mc->m_next;
362 sc->sc_mc->m_next = NULL;
363
364 irframepktin(sc, m, sc->sc_flags & SC_PKTLOST);
365 if (sc->sc_flags & SC_PKTLOST) {
366 s = spltty();
367 sc->sc_flags &= ~SC_PKTLOST;
368 splx(s);
369 }
370
371 irframegetm(sc);
372 return 0;
373 }
374
375 if (sc->sc_flags & SC_FLUSH) {
376 if (sc->sc_flags & SC_LOG_FLUSH)
377 irframelogchar(sc, c);
378 return 0;
379 }
380
381 if (c < 0x20 && (sc->sc_rasyncmap & (1 << c)))
382 return 0;
383
384 s = spltty();
385 if (sc->sc_flags & SC_ESCAPED) {
386 sc->sc_flags &= ~SC_ESCAPED;
387 c ^= IRFRAME_TRANS;
388 } else if (c == IRFRAME_ESCAPE) {
389 sc->sc_flags |= SC_ESCAPED;
390 splx(s);
391 return 0;
392 }
393 splx(s);
394
395 /*
396 * Initialize buffer on first octet received.
397 * First octet could be address or protocol (when compressing
398 * address/control).
399 * Second octet is control.
400 * Third octet is first or second (when compressing protocol)
401 * octet of protocol.
402 * Fourth octet is second octet of protocol.
403 */
404 if (sc->sc_ilen == 0) {
405 /* reset the first input mbuf */
406 if (sc->sc_m == NULL) {
407 irframegetm(sc);
408 if (sc->sc_m == NULL) {
409 if (sc->sc_flags & SC_DEBUG)
410 printf("%s: no input mbufs!\n", sc->sc_if.if_xname);
411 goto flush;
412 }
413 }
414 m = sc->sc_m;
415 m->m_len = 0;
416 m->m_data = M_DATASTART(sc->sc_m);
417 sc->sc_mc = m;
418 sc->sc_mp = mtod(m, char *);
419 sc->sc_fcs = IRFRAME_INITFCS;
420 if (c != IRFRAME_ALLSTATIONS) {
421 if (sc->sc_flags & SC_REJ_COMP_AC) {
422 if (sc->sc_flags & SC_DEBUG)
423 printf("%s: garbage received: 0x%x (need 0xFF)\n",
424 sc->sc_if.if_xname, c);
425 goto flush;
426 }
427 *sc->sc_mp++ = IRFRAME_ALLSTATIONS;
428 *sc->sc_mp++ = IRFRAME_UI;
429 sc->sc_ilen += 2;
430 m->m_len += 2;
431 }
432 }
433 if (sc->sc_ilen == 1 && c != IRFRAME_UI) {
434 if (sc->sc_flags & SC_DEBUG)
435 printf("%s: missing UI (0x3), got 0x%x\n",
436 sc->sc_if.if_xname, c);
437 goto flush;
438 }
439 if (sc->sc_ilen == 2 && (c & 1) == 1) {
440 /* a compressed protocol */
441 *sc->sc_mp++ = 0;
442 sc->sc_ilen++;
443 sc->sc_mc->m_len++;
444 }
445 if (sc->sc_ilen == 3 && (c & 1) == 0) {
446 if (sc->sc_flags & SC_DEBUG)
447 printf("%s: bad protocol %x\n", sc->sc_if.if_xname,
448 (sc->sc_mp[-1] << 8) + c);
449 goto flush;
450 }
451
452 /* packet beyond configured mru? */
453 if (++sc->sc_ilen > sc->sc_mru + IRFRAME_HDRLEN + IRFRAME_FCSLEN) {
454 if (sc->sc_flags & SC_DEBUG)
455 printf("%s: packet too big\n", sc->sc_if.if_xname);
456 goto flush;
457 }
458
459 /* is this mbuf full? */
460 m = sc->sc_mc;
461 if (M_TRAILINGSPACE(m) <= 0) {
462 if (m->m_next == NULL) {
463 irframegetm(sc);
464 if (m->m_next == NULL) {
465 if (sc->sc_flags & SC_DEBUG)
466 printf("%s: too few input mbufs!\n", sc->sc_if.if_xname);
467 goto flush;
468 }
469 }
470 sc->sc_mc = m = m->m_next;
471 m->m_len = 0;
472 m->m_data = M_DATASTART(m);
473 sc->sc_mp = mtod(m, char *);
474 }
475
476 ++m->m_len;
477 *sc->sc_mp++ = c;
478 sc->sc_fcs = IRFRAME_FCS(sc->sc_fcs, c);
479 return 0;
480
481 flush:
482 if (!(sc->sc_flags & SC_FLUSH)) {
483 s = spltty();
484 sc->sc_if.if_ierrors++;
485 sc->sc_stats.irframe_ierrors++;
486 sc->sc_flags |= SC_FLUSH;
487 splx(s);
488 if (sc->sc_flags & SC_LOG_FLUSH)
489 irframelogchar(sc, c);
490 }
491 #endif
492 return 0;
493 }
494
495
496 /**********************************************************************
497 * CRC
498 **********************************************************************/
499
500 static const int fcstab[] = {
501 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
502 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
503 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
504 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
505 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
506 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
507 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
508 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
509 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
510 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
511 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
512 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
513 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
514 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
515 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
516 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
517 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
518 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
519 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
520 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
521 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
522 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
523 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
524 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
525 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
526 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
527 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
528 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
529 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
530 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
531 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
532 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
533 };
534
535 static const int INITFCS = 0xffff;
536 static const int GOODFCS = 0xf0b8;
537
538 static __inline int updateFCS(int fcs, int c) {
539 return (fcs >> 8) ^ fcstab[(fcs^c) & 0xff];
540 }
541
542 /*** irframe methods ***/
543
544 int
545 irframet_open(void *h, int flag, int mode, struct proc *p)
546 {
547 struct tty *tp = h;
548
549 tp = tp;
550 DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
551 return (0);
552 }
553
554 int
555 irframet_close(void *h, int flag, int mode, struct proc *p)
556 {
557 struct tty *tp = h;
558
559 tp = tp;
560 DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
561 return (0);
562 }
563
564 int
565 irframet_read(void *h, struct uio *uio, int flag)
566 {
567 struct tty *tp = h;
568
569 tp = tp;
570 DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
571 return (0);
572 }
573
574 static int
575 putch(int c, struct tty *tp)
576 {
577 int s;
578 int error;
579
580 if (tp->t_outq.c_cc > tp->t_hiwat) {
581 irframetstart(tp);
582 s = spltty();
583 /*
584 * This can only occur if FLUSHO is set in t_lflag,
585 * or if ttstart/oproc is synchronous (or very fast).
586 */
587 if (tp->t_outq.c_cc <= tp->t_hiwat) {
588 splx(s);
589 goto go;
590 }
591 SET(tp->t_state, TS_ASLEEP);
592 error = ttysleep(tp, &tp->t_outq, TTOPRI | PCATCH, ttyout, 0);
593 splx(s);
594 if (error)
595 return (error);
596 }
597 go:
598 if (putc(c, &tp->t_rawq) < 0) {
599 printf("irframe: putc failed\n");
600 return (EIO);
601 }
602 return (0);
603 }
604
605 static int
606 put_esc(int c, struct tty *tp)
607 {
608 int error;
609
610 if (c == SIR_BOF || c == SIR_EOF || c == SIR_CE) {
611 error = putch(SIR_CE, tp);
612 if (!error)
613 error = putch(SIR_ESC_BIT^c, tp);
614 } else {
615 error = putch(c, tp);
616 }
617 return (error);
618 }
619
620 int
621 irframet_write(void *h, struct uio *uio, int flag)
622 {
623 u_int8_t buf[MAX_IRDA_FRAME];
624 size_t n;
625 int error;
626
627 DPRINTF(("%s\n", __FUNCTION__));
628
629 n = uio->uio_resid;
630 if (n > MAX_IRDA_FRAME)
631 return (EINVAL);
632 error = uiomove(buf, n, uio);
633 if (error)
634 return (error);
635 return (irframet_write_buf(h, buf, n));
636 }
637
638 int
639 irframet_write_buf(void *h, void *buf, size_t len)
640 {
641 struct tty *tp = h;
642 struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
643 u_int8_t *cp = buf;
644 int c, error, ofcs, i;
645
646 DPRINTF(("%s: tp=%p len=%d\n", __FUNCTION__, tp, len));
647
648 ofcs = INITFCS;
649 error = 0;
650
651 for (i = 0; i < sc->sc_ebofs; i++)
652 putch(SIR_EXTRA_BOF, tp);
653 putch(SIR_BOF, tp);
654
655 while (len-- > 0) {
656 c = *cp++;
657 ofcs = updateFCS(ofcs, c);
658 error = put_esc(c, tp);
659 if (error)
660 return (error);
661 }
662
663 ofcs = ~ofcs;
664 error = put_esc(ofcs & 0xff, tp);
665 if (!error)
666 error = put_esc((ofcs >> 8) & 0xff, tp);
667 if (!error)
668 error = putch(SIR_EOF, tp);
669
670 irframetstart(tp);
671
672 return (error);
673 }
674
675 int
676 irframet_poll(void *h, int events, struct proc *p)
677 {
678 struct oboe_softc *sc = h;
679 int revents = 0;
680 int s;
681
682 DPRINTF(("%s: sc=%p\n", __FUNCTION__, sc));
683
684 s = splir();
685 if (events & (POLLOUT | POLLWRNORM))
686 revents |= events & (POLLOUT | POLLWRNORM);
687 #if 0
688 if (events & (POLLIN | POLLRDNORM)) {
689 if (sc->sc_saved > 0) {
690 DPRINTF(("%s: have data\n", __FUNCTION__));
691 revents |= events & (POLLIN | POLLRDNORM);
692 } else {
693 DPRINTF(("%s: recording select", __FUNCTION__));
694 selrecord(p, &sc->sc_rsel);
695 }
696 }
697 #endif
698 splx(s);
699
700 return (revents);
701 }
702
703 int
704 irframet_set_params(void *h, struct irda_params *p)
705 {
706 struct tty *tp = h;
707 struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
708
709 DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
710
711 /* XXX speed */
712 sc->sc_ebofs = p->ebofs;
713 /* XXX maxsize */
714
715 return (0);
716 }
717
718 int
719 irframet_reset_params(void *h)
720 {
721 struct tty *tp = h;
722 struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
723
724 DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
725
726 sc->sc_ebofs = IRDA_DEFAULT_EBOFS;
727
728 return (0);
729 }
730
731 int
732 irframet_get_speeds(void *h, int *speeds)
733 {
734 struct tty *tp = h;
735
736 tp = tp;
737 DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
738 *speeds = IRDA_SPEEDS_SIR;
739 return (0);
740 }
741
742 int
743 irframet_get_turnarounds(void *h, int *turnarounds)
744 {
745 struct tty *tp = h;
746
747 tp = tp;
748 DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
749 *turnarounds = IRDA_TURNT_10000;
750 return (0);
751 }
752