--- sys/dev/usb/ugen.c.orig Thu Dec 15 16:57:32 2005 +++ sys/dev/usb/ugen.c Sat Apr 22 16:16:47 2006 @@ -1,4 +1,4 @@ -/* $NetBSD: ugen.c,v 1.59 2002/07/11 21:14:28 augustss Exp $ */ +/* $NetBSD: ugen.c,v 1.79 2006/03/01 12:38:13 yamt Exp $ */ /* Also already merged from NetBSD: * $NetBSD: ugen.c,v 1.61 2002/09/23 05:51:20 simonb Exp $ @@ -284,6 +284,9 @@ ugen_make_devnodes(sc); #endif + usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev, + USBDEV(sc->sc_dev)); + USB_ATTACH_SUCCESS_RETURN; } @@ -383,6 +386,7 @@ M_WAITOK); niface_cache = niface; + memset(sc->sc_endpoints, 0, sizeof sc->sc_endpoints); for (ifaceno = 0; ifaceno < niface; ifaceno++) { DPRINTFN(1,("ugen_set_config: ifaceno %d\n", ifaceno)); err = usbd_device2interface_handle(dev, ifaceno, &iface); @@ -511,7 +515,7 @@ for (dir = OUT; dir <= IN; dir++) { if (flag & (dir == OUT ? FWRITE : FREAD)) { sce = &sc->sc_endpoints[endpt][dir]; - if (sce->edesc == 0) + if (sce == 0 ||sce->edesc == 0) return (ENXIO); } } @@ -650,7 +654,7 @@ if (!(flag & (dir == OUT ? FWRITE : FREAD))) continue; sce = &sc->sc_endpoints[endpt][dir]; - if (sce->pipeh == NULL) + if (sce == NULL || sce->pipeh == NULL) continue; DPRINTFN(5, ("ugenclose: endpt=%d dir=%d sce=%p\n", endpt, dir, sce)); @@ -835,6 +839,9 @@ USB_GET_SC(ugen, UGENUNIT(dev), sc); + if(sc->sc_dying) + return (EIO); + UGEN_DEV_REF(dev, sc); error = ugen_do_read(sc, endpt, uio, flag); UGEN_DEV_RELE(dev, sc); @@ -933,6 +940,9 @@ USB_GET_SC(ugen, UGENUNIT(dev), sc); + if (sc->sc_dying) + return (EIO); + UGEN_DEV_REF(dev, sc); error = ugen_do_write(sc, endpt, uio, flag); UGEN_DEV_RELE(dev, sc); @@ -969,8 +979,29 @@ return; USB_GET_SC(ugen, UGENUNIT(dev), sc); sce = &sc->sc_endpoints[endpt][IN]; - if (sce->pipeh) + if (sce && sce->pipeh) + { + usbd_abort_pipe(sce->pipeh); + + if (sce->state & UGEN_ASLP) { + sce->state &= ~UGEN_ASLP; + DPRINTFN(5, ("ugenpurge: waking %p\n", sce)); + wakeup(sce); + } + selwakeuppri(&sce->rsel, PZERO); + } + sce = &sc->sc_endpoints[endpt][OUT]; + if (sce && sce->pipeh) + { usbd_abort_pipe(sce->pipeh); + + if (sce->state & UGEN_ASLP) { + sce->state &= ~UGEN_ASLP; + DPRINTFN(5, ("ugenpurge: waking %p\n", sce)); + wakeup(sce); + } + selwakeuppri(&sce->rsel, PZERO); + } } #endif @@ -994,7 +1025,7 @@ for (i = 0; i < USB_MAX_ENDPOINTS; i++) { for (dir = OUT; dir <= IN; dir++) { sce = &sc->sc_endpoints[i][dir]; - if (sce->pipeh) + if (sce && sce->pipeh) usbd_abort_pipe(sce->pipeh); } } @@ -1035,6 +1066,9 @@ destroy_dev(sc->dev); #endif + usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev, + USBDEV(sc->sc_dev)); + return (0); } @@ -1292,7 +1326,7 @@ /* This flag only affects read */ sce = &sc->sc_endpoints[endpt][IN]; - if (sce->pipeh == NULL) { + if (sce == NULL || sce->pipeh == NULL) { printf("ugenioctl: USB_SET_SHORT_XFER, no pipe\n"); return (EIO); } @@ -1304,6 +1338,12 @@ return (0); case USB_SET_TIMEOUT: sce = &sc->sc_endpoints[endpt][IN]; + if (sce == NULL + /* XXX this shouldn't happen, but the distinction between + input and output pipes isn't clear enough. + || sce->pipeh == NULL */ + ) + return (EINVAL); sce->timeout = *(int *)addr; return (0); default: @@ -1331,9 +1371,6 @@ err = ugen_set_config(sc, *(int *)addr); switch (err) { case USBD_NORMAL_COMPLETION: -#if defined(__FreeBSD__) - ugen_make_devnodes(sc); -#endif break; case USBD_IN_USE: return (EBUSY); @@ -1541,6 +1578,9 @@ USB_GET_SC(ugen, UGENUNIT(dev), sc); + if (sc->sc_dying) + return (EIO); + UGEN_DEV_REF(dev, sc); error = ugen_do_ioctl(sc, endpt, cmd, addr, flag, p); UGEN_DEV_RELE(dev, sc); @@ -1555,6 +1595,10 @@ int revents = 0; int s; + /* Do not allow to poll a control endpoint */ + if ( UGENENDPOINT(dev) == USB_CONTROL_ENDPOINT ) + return (EIO); + USB_GET_SC(ugen, UGENUNIT(dev), sc); if (sc->sc_dying) @@ -1562,6 +1606,8 @@ /* XXX always IN */ sce = &sc->sc_endpoints[UGENENDPOINT(dev)][IN]; + if (sce == NULL) + return (EIO); #ifdef DIAGNOSTIC if (!sce->edesc) { printf("ugenpoll: no edesc\n");