]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/usb/urio.c
This commit was generated by cvs2svn to compensate for changes in r159399,
[FreeBSD/FreeBSD.git] / sys / dev / usb / 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 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
33
34
35 /*
36  * 2000/3/24  added NetBSD/OpenBSD support (from Alex Nemirovsky)
37  * 2000/3/07  use two bulk-pipe handles for read and write (Dirk)
38  * 2000/3/06  change major number(143), and copyright header
39  *            some fix for 4.0 (Dirk)
40  * 2000/3/05  codes for FreeBSD 4.x - CURRENT (Thanks to Dirk-Willem van Gulik)
41  * 2000/3/01  remove retry code from urioioctl()
42  *            change method of bulk transfer (no interrupt)
43  * 2000/2/28  small fixes for new rio_usb.h
44  * 2000/2/24  first version.
45  */
46
47 #include <sys/param.h>
48 #include <sys/systm.h>
49 #include <sys/kernel.h>
50 #include <sys/malloc.h>
51 #if defined(__NetBSD__)
52 #include <sys/device.h>
53 #include <sys/ioctl.h>
54 #elif defined(__FreeBSD__)
55 #include <sys/module.h>
56 #include <sys/bus.h>
57 #include <sys/ioccom.h>
58 #endif
59 #include <sys/fcntl.h>
60 #include <sys/filio.h>
61 #include <sys/conf.h>
62 #include <sys/uio.h>
63 #include <sys/tty.h>
64 #include <sys/file.h>
65 #if __FreeBSD_version >= 500014
66 #include <sys/selinfo.h>
67 #else
68 #include <sys/select.h>
69 #endif
70 #include <sys/poll.h>
71 #include <sys/sysctl.h>
72 #include <sys/uio.h>
73
74 #include <dev/usb/usb.h>
75 #include <dev/usb/usbdi.h>
76 #include <dev/usb/usbdi_util.h>
77
78 #include "usbdevs.h"
79 #include <dev/usb/rio500_usb.h>
80
81 #ifdef USB_DEBUG
82 #define DPRINTF(x)      if (uriodebug) logprintf x
83 #define DPRINTFN(n,x)   if (uriodebug>(n)) logprintf x
84 int     uriodebug = 0;
85 SYSCTL_NODE(_hw_usb, OID_AUTO, urio, CTLFLAG_RW, 0, "USB urio");
86 SYSCTL_INT(_hw_usb_urio, OID_AUTO, debug, CTLFLAG_RW,
87            &uriodebug, 0, "urio debug level");
88 #else
89 #define DPRINTF(x)
90 #define DPRINTFN(n,x)
91 #endif
92
93 /* difference of usbd interface */
94 #define USBDI 1
95
96 #define RIO_OUT 0
97 #define RIO_IN  1
98 #define RIO_NODIR  2
99
100 #if defined(__NetBSD__)
101 int urioopen(dev_t, int, int, struct proc *);
102 int urioclose(dev_t, int, int, struct proc *p);
103 int urioread(dev_t, struct uio *uio, int);
104 int uriowrite(dev_t, struct uio *uio, int);
105 int urioioctl(dev_t, u_long, caddr_t, int, struct proc *);
106
107 cdev_decl(urio);
108 #define RIO_UE_GET_DIR(p) ((UE_GET_DIR(p) == UE_DIR_IN) ? RIO_IN :\
109                           ((UE_GET_DIR(p) == UE_DIR_OUT) ? RIO_OUT :\
110                                                            RIO_NODIR))
111 #elif defined(__FreeBSD__)
112 d_open_t  urioopen;
113 d_close_t urioclose;
114 d_read_t  urioread;
115 d_write_t uriowrite;
116 d_ioctl_t urioioctl;
117
118
119 Static struct cdevsw urio_cdevsw = {
120         .d_version =    D_VERSION,
121         .d_flags =      D_NEEDGIANT,
122         .d_open =       urioopen,
123         .d_close =      urioclose,
124         .d_read =       urioread,
125         .d_write =      uriowrite,
126         .d_ioctl =      urioioctl,
127         .d_name =       "urio",
128 #if __FreeBSD_version < 500014
129         .d_bmaj =       -1
130 #endif
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__)
151         struct cdev *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
204         sc->sc_udev = udev = uaa->device;
205
206 #if defined(__FreeBSD__)
207         if ((!uaa->device) || (!uaa->iface)) {
208                 ermsg = "device or iface";
209                 goto nobulk;
210         }
211         sc->sc_iface = iface = uaa->iface;
212 #elif defined(__NetBSD__) || defined(__OpenBSD__)
213         if (!udev) {
214                 ermsg = "device";
215                 goto nobulk;
216         }
217         r = usbd_interface_count(udev, &niface);
218         if (r) {
219                 ermsg = "iface";
220                 goto nobulk;
221         }
222         r = usbd_device2interface_handle(udev, 0, &iface);
223         if (r) {
224                 ermsg = "iface";
225                 goto nobulk;
226         }
227         sc->sc_iface = iface;
228 #endif
229         sc->sc_opened = 0;
230         sc->sc_pipeh_in = 0;
231         sc->sc_pipeh_out = 0;
232         sc->sc_refcnt = 0;
233
234         r = usbd_endpoint_count(iface, &epcount);
235         if (r != USBD_NORMAL_COMPLETION) {
236                 ermsg = "endpoints";
237                 goto nobulk;
238         }
239
240         sc->sc_epaddr[RIO_OUT] = 0xff;
241         sc->sc_epaddr[RIO_IN] = 0x00;
242
243         for (i = 0; i < epcount; i++) {
244                 usb_endpoint_descriptor_t *edesc =
245                         usbd_interface2endpoint_descriptor(iface, i);
246                 int d;
247
248                 if (!edesc) {
249                         ermsg = "interface endpoint";
250                         goto nobulk;
251                 }
252
253                 d = RIO_UE_GET_DIR(edesc->bEndpointAddress);
254                 if (d != RIO_NODIR)
255                         sc->sc_epaddr[d] = edesc->bEndpointAddress;
256         }
257         if ( sc->sc_epaddr[RIO_OUT] == 0xff ||
258              sc->sc_epaddr[RIO_IN] == 0x00) {
259                 ermsg = "Rio I&O";
260                 goto nobulk;
261         }
262
263 #if defined(__FreeBSD__)
264         /* XXX no error trapping, no storing of struct cdev **/
265         sc->sc_dev_t = make_dev(&urio_cdevsw, device_get_unit(self),
266                         UID_ROOT, GID_OPERATOR,
267                         0644, "urio%d", device_get_unit(self));
268 #elif defined(__NetBSD__) || defined(__OpenBSD__)
269         usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
270                            USBDEV(sc->sc_dev));
271 #endif
272
273         DPRINTFN(10, ("urio_attach: %p\n", sc->sc_udev));
274
275         USB_ATTACH_SUCCESS_RETURN;
276
277  nobulk:
278         printf("%s: could not find %s\n", USBDEVNAME(sc->sc_dev),ermsg);
279         USB_ATTACH_ERROR_RETURN;
280 }
281
282
283 int
284 urioopen(struct cdev *dev, int flag, int mode, usb_proc_ptr p)
285 {
286 #if (USBDI >= 1)
287         struct urio_softc * sc;
288 #endif
289         int unit = URIOUNIT(dev);
290         USB_GET_SC_OPEN(urio, unit, sc);
291
292         DPRINTFN(5, ("urioopen: flag=%d, mode=%d, unit=%d\n",
293                      flag, mode, unit));
294
295         if (sc->sc_opened)
296                 return EBUSY;
297
298         if ((flag & (FWRITE|FREAD)) != (FWRITE|FREAD))
299                 return EACCES;
300
301         sc->sc_opened = 1;
302         sc->sc_pipeh_in = 0;
303         sc->sc_pipeh_out = 0;
304         if (usbd_open_pipe(sc->sc_iface,
305                 sc->sc_epaddr[RIO_IN], 0, &sc->sc_pipeh_in)
306                         != USBD_NORMAL_COMPLETION)
307         {
308                         sc->sc_pipeh_in = 0;
309                         return EIO;
310         };
311         if (usbd_open_pipe(sc->sc_iface,
312                 sc->sc_epaddr[RIO_OUT], 0, &sc->sc_pipeh_out)
313                         != USBD_NORMAL_COMPLETION)
314         {
315                         usbd_close_pipe(sc->sc_pipeh_in);
316                         sc->sc_pipeh_in = 0;
317                         sc->sc_pipeh_out = 0;
318                         return EIO;
319         };
320         return 0;
321 }
322
323 int
324 urioclose(struct cdev *dev, int flag, int mode, usb_proc_ptr p)
325 {
326 #if (USBDI >= 1)
327         struct urio_softc * sc;
328 #endif
329         int unit = URIOUNIT(dev);
330         USB_GET_SC(urio, unit, sc);
331
332         DPRINTFN(5, ("urioclose: flag=%d, mode=%d, unit=%d\n", flag, mode, unit));
333         if (sc->sc_pipeh_in)
334                 usbd_close_pipe(sc->sc_pipeh_in);
335
336         if (sc->sc_pipeh_out)
337                 usbd_close_pipe(sc->sc_pipeh_out);
338
339         sc->sc_pipeh_in = 0;
340         sc->sc_pipeh_out = 0;
341         sc->sc_opened = 0;
342         sc->sc_refcnt = 0;
343         return 0;
344 }
345
346 int
347 urioread(struct cdev *dev, struct uio *uio, int flag)
348 {
349 #if (USBDI >= 1)
350         struct urio_softc * sc;
351         usbd_xfer_handle reqh;
352 #else
353         usbd_request_handle reqh;
354         usbd_private_handle r_priv;
355         void *r_buff;
356         usbd_status r_status;
357 #endif
358         int unit = URIOUNIT(dev);
359         usbd_status r;
360         char buf[URIO_BBSIZE];
361         u_int32_t n, tn;
362         int error = 0;
363
364         USB_GET_SC(urio, unit, sc);
365
366         DPRINTFN(5, ("urioread: %d\n", unit));
367         if (!sc->sc_opened)
368                 return EIO;
369
370 #if (USBDI >= 1)
371         sc->sc_refcnt++;
372         reqh = usbd_alloc_xfer(sc->sc_udev);
373 #else
374         reqh = usbd_alloc_request();
375 #endif
376         if (reqh == 0)
377                 return ENOMEM;
378         while ((n = min(URIO_BBSIZE, uio->uio_resid)) != 0) {
379                 DPRINTFN(1, ("urioread: start transfer %d bytes\n", n));
380                 tn = n;
381 #if (USBDI >= 1)
382                 usbd_setup_xfer(reqh, sc->sc_pipeh_in, 0, buf, tn,
383                                        0, RIO_RW_TIMEOUT, 0);
384 #else
385                 r = usbd_setup_request(reqh, sc->sc_pipeh_in, 0, buf, tn,
386                                        0, RIO_RW_TIMEOUT, 0);
387                 if (r != USBD_NORMAL_COMPLETION) {
388                         error = EIO;
389                         break;
390                 }
391 #endif
392                 r = usbd_sync_transfer(reqh);
393                 if (r != USBD_NORMAL_COMPLETION) {
394                         DPRINTFN(1, ("urioread: error=%d\n", r));
395                         usbd_clear_endpoint_stall(sc->sc_pipeh_in);
396                         tn = 0;
397                         error = EIO;
398                         break;
399                 }
400 #if (USBDI >= 1)
401                 usbd_get_xfer_status(reqh, 0, 0, &tn, 0);
402 #else
403                 usbd_get_request_status(reqh, &r_priv, &r_buff, &tn, &r_status);
404 #endif
405
406                 DPRINTFN(1, ("urioread: got %d bytes\n", tn));
407                 error = uiomove(buf, tn, uio);
408                 if (error || tn < n)
409                         break;
410         }
411 #if (USBDI >= 1)
412         usbd_free_xfer(reqh);
413 #else
414         usbd_free_request(reqh);
415 #endif
416
417         return error;
418 }
419
420 int
421 uriowrite(struct cdev *dev, struct uio *uio, int flag)
422 {
423 #if (USBDI >= 1)
424         struct urio_softc * sc;
425         usbd_xfer_handle reqh;
426 #else
427         usbd_request_handle reqh;
428 #endif
429         int unit = URIOUNIT(dev);
430         usbd_status r;
431         char buf[URIO_BBSIZE];
432         u_int32_t n;
433         int error = 0;
434
435         USB_GET_SC(urio, unit, sc);
436
437         DPRINTFN(5, ("uriowrite: %d\n", unit));
438         if (!sc->sc_opened)
439                 return EIO;
440
441 #if (USBDI >= 1)
442         sc->sc_refcnt++;
443         reqh = usbd_alloc_xfer(sc->sc_udev);
444 #else
445         reqh = usbd_alloc_request();
446 #endif
447         if (reqh == 0)
448                 return EIO;
449         while ((n = min(URIO_BBSIZE, uio->uio_resid)) != 0) {
450                 error = uiomove(buf, n, uio);
451                 if (error)
452                         break;
453                 DPRINTFN(1, ("uriowrite: transfer %d bytes\n", n));
454 #if (USBDI >= 1)
455                 usbd_setup_xfer(reqh, sc->sc_pipeh_out, 0, buf, n,
456                                        0, RIO_RW_TIMEOUT, 0);
457 #else
458                 r = usbd_setup_request(reqh, sc->sc_pipeh_out, 0, buf, n,
459                                        0, RIO_RW_TIMEOUT, 0);
460                 if (r != USBD_NORMAL_COMPLETION) {
461                         error = EIO;
462                         break;
463                 }
464 #endif
465                 r = usbd_sync_transfer(reqh);
466                 if (r != USBD_NORMAL_COMPLETION) {
467                         DPRINTFN(1, ("uriowrite: error=%d\n", r));
468                         usbd_clear_endpoint_stall(sc->sc_pipeh_out);
469                         error = EIO;
470                         break;
471                 }
472 #if (USBDI >= 1)
473                 usbd_get_xfer_status(reqh, 0, 0, 0, 0);
474 #endif
475         }
476
477 #if (USBDI >= 1)
478         usbd_free_xfer(reqh);
479 #else
480         usbd_free_request(reqh);
481 #endif
482
483         return error;
484 }
485
486
487 int
488 urioioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, usb_proc_ptr p)
489 {
490 #if (USBDI >= 1)
491         struct urio_softc * sc;
492 #endif
493         int unit = URIOUNIT(dev);
494         struct RioCommand *rio_cmd;
495         int requesttype, len;
496         struct iovec iov;
497         struct uio uio;
498         usb_device_request_t req;
499         int req_flags = 0, req_actlen = 0;
500         void *ptr = 0;
501         int error = 0;
502         usbd_status r;
503
504         USB_GET_SC(urio, unit, sc);
505
506         switch (cmd) {
507         case RIO_RECV_COMMAND:
508                 if (!(flag & FWRITE))
509                         return EPERM;
510                 rio_cmd = (struct RioCommand *)addr;
511                 if (rio_cmd == NULL)
512                         return EINVAL;
513                 len = rio_cmd->length;
514
515                 requesttype = rio_cmd->requesttype | UT_READ_VENDOR_DEVICE;
516                 DPRINTFN(1,("sending command:reqtype=%0x req=%0x value=%0x index=%0x len=%0x\n",
517                         requesttype, rio_cmd->request, rio_cmd->value, rio_cmd->index, len));
518                 break;
519
520         case RIO_SEND_COMMAND:
521                 if (!(flag & FWRITE))
522                         return EPERM;
523                 rio_cmd = (struct RioCommand *)addr;
524                 if (rio_cmd == NULL)
525                         return EINVAL;
526                 len = rio_cmd->length;
527
528                 requesttype = rio_cmd->requesttype | UT_WRITE_VENDOR_DEVICE;
529                 DPRINTFN(1,("sending command:reqtype=%0x req=%0x value=%0x index=%0x len=%0x\n",
530                         requesttype, rio_cmd->request, rio_cmd->value, rio_cmd->index, len));
531                 break;
532
533         default:
534                 return EINVAL;
535                 break;
536         }
537
538         /* Send rio control message */
539         req.bmRequestType = requesttype;
540         req.bRequest = rio_cmd->request;
541         USETW(req.wValue, rio_cmd->value);
542         USETW(req.wIndex, rio_cmd->index);
543         USETW(req.wLength, len);
544
545         if (len < 0 || len > 32767)
546                 return EINVAL;
547         if (len != 0) {
548                 iov.iov_base = (caddr_t)rio_cmd->buffer;
549                 iov.iov_len = len;
550                 uio.uio_iov = &iov;
551                 uio.uio_iovcnt = 1;
552                 uio.uio_resid = len;
553                 uio.uio_offset = 0;
554                 uio.uio_segflg = UIO_USERSPACE;
555                 uio.uio_rw =
556                         req.bmRequestType & UT_READ ?
557                         UIO_READ : UIO_WRITE;
558                 uio.uio_procp = p;
559                 ptr = malloc(len, M_TEMP, M_WAITOK);
560                 if (uio.uio_rw == UIO_WRITE) {
561                         error = uiomove(ptr, len, &uio);
562                         if (error)
563                                 goto ret;
564                 }
565         }
566
567         r = usbd_do_request_flags(sc->sc_udev, &req,
568                                   ptr, req_flags, &req_actlen,
569                                   USBD_DEFAULT_TIMEOUT);
570         if (r == USBD_NORMAL_COMPLETION) {
571                 error = 0;
572                 if (len != 0) {
573                         if (uio.uio_rw == UIO_READ) {
574                                 error = uiomove(ptr, len, &uio);
575                         }
576                 }
577         } else {
578                 error = EIO;
579         }
580
581 ret:
582         if (ptr)
583                 free(ptr, M_TEMP);
584         return error;
585 }
586
587
588 #if defined(__NetBSD__) || defined(__OpenBSD__)
589 int
590 urio_activate(device_ptr_t self, enum devact act)
591 {
592         struct urio_softc *sc = (struct urio_softc *)self;
593
594         switch (act) {
595         case DVACT_ACTIVATE:
596                 return (EOPNOTSUPP);
597                 break;
598
599         case DVACT_DEACTIVATE:
600                 sc->sc_dying = 1;
601                 break;
602         }
603         return (0);
604 }
605
606 USB_DETACH(urio)
607 {
608         USB_DETACH_START(urio, sc);
609         struct urio_endpoint *sce;
610         int i, dir;
611         int s;
612 #if defined(__NetBSD__) || defined(__OpenBSD__)
613         int maj, mn;
614
615         DPRINTF(("urio_detach: sc=%p flags=%d\n", sc, flags));
616 #elif defined(__FreeBSD__)
617         DPRINTF(("urio_detach: sc=%p\n", sc));
618 #endif
619
620         sc->sc_dying = 1;
621         /* Abort all pipes.  Causes processes waiting for transfer to wake. */
622 #if 0
623         for (i = 0; i < USB_MAX_ENDPOINTS; i++) {
624                 for (dir = OUT; dir <= IN; dir++) {
625                         sce = &sc->sc_endpoints[i][dir];
626                         if (sce && sce->pipeh)
627                                 usbd_abort_pipe(sce->pipeh);
628                 }
629         }
630
631         s = splusb();
632         if (--sc->sc_refcnt >= 0) {
633                 /* Wake everyone */
634                 for (i = 0; i < USB_MAX_ENDPOINTS; i++)
635                         wakeup(&sc->sc_endpoints[i][IN]);
636                 /* Wait for processes to go away. */
637                 usb_detach_wait(USBDEV(sc->sc_dev));
638         }
639         splx(s);
640 #else
641         if (sc->sc_pipeh_in)
642                 usbd_abort_pipe(sc->sc_pipeh_in);
643
644         if (sc->sc_pipeh_out)
645                 usbd_abort_pipe(sc->sc_pipeh_out);
646
647         s = splusb();
648         if (--sc->sc_refcnt >= 0) {
649                 /* Wait for processes to go away. */
650                 usb_detach_wait(USBDEV(sc->sc_dev));
651         }
652         splx(s);
653 #endif
654
655 #if defined(__NetBSD__) || defined(__OpenBSD__)
656         /* locate the major number */
657         for (maj = 0; maj < nchrdev; maj++)
658                 if (cdevsw[maj].d_open == urioopen)
659                         break;
660
661         /* Nuke the vnodes for any open instances (calls close). */
662         mn = self->dv_unit * USB_MAX_ENDPOINTS;
663         vdevgone(maj, mn, mn + USB_MAX_ENDPOINTS - 1, VCHR);
664 #endif
665
666         usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
667                            USBDEV(sc->sc_dev));
668
669         return (0);
670 }
671 #endif /* defined(__NetBSD__) || defined(__OpenBSD__) */
672
673 #if defined(__FreeBSD__)
674 Static int
675 urio_detach(device_t self)
676 {
677         struct urio_softc *sc = device_get_softc(self);
678
679         DPRINTF(("%s: disconnected\n", USBDEVNAME(self)));
680         destroy_dev(sc->sc_dev_t);
681         /* XXX not implemented yet */
682         device_set_desc(self, NULL);
683         return 0;
684 }
685
686 DRIVER_MODULE(urio, uhub, urio_driver, urio_devclass, usbd_driver_load, 0);
687 #endif