57cb0d4f144db453447b51df63d8fee427091a59
[dragonfly.git] / sys / dev / usbmisc / urio / urio.c
1 /*
2  * Copyright (c) 2000 Iwasa Kazmi
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions, and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
18  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * This code is based on ugen.c and ulpt.c developed by Lennart Augustsson.
27  * This code includes software developed by the NetBSD Foundation, Inc. and
28  * its contributors.
29  */
30
31 /*
32  * $FreeBSD: src/sys/dev/usb/urio.c,v 1.28 2003/08/25 22:01:06 joe Exp $
33  * $DragonFly: src/sys/dev/usbmisc/urio/urio.c,v 1.9 2004/05/13 23:49:22 dillon Exp $
34  */
35
36 /*
37  * 2000/3/24  added NetBSD/OpenBSD support (from Alex Nemirovsky)
38  * 2000/3/07  use two bulk-pipe handles for read and write (Dirk)
39  * 2000/3/06  change major number(143), and copyright header
40  *            some fix for 4.0 (Dirk)
41  * 2000/3/05  codes for FreeBSD 4.x - CURRENT (Thanks to Dirk-Willem van Gulik)
42  * 2000/3/01  remove retry code from urioioctl()
43  *            change method of bulk transfer (no interrupt)
44  * 2000/2/28  small fixes for new rio_usb.h
45  * 2000/2/24  first version.
46  */
47
48 #include <sys/param.h>
49 #include <sys/systm.h>
50 #include <sys/kernel.h>
51 #include <sys/malloc.h>
52 #if defined(__NetBSD__)
53 #include <sys/device.h>
54 #include <sys/ioctl.h>
55 #elif defined(__FreeBSD__) || defined(__DragonFly__)
56 #include <sys/module.h>
57 #include <sys/bus.h>
58 #include <sys/ioccom.h>
59 #endif
60 #include <sys/fcntl.h>
61 #include <sys/filio.h>
62 #include <sys/conf.h>
63 #include <sys/uio.h>
64 #include <sys/tty.h>
65 #include <sys/file.h>
66 #if defined(__FreeBSD__) && __FreeBSD_version >= 500014
67 #include <sys/selinfo.h>
68 #else
69 #include <sys/select.h>
70 #endif
71 #include <sys/vnode.h>
72 #include <sys/poll.h>
73 #include <sys/sysctl.h>
74 #include <sys/proc.h>
75
76 #include <bus/usb/usb.h>
77 #include <bus/usb/usbdi.h>
78 #include <bus/usb/usbdi_util.h>
79
80 #include <bus/usb/usbdevs.h>
81 #include <bus/usb/rio500_usb.h>
82
83 #ifdef USB_DEBUG
84 #define DPRINTF(x)      if (uriodebug) logprintf x
85 #define DPRINTFN(n,x)   if (uriodebug>(n)) logprintf x
86 int     uriodebug = 0;
87 SYSCTL_NODE(_hw_usb, OID_AUTO, urio, CTLFLAG_RW, 0, "USB urio");
88 SYSCTL_INT(_hw_usb_urio, OID_AUTO, debug, CTLFLAG_RW,
89            &uriodebug, 0, "urio debug level");
90 #else
91 #define DPRINTF(x)
92 #define DPRINTFN(n,x)
93 #endif
94
95 /* difference of usbd interface */
96 #define USBDI 1
97
98 #define RIO_OUT 0
99 #define RIO_IN  1
100 #define RIO_NODIR  2
101
102 #if defined(__NetBSD__)
103 int urioopen(dev_t, int, int, struct proc *);
104 int urioclose(dev_t, int, int, struct proc *p);
105 int urioread(dev_t, struct uio *uio, int);
106 int uriowrite(dev_t, struct uio *uio, int);
107 int urioioctl(dev_t, u_long, caddr_t, int, struct proc *);
108
109 cdev_decl(urio);
110 #define RIO_UE_GET_DIR(p) ((UE_GET_DIR(p) == UE_DIR_IN) ? RIO_IN :\
111                           ((UE_GET_DIR(p) == UE_DIR_OUT) ? RIO_OUT :\
112                                                            RIO_NODIR))
113 #elif defined(__FreeBSD__) || defined(__DragonFly__)
114 d_open_t  urioopen;
115 d_close_t urioclose;
116 d_read_t  urioread;
117 d_write_t uriowrite;
118 d_ioctl_t urioioctl;
119
120 #define URIO_CDEV_MAJOR 143
121
122 Static struct cdevsw urio_cdevsw = {
123         /* name */      "urio",         
124         /* cmaj */      URIO_CDEV_MAJOR,
125         /* flags */     0,
126         /* port */      NULL,
127         /* clone */     NULL,
128         urioopen,       urioclose,      urioread,       uriowrite,
129         urioioctl,      nopoll,         nommap,         nostrategy,
130         nodump,         nopsize
131 };
132 #define RIO_UE_GET_DIR(p) ((UE_GET_DIR(p) == UE_DIR_IN) ? RIO_IN :\
133                           ((UE_GET_DIR(p) == UE_DIR_OUT) ? RIO_OUT :\
134                                                            RIO_NODIR))
135 #endif  /*defined(__FreeBSD__)*/
136
137 #define URIO_BBSIZE     1024
138
139 struct urio_softc {
140         USBBASEDEVICE sc_dev;
141         usbd_device_handle sc_udev;
142         usbd_interface_handle sc_iface;
143
144         int sc_opened;
145         usbd_pipe_handle sc_pipeh_in;
146         usbd_pipe_handle sc_pipeh_out;
147         int sc_epaddr[2];
148
149         int sc_refcnt;
150 #if defined(__FreeBSD__) || defined(__DragonFly__)
151         dev_t sc_dev_t;
152 #endif  /* defined(__FreeBSD__) */
153 #if defined(__NetBSD__) || defined(__OpenBSD__)
154         u_char sc_dying;
155 #endif
156 };
157
158 #define URIOUNIT(n) (minor(n))
159
160 #define RIO_RW_TIMEOUT 4000     /* ms */
161
162 USB_DECLARE_DRIVER(urio);
163
164 USB_MATCH(urio)
165 {
166         USB_MATCH_START(urio, uaa);
167         usb_device_descriptor_t *dd;
168
169         DPRINTFN(10,("urio_match\n"));
170         if (!uaa->iface)
171                 return UMATCH_NONE;
172
173         dd = usbd_get_device_descriptor(uaa->device);
174
175         if (dd &&
176             ((UGETW(dd->idVendor) == USB_VENDOR_DIAMOND &&
177             UGETW(dd->idProduct) == USB_PRODUCT_DIAMOND_RIO500USB) ||
178             (UGETW(dd->idVendor) == USB_VENDOR_DIAMOND2 &&
179               (UGETW(dd->idProduct) == USB_PRODUCT_DIAMOND2_RIO600USB ||
180               UGETW(dd->idProduct) == USB_PRODUCT_DIAMOND2_RIO800USB))))
181                 return UMATCH_VENDOR_PRODUCT;
182         else
183                 return UMATCH_NONE;
184 }
185
186 USB_ATTACH(urio)
187 {
188         USB_ATTACH_START(urio, sc, uaa);
189         char devinfo[1024];
190         usbd_device_handle udev;
191         usbd_interface_handle iface;
192         u_int8_t epcount;
193 #if defined(__NetBSD__) || defined(__OpenBSD__)
194         u_int8_t niface;
195 #endif
196         usbd_status r;
197         char * ermsg = "<none>";
198         int i;
199
200         DPRINTFN(10,("urio_attach: sc=%p\n", sc));
201         usbd_devinfo(uaa->device, 0, devinfo);
202         USB_ATTACH_SETUP;
203         printf("%s: %s\n", USBDEVNAME(sc->sc_dev), devinfo);
204
205         sc->sc_udev = udev = uaa->device;
206
207 #if defined(__FreeBSD__) || defined(__DragonFly__)
208         if ((!uaa->device) || (!uaa->iface)) {
209                 ermsg = "device or iface";
210                 goto nobulk;
211         }
212         sc->sc_iface = iface = uaa->iface;
213 #elif defined(__NetBSD__) || defined(__OpenBSD__)
214         if (!udev) {
215                 ermsg = "device";
216                 goto nobulk;
217         }
218         r = usbd_interface_count(udev, &niface);
219         if (r) {
220                 ermsg = "iface";
221                 goto nobulk;
222         }
223         r = usbd_device2interface_handle(udev, 0, &iface);
224         if (r) {
225                 ermsg = "iface";
226                 goto nobulk;
227         }
228         sc->sc_iface = iface;
229 #endif
230         sc->sc_opened = 0;
231         sc->sc_pipeh_in = 0;
232         sc->sc_pipeh_out = 0;
233         sc->sc_refcnt = 0;
234
235         r = usbd_endpoint_count(iface, &epcount);
236         if (r != USBD_NORMAL_COMPLETION) {
237                 ermsg = "endpoints";
238                 goto nobulk;
239         }
240
241         sc->sc_epaddr[RIO_OUT] = 0xff;
242         sc->sc_epaddr[RIO_IN] = 0x00;
243
244         for (i = 0; i < epcount; i++) {
245                 usb_endpoint_descriptor_t *edesc =
246                         usbd_interface2endpoint_descriptor(iface, i);
247                 int d;
248
249                 if (!edesc) {
250                         ermsg = "interface endpoint";
251                         goto nobulk;
252                 }
253
254                 d = RIO_UE_GET_DIR(edesc->bEndpointAddress);
255                 if (d != RIO_NODIR)
256                         sc->sc_epaddr[d] = edesc->bEndpointAddress;
257         }
258         if ( sc->sc_epaddr[RIO_OUT] == 0xff ||
259              sc->sc_epaddr[RIO_IN] == 0x00) {
260                 ermsg = "Rio I&O";
261                 goto nobulk;
262         }
263
264 #if defined(__FreeBSD__) || defined(__DragonFly__)
265         /* XXX no error trapping, no storing of dev_t */
266         sc->sc_dev_t = make_dev(&urio_cdevsw, device_get_unit(self),
267                         UID_ROOT, GID_OPERATOR,
268                         0644, "urio%d", device_get_unit(self));
269 #elif defined(__NetBSD__) || defined(__OpenBSD__)
270         usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
271                            USBDEV(sc->sc_dev));
272 #endif
273
274         DPRINTFN(10, ("urio_attach: %p\n", sc->sc_udev));
275
276         USB_ATTACH_SUCCESS_RETURN;
277
278  nobulk:
279         printf("%s: could not find %s\n", USBDEVNAME(sc->sc_dev),ermsg);
280         USB_ATTACH_ERROR_RETURN;
281 }
282
283
284 int
285 urioopen(dev_t dev, int flag, int mode, usb_proc_ptr p)
286 {
287 #if (USBDI >= 1)
288         struct urio_softc * sc;
289 #endif
290         int unit = URIOUNIT(dev);
291         USB_GET_SC_OPEN(urio, unit, sc);
292
293         DPRINTFN(5, ("urioopen: flag=%d, mode=%d, unit=%d\n",
294                      flag, mode, unit));
295
296         if (sc->sc_opened)
297                 return EBUSY;
298
299         if ((flag & (FWRITE|FREAD)) != (FWRITE|FREAD))
300                 return EACCES;
301
302         sc->sc_opened = 1;
303         sc->sc_pipeh_in = 0;
304         sc->sc_pipeh_out = 0;
305         if (usbd_open_pipe(sc->sc_iface,
306                 sc->sc_epaddr[RIO_IN], 0, &sc->sc_pipeh_in)
307                         != USBD_NORMAL_COMPLETION)
308         {
309                         sc->sc_pipeh_in = 0;
310                         return EIO;
311         };
312         if (usbd_open_pipe(sc->sc_iface,
313                 sc->sc_epaddr[RIO_OUT], 0, &sc->sc_pipeh_out)
314                         != USBD_NORMAL_COMPLETION)
315         {
316                         usbd_close_pipe(sc->sc_pipeh_in);
317                         sc->sc_pipeh_in = 0;
318                         sc->sc_pipeh_out = 0;
319                         return EIO;
320         };
321         return 0;
322 }
323
324 int
325 urioclose(dev_t dev, int flag, int mode, usb_proc_ptr p)
326 {
327 #if (USBDI >= 1)
328         struct urio_softc * sc;
329 #endif
330         int unit = URIOUNIT(dev);
331         USB_GET_SC(urio, unit, sc);
332
333         DPRINTFN(5, ("urioclose: flag=%d, mode=%d, unit=%d\n", flag, mode, unit));
334         if (sc->sc_pipeh_in)
335                 usbd_close_pipe(sc->sc_pipeh_in);
336
337         if (sc->sc_pipeh_out)
338                 usbd_close_pipe(sc->sc_pipeh_out);
339
340         sc->sc_pipeh_in = 0;
341         sc->sc_pipeh_out = 0;
342         sc->sc_opened = 0;
343         sc->sc_refcnt = 0;
344         return 0;
345 }
346
347 int
348 urioread(dev_t dev, struct uio *uio, int flag)
349 {
350 #if (USBDI >= 1)
351         struct urio_softc * sc;
352         usbd_xfer_handle reqh;
353 #else
354         usbd_request_handle reqh;
355         usbd_private_handle r_priv;
356         void *r_buff;
357         usbd_status r_status;
358 #endif
359         int unit = URIOUNIT(dev);
360         usbd_status r;
361         char buf[URIO_BBSIZE];
362         u_int32_t n, tn;
363         int error = 0;
364
365         USB_GET_SC(urio, unit, sc);
366
367         DPRINTFN(5, ("urioread: %d\n", unit));
368         if (!sc->sc_opened)
369                 return EIO;
370
371 #if (USBDI >= 1)
372         sc->sc_refcnt++;
373         reqh = usbd_alloc_xfer(sc->sc_udev);
374 #else
375         reqh = usbd_alloc_request();
376 #endif
377         if (reqh == 0)
378                 return ENOMEM;
379         while ((n = min(URIO_BBSIZE, uio->uio_resid)) != 0) {
380                 DPRINTFN(1, ("urioread: start transfer %d bytes\n", n));
381                 tn = n;
382 #if (USBDI >= 1)
383                 usbd_setup_xfer(reqh, sc->sc_pipeh_in, 0, buf, tn,
384                                        0, RIO_RW_TIMEOUT, 0);
385 #else
386                 r = usbd_setup_request(reqh, sc->sc_pipeh_in, 0, buf, tn,
387                                        0, RIO_RW_TIMEOUT, 0);
388                 if (r != USBD_NORMAL_COMPLETION) {
389                         error = EIO;
390                         break;
391                 }
392 #endif
393                 r = usbd_sync_transfer(reqh);
394                 if (r != USBD_NORMAL_COMPLETION) {
395                         DPRINTFN(1, ("urioread: error=%d\n", r));
396                         usbd_clear_endpoint_stall(sc->sc_pipeh_in);
397                         tn = 0;
398                         error = EIO;
399                         break;
400                 }
401 #if (USBDI >= 1)
402                 usbd_get_xfer_status(reqh, 0, 0, &tn, 0);
403 #else
404                 usbd_get_request_status(reqh, &r_priv, &r_buff, &tn, &r_status);
405 #endif
406
407                 DPRINTFN(1, ("urioread: got %d bytes\n", tn));
408                 error = uiomove(buf, tn, uio);
409                 if (error || tn < n)
410                         break;
411         }
412 #if (USBDI >= 1)
413         usbd_free_xfer(reqh);
414 #else
415         usbd_free_request(reqh);
416 #endif
417
418         return error;
419 }
420
421 int
422 uriowrite(dev_t dev, struct uio *uio, int flag)
423 {
424 #if (USBDI >= 1)
425         struct urio_softc * sc;
426         usbd_xfer_handle reqh;
427 #else
428         usbd_request_handle reqh;
429 #endif
430         int unit = URIOUNIT(dev);
431         usbd_status r;
432         char buf[URIO_BBSIZE];
433         u_int32_t n;
434         int error = 0;
435
436         USB_GET_SC(urio, unit, sc);
437
438         DPRINTFN(5, ("uriowrite: %d\n", unit));
439         if (!sc->sc_opened)
440                 return EIO;
441
442 #if (USBDI >= 1)
443         sc->sc_refcnt++;
444         reqh = usbd_alloc_xfer(sc->sc_udev);
445 #else
446         reqh = usbd_alloc_request();
447 #endif
448         if (reqh == 0)
449                 return EIO;
450         while ((n = min(URIO_BBSIZE, uio->uio_resid)) != 0) {
451                 error = uiomove(buf, n, uio);
452                 if (error)
453                         break;
454                 DPRINTFN(1, ("uriowrite: transfer %d bytes\n", n));
455 #if (USBDI >= 1)
456                 usbd_setup_xfer(reqh, sc->sc_pipeh_out, 0, buf, n,
457                                        0, RIO_RW_TIMEOUT, 0);
458 #else
459                 r = usbd_setup_request(reqh, sc->sc_pipeh_out, 0, buf, n,
460                                        0, RIO_RW_TIMEOUT, 0);
461                 if (r != USBD_NORMAL_COMPLETION) {
462                         error = EIO;
463                         break;
464                 }
465 #endif
466                 r = usbd_sync_transfer(reqh);
467                 if (r != USBD_NORMAL_COMPLETION) {
468                         DPRINTFN(1, ("uriowrite: error=%d\n", r));
469                         usbd_clear_endpoint_stall(sc->sc_pipeh_out);
470                         error = EIO;
471                         break;
472                 }
473 #if (USBDI >= 1)
474                 usbd_get_xfer_status(reqh, 0, 0, 0, 0);
475 #endif
476         }
477
478 #if (USBDI >= 1)
479         usbd_free_xfer(reqh);
480 #else
481         usbd_free_request(reqh);
482 #endif
483
484         return error;
485 }
486
487
488 int
489 urioioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, usb_proc_ptr p)
490 {
491 #if (USBDI >= 1)
492         struct urio_softc * sc;
493 #endif
494         int unit = URIOUNIT(dev);
495         struct RioCommand *rio_cmd;
496         int requesttype, len;
497         struct iovec iov;
498         struct uio uio;
499         usb_device_request_t req;
500         int req_flags = 0, req_actlen = 0;
501         void *ptr = 0;
502         int error = 0;
503         usbd_status r;
504
505         USB_GET_SC(urio, unit, sc);
506
507         switch (cmd) {
508         case RIO_RECV_COMMAND:
509                 if (!(flag & FWRITE))
510                         return EPERM;
511                 rio_cmd = (struct RioCommand *)addr;
512                 if (rio_cmd == NULL)
513                         return EINVAL;
514                 len = rio_cmd->length;
515
516                 requesttype = rio_cmd->requesttype | UT_READ_VENDOR_DEVICE;
517                 DPRINTFN(1,("sending command:reqtype=%0x req=%0x value=%0x index=%0x len=%0x\n",
518                         requesttype, rio_cmd->request, rio_cmd->value, rio_cmd->index, len));
519                 break;
520
521         case RIO_SEND_COMMAND:
522                 if (!(flag & FWRITE))
523                         return EPERM;
524                 rio_cmd = (struct RioCommand *)addr;
525                 if (rio_cmd == NULL)
526                         return EINVAL;
527                 len = rio_cmd->length;
528
529                 requesttype = rio_cmd->requesttype | UT_WRITE_VENDOR_DEVICE;
530                 DPRINTFN(1,("sending command:reqtype=%0x req=%0x value=%0x index=%0x len=%0x\n",
531                         requesttype, rio_cmd->request, rio_cmd->value, rio_cmd->index, len));
532                 break;
533
534         default:
535                 return EINVAL;
536                 break;
537         }
538
539         /* Send rio control message */
540         req.bmRequestType = requesttype;
541         req.bRequest = rio_cmd->request;
542         USETW(req.wValue, rio_cmd->value);
543         USETW(req.wIndex, rio_cmd->index);
544         USETW(req.wLength, len);
545
546         if (len < 0 || len > 32767)
547                 return EINVAL;
548         if (len != 0) {
549                 iov.iov_base = (caddr_t)rio_cmd->buffer;
550                 iov.iov_len = len;
551                 uio.uio_iov = &iov;
552                 uio.uio_iovcnt = 1;
553                 uio.uio_resid = len;
554                 uio.uio_offset = 0;
555                 uio.uio_segflg = UIO_USERSPACE;
556                 uio.uio_rw =
557                         req.bmRequestType & UT_READ ?
558                         UIO_READ : UIO_WRITE;
559                 uio.uio_td = p;
560                 ptr = malloc(len, M_TEMP, M_WAITOK);
561                 if (uio.uio_rw == UIO_WRITE) {
562                         error = uiomove(ptr, len, &uio);
563                         if (error)
564                                 goto ret;
565                 }
566         }
567
568         r = usbd_do_request_flags(sc->sc_udev, &req,
569                                   ptr, req_flags, &req_actlen,
570                                   USBD_DEFAULT_TIMEOUT);
571         if (r == USBD_NORMAL_COMPLETION) {
572                 error = 0;
573                 if (len != 0) {
574                         if (uio.uio_rw == UIO_READ) {
575                                 error = uiomove(ptr, len, &uio);
576                         }
577                 }
578         } else {
579                 error = EIO;
580         }
581
582 ret:
583         if (ptr)
584                 free(ptr, M_TEMP);
585         return error;
586 }
587
588
589 #if defined(__NetBSD__) || defined(__OpenBSD__)
590 int
591 urio_activate(device_ptr_t self, enum devact act)
592 {
593         struct urio_softc *sc = (struct urio_softc *)self;
594
595         switch (act) {
596         case DVACT_ACTIVATE:
597                 return (EOPNOTSUPP);
598                 break;
599
600         case DVACT_DEACTIVATE:
601                 sc->sc_dying = 1;
602                 break;
603         }
604         return (0);
605 }
606
607 USB_DETACH(urio)
608 {
609         USB_DETACH_START(urio, sc);
610         struct urio_endpoint *sce;
611         int i, dir;
612         int s;
613 #if defined(__NetBSD__) || defined(__OpenBSD__)
614         int maj, mn;
615
616         DPRINTF(("urio_detach: sc=%p flags=%d\n", sc, flags));
617 #elif defined(__FreeBSD__) || defined(__DragonFly__)
618         DPRINTF(("urio_detach: sc=%p\n", sc));
619 #endif
620
621         sc->sc_dying = 1;
622         /* Abort all pipes.  Causes processes waiting for transfer to wake. */
623 #if 0
624         for (i = 0; i < USB_MAX_ENDPOINTS; i++) {
625                 for (dir = OUT; dir <= IN; dir++) {
626                         sce = &sc->sc_endpoints[i][dir];
627                         if (sce && sce->pipeh)
628                                 usbd_abort_pipe(sce->pipeh);
629                 }
630         }
631
632         s = splusb();
633         if (--sc->sc_refcnt >= 0) {
634                 /* Wake everyone */
635                 for (i = 0; i < USB_MAX_ENDPOINTS; i++)
636                         wakeup(&sc->sc_endpoints[i][IN]);
637                 /* Wait for processes to go away. */
638                 usb_detach_wait(USBDEV(sc->sc_dev));
639         }
640         splx(s);
641 #else
642         if (sc->sc_pipeh_in)
643                 usbd_abort_pipe(sc->sc_pipeh_in);
644
645         if (sc->sc_pipeh_out)
646                 usbd_abort_pipe(sc->sc_pipeh_out);
647
648         s = splusb();
649         if (--sc->sc_refcnt >= 0) {
650                 /* Wait for processes to go away. */
651                 usb_detach_wait(USBDEV(sc->sc_dev));
652         }
653         splx(s);
654 #endif
655
656 #if defined(__NetBSD__) || defined(__OpenBSD__)
657         /* locate the major number */
658         for (maj = 0; maj < nchrdev; maj++)
659                 if (cdevsw[maj].d_open == urioopen)
660                         break;
661
662         /* Nuke the vnodes for any open instances (calls close). */
663         mn = self->dv_unit * USB_MAX_ENDPOINTS;
664         vdevgone(maj, mn, mn + USB_MAX_ENDPOINTS - 1, VCHR);
665 #endif
666
667         usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
668                            USBDEV(sc->sc_dev));
669
670         return (0);
671 }
672 #endif /* defined(__NetBSD__) || defined(__OpenBSD__) */
673
674 #if defined(__FreeBSD__) || defined(__DragonFly__)
675 Static int
676 urio_detach(device_t self)
677 {
678         struct urio_softc *sc = device_get_softc(self);
679
680         DPRINTF(("%s: disconnected\n", USBDEVNAME(self)));
681         destroy_dev(sc->sc_dev_t);
682         /* XXX not implemented yet */
683         device_set_desc(self, NULL);
684         return 0;
685 }
686
687 DRIVER_MODULE(urio, uhub, urio_driver, urio_devclass, usbd_driver_load, 0);
688 #endif