ugen.c
来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 1,003 行 · 第 1/2 页
C
1,003 行
/* $NetBSD: ugen.c,v 1.11 1999/01/08 11:58:25 augustss Exp $ *//* $FreeBSD: src/sys/dev/usb/ugen.c,v 1.8.2.1 1999/05/08 23:04:46 n_hibma Exp $ *//* * 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 UGEN_DEBUG#define DPRINTF(x) if (ugendebug) logprintf x#define DPRINTFN(n,x) if (ugendebug>(n)) logprintf xint ugendebug = 1;#else#define DPRINTF(x)#define DPRINTFN(n,x)#endifstruct 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 1024struct 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 */};#if defined(__NetBSD__)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 *));#elif defined(__FreeBSD__)d_open_t ugenopen;d_close_t ugenclose;d_read_t ugenread;d_write_t ugenwrite;d_ioctl_t ugenioctl;d_poll_t ugenpoll;#define UGEN_CDEV_MAJOR 114static struct cdevsw ugen_cdevsw = { ugenopen, ugenclose, ugenread, ugenwrite, ugenioctl, nostop, nullreset, nodevtotty, ugenpoll, nommap, nostrat, "ugen", NULL, -1};#endifvoid ugenintr __P((usbd_request_handle reqh, usbd_private_handle addr, usbd_status status));void ugen_disco __P((void *));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;}intugen_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);}voidugen_disco(p) void *p;{ struct ugen_softc *sc = p; sc->sc_disconnected = 1;}intugenopen(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);}intugenclose(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);}intugenread(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);}intugenwrite(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);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?