int ugenclose(dev_t dev, int flag, int mode, struct proc *p) { struct ugen_softc *sc = ugen_cd.cd_devs[UGENUNIT(dev)]; int endpt = UGENENDPOINT(dev); int error; if (sc == NULL || usbd_is_dying(sc->sc_udev)) return (EIO); DPRINTFN(5, ("ugenclose: flag=%d, mode=%d, unit=%d, endpt=%d\n", flag, mode, UGENUNIT(dev), endpt)); sc->sc_refcnt++; error = ugen_do_close(sc, endpt, flag); if (--sc->sc_refcnt < 0) usb_detach_wakeup(&sc->sc_dev); return (error); }
int ugenclose(dev_t dev, int flag, int mode, struct proc *p) { int endpt = UGENENDPOINT(dev); struct ugen_softc *sc; struct ugen_endpoint *sce; int dir; int i; sc = ugen_cd.cd_devs[UGENUNIT(dev)]; DPRINTFN(5, ("ugenclose: flag=%d, mode=%d, unit=%d, endpt=%d\n", flag, mode, UGENUNIT(dev), endpt)); #ifdef DIAGNOSTIC if (!sc->sc_is_open[endpt]) { printf("ugenclose: not open\n"); return (EINVAL); } #endif if (endpt == USB_CONTROL_ENDPOINT) { DPRINTFN(5, ("ugenclose: close control\n")); sc->sc_is_open[endpt] = 0; return (0); } for (dir = OUT; dir <= IN; dir++) { if (!(flag & (dir == OUT ? FWRITE : FREAD))) continue; sce = &sc->sc_endpoints[endpt][dir]; if (sce == NULL || sce->pipeh == NULL) continue; DPRINTFN(5, ("ugenclose: endpt=%d dir=%d sce=%p\n", endpt, dir, sce)); usbd_abort_pipe(sce->pipeh); usbd_close_pipe(sce->pipeh); sce->pipeh = NULL; switch (sce->edesc->bmAttributes & UE_XFERTYPE) { case UE_INTERRUPT: ndflush(&sce->q, sce->q.c_cc); clfree(&sce->q); break; case UE_ISOCHRONOUS: for (i = 0; i < UGEN_NISOREQS; ++i) usbd_free_xfer(sce->isoreqs[i].xfer); default: break; } if (sce->ibuf != NULL) { free(sce->ibuf, M_USBDEV, 0); sce->ibuf = NULL; } } sc->sc_is_open[endpt] = 0; return (0); }
int ugenopen(dev_t dev, int flag, int mode, struct proc *p) { struct ugen_softc *sc; int unit = UGENUNIT(dev); int endpt = UGENENDPOINT(dev); usb_endpoint_descriptor_t *edesc; struct ugen_endpoint *sce; int dir, isize; usbd_status err; struct usbd_xfer *xfer; void *buf; int i, j; if (unit >= ugen_cd.cd_ndevs) return (ENXIO); sc = ugen_cd.cd_devs[unit]; if (sc == NULL) return (ENXIO); DPRINTFN(5, ("ugenopen: flag=%d, mode=%d, unit=%d endpt=%d\n", flag, mode, unit, endpt)); if (sc == NULL || usbd_is_dying(sc->sc_udev)) return (ENXIO); if (sc->sc_is_open[endpt]) return (EBUSY); if (endpt == USB_CONTROL_ENDPOINT) { sc->sc_is_open[USB_CONTROL_ENDPOINT] = 1; return (0); } /* Make sure there are pipes for all directions. */ for (dir = OUT; dir <= IN; dir++) { if (flag & (dir == OUT ? FWRITE : FREAD)) { sce = &sc->sc_endpoints[endpt][dir]; if (sce == 0 || sce->edesc == 0) return (ENXIO); } } /* Actually open the pipes. */ /* XXX Should back out properly if it fails. */ for (dir = OUT; dir <= IN; dir++) { if (!(flag & (dir == OUT ? FWRITE : FREAD))) continue; sce = &sc->sc_endpoints[endpt][dir]; sce->state = 0; sce->timeout = USBD_NO_TIMEOUT; DPRINTFN(5, ("ugenopen: sc=%p, endpt=%d, dir=%d, sce=%p\n", sc, endpt, dir, sce)); edesc = sce->edesc; switch (edesc->bmAttributes & UE_XFERTYPE) { case UE_INTERRUPT: if (dir == OUT) { err = usbd_open_pipe(sce->iface, edesc->bEndpointAddress, 0, &sce->pipeh); if (err) return (EIO); break; } isize = UGETW(edesc->wMaxPacketSize); if (isize == 0) /* shouldn't happen */ return (EINVAL); sce->ibuf = malloc(isize, M_USBDEV, M_WAITOK); DPRINTFN(5, ("ugenopen: intr endpt=%d,isize=%d\n", endpt, isize)); clalloc(&sce->q, UGEN_IBSIZE, 0); err = usbd_open_pipe_intr(sce->iface, edesc->bEndpointAddress, USBD_SHORT_XFER_OK, &sce->pipeh, sce, sce->ibuf, isize, ugenintr, USBD_DEFAULT_INTERVAL); if (err) { free(sce->ibuf, M_USBDEV, 0); clfree(&sce->q); return (EIO); } DPRINTFN(5, ("ugenopen: interrupt open done\n")); break; case UE_BULK: err = usbd_open_pipe(sce->iface, edesc->bEndpointAddress, 0, &sce->pipeh); if (err) return (EIO); break; case UE_ISOCHRONOUS: if (dir == OUT) return (EINVAL); isize = UGETW(edesc->wMaxPacketSize); if (isize == 0) /* shouldn't happen */ return (EINVAL); sce->ibuf = malloc(isize * UGEN_NISOFRAMES, M_USBDEV, M_WAITOK); sce->cur = sce->fill = sce->ibuf; sce->limit = sce->ibuf + isize * UGEN_NISOFRAMES; DPRINTFN(5, ("ugenopen: isoc endpt=%d, isize=%d\n", endpt, isize)); err = usbd_open_pipe(sce->iface, edesc->bEndpointAddress, 0, &sce->pipeh); if (err) { free(sce->ibuf, M_USBDEV, 0); return (EIO); } for(i = 0; i < UGEN_NISOREQS; ++i) { sce->isoreqs[i].sce = sce; xfer = usbd_alloc_xfer(sc->sc_udev); if (xfer == 0) goto bad; sce->isoreqs[i].xfer = xfer; buf = usbd_alloc_buffer (xfer, isize * UGEN_NISORFRMS); if (buf == 0) { i++; goto bad; } sce->isoreqs[i].dmabuf = buf; for(j = 0; j < UGEN_NISORFRMS; ++j) sce->isoreqs[i].sizes[j] = isize; usbd_setup_isoc_xfer (xfer, sce->pipeh, &sce->isoreqs[i], sce->isoreqs[i].sizes, UGEN_NISORFRMS, USBD_NO_COPY, ugen_isoc_rintr); (void)usbd_transfer(xfer); } DPRINTFN(5, ("ugenopen: isoc open done\n")); break; bad: while (--i >= 0) /* implicit buffer free */ usbd_free_xfer(sce->isoreqs[i].xfer); return (ENOMEM); case UE_CONTROL: sce->timeout = USBD_DEFAULT_TIMEOUT; return (EINVAL); } } sc->sc_is_open[endpt] = 1; return (0); }
int ugenkqfilter(dev_t dev, struct knote *kn) { struct ugen_softc *sc; struct ugen_endpoint *sce; struct klist *klist; int s; sc = ugen_cd.cd_devs[UGENUNIT(dev)]; if (usbd_is_dying(sc->sc_udev)) return (ENXIO); /* XXX always IN */ sce = &sc->sc_endpoints[UGENENDPOINT(dev)][IN]; if (sce == NULL) return (EINVAL); switch (kn->kn_filter) { case EVFILT_READ: klist = &sce->rsel.si_note; switch (sce->edesc->bmAttributes & UE_XFERTYPE) { case UE_INTERRUPT: kn->kn_fop = &ugenread_intr_filtops; break; case UE_ISOCHRONOUS: kn->kn_fop = &ugenread_isoc_filtops; break; case UE_BULK: /* * We have no easy way of determining if a read will * yield any data or a write will happen. * So, emulate "seltrue". */ kn->kn_fop = &ugen_seltrue_filtops; break; default: return (EINVAL); } break; case EVFILT_WRITE: klist = &sce->rsel.si_note; switch (sce->edesc->bmAttributes & UE_XFERTYPE) { case UE_INTERRUPT: case UE_ISOCHRONOUS: /* XXX poll doesn't support this */ return (EINVAL); case UE_BULK: /* * We have no easy way of determining if a read will * yield any data or a write will happen. * So, emulate "seltrue". */ kn->kn_fop = &ugen_seltrue_filtops; break; default: return (EINVAL); } break; default: return (EINVAL); } kn->kn_hook = (void *)sce; s = splusb(); SLIST_INSERT_HEAD(klist, kn, kn_selnext); splx(s); return (0); }