summaryrefslogtreecommitdiff
path: root/sys/dev/usb/ugen.c
diff options
context:
space:
mode:
authorcvs2svn <cvs2svn@FreeBSD.org>1999-01-21 00:55:32 +0000
committercvs2svn <cvs2svn@FreeBSD.org>1999-01-21 00:55:32 +0000
commit76b5366091f76c9bc73570149ef5055648fc2c39 (patch)
tree590d020e0f2a5bea6e09d66d951a674443b21d67 /sys/dev/usb/ugen.c
parent4b4d01da6f07f7754ff6a6e4f5223e9f0984d1a6 (diff)
Notes
Diffstat (limited to 'sys/dev/usb/ugen.c')
-rw-r--r--sys/dev/usb/ugen.c985
1 files changed, 0 insertions, 985 deletions
diff --git a/sys/dev/usb/ugen.c b/sys/dev/usb/ugen.c
deleted file mode 100644
index f739b4b642c9..000000000000
--- a/sys/dev/usb/ugen.c
+++ /dev/null
@@ -1,985 +0,0 @@
-/* $NetBSD: ugen.c,v 1.11 1999/01/08 11:58:25 augustss Exp $ */
-/* $FreeBSD$ */
-
-/*
- * Copyright (c) 1998 The NetBSD Foundation, Inc.
- * All rights reserved.
- *
- * This code is derived from software contributed to The NetBSD Foundation
- * by Lennart Augustsson (augustss@carlstedt.se) at
- * Carlstedt Research & Technology.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the NetBSD
- * Foundation, Inc. and its contributors.
- * 4. Neither the name of The NetBSD Foundation nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/kernel.h>
-#include <sys/malloc.h>
-#if defined(__NetBSD__)
-#include <sys/device.h>
-#include <sys/ioctl.h>
-#elif defined(__FreeBSD__)
-#include <sys/module.h>
-#include <sys/bus.h>
-#include <sys/ioccom.h>
-#include <sys/conf.h>
-#include <sys/fcntl.h>
-#include <sys/filio.h>
-#endif
-#include <sys/tty.h>
-#include <sys/file.h>
-#include <sys/select.h>
-#include <sys/proc.h>
-#include <sys/vnode.h>
-#include <sys/poll.h>
-
-#include <dev/usb/usb.h>
-#include <dev/usb/usbdi.h>
-#include <dev/usb/usbdi_util.h>
-
-#ifdef USB_DEBUG
-#define DPRINTF(x) if (ugendebug) printf x
-#define DPRINTFN(n,x) if (ugendebug>(n)) printf x
-int ugendebug = 1;
-#else
-#define DPRINTF(x)
-#define DPRINTFN(n,x)
-#endif
-
-struct ugen_endpoint {
- struct ugen_softc *sc;
- usb_endpoint_descriptor_t *edesc;
- usbd_interface_handle iface;
- int state;
-#define UGEN_OPEN 0x01 /* device is open */
-#define UGEN_ASLP 0x02 /* waiting for data */
-#define UGEN_SHORT_OK 0x04 /* short xfers are OK */
- usbd_pipe_handle pipeh;
- struct clist q;
- struct selinfo rsel;
- void *ibuf;
-};
-
-#define UGEN_CHUNK 128 /* chunk size for read */
-#define UGEN_IBSIZE 1020 /* buffer size */
-#define UGEN_BBSIZE 1024
-
-struct ugen_softc {
- bdevice sc_dev; /* base device */
- struct usbd_device *sc_udev;
-
- struct ugen_endpoint sc_endpoints[USB_MAX_ENDPOINTS][2];
-#define OUT 0 /* index order is important, from UE_OUT */
-#define IN 1 /* from UE_IN */
-
- int sc_disconnected; /* device is gone */
-};
-
-int ugenopen __P((dev_t, int, int, struct proc *));
-int ugenclose __P((dev_t, int, int, struct proc *p));
-int ugenread __P((dev_t, struct uio *uio, int));
-int ugenwrite __P((dev_t, struct uio *uio, int));
-int ugenioctl __P((dev_t, u_long, caddr_t, int, struct proc *));
-int ugenpoll __P((dev_t, int, struct proc *));
-void ugenintr __P((usbd_request_handle reqh, usbd_private_handle addr,
- usbd_status status));
-void ugen_disco __P((void *));
-
-#define UGEN_CDEV_MAJOR 114
-
-int ugen_set_config __P((struct ugen_softc *sc, int configno));
-usb_config_descriptor_t *ugen_get_cdesc __P((struct ugen_softc *sc, int index,
- int *lenp));
-usbd_status ugen_set_interface __P((struct ugen_softc *, int, int));
-int ugen_get_alt_index __P((struct ugen_softc *sc, int ifaceidx));
-
-#define UGENUNIT(n) (((n) >> 4) & 0xf)
-#define UGENENDPOINT(n) ((n) & 0xf)
-
-USB_DECLARE_DRIVER(ugen);
-
-USB_MATCH(ugen)
-{
- USB_MATCH_START(ugen, uaa);
-
- if (uaa->usegeneric)
- return (UMATCH_GENERIC);
- else
- return (UMATCH_NONE);
-}
-
-USB_ATTACH(ugen)
-{
- USB_ATTACH_START(ugen, sc, uaa);
- char devinfo[1024];
- usbd_status r;
- int conf;
-
- usbd_devinfo(uaa->device, 0, devinfo);
- USB_ATTACH_SETUP;
- printf("%s: %s\n", USBDEVNAME(sc->sc_dev), devinfo);
-
- sc->sc_udev = uaa->device;
- conf = 1; /* XXX should not hard code 1 */
- r = ugen_set_config(sc, conf);
- if (r != USBD_NORMAL_COMPLETION) {
- printf("%s: setting configuration %d failed\n",
- USBDEVNAME(sc->sc_dev), conf);
- sc->sc_disconnected = 1;
- USB_ATTACH_ERROR_RETURN;
- }
- USB_ATTACH_SUCCESS_RETURN;
-}
-
-int
-ugen_set_config(sc, configno)
- struct ugen_softc *sc;
- int configno;
-{
- usbd_device_handle dev = sc->sc_udev;
- usbd_interface_handle iface;
- usb_endpoint_descriptor_t *ed;
- struct ugen_endpoint *sce;
- u_int8_t niface, nendpt;
- int ifaceno, endptno, endpt;
- usbd_status r;
-
- DPRINTFN(1,("ugen_set_config: %s to configno %d, sc=%p\n",
- USBDEVNAME(sc->sc_dev), configno, sc));
- if (usbd_get_config_descriptor(dev)->bConfigurationValue != configno) {
- /* Avoid setting the current value. */
- r = usbd_set_config_no(dev, configno, 0);
- if (r != USBD_NORMAL_COMPLETION)
- return (r);
- }
-
- r = usbd_interface_count(dev, &niface);
- if (r != USBD_NORMAL_COMPLETION)
- return (r);
- memset(sc->sc_endpoints, 0, sizeof sc->sc_endpoints);
- for (ifaceno = 0; ifaceno < niface; ifaceno++) {
- DPRINTFN(1,("ugen_set_config: ifaceno %d\n", ifaceno));
- r = usbd_device2interface_handle(dev, ifaceno, &iface);
- if (r != USBD_NORMAL_COMPLETION)
- return (r);
- r = usbd_endpoint_count(iface, &nendpt);
- if (r != USBD_NORMAL_COMPLETION)
- return (r);
- for (endptno = 0; endptno < nendpt; endptno++) {
- ed = usbd_interface2endpoint_descriptor(iface,endptno);
- endpt = ed->bEndpointAddress;
- sce = &sc->sc_endpoints[UE_GET_ADDR(endpt)]
- [UE_GET_IN(endpt)];
- DPRINTFN(1,("ugen_set_config: endptno %d, endpt=0x%02x"
- "(%d,%d), sce=%p\n",
- endptno, endpt, UE_GET_ADDR(endpt),
- UE_GET_IN(endpt), sce));
- sce->sc = sc;
- sce->edesc = ed;
- sce->iface = iface;
- }
- }
- return (USBD_NORMAL_COMPLETION);
-}
-
-void
-ugen_disco(p)
- void *p;
-{
- struct ugen_softc *sc = p;
- sc->sc_disconnected = 1;
-}
-
-int
-ugenopen(dev, flag, mode, p)
- dev_t dev;
- int flag;
- int mode;
- struct proc *p;
-{
- int unit = UGENUNIT(dev);
- int endpt = UGENENDPOINT(dev);
- usb_endpoint_descriptor_t *edesc;
- struct ugen_endpoint *sce;
- int dir, isize;
- usbd_status r;
-
- USB_GET_SC_OPEN(ugen, unit, sc);
- DPRINTFN(5, ("ugenopen: flag=%d, mode=%d, unit=%d endpt=%d\n",
- flag, mode, unit, endpt));
-
- if (sc->sc_disconnected)
- return (EIO);
-
- if (endpt == USB_CONTROL_ENDPOINT) {
- /*if ((flag & (FWRITE|FREAD)) != (FWRITE|FREAD))
- return (EACCES);*/
- sce = &sc->sc_endpoints[USB_CONTROL_ENDPOINT][OUT];
- if (sce->state & UGEN_OPEN)
- return (EBUSY);
- } else {
- switch (flag & (FWRITE|FREAD)) {
- case FWRITE:
- dir = OUT;
- break;
- case FREAD:
- dir = IN;
- break;
- default:
- return (EACCES);
- }
- sce = &sc->sc_endpoints[endpt][dir];
- DPRINTFN(5, ("ugenopen: sc=%p, endpt=%d, dir=%d, sce=%p\n",
- sc, endpt, dir, sce));
- if (sce->state & UGEN_OPEN)
- return (EBUSY);
- edesc = sce->edesc;
- if (!edesc)
- return (ENXIO);
- switch (edesc->bmAttributes & UE_XFERTYPE) {
- case UE_INTERRUPT:
- isize = UGETW(edesc->wMaxPacketSize);
- if (isize == 0) /* shouldn't happen */
- return (EINVAL);
- sce->ibuf = malloc(isize, M_USB, M_WAITOK);
- DPRINTFN(5, ("ugenopen: intr endpt=%d,isize=%d\n",
- endpt, isize));
-#if defined(__NetBSD__)
- if (clalloc(&sce->q, UGEN_IBSIZE, 0) == -1)
- return (ENOMEM);
-#elif defined(__FreeBSD__)
- clist_alloc_cblocks(&sce->q, UGEN_IBSIZE, 0);
-#endif
- r = usbd_open_pipe_intr(sce->iface,
- edesc->bEndpointAddress,
- USBD_SHORT_XFER_OK, &sce->pipeh, sce,
- sce->ibuf, isize, ugenintr);
- if (r != USBD_NORMAL_COMPLETION) {
- free(sce->ibuf, M_USB);
-#if defined(__NetBSD__)
- clfree(&sce->q);
-#elif defined(__FreeBSD__)
- clist_free_cblocks(&sce->q);
-#endif
- return (EIO);
- }
- usbd_set_disco(sce->pipeh, ugen_disco, sc);
- DPRINTFN(5, ("ugenopen: interrupt open done\n"));
- break;
- case UE_BULK:
- r = usbd_open_pipe(sce->iface,
- edesc->bEndpointAddress, 0,
- &sce->pipeh);
- if (r != USBD_NORMAL_COMPLETION)
- return (EIO);
- break;
- case UE_CONTROL:
- case UE_ISOCHRONOUS:
- return (EINVAL);
- }
- }
- sce->state |= UGEN_OPEN;
- return (0);
-}
-
-int
-ugenclose(dev, flag, mode, p)
- dev_t dev;
- int flag;
- int mode;
- struct proc *p;
-{
- USB_GET_SC(ugen, UGENUNIT(dev), sc);
- int endpt = UGENENDPOINT(dev);
- struct ugen_endpoint *sce;
- int dir;
-
- DPRINTFN(5, ("ugenclose: flag=%d, mode=%d\n", flag, mode));
- if (sc->sc_disconnected)
- return (EIO);
-
- if (endpt == USB_CONTROL_ENDPOINT) {
- DPRINTFN(5, ("ugenclose: close control\n"));
- sc->sc_endpoints[endpt][OUT].state = 0;
- return (0);
- }
-
- flag = FWRITE | FREAD; /* XXX bug if generic open/close */
-
- /* The open modes have been joined, so check for both modes. */
- for (dir = OUT; dir <= IN; dir++) {
- if (flag & (dir == OUT ? FWRITE : FREAD)) {
- sce = &sc->sc_endpoints[endpt][dir];
- if (!sce || !sce->pipeh) /* XXX */
- continue; /* XXX */
- DPRINTFN(5, ("ugenclose: endpt=%d dir=%d sce=%p\n",
- endpt, dir, sce));
- sce->state = 0;
-
- usbd_abort_pipe(sce->pipeh);
- usbd_close_pipe(sce->pipeh);
- sce->pipeh = 0;
-
- if (sce->ibuf) {
- free(sce->ibuf, M_USB);
- sce->ibuf = 0;
- }
- }
- }
-
- return (0);
-}
-
-int
-ugenread(dev, uio, flag)
- dev_t dev;
- struct uio *uio;
- int flag;
-{
- USB_GET_SC(ugen, UGENUNIT(dev), sc);
- int endpt = UGENENDPOINT(dev);
- struct ugen_endpoint *sce = &sc->sc_endpoints[endpt][IN];
- u_int32_t n, tn;
- char buf[UGEN_BBSIZE];
- usbd_request_handle reqh;
- usbd_status r;
- int s;
- int error = 0;
- u_char buffer[UGEN_CHUNK];
-
- DPRINTFN(5, ("ugenread: %d:%d\n", UGENUNIT(dev), UGENENDPOINT(dev)));
- if (sc->sc_disconnected)
- return (EIO);
-
-#ifdef DIAGNOSTIC
- if (!sce->edesc) {
- printf("ugenread: no edesc\n");
- return (EIO);
- }
- if (!sce->pipeh) {
- printf("ugenread: no pipe\n");
- return (EIO);
- }
-#endif
-
- switch (sce->edesc->bmAttributes & UE_XFERTYPE) {
- case UE_INTERRUPT:
- /* Block until activity occured. */
- s = splusb();
- while (sce->q.c_cc == 0) {
- if (flag & IO_NDELAY) {
- splx(s);
- return (EWOULDBLOCK);
- }
- sce->state |= UGEN_ASLP;
- DPRINTFN(5, ("ugenread: sleep on %p\n", sc));
- error = tsleep((caddr_t)sce, PZERO | PCATCH,
- "ugenri", 0);
- DPRINTFN(5, ("ugenread: woke, error=%d\n", error));
- if (error) {
- sce->state &= ~UGEN_ASLP;
- splx(s);
- return (error);
- }
- }
- splx(s);
-
- /* Transfer as many chunks as possible. */
- while (sce->q.c_cc > 0 && uio->uio_resid > 0) {
- n = min(sce->q.c_cc, uio->uio_resid);
- if (n > sizeof(buffer))
- n = sizeof(buffer);
-
- /* Remove a small chunk from the input queue. */
- q_to_b(&sce->q, buffer, n);
- DPRINTFN(5, ("ugenread: got %d chars\n", n));
-
- /* Copy the data to the user process. */
- error = uiomove(buffer, n, uio);
- if (error)
- break;
- }
- break;
- case UE_BULK:
- reqh = usbd_alloc_request();
- if (reqh == 0)
- return (ENOMEM);
- while ((n = min(UGEN_BBSIZE, uio->uio_resid)) != 0) {
- DPRINTFN(1, ("ugenread: start transfer %d bytes\n", n));
- tn = n;
- r = usbd_bulk_transfer(reqh, sce->pipeh, 0, buf,
- &tn, "ugenrb");
- if (r != USBD_NORMAL_COMPLETION) {
- if (r == USBD_INTERRUPTED)
- error = EINTR;
- else
- error = EIO;
- break;
- }
- DPRINTFN(1, ("ugenread: got %d bytes\n", tn));
- error = uiomove(buf, tn, uio);
- if (error || tn < n)
- break;
- }
- usbd_free_request(reqh);
- break;
- default:
- return (ENXIO);
- }
-
- return (error);
-}
-
-int
-ugenwrite(dev, uio, flag)
- dev_t dev;
- struct uio *uio;
- int flag;
-{
- USB_GET_SC(ugen, UGENUNIT(dev), sc);
- int endpt = UGENENDPOINT(dev);
- struct ugen_endpoint *sce = &sc->sc_endpoints[endpt][OUT];
- size_t n;
- int error = 0;
- char buf[UGEN_BBSIZE];
- usbd_request_handle reqh;
- usbd_status r;
-
- if (sc->sc_disconnected)
- return (EIO);
-
-#ifdef DIAGNOSTIC
- if (!sce->edesc) {
- printf("ugenwrite: no edesc\n");
- return (EIO);
- }
- if (!sce->pipeh) {
- printf("ugenwrite: no pipe\n");
- return (EIO);
- }
-#endif
-
- DPRINTF(("ugenwrite\n"));
- switch (sce->edesc->bmAttributes & UE_XFERTYPE) {
- case UE_BULK:
- reqh = usbd_alloc_request();
- if (reqh == 0)
- return (EIO);
- while ((n = min(UGEN_BBSIZE, uio->uio_resid)) != 0) {
- error = uiomove(buf, n, uio);
- if (error)
- break;
- DPRINTFN(1, ("ugenwrite: transfer %d bytes\n", n));
- r = usbd_bulk_transfer(reqh, sce->pipeh, 0, buf,
- &n, "ugenwb");
- if (r != USBD_NORMAL_COMPLETION) {
- if (r == USBD_INTERRUPTED)
- error = EINTR;
- else
- error = EIO;
- break;
- }
- }
- usbd_free_request(reqh);
- break;
- default:
- return (ENXIO);
- }
- return (error);
-}
-
-
-void
-ugenintr(reqh, addr, status)
- usbd_request_handle reqh;
- usbd_private_handle addr;
- usbd_status status;
-{
- struct ugen_endpoint *sce = addr;
- /*struct ugen_softc *sc = sce->sc;*/
- usbd_private_handle priv;
- void *buffer;
- u_int32_t count;
- usbd_status xstatus;
- u_char *ibuf;
-
- if (status == USBD_CANCELLED)
- return;
-
- if (status != USBD_NORMAL_COMPLETION) {
- DPRINTF(("ugenintr: status=%d\n", status));
- usbd_clear_endpoint_stall_async(sce->pipeh);
- return;
- }
-
- (void)usbd_get_request_status(reqh, &priv, &buffer, &count, &xstatus);
- ibuf = sce->ibuf;
-
- DPRINTFN(5, ("ugenintr: reqh=%p status=%d count=%d\n",
- reqh, xstatus, count));
- DPRINTFN(5, (" data = %02x %02x %02x\n",
- ibuf[0], ibuf[1], ibuf[2]));
-
- (void)b_to_q(ibuf, count, &sce->q);
-
- if (sce->state & UGEN_ASLP) {
- sce->state &= ~UGEN_ASLP;
- DPRINTFN(5, ("ugen_intr: waking %p\n", sce));
- wakeup((caddr_t)sce);
- }
- selwakeup(&sce->rsel);
-}
-
-usbd_status
-ugen_set_interface(sc, ifaceidx, altno)
- struct ugen_softc *sc;
- int ifaceidx, altno;
-{
- usbd_interface_handle iface;
- usb_endpoint_descriptor_t *ed;
- usbd_status r;
- struct ugen_endpoint *sce;
- u_int8_t niface, nendpt, endptno, endpt;
-
- DPRINTFN(15, ("ugen_set_interface %d %d\n", ifaceidx, altno));
-
- r = usbd_interface_count(sc->sc_udev, &niface);
- if (r != USBD_NORMAL_COMPLETION)
- return (r);
- if (ifaceidx < 0 || ifaceidx >= niface)
- return (USBD_INVAL);
-
- r = usbd_device2interface_handle(sc->sc_udev, ifaceidx, &iface);
- if (r != USBD_NORMAL_COMPLETION)
- return (r);
- r = usbd_endpoint_count(iface, &nendpt);
- if (r != USBD_NORMAL_COMPLETION)
- return (r);
- for (endptno = 0; endptno < nendpt; endptno++) {
- ed = usbd_interface2endpoint_descriptor(iface,endptno);
- endpt = ed->bEndpointAddress;
- sce = &sc->sc_endpoints[UE_GET_ADDR(endpt)][UE_GET_IN(endpt)];
- sce->sc = 0;
- sce->edesc = 0;
- sce->iface = 0;
- }
-
- /* change setting */
- r = usbd_set_interface(iface, altno);
- if (r != USBD_NORMAL_COMPLETION)
- return (r);
-
- r = usbd_endpoint_count(iface, &nendpt);
- if (r != USBD_NORMAL_COMPLETION)
- return (r);
- for (endptno = 0; endptno < nendpt; endptno++) {
- ed = usbd_interface2endpoint_descriptor(iface,endptno);
- endpt = ed->bEndpointAddress;
- sce = &sc->sc_endpoints[UE_GET_ADDR(endpt)][UE_GET_IN(endpt)];
- sce->sc = sc;
- sce->edesc = ed;
- sce->iface = iface;
- }
- return (0);
-}
-
-/* Retrieve a complete descriptor for a certain device and index. */
-usb_config_descriptor_t *
-ugen_get_cdesc(sc, index, lenp)
- struct ugen_softc *sc;
- int index;
- int *lenp;
-{
- usb_config_descriptor_t *cdesc, *tdesc, cdescr;
- int len;
- usbd_status r;
-
- if (index == USB_CURRENT_CONFIG_INDEX) {
- tdesc = usbd_get_config_descriptor(sc->sc_udev);
- len = UGETW(tdesc->wTotalLength);
- if (lenp)
- *lenp = len;
- cdesc = malloc(len, M_TEMP, M_WAITOK);
- memcpy(cdesc, tdesc, len);
- DPRINTFN(5,("ugen_get_cdesc: current, len=%d\n", len));
- } else {
- r = usbd_get_config_desc(sc->sc_udev, index, &cdescr);
- if (r != USBD_NORMAL_COMPLETION)
- return (0);
- len = UGETW(cdescr.wTotalLength);
- DPRINTFN(5,("ugen_get_cdesc: index=%d, len=%d\n", index, len));
- if (lenp)
- *lenp = len;
- cdesc = malloc(len, M_TEMP, M_WAITOK);
- r = usbd_get_config_desc_full(sc->sc_udev, index, cdesc, len);
- if (r != USBD_NORMAL_COMPLETION) {
- free(cdesc, M_TEMP);
- return (0);
- }
- }
- return (cdesc);
-}
-
-int
-ugen_get_alt_index(sc, ifaceidx)
- struct ugen_softc *sc;
- int ifaceidx;
-{
- usbd_interface_handle iface;
- usbd_status r;
-
- r = usbd_device2interface_handle(sc->sc_udev, ifaceidx, &iface);
- if (r != USBD_NORMAL_COMPLETION)
- return (-1);
- return (usbd_get_interface_altindex(iface));
-}
-
-int
-ugenioctl(dev, cmd, addr, flag, p)
- dev_t dev;
- u_long cmd;
- caddr_t addr;
- int flag;
- struct proc *p;
-{
- USB_GET_SC(ugen, UGENUNIT(dev), sc);
- int endpt = UGENENDPOINT(dev);
- struct ugen_endpoint *sce;
- usbd_status r;
- usbd_interface_handle iface;
- struct usb_config_desc *cd;
- usb_config_descriptor_t *cdesc;
- struct usb_interface_desc *id;
- usb_interface_descriptor_t *idesc;
- struct usb_endpoint_desc *ed;
- usb_endpoint_descriptor_t *edesc;
- struct usb_alt_interface *ai;
- struct usb_string_desc *si;
- u_int8_t conf, alt;
-
- DPRINTFN(5, ("ugenioctl: cmd=%08lx\n", cmd));
- if (sc->sc_disconnected)
- return (EIO);
-
- switch (cmd) {
- case FIONBIO:
- /* All handled in the upper FS layer. */
- return (0);
- case USB_SET_SHORT_XFER:
- /* This flag only affects read */
- sce = &sc->sc_endpoints[endpt][IN];
-#ifdef DIAGNOSTIC
- if (!sce->pipeh) {
- printf("ugenioctl: no pipe\n");
- return (EIO);
- }
-#endif
- if (*(int *)addr)
- sce->state |= UGEN_SHORT_OK;
- else
- sce->state &= ~UGEN_SHORT_OK;
- return (0);
- default:
- break;
- }
-
- if (endpt != USB_CONTROL_ENDPOINT)
- return (EINVAL);
-
- switch (cmd) {
-#ifdef USB_DEBUG
- case USB_SETDEBUG:
- ugendebug = *(int *)addr;
- break;
-#endif
- case USB_GET_CONFIG:
- r = usbd_get_config(sc->sc_udev, &conf);
- if (r != USBD_NORMAL_COMPLETION)
- return (EIO);
- *(int *)addr = conf;
- break;
- case USB_SET_CONFIG:
- if (!(flag & FWRITE))
- return (EPERM);
- r = ugen_set_config(sc, *(int *)addr);
- if (r != USBD_NORMAL_COMPLETION)
- return (EIO);
- break;
- case USB_GET_ALTINTERFACE:
- ai = (struct usb_alt_interface *)addr;
- r = usbd_device2interface_handle(sc->sc_udev,
- ai->interface_index, &iface);
- if (r != USBD_NORMAL_COMPLETION)
- return (EINVAL);
- idesc = usbd_get_interface_descriptor(iface);
- if (!idesc)
- return (EIO);
- ai->alt_no = idesc->bAlternateSetting;
- break;
- case USB_SET_ALTINTERFACE:
- if (!(flag & FWRITE))
- return (EPERM);
- ai = (struct usb_alt_interface *)addr;
- r = usbd_device2interface_handle(sc->sc_udev,
- ai->interface_index, &iface);
- if (r != USBD_NORMAL_COMPLETION)
- return (EINVAL);
- r = ugen_set_interface(sc, ai->interface_index, ai->alt_no);
- if (r != USBD_NORMAL_COMPLETION)
- return (EINVAL);
- break;
- case USB_GET_NO_ALT:
- ai = (struct usb_alt_interface *)addr;
- cdesc = ugen_get_cdesc(sc, ai->config_index, 0);
- if (!cdesc)
- return (EINVAL);
- idesc = usbd_find_idesc(cdesc, ai->interface_index, 0);
- if (!idesc)
- return (EINVAL);
- ai->alt_no = usbd_get_no_alts(cdesc, idesc->bInterfaceNumber);
- break;
- case USB_GET_DEVICE_DESC:
- *(usb_device_descriptor_t *)addr =
- *usbd_get_device_descriptor(sc->sc_udev);
- break;
- case USB_GET_CONFIG_DESC:
- cd = (struct usb_config_desc *)addr;
- cdesc = ugen_get_cdesc(sc, cd->config_index, 0);
- if (!cdesc)
- return (EINVAL);
- cd->desc = *cdesc;
- free(cdesc, M_TEMP);
- break;
- case USB_GET_INTERFACE_DESC:
- id = (struct usb_interface_desc *)addr;
- cdesc = ugen_get_cdesc(sc, id->config_index, 0);
- if (!cdesc)
- return (EINVAL);
- if (id->config_index == USB_CURRENT_CONFIG_INDEX &&
- id->alt_index == USB_CURRENT_ALT_INDEX)
- alt = ugen_get_alt_index(sc, id->interface_index);
- else
- alt = id->alt_index;
- idesc = usbd_find_idesc(cdesc, id->interface_index, alt);
- if (!idesc) {
- free(cdesc, M_TEMP);
- return (EINVAL);
- }
- id->desc = *idesc;
- free(cdesc, M_TEMP);
- break;
- case USB_GET_ENDPOINT_DESC:
- ed = (struct usb_endpoint_desc *)addr;
- cdesc = ugen_get_cdesc(sc, ed->config_index, 0);
- if (!cdesc)
- return (EINVAL);
- if (ed->config_index == USB_CURRENT_CONFIG_INDEX &&
- ed->alt_index == USB_CURRENT_ALT_INDEX)
- alt = ugen_get_alt_index(sc, ed->interface_index);
- else
- alt = ed->alt_index;
- edesc = usbd_find_edesc(cdesc, ed->interface_index,
- alt, ed->endpoint_index);
- if (!edesc) {
- free(cdesc, M_TEMP);
- return (EINVAL);
- }
- ed->desc = *edesc;
- free(cdesc, M_TEMP);
- break;
- case USB_GET_FULL_DESC:
- {
- int len;
- struct iovec iov;
- struct uio uio;
- struct usb_full_desc *fd = (struct usb_full_desc *)addr;
- int error;
-
- cdesc = ugen_get_cdesc(sc, fd->config_index, &len);
- if (len > fd->size)
- len = fd->size;
- iov.iov_base = (caddr_t)fd->data;
- iov.iov_len = len;
- uio.uio_iov = &iov;
- uio.uio_iovcnt = 1;
- uio.uio_resid = len;
- uio.uio_offset = 0;
- uio.uio_segflg = UIO_USERSPACE;
- uio.uio_rw = UIO_READ;
- uio.uio_procp = p;
- error = uiomove((caddr_t)cdesc, len, &uio);
- free(cdesc, M_TEMP);
- return (error);
- }
- case USB_GET_STRING_DESC:
- si = (struct usb_string_desc *)addr;
- r = usbd_get_string_desc(sc->sc_udev, si->string_index,
- si->language_id, &si->desc);
- if (r != USBD_NORMAL_COMPLETION)
- return (EINVAL);
- break;
- case USB_DO_REQUEST:
- {
- struct usb_ctl_request *ur = (void *)addr;
- int len = UGETW(ur->request.wLength);
- struct iovec iov;
- struct uio uio;
- void *ptr = 0;
- usbd_status r;
- int error = 0;
-
- if (!(flag & FWRITE))
- return (EPERM);
- /* Avoid requests that would damage the bus integrity. */
- if ((ur->request.bmRequestType == UT_WRITE_DEVICE &&
- ur->request.bRequest == UR_SET_ADDRESS) ||
- (ur->request.bmRequestType == UT_WRITE_DEVICE &&
- ur->request.bRequest == UR_SET_CONFIG) ||
- (ur->request.bmRequestType == UT_WRITE_INTERFACE &&
- ur->request.bRequest == UR_SET_INTERFACE))
- return (EINVAL);
-
- if (len < 0 || len > 32767)
- return (EINVAL);
- if (len != 0) {
- iov.iov_base = (caddr_t)ur->data;
- iov.iov_len = len;
- uio.uio_iov = &iov;
- uio.uio_iovcnt = 1;
- uio.uio_resid = len;
- uio.uio_offset = 0;
- uio.uio_segflg = UIO_USERSPACE;
- uio.uio_rw =
- ur->request.bmRequestType & UT_READ ?
- UIO_READ : UIO_WRITE;
- uio.uio_procp = p;
- ptr = malloc(len, M_TEMP, M_WAITOK);
- if (uio.uio_rw == UIO_WRITE) {
- error = uiomove(ptr, len, &uio);
- if (error)
- goto ret;
- }
- }
- r = usbd_do_request_flags(sc->sc_udev, &ur->request,
- ptr, ur->flags, &ur->actlen);
- if (r) {
- error = EIO;
- goto ret;
- }
- if (len != 0) {
- if (uio.uio_rw == UIO_READ) {
- error = uiomove(ptr, len, &uio);
- if (error)
- goto ret;
- }
- }
- ret:
- if (ptr)
- free(ptr, M_TEMP);
- return (error);
- }
- case USB_GET_DEVICEINFO:
- usbd_fill_deviceinfo(sc->sc_udev,
- (struct usb_device_info *)addr);
- break;
- default:
- return (EINVAL);
- }
- return (0);
-}
-
-int
-ugenpoll(dev, events, p)
- dev_t dev;
- int events;
- struct proc *p;
-{
- USB_GET_SC(ugen, UGENUNIT(dev), sc);
- /* XXX */
- struct ugen_endpoint *sce;
- int revents = 0;
- int s;
-
- if (sc->sc_disconnected)
- return (EIO);
-
- sce = &sc->sc_endpoints[UGENENDPOINT(dev)][IN];
-#ifdef DIAGNOSTIC
- if (!sce->edesc) {
- printf("ugenwrite: no edesc\n");
- return (EIO);
- }
- if (!sce->pipeh) {
- printf("ugenpoll: no pipe\n");
- return (EIO);
- }
-#endif
- s = splusb();
- switch (sce->edesc->bmAttributes & UE_XFERTYPE) {
- case UE_INTERRUPT:
- if (events & (POLLIN | POLLRDNORM)) {
- if (sce->q.c_cc > 0)
- revents |= events & (POLLIN | POLLRDNORM);
- else
- selrecord(p, &sce->rsel);
- }
- break;
- case UE_BULK:
- /*
- * We have no easy way of determining if a read will
- * yield any data or a write will happen.
- * Pretend they will.
- */
- revents |= events &
- (POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM);
- break;
- default:
- break;
- }
- splx(s);
- return (revents);
-}
-
-#if defined(__FreeBSD__)
-static int
-ugen_detach(device_t self)
-{
- char *devinfo = (char *) device_get_desc(self);
-
- if (devinfo) {
- device_set_desc(self, NULL);
- free(devinfo, M_USB);
- }
- return 0;
-}
-
-DRIVER_MODULE(ugen, uhub, ugen_driver, ugen_devclass, usbd_driver_load, 0);
-#endif