xref: /netbsd-src/sys/dev/usb/uirda.c (revision 8b0f9554ff8762542c4defc4f70e1eb76fb508fa)
1 /*	$NetBSD: uirda.c,v 1.27 2007/12/05 17:19:55 pooka 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@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 #include <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: uirda.c,v 1.27 2007/12/05 17:19:55 pooka Exp $");
41 
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/kernel.h>
45 #include <sys/device.h>
46 #include <sys/mutex.h>
47 #include <sys/ioctl.h>
48 #include <sys/conf.h>
49 #include <sys/file.h>
50 #include <sys/poll.h>
51 #include <sys/select.h>
52 #include <sys/proc.h>
53 
54 #include <dev/usb/usb.h>
55 #include <dev/usb/usbdi.h>
56 #include <dev/usb/usbdi_util.h>
57 #include <dev/usb/usbdevs.h>
58 
59 #include <dev/ir/ir.h>
60 #include <dev/ir/irdaio.h>
61 #include <dev/ir/irframevar.h>
62 
63 #include <dev/usb/uirdavar.h>
64 
65 #ifdef UIRDA_DEBUG
66 #define DPRINTF(x)	if (uirdadebug) logprintf x
67 #define DPRINTFN(n,x)	if (uirdadebug>(n)) logprintf x
68 int	uirdadebug = 0;
69 #else
70 #define DPRINTF(x)
71 #define DPRINTFN(n,x)
72 #endif
73 
74 
75 /* Class specific requests */
76 #define UR_IRDA_RECEIVING		0x01	/* Receive in progress? */
77 #define UR_IRDA_CHECK_MEDIA_BUSY	0x03
78 #define UR_IRDA_SET_RATE_SNIFF		0x04	/* opt */
79 #define UR_IRDA_SET_UNICAST_LIST	0x05	/* opt */
80 #define UR_IRDA_GET_DESC		0x06
81 
82 #define UIRDA_NEBOFS 8
83 static struct {
84 	int count;
85 	int mask;
86 	int header;
87 } uirda_ebofs[UIRDA_NEBOFS] = {
88 	{ 0, UI_EB_0, UIRDA_EB_0 },
89 	{ 1, UI_EB_1, UIRDA_EB_1 },
90 	{ 2, UI_EB_2, UIRDA_EB_2 },
91 	{ 3, UI_EB_3, UIRDA_EB_3 },
92 	{ 6, UI_EB_6, UIRDA_EB_6 },
93 	{ 12, UI_EB_12, UIRDA_EB_12 },
94 	{ 24, UI_EB_24, UIRDA_EB_24 },
95 	{ 48, UI_EB_48, UIRDA_EB_48 }
96 };
97 
98 #define UIRDA_NSPEEDS 9
99 static struct {
100 	int speed;
101 	int mask;
102 	int header;
103 } uirda_speeds[UIRDA_NSPEEDS] = {
104 	{ 4000000, UI_BR_4000000, UIRDA_4000000 },
105 	{ 1152000, UI_BR_1152000, UIRDA_1152000 },
106 	{ 576000, UI_BR_576000, UIRDA_576000 },
107 	{ 115200, UI_BR_115200, UIRDA_115200 },
108 	{ 57600, UI_BR_57600, UIRDA_57600 },
109 	{ 38400, UI_BR_38400, UIRDA_38400 },
110 	{ 19200, UI_BR_19200, UIRDA_19200 },
111 	{ 9600, UI_BR_9600, UIRDA_9600 },
112 	{ 2400, UI_BR_2400, UIRDA_2400 },
113 };
114 
115 
116 
117 int uirda_open(void *h, int flag, int mode, struct lwp *l);
118 int uirda_close(void *h, int flag, int mode, struct lwp *l);
119 int uirda_read(void *h, struct uio *uio, int flag);
120 int uirda_write(void *h, struct uio *uio, int flag);
121 int uirda_set_params(void *h, struct irda_params *params);
122 int uirda_get_speeds(void *h, int *speeds);
123 int uirda_get_turnarounds(void *h, int *times);
124 int uirda_poll(void *h, int events, struct lwp *l);
125 int uirda_kqfilter(void *h, struct knote *kn);
126 
127 struct irframe_methods uirda_methods = {
128 	uirda_open, uirda_close, uirda_read, uirda_write, uirda_poll,
129 	uirda_kqfilter, uirda_set_params, uirda_get_speeds,
130 	uirda_get_turnarounds
131 };
132 
133 void uirda_rd_cb(usbd_xfer_handle xfer,	usbd_private_handle priv,
134 		 usbd_status status);
135 usbd_status uirda_start_read(struct uirda_softc *sc);
136 
137 /*
138  * These devices don't quite follow the spec.  Speed changing is broken
139  * and they don't handle windows.
140  * But we change speed in a safe way, and don't use windows now.
141  * Some devices also seem to have an interrupt pipe that can be ignored.
142  *
143  * Table information taken from Linux driver.
144  */
145 Static const struct usb_devno uirda_devs[] = {
146 	{ USB_VENDOR_ACTISYS, USB_PRODUCT_ACTISYS_IR2000U },
147 	{ USB_VENDOR_EXTENDED, USB_PRODUCT_EXTENDED_XTNDACCESS },
148 	{ USB_VENDOR_KAWATSU, USB_PRODUCT_KAWATSU_KC180 },
149 };
150 #define uirda_lookup(v, p) (usb_lookup(uirda_devs, v, p))
151 
152 USB_DECLARE_DRIVER(uirda);
153 
154 USB_MATCH(uirda)
155 {
156 	USB_IFMATCH_START(uirda, uaa);
157 
158 	DPRINTFN(50,("uirda_match\n"));
159 
160 	if (uirda_lookup(uaa->vendor, uaa->product) != NULL)
161 		return (UMATCH_VENDOR_PRODUCT);
162 
163 	if (uaa->class == UICLASS_APPL_SPEC &&
164 	    uaa->subclass == UISUBCLASS_IRDA &&
165 	    uaa->proto == UIPROTO_IRDA)
166 		return (UMATCH_IFACECLASS_IFACESUBCLASS_IFACEPROTO);
167 	return (UMATCH_NONE);
168 }
169 
170 USB_ATTACH(uirda)
171 {
172 	USB_IFATTACH_START(uirda, sc, uaa);
173 	usbd_device_handle	dev = uaa->device;
174 	usbd_interface_handle	iface = uaa->iface;
175 	char			*devinfop;
176 	usb_endpoint_descriptor_t *ed;
177 	usbd_status		err;
178 	u_int8_t		epcount;
179 	u_int			specrev;
180 	int			i;
181 	struct ir_attach_args	ia;
182 
183 	DPRINTFN(10,("uirda_attach: sc=%p\n", sc));
184 
185 	devinfop = usbd_devinfo_alloc(dev, 0);
186 	USB_ATTACH_SETUP;
187 	printf("%s: %s\n", USBDEVNAME(sc->sc_dev), devinfop);
188 	usbd_devinfo_free(devinfop);
189 
190 	sc->sc_udev = dev;
191 	sc->sc_iface = iface;
192 
193 	if (sc->sc_hdszi == 0)
194 		sc->sc_hdszi = UIRDA_INPUT_HEADER_SIZE;
195 
196 	epcount = 0;
197 	(void)usbd_endpoint_count(iface, &epcount);
198 
199 	sc->sc_rd_addr = -1;
200 	sc->sc_wr_addr = -1;
201 	for (i = 0; i < epcount; i++) {
202 		ed = usbd_interface2endpoint_descriptor(iface, i);
203 		if (ed == NULL) {
204 			printf("%s: couldn't get ep %d\n",
205 			    USBDEVNAME(sc->sc_dev), i);
206 			USB_ATTACH_ERROR_RETURN;
207 		}
208 		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
209 		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
210 			sc->sc_rd_addr = ed->bEndpointAddress;
211 		} else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
212 			   UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
213 			sc->sc_wr_addr = ed->bEndpointAddress;
214 		}
215 	}
216 	if (sc->sc_rd_addr == -1 || sc->sc_wr_addr == -1) {
217 		printf("%s: missing endpoint\n", USBDEVNAME(sc->sc_dev));
218 		USB_ATTACH_ERROR_RETURN;
219 	}
220 
221 	if (sc->sc_loadfw(sc) != 0) {
222 		USB_ATTACH_ERROR_RETURN;
223 	}
224 
225 	/* Get the IrDA descriptor */
226 	err = usbd_get_class_desc(sc->sc_udev, UDESC_IRDA, 0,
227 		USB_IRDA_DESCRIPTOR_SIZE, &sc->sc_irdadesc);
228 	printf("error %d reading class desc\n", err);
229 	if (err) {
230 		err = usbd_get_desc(sc->sc_udev, UDESC_IRDA, 0,
231 		  USB_IRDA_DESCRIPTOR_SIZE, &sc->sc_irdadesc);
232 	}
233 	printf("error %d reading desc\n", err);
234 	if (err) {
235 		/* maybe it's embedded in the config desc? */
236 		usbd_desc_iter_t iter;
237 		const usb_descriptor_t *d;
238 		usb_desc_iter_init(sc->sc_udev, &iter);
239 		for (;;) {
240 			d = usb_desc_iter_next(&iter);
241 			if (!d || d->bDescriptorType == UDESC_IRDA)
242 				break;
243 		}
244 		if (d == NULL) {
245 			printf("%s: Cannot get IrDA descriptor\n",
246 			       USBDEVNAME(sc->sc_dev));
247 			USB_ATTACH_ERROR_RETURN;
248 		}
249 		memcpy(&sc->sc_irdadesc, d, USB_IRDA_DESCRIPTOR_SIZE);
250 	}
251 	DPRINTF(("uirda_attach: bDescriptorSize %d bDescriptorType 0x%x "
252 		 "bmDataSize=0x%02x bmWindowSize=0x%02x "
253 		 "bmMinTurnaroundTime=0x%02x wBaudRate=0x%04x "
254 		 "bmAdditionalBOFs=0x%02x bIrdaSniff=%d bMaxUnicastList=%d\n",
255 		 sc->sc_irdadesc.bLength,
256 		 sc->sc_irdadesc.bDescriptorType,
257 		 sc->sc_irdadesc.bmDataSize,
258 		 sc->sc_irdadesc.bmWindowSize,
259 		 sc->sc_irdadesc.bmMinTurnaroundTime,
260 		 UGETW(sc->sc_irdadesc.wBaudRate),
261 		 sc->sc_irdadesc.bmAdditionalBOFs,
262 		 sc->sc_irdadesc.bIrdaSniff,
263 		 sc->sc_irdadesc.bMaxUnicastList));
264 
265 	specrev = UGETW(sc->sc_irdadesc.bcdSpecRevision);
266 	printf("%s: USB-IrDA protocol version %x.%02x\n",
267 	       USBDEVNAME(sc->sc_dev), specrev >> 8, specrev & 0xff);
268 
269 	DPRINTFN(10, ("uirda_attach: %p\n", sc->sc_udev));
270 
271 	usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
272 			   USBDEV(sc->sc_dev));
273 
274 	mutex_init(&sc->sc_wr_buf_lk, MUTEX_DEFAULT, IPL_NONE);
275 	mutex_init(&sc->sc_rd_buf_lk, MUTEX_DEFAULT, IPL_NONE);
276 
277 	ia.ia_type = IR_TYPE_IRFRAME;
278 	ia.ia_methods = sc->sc_irm ? sc->sc_irm : &uirda_methods;
279 	ia.ia_handle = sc;
280 
281 	sc->sc_child = config_found(self, &ia, ir_print);
282 
283 	USB_ATTACH_SUCCESS_RETURN;
284 }
285 
286 USB_DETACH(uirda)
287 {
288 	USB_DETACH_START(uirda, sc);
289 	int s;
290 	int rv = 0;
291 
292 	DPRINTF(("uirda_detach: sc=%p flags=%d\n", sc, flags));
293 
294 	sc->sc_dying = 1;
295 	/* Abort all pipes.  Causes processes waiting for transfer to wake. */
296 	if (sc->sc_rd_pipe != NULL) {
297 		usbd_abort_pipe(sc->sc_rd_pipe);
298 		usbd_close_pipe(sc->sc_rd_pipe);
299 		sc->sc_rd_pipe = NULL;
300 	}
301 	if (sc->sc_wr_pipe != NULL) {
302 		usbd_abort_pipe(sc->sc_wr_pipe);
303 		usbd_close_pipe(sc->sc_wr_pipe);
304 		sc->sc_wr_pipe = NULL;
305 	}
306 	wakeup(&sc->sc_rd_count);
307 
308 	s = splusb();
309 	if (--sc->sc_refcnt >= 0) {
310 		/* Wait for processes to go away. */
311 		usb_detach_wait(USBDEV(sc->sc_dev));
312 	}
313 	splx(s);
314 
315 	if (sc->sc_child != NULL) {
316 		rv = config_detach(sc->sc_child, flags);
317 		sc->sc_child = NULL;
318 	}
319 
320 	usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
321 			   USBDEV(sc->sc_dev));
322 
323 	mutex_destroy(&sc->sc_wr_buf_lk);
324 	mutex_destroy(&sc->sc_rd_buf_lk);
325 
326 	return (rv);
327 }
328 
329 int
330 uirda_activate(device_ptr_t self, enum devact act)
331 {
332 	struct uirda_softc *sc = (struct uirda_softc *)self;
333 	int error = 0;
334 
335 	switch (act) {
336 	case DVACT_ACTIVATE:
337 		return (EOPNOTSUPP);
338 		break;
339 
340 	case DVACT_DEACTIVATE:
341 		sc->sc_dying = 1;
342 		if (sc->sc_child != NULL)
343 			error = config_deactivate(sc->sc_child);
344 		break;
345 	}
346 	return (error);
347 }
348 
349 int
350 uirda_open(void *h, int flag, int mode,
351     struct lwp *l)
352 {
353 	struct uirda_softc *sc = h;
354 	int error;
355 	usbd_status err;
356 
357 	DPRINTF(("%s: sc=%p\n", __func__, sc));
358 
359 	err = usbd_open_pipe(sc->sc_iface, sc->sc_rd_addr, 0, &sc->sc_rd_pipe);
360 	if (err) {
361 		error = EIO;
362 		goto bad1;
363 	}
364 	err = usbd_open_pipe(sc->sc_iface, sc->sc_wr_addr, 0, &sc->sc_wr_pipe);
365 	if (err) {
366 		error = EIO;
367 		goto bad2;
368 	}
369 	sc->sc_rd_xfer = usbd_alloc_xfer(sc->sc_udev);
370 	if (sc->sc_rd_xfer == NULL) {
371 		error = ENOMEM;
372 		goto bad3;
373 	}
374 	sc->sc_wr_xfer = usbd_alloc_xfer(sc->sc_udev);
375 	if (sc->sc_wr_xfer == NULL) {
376 		error = ENOMEM;
377 		goto bad4;
378 	}
379 	sc->sc_rd_buf = usbd_alloc_buffer(sc->sc_rd_xfer,
380 			    IRDA_MAX_FRAME_SIZE + sc->sc_hdszi);
381 	if (sc->sc_rd_buf == NULL) {
382 		error = ENOMEM;
383 		goto bad5;
384 	}
385 	sc->sc_wr_buf = usbd_alloc_buffer(sc->sc_wr_xfer,
386 			    IRDA_MAX_FRAME_SIZE + UIRDA_OUTPUT_HEADER_SIZE +
387 				2 + 1 /* worst case ST-UIRDA */);
388 	if (sc->sc_wr_buf == NULL) {
389 		error = ENOMEM;
390 		goto bad5;
391 	}
392 	sc->sc_rd_count = 0;
393 	sc->sc_rd_err = 0;
394 	sc->sc_params.speed = 0;
395 	sc->sc_params.ebofs = 0;
396 	sc->sc_params.maxsize = IRDA_MAX_FRAME_SIZE;
397 	sc->sc_wr_hdr = -1;
398 
399 	err = uirda_start_read(sc);
400 	/* XXX check err */
401 
402 	return (0);
403 
404 bad5:
405 	usbd_free_xfer(sc->sc_wr_xfer);
406 	sc->sc_wr_xfer = NULL;
407 bad4:
408 	usbd_free_xfer(sc->sc_rd_xfer);
409 	sc->sc_rd_xfer = NULL;
410 bad3:
411 	usbd_close_pipe(sc->sc_wr_pipe);
412 	sc->sc_wr_pipe = NULL;
413 bad2:
414 	usbd_close_pipe(sc->sc_rd_pipe);
415 	sc->sc_rd_pipe = NULL;
416 bad1:
417 	return (error);
418 }
419 
420 int
421 uirda_close(void *h, int flag, int mode,
422     struct lwp *l)
423 {
424 	struct uirda_softc *sc = h;
425 
426 	DPRINTF(("%s: sc=%p\n", __func__, sc));
427 
428 	if (sc->sc_rd_pipe != NULL) {
429 		usbd_abort_pipe(sc->sc_rd_pipe);
430 		usbd_close_pipe(sc->sc_rd_pipe);
431 		sc->sc_rd_pipe = NULL;
432 	}
433 	if (sc->sc_wr_pipe != NULL) {
434 		usbd_abort_pipe(sc->sc_wr_pipe);
435 		usbd_close_pipe(sc->sc_wr_pipe);
436 		sc->sc_wr_pipe = NULL;
437 	}
438 	if (sc->sc_rd_xfer != NULL) {
439 		usbd_free_xfer(sc->sc_rd_xfer);
440 		sc->sc_rd_xfer = NULL;
441 		sc->sc_rd_buf = NULL;
442 	}
443 	if (sc->sc_wr_xfer != NULL) {
444 		usbd_free_xfer(sc->sc_wr_xfer);
445 		sc->sc_wr_xfer = NULL;
446 		sc->sc_wr_buf = NULL;
447 	}
448 
449 	return (0);
450 }
451 
452 int
453 uirda_read(void *h, struct uio *uio, int flag)
454 {
455 	struct uirda_softc *sc = h;
456 	usbd_status err;
457 	int s;
458 	int error;
459 	u_int n;
460 
461 	DPRINTFN(1,("%s: sc=%p\n", __func__, sc));
462 
463 	if (sc->sc_dying)
464 		return (EIO);
465 
466 #ifdef DIAGNOSTIC
467 	if (sc->sc_rd_buf == NULL)
468 		return (EINVAL);
469 #endif
470 
471 	sc->sc_refcnt++;
472 
473 	do {
474 		s = splusb();
475 		while (sc->sc_rd_count == 0) {
476 			DPRINTFN(5,("uirda_read: calling tsleep()\n"));
477 			error = tsleep(&sc->sc_rd_count, PZERO | PCATCH,
478 				       "uirdrd", 0);
479 			if (sc->sc_dying)
480 				error = EIO;
481 			if (error) {
482 				splx(s);
483 				DPRINTF(("uirda_read: tsleep() = %d\n", error));
484 				goto ret;
485 			}
486 		}
487 		splx(s);
488 
489 		mutex_enter(&sc->sc_rd_buf_lk);
490 		n = sc->sc_rd_count - sc->sc_hdszi;
491 		DPRINTFN(1,("%s: sc=%p n=%u, hdr=0x%02x\n", __func__,
492 			    sc, n, sc->sc_rd_buf[0]));
493 		if (n > uio->uio_resid)
494 			error = EINVAL;
495 		else
496 			error = uiomove(sc->sc_rd_buf + sc->sc_hdszi, n, uio);
497 		sc->sc_rd_count = 0;
498 		mutex_exit(&sc->sc_rd_buf_lk);
499 
500 		err = uirda_start_read(sc);
501 		/* XXX check err */
502 
503 	} while (n == 0);
504 
505 	DPRINTFN(1,("uirda_read: return %d\n", error));
506 
507  ret:
508 	if (--sc->sc_refcnt < 0)
509 		usb_detach_wakeup(USBDEV(sc->sc_dev));
510 	return (error);
511 }
512 
513 int
514 uirda_write(void *h, struct uio *uio, int flag)
515 {
516 	struct uirda_softc *sc = h;
517 	usbd_status err;
518 	u_int32_t n;
519 	int error = 0;
520 
521 	DPRINTFN(1,("%s: sc=%p\n", __func__, sc));
522 
523 	if (sc->sc_dying)
524 		return (EIO);
525 
526 #ifdef DIAGNOSTIC
527 	if (sc->sc_wr_buf == NULL)
528 		return (EINVAL);
529 #endif
530 
531 	n = uio->uio_resid;
532 	if (n > sc->sc_params.maxsize)
533 		return (EINVAL);
534 
535 	sc->sc_refcnt++;
536 	mutex_enter(&sc->sc_wr_buf_lk);
537 
538 	sc->sc_wr_buf[0] = UIRDA_EB_NO_CHANGE | UIRDA_NO_SPEED;
539 	error = uiomove(sc->sc_wr_buf + UIRDA_OUTPUT_HEADER_SIZE, n, uio);
540 	if (!error) {
541 		DPRINTFN(1, ("uirdawrite: transfer %d bytes\n", n));
542 
543 		n += UIRDA_OUTPUT_HEADER_SIZE;
544 		err = usbd_bulk_transfer(sc->sc_wr_xfer, sc->sc_wr_pipe,
545 			  USBD_FORCE_SHORT_XFER | USBD_NO_COPY,
546 			  UIRDA_WR_TIMEOUT,
547 			  sc->sc_wr_buf, &n, "uirdawr");
548 		DPRINTFN(2, ("uirdawrite: err=%d\n", err));
549 		if (err) {
550 			if (err == USBD_INTERRUPTED)
551 				error = EINTR;
552 			else if (err == USBD_TIMEOUT)
553 				error = ETIMEDOUT;
554 			else
555 				error = EIO;
556 		}
557 	}
558 
559 	mutex_exit(&sc->sc_wr_buf_lk);
560 	if (--sc->sc_refcnt < 0)
561 		usb_detach_wakeup(USBDEV(sc->sc_dev));
562 
563 	DPRINTFN(1,("%s: sc=%p done\n", __func__, sc));
564 	return (error);
565 }
566 
567 int
568 uirda_poll(void *h, int events, struct lwp *l)
569 {
570 	struct uirda_softc *sc = h;
571 	int revents = 0;
572 	int s;
573 
574 	DPRINTFN(1,("%s: sc=%p\n", __func__, sc));
575 
576 	s = splusb();
577 	if (events & (POLLOUT | POLLWRNORM))
578 		revents |= events & (POLLOUT | POLLWRNORM);
579 	if (events & (POLLIN | POLLRDNORM)) {
580 		if (sc->sc_rd_count != 0) {
581 			DPRINTFN(2,("%s: have data\n", __func__));
582 			revents |= events & (POLLIN | POLLRDNORM);
583 		} else {
584 			DPRINTFN(2,("%s: recording select\n", __func__));
585 			selrecord(l, &sc->sc_rd_sel);
586 		}
587 	}
588 	splx(s);
589 
590 	return (revents);
591 }
592 
593 static void
594 filt_uirdardetach(struct knote *kn)
595 {
596 	struct uirda_softc *sc = kn->kn_hook;
597 	int s;
598 
599 	s = splusb();
600 	SLIST_REMOVE(&sc->sc_rd_sel.sel_klist, kn, knote, kn_selnext);
601 	splx(s);
602 }
603 
604 static int
605 filt_uirdaread(struct knote *kn, long hint)
606 {
607 	struct uirda_softc *sc = kn->kn_hook;
608 
609 	kn->kn_data = sc->sc_rd_count;
610 	return (kn->kn_data > 0);
611 }
612 
613 static void
614 filt_uirdawdetach(struct knote *kn)
615 {
616 	struct uirda_softc *sc = kn->kn_hook;
617 	int s;
618 
619 	s = splusb();
620 	SLIST_REMOVE(&sc->sc_wr_sel.sel_klist, kn, knote, kn_selnext);
621 	splx(s);
622 }
623 
624 static const struct filterops uirdaread_filtops =
625 	{ 1, NULL, filt_uirdardetach, filt_uirdaread };
626 static const struct filterops uirdawrite_filtops =
627 	{ 1, NULL, filt_uirdawdetach, filt_seltrue };
628 
629 int
630 uirda_kqfilter(void *h, struct knote *kn)
631 {
632 	struct uirda_softc *sc = kn->kn_hook;
633 	struct klist *klist;
634 	int s;
635 
636 	switch (kn->kn_filter) {
637 	case EVFILT_READ:
638 		klist = &sc->sc_rd_sel.sel_klist;
639 		kn->kn_fop = &uirdaread_filtops;
640 		break;
641 	case EVFILT_WRITE:
642 		klist = &sc->sc_wr_sel.sel_klist;
643 		kn->kn_fop = &uirdawrite_filtops;
644 		break;
645 	default:
646 		return (EINVAL);
647 	}
648 
649 	kn->kn_hook = sc;
650 
651 	s = splusb();
652 	SLIST_INSERT_HEAD(klist, kn, kn_selnext);
653 	splx(s);
654 
655 	return (0);
656 }
657 
658 int
659 uirda_set_params(void *h, struct irda_params *p)
660 {
661 	struct uirda_softc *sc = h;
662 	usbd_status err;
663 	int i;
664 	u_int8_t hdr;
665 	u_int32_t n;
666 	u_int mask;
667 
668 	DPRINTF(("%s: sc=%p, speed=%d ebofs=%d maxsize=%d\n", __func__,
669 		 sc, p->speed, p->ebofs, p->maxsize));
670 
671 	if (sc->sc_dying)
672 		return (EIO);
673 
674 	hdr = 0;
675 	if (p->ebofs != sc->sc_params.ebofs) {
676 		/* round up ebofs */
677 		mask = 1 /* sc->sc_irdadesc.bmAdditionalBOFs*/;
678 		DPRINTF(("u.s.p.: mask=0x%x, sc->ebofs=%d, p->ebofs=%d\n",
679 			mask, sc->sc_params.ebofs, p->ebofs));
680 		for (i = 0; i < UIRDA_NEBOFS; i++) {
681 			DPRINTF(("u.s.p.: u_e[%d].mask=0x%x, count=%d\n",
682 				i, uirda_ebofs[i].mask, uirda_ebofs[i].count));
683 			if ((mask & uirda_ebofs[i].mask) &&
684 			    uirda_ebofs[i].count >= p->ebofs) {
685 				hdr = uirda_ebofs[i].header;
686 				goto found1;
687 			}
688 		}
689 		for (i = 0; i < UIRDA_NEBOFS; i++) {
690 			DPRINTF(("u.s.p.: u_e[%d].mask=0x%x, count=%d\n",
691 				i, uirda_ebofs[i].mask, uirda_ebofs[i].count));
692 			if ((mask & uirda_ebofs[i].mask)) {
693 				hdr = uirda_ebofs[i].header;
694 				goto found1;
695 			}
696 		}
697 		/* no good value found */
698 		return (EINVAL);
699 	found1:
700 		DPRINTF(("uirda_set_params: ebofs hdr=0x%02x\n", hdr));
701 		;
702 
703 	}
704 	if (hdr != 0 || p->speed != sc->sc_params.speed) {
705 		/* find speed */
706 		mask = UGETW(sc->sc_irdadesc.wBaudRate);
707 		for (i = 0; i < UIRDA_NSPEEDS; i++) {
708 			if ((mask & uirda_speeds[i].mask) &&
709 			    uirda_speeds[i].speed == p->speed) {
710 				hdr |= uirda_speeds[i].header;
711 				goto found2;
712 			}
713 		}
714 		/* no good value found */
715 		return (EINVAL);
716 	found2:
717 		DPRINTF(("uirda_set_params: speed hdr=0x%02x\n", hdr));
718 		;
719 	}
720 	if (p->maxsize != sc->sc_params.maxsize) {
721 		if (p->maxsize > IRDA_MAX_FRAME_SIZE)
722 			return (EINVAL);
723 		sc->sc_params.maxsize = p->maxsize;
724 #if 0
725 		DPRINTF(("%s: new buffers, old size=%d\n", __func__,
726 			 sc->sc_params.maxsize));
727 		if (p->maxsize > 10000 || p < 0) /* XXX */
728 			return (EINVAL);
729 
730 		/* Change the write buffer */
731 		mutex_enter(&sc->sc_wr_buf_lk);
732 		if (sc->sc_wr_buf != NULL)
733 			usbd_free_buffer(sc->sc_wr_xfer);
734 		sc->sc_wr_buf = usbd_alloc_buffer(sc->sc_wr_xfer, p->maxsize+1);
735 		mutex_exit(&sc->sc_wr_buf_lk);
736 		if (sc->sc_wr_buf == NULL)
737 			return (ENOMEM);
738 
739 		/* Change the read buffer */
740 		mutex_enter(&sc->sc_rd_buf_lk);
741 		usbd_abort_pipe(sc->sc_rd_pipe);
742 		if (sc->sc_rd_buf != NULL)
743 			usbd_free_buffer(sc->sc_rd_xfer);
744 		sc->sc_rd_buf = usbd_alloc_buffer(sc->sc_rd_xfer, p->maxsize+1);
745 		sc->sc_rd_count = 0;
746 		if (sc->sc_rd_buf == NULL) {
747 			mutex_exit(&sc->sc_rd_buf_lk);
748 			return (ENOMEM);
749 		}
750 		sc->sc_params.maxsize = p->maxsize;
751 		err = uirda_start_read(sc); /* XXX check */
752 		mutex_exit(&sc->sc_rd_buf_lk);
753 #endif
754 	}
755 	if (hdr != 0 && hdr != sc->sc_wr_hdr) {
756 		/*
757 		 * A change has occurred, transmit a 0 length frame with
758 		 * the new settings.  The 0 length frame is not sent to the
759 		 * device.
760 		 */
761 		DPRINTF(("%s: sc=%p setting header 0x%02x\n",
762 			 __func__, sc, hdr));
763 		sc->sc_wr_hdr = hdr;
764 		mutex_enter(&sc->sc_wr_buf_lk);
765 		sc->sc_wr_buf[0] = hdr;
766 		n = UIRDA_OUTPUT_HEADER_SIZE;
767 		err = usbd_bulk_transfer(sc->sc_wr_xfer, sc->sc_wr_pipe,
768 			  USBD_FORCE_SHORT_XFER | USBD_NO_COPY,
769 			  UIRDA_WR_TIMEOUT, sc->sc_wr_buf, &n, "uirdast");
770 		if (err) {
771 			printf("%s: set failed, err=%d\n",
772 			    USBDEVNAME(sc->sc_dev), err);
773 			usbd_clear_endpoint_stall(sc->sc_wr_pipe);
774 		}
775 		mutex_exit(&sc->sc_wr_buf_lk);
776 	}
777 
778 	sc->sc_params = *p;
779 
780 	return (0);
781 }
782 
783 int
784 uirda_get_speeds(void *h, int *speeds)
785 {
786 	struct uirda_softc *sc = h;
787 	u_int isp;
788 	u_int usp;
789 
790 	DPRINTF(("%s: sc=%p\n", __func__, sc));
791 
792 	if (sc->sc_dying)
793 		return (EIO);
794 
795 	usp = UGETW(sc->sc_irdadesc.wBaudRate);
796 	isp = 0;
797 	if (usp & UI_BR_4000000) isp |= IRDA_SPEED_4000000;
798 	if (usp & UI_BR_1152000) isp |= IRDA_SPEED_1152000;
799 	if (usp & UI_BR_576000)  isp |= IRDA_SPEED_576000;
800 	if (usp & UI_BR_115200)  isp |= IRDA_SPEED_115200;
801 	if (usp & UI_BR_57600)   isp |= IRDA_SPEED_57600;
802 	if (usp & UI_BR_38400)   isp |= IRDA_SPEED_38400;
803 	if (usp & UI_BR_19200)   isp |= IRDA_SPEED_19200;
804 	if (usp & UI_BR_9600)    isp |= IRDA_SPEED_9600;
805 	if (usp & UI_BR_2400)    isp |= IRDA_SPEED_2400;
806 	*speeds = isp;
807 	DPRINTF(("%s: speeds = 0x%x\n", __func__, isp));
808 	return (0);
809 }
810 
811 int
812 uirda_get_turnarounds(void *h, int *turnarounds)
813 {
814 	struct uirda_softc *sc = h;
815 	u_int ita;
816 	u_int uta;
817 
818 	DPRINTF(("%s: sc=%p\n", __func__, sc));
819 
820 	if (sc->sc_dying)
821 		return (EIO);
822 
823 	uta = sc->sc_irdadesc.bmMinTurnaroundTime;
824 	ita = 0;
825 	if (uta & UI_TA_0)     ita |= IRDA_TURNT_0;
826 	if (uta & UI_TA_10)    ita |= IRDA_TURNT_10;
827 	if (uta & UI_TA_50)    ita |= IRDA_TURNT_50;
828 	if (uta & UI_TA_100)   ita |= IRDA_TURNT_100;
829 	if (uta & UI_TA_500)   ita |= IRDA_TURNT_500;
830 	if (uta & UI_TA_1000)  ita |= IRDA_TURNT_1000;
831 	if (uta & UI_TA_5000)  ita |= IRDA_TURNT_5000;
832 	if (uta & UI_TA_10000) ita |= IRDA_TURNT_10000;
833 	*turnarounds = ita;
834 	return (0);
835 }
836 
837 void
838 uirda_rd_cb(usbd_xfer_handle xfer, usbd_private_handle priv,
839 	    usbd_status status)
840 {
841 	struct uirda_softc *sc = priv;
842 	u_int32_t size;
843 
844 	DPRINTFN(1,("%s: sc=%p\n", __func__, sc));
845 
846 	if (status == USBD_CANCELLED) /* this is normal */
847 		return;
848 	if (status) {
849 		size = sc->sc_hdszi;
850 		sc->sc_rd_err = 1;
851 	} else {
852 		usbd_get_xfer_status(xfer, NULL, NULL, &size, NULL);
853 	}
854 	DPRINTFN(1,("%s: sc=%p size=%u, err=%d\n", __func__, sc, size,
855 		    sc->sc_rd_err));
856 	sc->sc_rd_count = size;
857 	wakeup(&sc->sc_rd_count); /* XXX should use flag */
858 	selnotify(&sc->sc_rd_sel, 0);
859 }
860 
861 usbd_status
862 uirda_start_read(struct uirda_softc *sc)
863 {
864 	usbd_status err;
865 
866 	DPRINTFN(1,("%s: sc=%p, size=%d\n", __func__, sc,
867 		    sc->sc_params.maxsize + UIRDA_INPUT_HEADER_SIZE));
868 
869 	if (sc->sc_dying)
870 		return (USBD_IOERROR);
871 
872 	if (sc->sc_rd_err) {
873 		sc->sc_rd_err = 0;
874 		DPRINTF(("uirda_start_read: clear stall\n"));
875 		usbd_clear_endpoint_stall(sc->sc_rd_pipe);
876 	}
877 
878 	usbd_setup_xfer(sc->sc_rd_xfer, sc->sc_rd_pipe, sc, sc->sc_rd_buf,
879 			sc->sc_params.maxsize + sc->sc_hdszi,
880 			USBD_SHORT_XFER_OK | USBD_NO_COPY,
881 			USBD_NO_TIMEOUT, uirda_rd_cb);
882 	err = usbd_transfer(sc->sc_rd_xfer);
883 	if (err != USBD_IN_PROGRESS) {
884 		DPRINTF(("uirda_start_read: err=%d\n", err));
885 		return (err);
886 	}
887 	return (USBD_NORMAL_COMPLETION);
888 }
889 
890 usbd_status
891 usbd_get_class_desc(usbd_device_handle dev, int type, int index, int len, void *desc)
892 {
893 	usb_device_request_t req;
894 
895 	DPRINTFN(3,("usbd_get_desc: type=%d, index=%d, len=%d\n",
896 		    type, index, len));
897 
898 	req.bmRequestType = 0xa1; /* XXX ? */
899 	req.bRequest = UR_GET_DESCRIPTOR;
900 	USETW2(req.wValue, type, index);
901 	USETW(req.wIndex, 0);
902 	USETW(req.wLength, len);
903 	return (usbd_do_request(dev, &req, desc));
904 }
905