Initial commit of ported NetBSD USB stack
This commit is contained in:
parent
48ecb15bdc
commit
0cec007c5f
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=41366
@ -11,7 +11,7 @@
|
||||
# device lines is present in the ./LINT configuration file. If you are
|
||||
# in doubt as to the purpose or necessity of a line, check first in LINT.
|
||||
#
|
||||
# $Id: GENERIC,v 1.130 1998/11/03 22:01:21 des Exp $
|
||||
# $Id: GENERIC,v 1.131 1998/11/12 11:29:28 obrien Exp $
|
||||
|
||||
machine "i386"
|
||||
cpu "I386_CPU"
|
||||
@ -179,3 +179,22 @@ options SYSVSHM
|
||||
# option. The number of devices determines the maximum number of
|
||||
# simultaneous BPF clients programs runnable.
|
||||
#pseudo-device bpfilter 4 #Berkeley packet filter
|
||||
|
||||
|
||||
# USB support
|
||||
#controller uhci0
|
||||
#controller usb0
|
||||
#
|
||||
# for the moment we have to specify the priorities of the device
|
||||
# drivers explicitly by the ordering in the list below. This will
|
||||
# be changed in the future.
|
||||
#
|
||||
#device ums0
|
||||
#device ukbd0
|
||||
#device ulpt0
|
||||
#device uhub0
|
||||
#device hid0
|
||||
#device ugen0
|
||||
#
|
||||
#options USB_DEBUG
|
||||
#options USBVERBOSE
|
||||
|
@ -599,3 +599,34 @@ vm/vm_swap.c standard
|
||||
vm/vm_unix.c standard
|
||||
vm/vnode_pager.c standard
|
||||
vm/vm_zone.c standard
|
||||
#
|
||||
# USB support
|
||||
dev/pci/uhci_pci.c optional uhci device-driver
|
||||
usb_if.o optional uhci device-driver \
|
||||
dependency "usb_if.c" \
|
||||
compile-with "${NORMAL_C}" \
|
||||
no-implicit-rule local
|
||||
usb_if.c optional uhci device-driver \
|
||||
dependency "$S/kern/makedevops.pl $S/dev/usb/usb_if.m" \
|
||||
compile-with "perl5 $S/kern/makedevops.pl -c $S/dev/usb/usb_if.m" \
|
||||
no-obj no-implicit-rule before-depend local \
|
||||
clean "usb_if.c"
|
||||
usb_if.h optional uhci device-driver \
|
||||
dependency "$S/kern/makedevops.pl $S/dev/usb/usb_if.m" \
|
||||
compile-with "perl5 $S/kern/makedevops.pl -h $S/dev/usb/usb_if.m" \
|
||||
no-obj no-implicit-rule before-depend \
|
||||
clean "usb_if.h"
|
||||
dev/usb/uhci.c optional uhci device-driver
|
||||
dev/usb/usb.c optional usb device-driver
|
||||
dev/usb/usbdi.c optional usb device-driver
|
||||
dev/usb/usbdi_util.c optional usb device-driver
|
||||
#dev/usb/usb_mem.c optional usb device-driver
|
||||
dev/usb/usb_subr.c optional usb device-driver
|
||||
dev/usb/usb_quirks.c optional usb device-driver
|
||||
dev/usb/hid.c optional usb device-driver
|
||||
dev/usb/uhub.c optional uhub device-driver
|
||||
dev/usb/ukbd.c optional ukbd device-driver
|
||||
dev/usb/ulpt.c optional ulpt device-driver
|
||||
dev/usb/ums.c optional ums device-driver
|
||||
dev/usb/ugen.c optional ugen device-driver
|
||||
#dev/usb/uhid.c optional hid device-driver
|
||||
|
@ -1,4 +1,4 @@
|
||||
# $Id: options,v 1.107 1998/11/05 14:28:17 dg Exp $
|
||||
# $Id: options,v 1.108 1998/11/23 09:58:59 phk Exp $
|
||||
#
|
||||
# On the handling of kernel options
|
||||
#
|
||||
@ -305,3 +305,7 @@ SIMOS opt_simos.h
|
||||
|
||||
# options for bus/device framework
|
||||
BUS_DEBUG opt_bus.h
|
||||
|
||||
# options for USB support
|
||||
USB_DEBUG opt_usb.h
|
||||
USBVERBOSE opt_usb.h
|
||||
|
338
sys/dev/pci/uhci_pci.c
Normal file
338
sys/dev/pci/uhci_pci.c
Normal file
@ -0,0 +1,338 @@
|
||||
/*
|
||||
* Copyright (c) 1998 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Lennart Augustsson <augustss@carlstedt.se>
|
||||
* 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 <dev/usb/usb_port.h>
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#if defined(__FreeBSD__)
|
||||
#include <sys/module.h>
|
||||
#include <sys/bus.h>
|
||||
#endif
|
||||
#include <sys/device.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/queue.h>
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
#include <machine/bus.h>
|
||||
#include <dev/pci/pcivar.h>
|
||||
#elif defined(__FreeBSD__)
|
||||
#include <pci/pcivar.h>
|
||||
#include <pci/pcireg.h>
|
||||
|
||||
#define PCI_CLASS_SERIALBUS 0x0c000000
|
||||
#define PCI_SUBCLASS_COMMUNICATIONS_SERIAL 0x00000000
|
||||
#define PCI_SUBCLASS_SERIALBUS_FIREWIRE 0x00000000
|
||||
#define PCI_SUBCLASS_SERIALBUS_ACCESS 0x00010000
|
||||
#define PCI_SUBCLASS_SERIALBUS_SSA 0x00020000
|
||||
#define PCI_SUBCLASS_SERIALBUS_USB 0x00030000
|
||||
#define PCI_SUBCLASS_SERIALBUS_FIBER 0x00040000
|
||||
#endif
|
||||
|
||||
#include <dev/usb/usb.h>
|
||||
#include <dev/usb/usbdi.h>
|
||||
#include <dev/usb/usbdivar.h>
|
||||
#include <dev/usb/usb_mem.h>
|
||||
|
||||
#include <dev/usb/uhcireg.h>
|
||||
#include <dev/usb/uhcivar.h>
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
int uhci_pci_match __P((struct device *, struct cfdata *, void *));
|
||||
void uhci_pci_attach __P((struct device *, struct device *, void *));
|
||||
|
||||
struct cfattach uhci_pci_ca = {
|
||||
sizeof(uhci_softc_t), uhci_pci_match, uhci_pci_attach
|
||||
};
|
||||
|
||||
#elif defined(__FreeBSD__)
|
||||
|
||||
#define PCI_INTERFACE_MASK 0x0000ff00
|
||||
#define PCI_INTERFACE_SHIFT 8
|
||||
#define PCI_INTERFACE(d) (((d)>>8)&PCI_INTERFACE_MASK)
|
||||
#define PCI_SUBCLASS(d) ((d)&PCI_SUBCLASS_MASK)
|
||||
#define PCI_CLASS(d) ((d)&PCI_CLASS_MASK)
|
||||
|
||||
#define PCI_VENDOR(d) ((d)&0xffff)
|
||||
#define PCI_DEVICE(d) (((d)>>8)&0xffff)
|
||||
|
||||
#define PCI_UHCI_DEVICEID_PIIX3 0x70208086ul
|
||||
#define PCI_UHCI_DEVICEID_PIIX4 0x71128086ul
|
||||
#define PCI_UHCI_DEVICEID_PIIX4E 0x71128086ul /* no separate step */
|
||||
|
||||
#define PCI_UHCI_BASE_REG 0x20
|
||||
|
||||
static char *uhci_pci_probe __P((pcici_t, pcidi_t));
|
||||
static void uhci_pci_attach __P((pcici_t, int));
|
||||
|
||||
u_long uhci_count = 0; /* global counter for nr. of devices found */
|
||||
|
||||
static struct pci_device uhci_pci_device = {
|
||||
"uhci",
|
||||
uhci_pci_probe,
|
||||
uhci_pci_attach,
|
||||
&uhci_count,
|
||||
NULL
|
||||
};
|
||||
|
||||
DATA_SET(pcidevice_set, uhci_pci_device);
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
int
|
||||
uhci_pci_match(parent, match, aux)
|
||||
struct device *parent;
|
||||
struct cfdata *match;
|
||||
void *aux;
|
||||
{
|
||||
struct pci_attach_args *pa = (struct pci_attach_args *) aux;
|
||||
|
||||
if (PCI_CLASS(pa->pa_class) == PCI_CLASS_SERIALBUS &&
|
||||
PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_SERIALBUS_USB &&
|
||||
PCI_INTERFACE(pa->pa_class) == PCI_INTERFACE_UHCI)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#elif defined(__FreeBSD__)
|
||||
static char *
|
||||
uhci_pci_probe(pcici_t config_id, pcidi_t device_id)
|
||||
{
|
||||
u_int32_t class;
|
||||
|
||||
if (device_id == PCI_UHCI_DEVICEID_PIIX3)
|
||||
return ("Intel 82371SB USB Host Controller");
|
||||
else if (device_id == PCI_UHCI_DEVICEID_PIIX4)
|
||||
return ("Intel 82371AB/EB USB Host Controller");
|
||||
else {
|
||||
class = pci_conf_read(config_id, PCI_CLASS_REG);
|
||||
if ( PCI_CLASS(class) == PCI_CLASS_SERIALBUS
|
||||
&& PCI_SUBCLASS(class) == PCI_SUBCLASS_SERIALBUS_USB
|
||||
&& PCI_INTERFACE(class) == PCI_INTERFACE_UHCI) {
|
||||
return ("UHCI Host Controller");
|
||||
}
|
||||
}
|
||||
|
||||
return NULL; /* dunno... */
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
void
|
||||
uhci_pci_attach(parent, self, aux)
|
||||
struct device *parent;
|
||||
struct device *self;
|
||||
void *aux;
|
||||
{
|
||||
uhci_softc_t *sc = (uhci_softc_t *)self;
|
||||
struct pci_attach_args *pa = (struct pci_attach_args *)aux;
|
||||
pci_chipset_tag_t pc = pa->pa_pc;
|
||||
char const *intrstr;
|
||||
pci_intr_handle_t ih;
|
||||
pcireg_t csr;
|
||||
char *typestr, *vendor;
|
||||
char devinfo[256];
|
||||
usbd_status r;
|
||||
|
||||
pci_devinfo(pa->pa_id, pa->pa_class, 0, devinfo);
|
||||
printf(": %s (rev. 0x%02x)\n", devinfo, PCI_REVISION(pa->pa_class));
|
||||
|
||||
/* Map I/O registers */
|
||||
if (pci_mapreg_map(pa, PCI_CBIO, PCI_MAPREG_TYPE_IO, 0,
|
||||
&sc->iot, &sc->ioh, NULL, NULL)) {
|
||||
printf("%s: can't map i/o space\n", sc->sc_bus.bdev.dv_xname);
|
||||
return;
|
||||
}
|
||||
|
||||
sc->sc_dmatag = pa->pa_dmat;
|
||||
|
||||
|
||||
/* Enable the device. */
|
||||
csr = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
|
||||
pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
|
||||
csr | PCI_COMMAND_MASTER_ENABLE);
|
||||
|
||||
/* Map and establish the interrupt. */
|
||||
return EFAULT;
|
||||
|
||||
if (pci_intr_map(pc, pa->pa_intrtag, pa->pa_intrpin,
|
||||
pa->pa_intrline, &ih)) {
|
||||
printf("%s: couldn't map interrupt\n",
|
||||
sc->sc_bus.bdev.dv_xname);
|
||||
return;
|
||||
}
|
||||
intrstr = pci_intr_string(pc, ih);
|
||||
sc->sc_ih = pci_intr_establish(pc, ih, IPL_USB, uhci_intr, sc);
|
||||
if (sc->sc_ih == NULL) {
|
||||
printf("%s: couldn't establish interrupt",
|
||||
sc->sc_bus.bdev.dv_xname);
|
||||
if (intrstr != NULL)
|
||||
printf(" at %s", intrstr);
|
||||
printf("\n");
|
||||
return;
|
||||
}
|
||||
printf("%s: interrupting at %s\n", sc->sc_bus.bdev.dv_xname, intrstr);
|
||||
|
||||
switch(pci_conf_read(pc, pa->pa_tag, PCI_USBREV) & PCI_USBREV_MASK) {
|
||||
case PCI_USBREV_PRE_1_0:
|
||||
typestr = "pre 1.0";
|
||||
break;
|
||||
case PCI_USBREV_1_0:
|
||||
typestr = "1.0";
|
||||
break;
|
||||
default:
|
||||
typestr = "unknown";
|
||||
break;
|
||||
}
|
||||
printf("%s: USB version %s\n", sc->sc_bus.bdev.dv_xname, typestr);
|
||||
|
||||
/* Figure out vendor for root hub descriptor. */
|
||||
vendor = pci_findvendor(pa->pa_id);
|
||||
if (vendor)
|
||||
strncpy(sc->sc_vendor, vendor, sizeof(sc->sc_vendor));
|
||||
else
|
||||
sprintf(sc->sc_vendor, "vendor 0x%04x", PCI_VENDOR(pa->pa_id));
|
||||
|
||||
r = uhci_init(sc);
|
||||
if (r != USBD_NORMAL_COMPLETION) {
|
||||
printf("%s: init failed, error=%d\n",
|
||||
sc->sc_bus.bdev.dv_xname, r);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Attach usb device. */
|
||||
config_found((void *)sc, &sc->sc_bus, usbctlprint);
|
||||
}
|
||||
|
||||
|
||||
#elif defined(__FreeBSD__)
|
||||
|
||||
static void
|
||||
uhci_pci_attach(config_id, unit)
|
||||
pcici_t config_id;
|
||||
int unit;
|
||||
{
|
||||
int irq;
|
||||
int id;
|
||||
char *typestr;
|
||||
char devinfo[256];
|
||||
usbd_status r;
|
||||
uhci_softc_t *sc = NULL;
|
||||
int legsup;
|
||||
|
||||
sc = malloc(sizeof(uhci_softc_t), M_DEVBUF, M_NOWAIT);
|
||||
if ( sc == NULL ) {
|
||||
printf("usb%d: could not allocate memory", unit);
|
||||
return;
|
||||
}
|
||||
memset(sc, 0, sizeof(uhci_softc_t));
|
||||
|
||||
sc->sc_iobase = pci_conf_read(config_id,PCI_UHCI_BASE_REG) & 0xffe0;
|
||||
sc->sc_int = pci_conf_read(config_id,PCI_INTERRUPT_REG) & 0xff;
|
||||
sc->unit = unit;
|
||||
|
||||
if ( !pci_map_int(config_id, (pci_inthand_t *)uhci_intr,
|
||||
(void *) sc, &bio_imask)) {
|
||||
printf("usb%d: Unable to map irq\n", unit);
|
||||
return;
|
||||
}
|
||||
|
||||
if (bootverbose) {
|
||||
printf("usb%d: interrupting at %d\n", unit, sc->sc_int);
|
||||
switch(pci_conf_read(config_id, PCI_USBREV) & PCI_USBREV_MASK) {
|
||||
case PCI_USBREV_PRE_1_0:
|
||||
typestr = "pre 1.0";
|
||||
break;
|
||||
case PCI_USBREV_1_0:
|
||||
typestr = "1.0";
|
||||
break;
|
||||
default:
|
||||
typestr = "unknown";
|
||||
break;
|
||||
}
|
||||
printf("usb%d: USB version %s\n", unit, typestr);
|
||||
}
|
||||
|
||||
/* Figure out vendor for root hub descriptor. */
|
||||
id = pci_conf_read(config_id, PCI_ID_REG);
|
||||
if (PCI_VENDOR(id) == 0x8086)
|
||||
sprintf(sc->sc_vendor, "Intel");
|
||||
else
|
||||
sprintf(sc->sc_vendor, "Vendor 0x%04x", PCI_VENDOR(id));
|
||||
|
||||
r = uhci_init(sc);
|
||||
if (r != USBD_NORMAL_COMPLETION) {
|
||||
printf("usb%d: init failed, error=%d\n", unit, r);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* We add a child to the root bus. After PCI configuration
|
||||
* has completed the root bus will start to probe and
|
||||
* attach all the devices attached to it, including our new
|
||||
* kid.
|
||||
*
|
||||
* FIXME Sometime in the future the UHCI controller itself will
|
||||
* become a kid of PCI device and this device add will no longer
|
||||
* be necessary.
|
||||
*
|
||||
* See README for an elaborate description of the bus
|
||||
* structure in spe.
|
||||
*/
|
||||
sc->sc_bus.bdev = device_add_child(root_bus, "usb", unit, sc);
|
||||
if (!sc->sc_bus.bdev)
|
||||
DEVICE_ERROR(sc->sc_bus.bdev,
|
||||
("unable to add USB device to root bus\n"));
|
||||
|
||||
id = pci_conf_read(config_id, PCI_ID_REG);
|
||||
switch (id) {
|
||||
case PCI_UHCI_DEVICEID_PIIX3:
|
||||
device_set_desc(sc->sc_bus.bdev, "Intel 82371SB USB Host Controller");
|
||||
break;
|
||||
case PCI_UHCI_DEVICEID_PIIX4:
|
||||
device_set_desc(sc->sc_bus.bdev, "Intel 82371AB/EB USB Host Controller");
|
||||
break;
|
||||
default:
|
||||
device_set_desc(sc->sc_bus.bdev, "UHCI Host Controller");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
#endif
|
469
sys/dev/usb/hid.c
Normal file
469
sys/dev/usb/hid.c
Normal file
@ -0,0 +1,469 @@
|
||||
/* $NetBSD: hid.c,v 1.2 1998/07/24 20:57:46 augustss Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1998 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Lennart Augustsson <augustss@carlstedt.se>
|
||||
* 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 <dev/usb/usb_port.h>
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/malloc.h>
|
||||
|
||||
#include <dev/usb/usb.h>
|
||||
#include <dev/usb/usbhid.h>
|
||||
|
||||
#include <dev/usb/hid.h>
|
||||
|
||||
#ifdef USB_DEBUG
|
||||
#define DPRINTF(x) if (usbdebug) printf x
|
||||
#define DPRINTFN(n,x) if (usbdebug>(n)) printf x
|
||||
extern int usbdebug;
|
||||
#else
|
||||
#define DPRINTF(x)
|
||||
#define DPRINTFN(n,x)
|
||||
#endif
|
||||
|
||||
static void hid_clear_local __P((struct hid_item *));
|
||||
|
||||
#define MAXUSAGE 100
|
||||
struct hid_data {
|
||||
u_char *start;
|
||||
u_char *end;
|
||||
u_char *p;
|
||||
struct hid_item cur;
|
||||
int32_t usages[MAXUSAGE];
|
||||
int nu;
|
||||
int minset;
|
||||
int multi;
|
||||
int multimax;
|
||||
int kindset;
|
||||
};
|
||||
|
||||
static void
|
||||
hid_clear_local(c)
|
||||
struct hid_item *c;
|
||||
{
|
||||
c->usage = 0;
|
||||
c->usage_minimum = 0;
|
||||
c->usage_maximum = 0;
|
||||
c->designator_index = 0;
|
||||
c->designator_minimum = 0;
|
||||
c->designator_maximum = 0;
|
||||
c->string_index = 0;
|
||||
c->string_minimum = 0;
|
||||
c->string_maximum = 0;
|
||||
c->set_delimiter = 0;
|
||||
}
|
||||
|
||||
struct hid_data *
|
||||
hid_start_parse(d, len, kindset)
|
||||
void *d;
|
||||
int len;
|
||||
int kindset;
|
||||
{
|
||||
struct hid_data *s;
|
||||
u_char *p = d;
|
||||
|
||||
s = malloc(sizeof *s, M_TEMP, M_WAITOK);
|
||||
memset(s, 0, sizeof *s);
|
||||
s->start = s->p = p;
|
||||
s->end = p + len;
|
||||
s->kindset = kindset;
|
||||
return (s);
|
||||
}
|
||||
|
||||
void
|
||||
hid_end_parse(s)
|
||||
struct hid_data *s;
|
||||
{
|
||||
while (s->cur.next) {
|
||||
struct hid_item *hi = s->cur.next->next;
|
||||
free(s->cur.next, M_TEMP);
|
||||
s->cur.next = hi;
|
||||
}
|
||||
free(s, M_TEMP);
|
||||
}
|
||||
|
||||
int
|
||||
hid_get_item(s, h)
|
||||
struct hid_data *s;
|
||||
struct hid_item *h;
|
||||
{
|
||||
struct hid_item *c = &s->cur;
|
||||
int bTag, bType, bSize;
|
||||
u_char *data;
|
||||
int32_t dval;
|
||||
u_char *p;
|
||||
struct hid_item *hi;
|
||||
int i;
|
||||
|
||||
top:
|
||||
if (s->multimax) {
|
||||
if (s->multi < s->multimax) {
|
||||
c->usage = s->usages[min(s->multi, s->nu-1)];
|
||||
s->multi++;
|
||||
*h = *c;
|
||||
c->loc.pos += c->loc.size;
|
||||
h->next = 0;
|
||||
return (1);
|
||||
} else {
|
||||
c->loc.count = s->multimax;
|
||||
s->multimax = 0;
|
||||
s->nu = 0;
|
||||
hid_clear_local(c);
|
||||
}
|
||||
}
|
||||
for (;;) {
|
||||
p = s->p;
|
||||
if (p >= s->end)
|
||||
return (0);
|
||||
|
||||
bSize = *p++;
|
||||
if (bSize == 0xfe) {
|
||||
/* long item */
|
||||
bSize = *p++;
|
||||
bSize |= *p++ << 8;
|
||||
bTag = *p++;
|
||||
data = p;
|
||||
p += bSize;
|
||||
bType = 0xff; /* XXX what should it be */
|
||||
} else {
|
||||
/* short item */
|
||||
bTag = bSize >> 4;
|
||||
bType = (bSize >> 2) & 3;
|
||||
bSize &= 3;
|
||||
if (bSize == 3) bSize = 4;
|
||||
data = p;
|
||||
p += bSize;
|
||||
}
|
||||
s->p = p;
|
||||
switch(bSize) {
|
||||
case 0:
|
||||
dval = 0;
|
||||
break;
|
||||
case 1:
|
||||
dval = (int8_t)*data++;
|
||||
break;
|
||||
case 2:
|
||||
dval = *data++;
|
||||
dval |= *data++ << 8;
|
||||
dval = (int16_t)dval;
|
||||
break;
|
||||
case 4:
|
||||
dval = *data++;
|
||||
dval |= *data++ << 8;
|
||||
dval |= *data++ << 16;
|
||||
dval |= *data++ << 24;
|
||||
break;
|
||||
default:
|
||||
printf("BAD LENGTH %d\n", bSize);
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (bType) {
|
||||
case 0: /* Main */
|
||||
switch (bTag) {
|
||||
case 8: /* Input */
|
||||
if (!(s->kindset & (1 << hid_input)))
|
||||
continue;
|
||||
c->kind = hid_input;
|
||||
c->flags = dval;
|
||||
ret:
|
||||
if (c->flags & HIO_VARIABLE) {
|
||||
s->multimax = c->loc.count;
|
||||
s->multi = 0;
|
||||
c->loc.count = 1;
|
||||
if (s->minset) {
|
||||
for (i = c->usage_minimum;
|
||||
i <= c->usage_maximum;
|
||||
i++) {
|
||||
s->usages[s->nu] = i;
|
||||
if (s->nu < MAXUSAGE-1)
|
||||
s->nu++;
|
||||
}
|
||||
s->minset = 0;
|
||||
}
|
||||
goto top;
|
||||
} else {
|
||||
*h = *c;
|
||||
h->next = 0;
|
||||
c->loc.pos +=
|
||||
c->loc.size * c->loc.count;
|
||||
hid_clear_local(c);
|
||||
s->minset = 0;
|
||||
return (1);
|
||||
}
|
||||
case 9: /* Output */
|
||||
if (!(s->kindset & (1 << hid_output)))
|
||||
continue;
|
||||
c->kind = hid_output;
|
||||
c->flags = dval;
|
||||
goto ret;
|
||||
case 10: /* Collection */
|
||||
c->kind = hid_collection;
|
||||
c->collection = dval;
|
||||
c->collevel++;
|
||||
*h = *c;
|
||||
hid_clear_local(c);
|
||||
s->nu = 0;
|
||||
return (1);
|
||||
case 11: /* Feature */
|
||||
if (!(s->kindset & (1 << hid_feature)))
|
||||
continue;
|
||||
c->kind = hid_feature;
|
||||
c->flags = dval;
|
||||
goto ret;
|
||||
case 12: /* End collection */
|
||||
c->kind = hid_endcollection;
|
||||
c->collevel--;
|
||||
*h = *c;
|
||||
hid_clear_local(c);
|
||||
s->nu = 0;
|
||||
return (1);
|
||||
default:
|
||||
printf("Main bTag=%d\n", bTag);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 1: /* Global */
|
||||
switch (bTag) {
|
||||
case 0:
|
||||
c->_usage_page = dval << 16;
|
||||
break;
|
||||
case 1:
|
||||
c->logical_minimum = dval;
|
||||
break;
|
||||
case 2:
|
||||
c->logical_maximum = dval;
|
||||
break;
|
||||
case 3:
|
||||
c->physical_maximum = dval;
|
||||
break;
|
||||
case 4:
|
||||
c->physical_maximum = dval;
|
||||
break;
|
||||
case 5:
|
||||
c->unit_exponent = dval;
|
||||
break;
|
||||
case 6:
|
||||
c->unit = dval;
|
||||
break;
|
||||
case 7:
|
||||
c->loc.size = dval;
|
||||
break;
|
||||
case 8:
|
||||
c->report_ID = dval;
|
||||
break;
|
||||
case 9:
|
||||
c->loc.count = dval;
|
||||
break;
|
||||
case 10: /* Push */
|
||||
hi = malloc(sizeof *hi, M_TEMP, M_WAITOK);
|
||||
*hi = s->cur;
|
||||
c->next = hi;
|
||||
break;
|
||||
case 11: /* Pop */
|
||||
hi = c->next;
|
||||
s->cur = *hi;
|
||||
free(hi, M_TEMP);
|
||||
break;
|
||||
default:
|
||||
printf("Global bTag=%d\n", bTag);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 2: /* Local */
|
||||
switch (bTag) {
|
||||
case 0:
|
||||
if (bSize == 1)
|
||||
dval = c->_usage_page | (dval&0xff);
|
||||
else if (bSize == 2)
|
||||
dval = c->_usage_page | (dval&0xffff);
|
||||
c->usage = dval;
|
||||
if (s->nu < MAXUSAGE)
|
||||
s->usages[s->nu++] = dval;
|
||||
/* else XXX */
|
||||
break;
|
||||
case 1:
|
||||
s->minset = 1;
|
||||
if (bSize == 1)
|
||||
dval = c->_usage_page | (dval&0xff);
|
||||
else if (bSize == 2)
|
||||
dval = c->_usage_page | (dval&0xffff);
|
||||
c->usage_minimum = dval;
|
||||
break;
|
||||
case 2:
|
||||
if (bSize == 1)
|
||||
dval = c->_usage_page | (dval&0xff);
|
||||
else if (bSize == 2)
|
||||
dval = c->_usage_page | (dval&0xffff);
|
||||
c->usage_maximum = dval;
|
||||
break;
|
||||
case 3:
|
||||
c->designator_index = dval;
|
||||
break;
|
||||
case 4:
|
||||
c->designator_minimum = dval;
|
||||
break;
|
||||
case 5:
|
||||
c->designator_maximum = dval;
|
||||
break;
|
||||
case 7:
|
||||
c->string_index = dval;
|
||||
break;
|
||||
case 8:
|
||||
c->string_minimum = dval;
|
||||
break;
|
||||
case 9:
|
||||
c->string_maximum = dval;
|
||||
break;
|
||||
case 10:
|
||||
c->set_delimiter = dval;
|
||||
break;
|
||||
default:
|
||||
printf("Local bTag=%d\n", bTag);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
printf("default bType=%d\n", bType);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
hid_report_size(buf, len, k, idp)
|
||||
void *buf;
|
||||
int len;
|
||||
enum hid_kind k;
|
||||
u_int8_t *idp;
|
||||
{
|
||||
struct hid_data *d;
|
||||
struct hid_item h;
|
||||
int size, id;
|
||||
|
||||
id = 0;
|
||||
for (d = hid_start_parse(buf, len, 1<<k); hid_get_item(d, &h); )
|
||||
if (h.report_ID)
|
||||
id = h.report_ID;
|
||||
hid_end_parse(d);
|
||||
size = h.loc.pos;
|
||||
if (id) {
|
||||
size += 8;
|
||||
*idp = id; /* XXX wrong */
|
||||
} else
|
||||
*idp = 0;
|
||||
return ((size + 7) / 8);
|
||||
}
|
||||
|
||||
int
|
||||
hid_locate(desc, size, u, k, loc, flags)
|
||||
void *desc;
|
||||
int size;
|
||||
u_int32_t u;
|
||||
enum hid_kind k;
|
||||
struct hid_location *loc;
|
||||
u_int32_t *flags;
|
||||
{
|
||||
struct hid_data *d;
|
||||
struct hid_item h;
|
||||
|
||||
for (d = hid_start_parse(desc, size, 1<<k); hid_get_item(d, &h); ) {
|
||||
if (h.kind == k && !(h.flags & HIO_CONST) && h.usage == u) {
|
||||
if (loc)
|
||||
*loc = h.loc;
|
||||
if (flags)
|
||||
*flags = h.flags;
|
||||
hid_end_parse(d);
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
hid_end_parse(d);
|
||||
loc->size = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
u_long
|
||||
hid_get_data(buf, loc)
|
||||
u_char *buf;
|
||||
struct hid_location *loc;
|
||||
{
|
||||
u_int hpos = loc->pos;
|
||||
u_int hsize = loc->size;
|
||||
u_int32_t data;
|
||||
int i, s;
|
||||
|
||||
DPRINTFN(10, ("hid_get_data: loc %d/%d\n", hpos, hsize));
|
||||
|
||||
if (hsize == 0)
|
||||
return (0);
|
||||
|
||||
data = 0;
|
||||
s = hpos / 8;
|
||||
for (i = hpos; i < hpos+hsize; i += 8)
|
||||
data |= buf[i / 8] << ((i / 8 - s) * 8);
|
||||
data >>= hpos % 8;
|
||||
data &= (1 << hsize) - 1;
|
||||
hsize = 32 - hsize;
|
||||
/* Sign extend */
|
||||
data = ((int32_t)data << hsize) >> hsize;
|
||||
DPRINTFN(10, ("hid_get_data: loc %d/%d = %lu\n",
|
||||
loc->pos, loc->size, (long)data));
|
||||
return (data);
|
||||
}
|
||||
|
||||
int
|
||||
hid_is_collection(desc, size, usage)
|
||||
void *desc;
|
||||
int size;
|
||||
u_int32_t usage;
|
||||
{
|
||||
struct hid_data *hd;
|
||||
struct hid_item hi;
|
||||
int r;
|
||||
|
||||
hd = hid_start_parse(desc, size, hid_input);
|
||||
if (!hd)
|
||||
return (0);
|
||||
|
||||
r = hid_get_item(hd, &hi) &&
|
||||
hi.kind == hid_collection &&
|
||||
hi.usage == usage;
|
||||
hid_end_parse(hd);
|
||||
return (r);
|
||||
}
|
89
sys/dev/usb/hid.h
Normal file
89
sys/dev/usb/hid.h
Normal file
@ -0,0 +1,89 @@
|
||||
/* $NetBSD: hid.h,v 1.2 1998/07/24 20:57:46 augustss Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1998 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Lennart Augustsson <augustss@carlstedt.se>
|
||||
* 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.
|
||||
*/
|
||||
|
||||
enum hid_kind {
|
||||
hid_input, hid_output, hid_feature, hid_collection, hid_endcollection
|
||||
};
|
||||
|
||||
struct hid_location {
|
||||
u_int32_t size;
|
||||
u_int32_t count;
|
||||
u_int32_t pos;
|
||||
};
|
||||
|
||||
struct hid_item {
|
||||
/* Global */
|
||||
int32_t _usage_page;
|
||||
int32_t logical_minimum;
|
||||
int32_t logical_maximum;
|
||||
int32_t physical_minimum;
|
||||
int32_t physical_maximum;
|
||||
int32_t unit_exponent;
|
||||
int32_t unit;
|
||||
int32_t report_ID;
|
||||
/* Local */
|
||||
int32_t usage;
|
||||
int32_t usage_minimum;
|
||||
int32_t usage_maximum;
|
||||
int32_t designator_index;
|
||||
int32_t designator_minimum;
|
||||
int32_t designator_maximum;
|
||||
int32_t string_index;
|
||||
int32_t string_minimum;
|
||||
int32_t string_maximum;
|
||||
int32_t set_delimiter;
|
||||
/* Misc */
|
||||
int32_t collection;
|
||||
int collevel;
|
||||
enum hid_kind kind;
|
||||
u_int32_t flags;
|
||||
/* Location */
|
||||
struct hid_location loc;
|
||||
/* */
|
||||
struct hid_item *next;
|
||||
};
|
||||
|
||||
struct hid_data *hid_start_parse __P((void *d, int len, int kindset));
|
||||
void hid_end_parse __P((struct hid_data *s));
|
||||
int hid_get_item __P((struct hid_data *s, struct hid_item *h));
|
||||
int hid_report_size __P((void *buf, int len, enum hid_kind k, u_int8_t *id));
|
||||
int hid_locate __P((void *desc, int size, u_int32_t usage,
|
||||
enum hid_kind kind, struct hid_location *loc,
|
||||
u_int32_t *flags));
|
||||
u_long hid_get_data __P((u_char *buf, struct hid_location *loc));
|
||||
int hid_is_collection __P((void *desc, int size, u_int32_t usage));
|
204
sys/dev/usb/ohcireg.h
Normal file
204
sys/dev/usb/ohcireg.h
Normal file
@ -0,0 +1,204 @@
|
||||
/* $NetBSD: ohcireg.h,v 1.2 1998/07/26 00:40:59 augustss Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1998 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Lennart Augustsson <augustss@carlstedt.se>
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _DEV_PCI_OHCIREG_H_
|
||||
#define _DEV_PCI_OHCIREG_H_
|
||||
|
||||
/*** PCI config registers ***/
|
||||
|
||||
#define PCI_CBMEM 0x10 /* configuration base memory */
|
||||
|
||||
#define PCI_INTERFACE_OHCI 0x10
|
||||
|
||||
/*** OHCI registers */
|
||||
|
||||
#define OHCI_REVISION 0x00 /* OHCI revision # */
|
||||
#define OHCI_REV_LO(rev) ((rev)&0xf)
|
||||
#define OHCI_REV_HI(rev) (((rev)>>4)&0xf)
|
||||
#define OHCI_REV_LEGACY(rev) ((rev) & 0x100)
|
||||
|
||||
#define OHCI_CONTROL 0x04
|
||||
#define OHCI_CBSR_MASK 0x00000003 /* Control/Bulk Service Ratio */
|
||||
#define OHCI_RATIO_1_1 0x00000000
|
||||
#define OHCI_RATIO_1_2 0x00000001
|
||||
#define OHCI_RATIO_1_3 0x00000002
|
||||
#define OHCI_RATIO_1_4 0x00000003
|
||||
#define OHCI_PLE 0x00000004 /* Periodic List Enable */
|
||||
#define OHCI_IE 0x00000008 /* Isochronous Enable */
|
||||
#define OHCI_CLE 0x00000010 /* Control List Enable */
|
||||
#define OHCI_BLE 0x00000020 /* Bulk List Enable */
|
||||
#define OHCI_HCFS_MASK 0x000000c0 /* HostControllerFunctionalState */
|
||||
#define OHCI_HCFS_RESET 0x00000000
|
||||
#define OHCI_HCFS_RESUME 0x00000040
|
||||
#define OHCI_HCFS_OPERATIONAL 0x00000080
|
||||
#define OHCI_HCFS_SUSPEND 0x000000c0
|
||||
#define OHCI_IR 0x00000100 /* Interrupt Routing */
|
||||
#define OHCI_RWC 0x00000200 /* Remote Wakeup Connected */
|
||||
#define OHCI_RWE 0x00000400 /* Remote Wakeup Enabled */
|
||||
#define OHCI_COMMAND_STATUS 0x08
|
||||
#define OHCI_HCR 0x00000001 /* Host Controller Reset */
|
||||
#define OHCI_CLF 0x00000002 /* Control List Filled */
|
||||
#define OHCI_BLF 0x00000004 /* Bulk List Filled */
|
||||
#define OHCI_OCR 0x00000008 /* Ownership Change Request */
|
||||
#define OHCI_SOC_MASK 0x00030000 /* Scheduling Overrun Count */
|
||||
#define OHCI_INTERRUPT_STATUS 0x0c
|
||||
#define OHCI_SO 0x00000001 /* Scheduling Overrun */
|
||||
#define OHCI_WDH 0x00000002 /* Writeback Done Head */
|
||||
#define OHCI_SF 0x00000004 /* Start of Frame */
|
||||
#define OHCI_RD 0x00000008 /* Resume Detected */
|
||||
#define OHCI_UE 0x00000010 /* Unrecoverable Error */
|
||||
#define OHCI_FNO 0x00000020 /* Frame Number Overflow */
|
||||
#define OHCI_RHSC 0x00000040 /* Root Hub Status Change */
|
||||
#define OHCI_OC 0x40000000 /* Ownership Change */
|
||||
#define OHCI_MIE 0x80000000 /* Master Interrupt Enable */
|
||||
#define OHCI_INTERRUPT_ENABLE 0x10
|
||||
#define OHCI_INTERRUPT_DISABLE 0x14
|
||||
#define OHCI_HCCA 0x18
|
||||
#define OHCI_PERIOD_CURRENT_ED 0x1c
|
||||
#define OHCI_CONTROL_HEAD_ED 0x20
|
||||
#define OHCI_CONTROL_CURRENT_ED 0x24
|
||||
#define OHCI_BULK_HEAD_ED 0x28
|
||||
#define OHCI_BULK_CURRENT_ED 0x2c
|
||||
#define OHCI_DONE_HEAD 0x30
|
||||
#define OHCI_FM_INTERVAL 0x34
|
||||
#define OHCI_GET_IVAL(s) ((s) & 0x3fff)
|
||||
#define OHCI_GET_FSMPS(s) (((s) >> 16) & 0x7fff)
|
||||
#define OHCI_FIT 0x80000000
|
||||
#define OHCI_FM_REMAINING 0x38
|
||||
#define OHCI_FM_NUMBER 0x3c
|
||||
#define OHCI_PERIODIC_START 0x40
|
||||
#define OHCI_LS_THRESHOLD 0x44
|
||||
#define OHCI_RH_DESCRIPTOR_A 0x48
|
||||
#define OHCI_GET_NDP(s) ((s) & 0xff)
|
||||
#define OHCI_PSM 0x0100 /* Power Switching Mode */
|
||||
#define OHCI_NPS 0x0200 /* No Power Switching */
|
||||
#define OHCI_GET_POTPGT(s) ((s) >> 24)
|
||||
#define OHCI_RH_DESCRIPTOR_B 0x4c
|
||||
#define OHCI_RH_STATUS 0x50
|
||||
#define OHCI_LPS 0x00000001 /* Local Power Status */
|
||||
#define OHCI_OCI 0x00000002 /* OverCurrent Indicator */
|
||||
#define OHCI_DRWE 0x00008000 /* Device Remote Wakeup Enable */
|
||||
#define OHCI_LPSC 0x00010000 /* Local Power Status Change */
|
||||
#define OHCI_CCIC 0x00020000 /* OverCurrent Indicator Change */
|
||||
#define OHCI_CRWE 0x80000000 /* Clear Remote Wakeup Enable */
|
||||
#define OHCI_RH_PORT_STATUS(n) (0x50 + (n)*4) /* 1 based indexing */
|
||||
|
||||
#define OHCI_LES (OHCI_PLE | OHCI_IE | OHCI_CLE | OHCI_BLE)
|
||||
#define OHCI_ALL_INTRS (OHCI_SO | OHCI_WDH | OHCI_SF | OHCI_RD | OHCI_UE | OHCI_FNO | OHCI_RHSC | OHCI_OC)
|
||||
#define OHCI_NORMAL_INTRS (OHCI_SO | OHCI_WDH | OHCI_RD | OHCI_UE | OHCI_RHSC)
|
||||
|
||||
#define OHCI_FSMPS(i) (((i-210)*6/7) << 16)
|
||||
#define OHCI_PERIODIC(i) ((i)*9/10)
|
||||
|
||||
typedef u_int32_t ohci_physaddr_t;
|
||||
|
||||
#define OHCI_NO_INTRS 32
|
||||
struct ohci_hcca {
|
||||
ohci_physaddr_t hcca_interrupt_table[OHCI_NO_INTRS];
|
||||
u_int32_t hcca_frame_number;
|
||||
ohci_physaddr_t hcca_done_head;
|
||||
#define OHCI_DONE_INTRS 1
|
||||
};
|
||||
#define OHCI_HCCA_SIZE 256
|
||||
#define OHCI_HCCA_ALIGN 256
|
||||
|
||||
typedef struct {
|
||||
u_int32_t ed_flags;
|
||||
#define OHCI_ED_GET_FA(s) ((s) & 0x7f)
|
||||
#define OHCI_ED_ADDRMASK 0x0000007f
|
||||
#define OHCI_ED_SET_FA(s) (s)
|
||||
#define OHCI_ED_GET_EN(s) (((s) >> 7) & 0xf)
|
||||
#define OHCI_ED_SET_EN(s) ((s) << 7)
|
||||
#define OHCI_ED_DIR_MASK 0x00001800
|
||||
#define OHCI_ED_DIR_TD 0x00000000
|
||||
#define OHCI_ED_DIR_OUT 0x00000800
|
||||
#define OHCI_ED_DIR_IN 0x00001000
|
||||
#define OHCI_ED_SPEED 0x00002000
|
||||
#define OHCI_ED_SKIP 0x00004000
|
||||
#define OHCI_ED_FORMAT_GEN 0x00000000
|
||||
#define OHCI_ED_FORMAT_ISO 0x00008000
|
||||
#define OHCI_ED_GET_MAXP(s) (((s) >> 16) & 0x07ff)
|
||||
#define OHCI_ED_SET_MAXP(s) ((s) << 16)
|
||||
ohci_physaddr_t ed_tailp;
|
||||
#define OHCI_HALTED 0x00000002
|
||||
#define OHCI_TOGGLECARRY 0x00000001
|
||||
#define OHCI_TAILMASK 0xfffffffc
|
||||
ohci_physaddr_t ed_headp;
|
||||
ohci_physaddr_t ed_nexted;
|
||||
} ohci_ed_t;
|
||||
#define OHCI_ED_SIZE 16
|
||||
#define OHCI_ED_ALIGN 16
|
||||
|
||||
typedef struct {
|
||||
u_int32_t td_flags;
|
||||
#define OHCI_TD_R 0x00040000 /* Buffer Rounding */
|
||||
#define OHCI_TD_DP_MASK 0x00180000 /* Direction / PID */
|
||||
#define OHCI_TD_SETUP 0x00000000
|
||||
#define OHCI_TD_OUT 0x00080000
|
||||
#define OHCI_TD_IN 0x00100000
|
||||
#define OHCI_TD_GET_DI(x) (((x) >> 21) & 7) /* Delay Interrupt */
|
||||
#define OHCI_TD_SET_DI(x) ((x) << 21)
|
||||
#define OHCI_TD_NOINTR 0x00e00000
|
||||
#define OHCI_TD_TOGGLE_CARRY 0x00000000
|
||||
#define OHCI_TD_TOGGLE_0 0x02000000
|
||||
#define OHCI_TD_TOGGLE_1 0x03000000
|
||||
#define OHCI_TD_GET_EC(x) (((x) >> 26) & 3) /* Error Count */
|
||||
#define OHCI_TD_GET_CC(x) ((x) >> 28) /* Condition Code */
|
||||
#define OHCI_TD_NOCC 0xf0000000
|
||||
ohci_physaddr_t td_cbp; /* Current Buffer Pointer */
|
||||
ohci_physaddr_t td_nexttd; /* Next TD */
|
||||
ohci_physaddr_t td_be; /* Buffer End */
|
||||
} ohci_td_t;
|
||||
#define OHCI_TD_SIZE 16
|
||||
#define OHCI_TD_ALIGN 16
|
||||
|
||||
#define OHCI_CC_NO_ERROR 0
|
||||
#define OHCI_CC_CRC 1
|
||||
#define OHCI_CC_BIT_STUFFING 2
|
||||
#define OHCI_CC_DATA_TOGGLE_MISMATCH 3
|
||||
#define OHCI_CC_STALL 4
|
||||
#define OHCI_CC_DEVICE_NOT_RESPONDING 5
|
||||
#define OHCI_CC_PID_CHECK_FAILURE 6
|
||||
#define OHCI_CC_UNEXPECTED_PID 7
|
||||
#define OHCI_CC_DATA_OVERRUN 8
|
||||
#define OHCI_CC_DATA_UNDERRUN 9
|
||||
#define OHCI_CC_BUFFER_OVERRUN 12
|
||||
#define OHCI_CC_BUFFER_UNDERRUN 13
|
||||
#define OHCI_CC_NOT_ACCESSED 15
|
||||
|
||||
#endif /* _DEV_PCI_OHCIREG_H_ */
|
107
sys/dev/usb/ohcivar.h
Normal file
107
sys/dev/usb/ohcivar.h
Normal file
@ -0,0 +1,107 @@
|
||||
/* $NetBSD: ohcivar.h,v 1.2 1998/07/24 21:09:07 augustss Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1998 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Lennart Augustsson <augustss@carlstedt.se>
|
||||
* 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.
|
||||
*/
|
||||
|
||||
typedef struct ohci_soft_ed {
|
||||
ohci_ed_t *ed;
|
||||
struct ohci_soft_ed *next;
|
||||
ohci_physaddr_t physaddr;
|
||||
} ohci_soft_ed_t;
|
||||
#define OHCI_ED_CHUNK 256
|
||||
|
||||
typedef struct ohci_soft_td {
|
||||
ohci_td_t *td;
|
||||
struct ohci_soft_td *nexttd; /* mirrors nexttd in TD */
|
||||
struct ohci_soft_td *dnext; /* next in done list */
|
||||
ohci_physaddr_t physaddr;
|
||||
LIST_ENTRY(ohci_soft_td) hnext;
|
||||
/*ohci_soft_ed_t *sed;*/
|
||||
usbd_request_handle reqh;
|
||||
u_int16_t len;
|
||||
} ohci_soft_td_t;
|
||||
#define OHCI_TD_CHUNK 256
|
||||
|
||||
#define OHCI_NO_EDS (2*OHCI_NO_INTRS-1)
|
||||
|
||||
#define OHCI_HASH_SIZE 128
|
||||
|
||||
typedef struct ohci_softc {
|
||||
struct usbd_bus sc_bus; /* base device */
|
||||
void *sc_ih; /* interrupt vectoring */
|
||||
bus_space_tag_t iot;
|
||||
bus_space_handle_t ioh;
|
||||
|
||||
bus_dma_tag_t sc_dmatag; /* DMA tag */
|
||||
/* XXX should keep track of all DMA memory */
|
||||
|
||||
usb_dma_t sc_hccadma;
|
||||
struct ohci_hcca *sc_hcca;
|
||||
ohci_soft_ed_t *sc_eds[OHCI_NO_EDS];
|
||||
u_int sc_bws[OHCI_NO_INTRS];
|
||||
|
||||
u_int32_t sc_eintrs;
|
||||
ohci_soft_ed_t *sc_ctrl_head;
|
||||
ohci_soft_ed_t *sc_bulk_head;
|
||||
|
||||
LIST_HEAD(, ohci_soft_td) sc_hash_tds[OHCI_HASH_SIZE];
|
||||
|
||||
int sc_noport;
|
||||
u_int8_t sc_addr; /* device address */
|
||||
u_int8_t sc_conf; /* device configuration */
|
||||
|
||||
ohci_soft_ed_t *sc_freeeds;
|
||||
ohci_soft_td_t *sc_freetds;
|
||||
|
||||
usbd_request_handle sc_intrreqh;
|
||||
|
||||
int sc_intrs;
|
||||
char sc_vendor[16];
|
||||
} ohci_softc_t;
|
||||
|
||||
usbd_status ohci_init __P((ohci_softc_t *));
|
||||
int ohci_intr __P((void *));
|
||||
|
||||
#define MS_TO_TICKS(ms) ((ms) * hz / 1000)
|
||||
|
||||
#ifdef USB_DEBUG
|
||||
#define DPRINTF(x) if (ohcidebug) printf x
|
||||
#define DPRINTFN(n,x) if (ohcidebug>(n)) printf x
|
||||
int ohcidebug;
|
||||
#else
|
||||
#define DPRINTF(x)
|
||||
#define DPRINTFN(n,x)
|
||||
#endif
|
29
sys/dev/usb/queue.addendum.h
Normal file
29
sys/dev/usb/queue.addendum.h
Normal file
@ -0,0 +1,29 @@
|
||||
/* These definitions are taken from the NetBSD /sys/sys/queue.h file
|
||||
* The copyright as in /sys/sys/queue.h from FreeBSD applies (they are the same)
|
||||
*/
|
||||
|
||||
/* This was called SIMPLEQ
|
||||
*/
|
||||
#ifndef STAILQ_HEAD_INITIALIZER
|
||||
#define STAILQ_HEAD_INITIALIZER(head) \
|
||||
{ NULL, &(head).stqh_first }
|
||||
#endif
|
||||
|
||||
/* This one was called SIMPLEQ_REMOVE_HEAD but removes not only the
|
||||
* head element, but a whole queue of elements from the head.
|
||||
*/
|
||||
#ifndef STAILQ_REMOVE_HEAD_QUEUE
|
||||
#define STAILQ_REMOVE_HEAD_QUEUE(head, elm, field) do { \
|
||||
if (((head)->stqh_first = (elm)->field.stqe_next) == NULL) \
|
||||
(head)->stqh_last = &(head)->stqh_first; \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
|
||||
/* This is called LIST and was called like that as well in the NetBSD version
|
||||
*/
|
||||
#ifndef LIST_HEAD_INITIALIZER
|
||||
#define LIST_HEAD_INITIALIZER(head) \
|
||||
{ NULL }
|
||||
#endif
|
||||
|
183
sys/dev/usb/ugen.c
Normal file
183
sys/dev/usb/ugen.c
Normal file
@ -0,0 +1,183 @@
|
||||
/*
|
||||
* Copyright (c) 1998 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Lennart Augustsson <augustss@carlstedt.se>
|
||||
* 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 <dev/usb/usb_port.h>
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/kernel.h>
|
||||
#if defined(__NetBSD__)
|
||||
#include <sys/device.h>
|
||||
#elif defined(__FreeBSD__)
|
||||
#include <sys/module.h>
|
||||
#include <sys/bus.h>
|
||||
#endif
|
||||
#include <sys/uio.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/syslog.h>
|
||||
|
||||
#include <dev/usb/usb.h>
|
||||
#include <dev/usb/usbdi.h>
|
||||
#include <dev/usb/usbdi_util.h>
|
||||
#include <dev/usb/usbdivar.h>
|
||||
#include <dev/usb/usbdevs.h>
|
||||
#include <dev/usb/usb_quirks.h>
|
||||
|
||||
#ifdef USB_DEBUG
|
||||
#define DPRINTF(x) if (usbdebug) printf x
|
||||
#define DPRINTFN(n,x) if (usbdebug>(n)) printf x
|
||||
extern int usbdebug;
|
||||
#else
|
||||
#define DPRINTF(x)
|
||||
#define DPRINTFN(n,x)
|
||||
#endif
|
||||
|
||||
struct ugen_softc {
|
||||
bdevice sc_dev;
|
||||
usbd_device_handle sc_udev; /* device */
|
||||
usbd_interface_handle sc_iface; /* interface */
|
||||
int sc_ifaceno;
|
||||
int sc_bulk;
|
||||
};
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
int ugen_match __P((struct device *, struct cfdata *, void *));
|
||||
void ugen_attach __P((struct device *, struct device *, void *));
|
||||
|
||||
extern struct cfdriver ugen_cd;
|
||||
|
||||
struct cfattach ugen_ca = {
|
||||
sizeof(struct ugen_softc), ugen_match, ugen_attach
|
||||
};
|
||||
#elif defined(__FreeBSD__)
|
||||
static device_probe_t ugen_match;
|
||||
static device_attach_t ugen_attach;
|
||||
static device_detach_t ugen_detach;
|
||||
|
||||
static devclass_t ugen_devclass;
|
||||
|
||||
static device_method_t ugen_methods[] = {
|
||||
DEVMETHOD(device_probe, ugen_match),
|
||||
DEVMETHOD(device_attach, ugen_attach),
|
||||
DEVMETHOD(device_detach, ugen_detach),
|
||||
{0,0}
|
||||
};
|
||||
|
||||
static driver_t ugen_driver = {
|
||||
"ugen",
|
||||
ugen_methods,
|
||||
DRIVER_TYPE_MISC,
|
||||
sizeof(struct ugen_softc)
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
int
|
||||
ugen_match(parent, match, aux)
|
||||
struct device *parent;
|
||||
struct cfdata *match;
|
||||
void *aux;
|
||||
{
|
||||
struct usb_attach_arg *uaa = aux;
|
||||
#elif defined(__FreeBSD__)
|
||||
static int
|
||||
ugen_match(device_t device)
|
||||
{
|
||||
struct usb_attach_arg *uaa = device_get_ivars(device);
|
||||
#endif
|
||||
usb_interface_descriptor_t *id;
|
||||
|
||||
DPRINTFN(10,("ugen_match\n"));
|
||||
if (uaa->usegeneric)
|
||||
return UMATCH_GENERIC;
|
||||
else
|
||||
return UMATCH_NONE;
|
||||
}
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
void
|
||||
ugen_attach(parent, self, aux)
|
||||
struct device *parent;
|
||||
struct device *self;
|
||||
void *aux;
|
||||
{
|
||||
struct ugen_softc *sc = (struct ugen_softc *)self;
|
||||
struct usb_attach_arg *uaa = aux;
|
||||
#elif defined(__FreeBSD__)
|
||||
static int
|
||||
ugen_attach(device_t self)
|
||||
{
|
||||
struct ugen_softc *sc = device_get_softc(self);
|
||||
struct usb_attach_arg *uaa = device_get_ivars(self);
|
||||
#endif
|
||||
usbd_device_handle dev = uaa->device;
|
||||
usb_device_descriptor_t *udd = &dev->ddesc;
|
||||
char devinfo[1024];
|
||||
|
||||
usbd_devinfo(dev, 0, devinfo);
|
||||
#if defined(__FreeBSD__)
|
||||
device_set_desc(self, devinfo);
|
||||
printf("%s%d", device_get_name(self), device_get_unit(self));
|
||||
#endif
|
||||
printf(": %s (device class %d/%d)\n", devinfo,
|
||||
udd->bDeviceClass, udd->bDeviceSubClass);
|
||||
sc->sc_dev = self;
|
||||
|
||||
ATTACH_SUCCESS_RETURN;
|
||||
}
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
static int
|
||||
ugen_detach(device_t self)
|
||||
{
|
||||
/* we need to cast away the const returned by
|
||||
* device_get_desc
|
||||
*/
|
||||
char *devinfo = (char *) device_get_desc(self);
|
||||
|
||||
if (devinfo) {
|
||||
device_set_desc(self, NULL);
|
||||
free(devinfo, M_USB);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DRIVER_MODULE(ugen, usb, ugen_driver, ugen_devclass, usb_driver_load, 0);
|
||||
#endif
|
2355
sys/dev/usb/uhci.c
Normal file
2355
sys/dev/usb/uhci.c
Normal file
File diff suppressed because it is too large
Load Diff
184
sys/dev/usb/uhcireg.h
Normal file
184
sys/dev/usb/uhcireg.h
Normal file
@ -0,0 +1,184 @@
|
||||
/* $NetBSD: uhcireg.h,v 1.2 1998/07/26 00:40:59 augustss Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1998 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Lennart Augustsson <augustss@carlstedt.se>
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _DEV_PCI_UHCIREG_H_
|
||||
#define _DEV_PCI_UHCIREG_H_
|
||||
|
||||
/*** PCI config registers ***/
|
||||
|
||||
#define PCI_USBREV 0x60 /* USB protocol revision */
|
||||
#define PCI_USBREV_MASK 0xff
|
||||
#define PCI_USBREV_PRE_1_0 0x00
|
||||
#define PCI_USBREV_1_0 0x10
|
||||
|
||||
#define PCI_CBIO 0x20 /* configuration base IO */
|
||||
|
||||
#define PCI_INTERFACE_UHCI 0x00
|
||||
|
||||
/*** UHCI registers ***/
|
||||
|
||||
#define UHCI_CMD 0x00
|
||||
#define UHCI_CMD_RS 0x0001
|
||||
#define UHCI_CMD_HCRESET 0x0002
|
||||
#define UHCI_CMD_GRESET 0x0004
|
||||
#define UHCI_CMD_EGSM 0x0008
|
||||
#define UHCI_CMD_FGR 0x0010
|
||||
#define UHCI_CMD_SWDBG 0x0020
|
||||
#define UHCI_CMD_CF 0x0040
|
||||
#define UHCI_CMD_MAXP 0x0080
|
||||
|
||||
#define UHCI_STS 0x02
|
||||
#define UHCI_STS_USBINT 0x0001
|
||||
#define UHCI_STS_USBEI 0x0002
|
||||
#define UHCI_STS_RD 0x0004
|
||||
#define UHCI_STS_HSE 0x0008
|
||||
#define UHCI_STS_HCPE 0x0010
|
||||
#define UHCI_STS_HCH 0x0020
|
||||
|
||||
#define UHCI_INTR 0x04
|
||||
#define UHCI_INTR_TOCRCIE 0x0001
|
||||
#define UHCI_INTR_RIE 0x0002
|
||||
#define UHCI_INTR_IOCE 0x0004
|
||||
#define UHCI_INTR_SPIE 0x0008
|
||||
|
||||
#define UHCI_FRNUM 0x06
|
||||
#define UHCI_FRNUM_MASK 0x03ff
|
||||
|
||||
|
||||
#define UHCI_FLBASEADDR 0x08
|
||||
|
||||
#define UHCI_SOF 0x0c
|
||||
#define UHCI_SOF_MASK 0x7f
|
||||
|
||||
#define UHCI_PORTSC1 0x010
|
||||
#define UHCI_PORTSC2 0x012
|
||||
#define UHCI_PORTSC_CCS 0x0001
|
||||
#define UHCI_PORTSC_CSC 0x0002
|
||||
#define UHCI_PORTSC_PE 0x0004
|
||||
#define UHCI_PORTSC_POEDC 0x0008
|
||||
#define UHCI_PORTSC_LS 0x0030
|
||||
#define UHCI_PORTSC_LS_SHIFT 4
|
||||
#define UHCI_PORTSC_RD 0x0040
|
||||
#define UHCI_PORTSC_LSDA 0x0100
|
||||
#define UHCI_PORTSC_PR 0x0200
|
||||
#define UHCI_PORTSC_OCI 0x0400
|
||||
#define UHCI_PORTSC_OCIC 0x0800
|
||||
#define UHCI_PORTSC_SUSP 0x1000
|
||||
|
||||
#define UHCI_FRAMELIST_COUNT 1024
|
||||
#define UHCI_FRAMELIST_ALIGN 4096
|
||||
|
||||
#define UHCI_TD_ALIGN 16
|
||||
#define UHCI_QH_ALIGN 16
|
||||
|
||||
typedef u_int32_t uhci_physaddr_t;
|
||||
#define UHCI_PTR_T 0x00000001
|
||||
#define UHCI_PTR_Q 0x00000002
|
||||
#define UHCI_PTR_VF 0x00000004
|
||||
|
||||
typedef union {
|
||||
struct uhci_soft_qh *sqh;
|
||||
struct uhci_soft_td *std;
|
||||
} uhci_soft_td_qh_t;
|
||||
|
||||
/*
|
||||
* The Queue Heads and Transfer Descriptors and accessed
|
||||
* by both the CPU and the USB controller which runs
|
||||
* concurrently. This means that they have to be accessed
|
||||
* with great care. As long as the data structures are
|
||||
* not linked into the controller's frame list they cannot
|
||||
* be accessed by it and anything goes. As soon as a
|
||||
* TD is accessible by the controller it "owns" the td_status
|
||||
* field; it will not be written by the CPU. Similarly
|
||||
* the controller "owns" the qh_elink field.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
uhci_physaddr_t td_link;
|
||||
u_int32_t td_status;
|
||||
#define UHCI_TD_GET_ACTLEN(s) (((s) + 1) & 0x3ff)
|
||||
#define UHCI_TD_ZERO_ACTLEN(t) ((t) | 0x3ff)
|
||||
#define UHCI_TD_BITSTUFF 0x00020000
|
||||
#define UHCI_TD_CRCTO 0x00040000
|
||||
#define UHCI_TD_NAK 0x00080000
|
||||
#define UHCI_TD_BABBLE 0x00100000
|
||||
#define UHCI_TD_DBUFFER 0x00200000
|
||||
#define UHCI_TD_STALLED 0x00400000
|
||||
#define UHCI_TD_ACTIVE 0x00800000
|
||||
#define UHCI_TD_IOC 0x01000000
|
||||
#define UHCI_TD_IOS 0x02000000
|
||||
#define UHCI_TD_LS 0x04000000
|
||||
#define UHCI_TD_GET_ERRCNT(s) (((s) >> 27) & 3)
|
||||
#define UHCI_TD_SET_ERRCNT(n) ((n) << 27)
|
||||
#define UHCI_TD_SPD 0x20000000
|
||||
u_int32_t td_token;
|
||||
#define UHCI_TD_PID_IN 0x00000069
|
||||
#define UHCI_TD_PID_OUT 0x000000e1
|
||||
#define UHCI_TD_PID_SETUP 0x0000002d
|
||||
#define UHCI_TD_GET_PID(s) ((s) & 0xff)
|
||||
#define UHCI_TD_SET_DEVADDR(a) ((a) << 8)
|
||||
#define UHCI_TD_GET_DEVADDR(s) (((s) >> 8) & 0x7f)
|
||||
#define UHCI_TD_SET_ENDPT(e) ((e) << 15)
|
||||
#define UHCI_TD_GET_ENDPT(s) (((s) >> 15) & 0xf)
|
||||
#define UHCI_TD_SET_DT(t) ((t) << 19)
|
||||
#define UHCI_TD_GET_DT(s) (((s) >> 19) & 1)
|
||||
#define UHCI_TD_SET_MAXLEN(l) (((l)-1) << 21)
|
||||
#define UHCI_TD_GET_MAXLEN(s) ((((s) >> 21) + 1) & 0x7ff)
|
||||
#define UHCI_TD_MAXLEN_MASK 0xffe00000
|
||||
u_int32_t td_buffer;
|
||||
uhci_soft_td_qh_t link; /* soft version of the td_link field */
|
||||
/* padding to 32 bytes */
|
||||
} uhci_td_t;
|
||||
#define UHCI_TD_SIZE 32
|
||||
|
||||
#define UHCI_TD_ERROR (UHCI_TD_BITSTUFF|UHCI_TD_CRCTO|UHCI_TD_BABBLE|UHCI_TD_DBUFFER|UHCI_TD_STALLED)
|
||||
|
||||
#define UHCI_TD_SETUP(len, endp, dev) (UHCI_TD_SET_MAXLEN(len) | UHCI_TD_SET_ENDPT(endp) | UHCI_TD_SET_DEVADDR(dev) | UHCI_TD_PID_SETUP)
|
||||
#define UHCI_TD_OUT(len, endp, dev, dt) (UHCI_TD_SET_MAXLEN(len) | UHCI_TD_SET_ENDPT(endp) | UHCI_TD_SET_DEVADDR(dev) | UHCI_TD_PID_OUT | UHCI_TD_SET_DT(dt))
|
||||
#define UHCI_TD_IN(len, endp, dev, dt) (UHCI_TD_SET_MAXLEN(len) | UHCI_TD_SET_ENDPT(endp) | UHCI_TD_SET_DEVADDR(dev) | UHCI_TD_PID_IN | UHCI_TD_SET_DT(dt))
|
||||
|
||||
typedef struct {
|
||||
uhci_physaddr_t qh_hlink;
|
||||
uhci_physaddr_t qh_elink;
|
||||
struct uhci_soft_qh *hlink; /* soft version of qh_hlink */
|
||||
struct uhci_soft_td *elink; /* soft version of qh_elink */
|
||||
/* padding to 32 bytes */
|
||||
} uhci_qh_t;
|
||||
#define UHCI_QH_SIZE 32
|
||||
|
||||
#endif /* _DEV_PCI_UHCIREG_H_ */
|
179
sys/dev/usb/uhcivar.h
Normal file
179
sys/dev/usb/uhcivar.h
Normal file
@ -0,0 +1,179 @@
|
||||
/* $NetBSD: uhcivar.h,v 1.3 1998/07/26 00:40:59 augustss Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1998 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Lennart Augustsson <augustss@carlstedt.se>
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* To avoid having 1024 TDs for each isochronous transfer we introduce
|
||||
* a virtual frame list. Every UHCI_VFRAMELIST_COUNT entries in the real
|
||||
* frame list points to a non-active TD. These, in turn, which form the
|
||||
* starts of the virtual frame list. This also has the advantage that it
|
||||
* simplifies linking in/out TD/QH in the schedule.
|
||||
* Furthermore, initially each of the inactive TDs point to an inactive
|
||||
* QH that forms the start of the interrupt traffic for that slot.
|
||||
* Each of these QHs point to the same QH that is the start of control
|
||||
* traffic.
|
||||
*
|
||||
* UHCI_VFRAMELIST_COUNT should be a power of 2 and <= UHCI_FRAMELIST_COUNT.
|
||||
*/
|
||||
#define UHCI_VFRAMELIST_COUNT 128
|
||||
|
||||
typedef struct uhci_soft_qh uhci_soft_qh_t;
|
||||
typedef struct uhci_soft_td uhci_soft_td_t;
|
||||
|
||||
/*
|
||||
* An interrupt info struct contains the information needed to
|
||||
* execute a requested routine when the controller generates an
|
||||
* interrupt. Since we cannot know which transfer generated
|
||||
* the interrupt all structs are linked together so they can be
|
||||
* searched at interrupt time.
|
||||
*/
|
||||
typedef struct uhci_intr_info {
|
||||
#if defined(__FreeBSD__)
|
||||
struct callout_handle callout_handler;
|
||||
#endif
|
||||
struct uhci_softc *sc;
|
||||
usbd_request_handle reqh;
|
||||
uhci_soft_td_t *stdstart;
|
||||
uhci_soft_td_t *stdend;
|
||||
LIST_ENTRY(uhci_intr_info) list;
|
||||
#ifdef DIAGNOSTIC
|
||||
int isdone;
|
||||
#endif
|
||||
} uhci_intr_info_t;
|
||||
|
||||
/*
|
||||
* Extra information that we need for a TD.
|
||||
*/
|
||||
struct uhci_soft_td {
|
||||
uhci_td_t *td; /* The real TD */
|
||||
uhci_physaddr_t physaddr; /* and its physical address. */
|
||||
};
|
||||
#define UHCI_TD_CHUNK 128 /*(PAGE_SIZE / UHCI_TD_SIZE)*/
|
||||
|
||||
/*
|
||||
* Extra information that we need for a QH.
|
||||
*/
|
||||
struct uhci_soft_qh {
|
||||
uhci_qh_t *qh; /* The real QH */
|
||||
uhci_physaddr_t physaddr; /* and its physical address. */
|
||||
int pos; /* Timeslot position */
|
||||
uhci_intr_info_t *intr_info; /* Who to call on completion. */
|
||||
};
|
||||
#define UHCI_QH_CHUNK 128 /*(PAGE_SIZE / UHCI_QH_SIZE)*/
|
||||
|
||||
/* Only used for buffer free list. */
|
||||
struct uhci_buffer {
|
||||
struct uhci_buffer *next;
|
||||
};
|
||||
#define UHCI_BUFFER_SIZE 64
|
||||
#define UHCI_BUFFER_CHUNK 64 /*(PAGE_SIZE / UHCI_BUFFER_SIZE)*/
|
||||
|
||||
/*
|
||||
* Information about an entry in the virtial frame list.
|
||||
*/
|
||||
struct uhci_vframe {
|
||||
uhci_soft_td_t *htd; /* pointer to dummy TD */
|
||||
uhci_soft_td_t *etd; /* pointer to last TD */
|
||||
uhci_soft_qh_t *hqh; /* pointer to dummy QH */
|
||||
uhci_soft_qh_t *eqh; /* pointer to last QH */
|
||||
u_int bandwidth; /* max bandwidth used by this frame */
|
||||
};
|
||||
|
||||
typedef struct uhci_softc {
|
||||
struct usbd_bus sc_bus; /* base device */
|
||||
#if defined(__NetBSD__)
|
||||
void *sc_ih; /* interrupt vectoring */
|
||||
bus_space_tag_t iot;
|
||||
bus_space_handle_t ioh;
|
||||
|
||||
bus_dma_tag_t sc_dmatag; /* DMA tag */
|
||||
/* XXX should keep track of all DMA memory */
|
||||
#elif defined(__FreeBSD__)
|
||||
int sc_iobase;
|
||||
int sc_int;
|
||||
int unit;
|
||||
#endif
|
||||
|
||||
uhci_physaddr_t *sc_pframes;
|
||||
struct uhci_vframe sc_vframes[UHCI_VFRAMELIST_COUNT];
|
||||
|
||||
uhci_soft_qh_t *sc_ctl_start; /* dummy QH for control */
|
||||
uhci_soft_qh_t *sc_ctl_end; /* last control QH */
|
||||
uhci_soft_qh_t *sc_bulk_start; /* dummy QH for bulk */
|
||||
uhci_soft_qh_t *sc_bulk_end; /* last bulk transfer */
|
||||
|
||||
uhci_soft_td_t *sc_freetds;
|
||||
uhci_soft_qh_t *sc_freeqhs;
|
||||
struct uhci_buffer *sc_freebuffers;
|
||||
|
||||
u_int8_t sc_addr; /* device address */
|
||||
u_int8_t sc_conf; /* device configuration */
|
||||
|
||||
char sc_isreset;
|
||||
|
||||
int sc_intrs;
|
||||
LIST_HEAD(, uhci_intr_info) sc_intrhead;
|
||||
|
||||
/* Info for the root hub interrupt channel. */
|
||||
int sc_ival;
|
||||
|
||||
char sc_vflock;
|
||||
#define UHCI_HAS_LOCK 1
|
||||
#define UHCI_WANT_LOCK 2
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
usb_dma_t *sc_mallocs;
|
||||
#endif
|
||||
|
||||
char sc_vendor[16];
|
||||
} uhci_softc_t;
|
||||
|
||||
usbd_status uhci_init __P((uhci_softc_t *));
|
||||
int uhci_intr __P((void *));
|
||||
#if 0
|
||||
void uhci_reset __P((void *));
|
||||
#endif
|
||||
|
||||
#ifdef USB_DEBUG
|
||||
#define DPRINTF(x) if (uhcidebug) printf x
|
||||
#define DPRINTFN(n,x) if (uhcidebug>(n)) printf x
|
||||
extern int uhcidebug;
|
||||
#else
|
||||
#define DPRINTF(x)
|
||||
#define DPRINTFN(n,x)
|
||||
#endif
|
||||
|
632
sys/dev/usb/uhid.c
Normal file
632
sys/dev/usb/uhid.c
Normal file
@ -0,0 +1,632 @@
|
||||
/* $NetBSD: uhid.c,v 1.3 1998/08/01 20:52:45 augustss Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1998 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Lennart Augustsson <augustss@carlstedt.se>
|
||||
* 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 <dev/usb/usb_port.h>
|
||||
|
||||
#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/ioccom.h>
|
||||
#include <sys/filio.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/bus.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/usbhid.h>
|
||||
|
||||
#include <dev/usb/usbdi.h>
|
||||
#include <dev/usb/usbdi_util.h>
|
||||
#include <dev/usb/usbdivar.h>
|
||||
#include <dev/usb/hid.h>
|
||||
#include <dev/usb/usb_quirks.h>
|
||||
|
||||
#ifdef USB_DEBUG
|
||||
#define DPRINTF(x) if (uhiddebug) printf x
|
||||
#define DPRINTFN(n,x) if (uhiddebug>(n)) printf x
|
||||
int uhiddebug = 0;
|
||||
#else
|
||||
#define DPRINTF(x)
|
||||
#define DPRINTFN(n,x)
|
||||
#endif
|
||||
|
||||
struct uhid_softc {
|
||||
bdevice sc_dev; /* base device */
|
||||
usbd_interface_handle sc_iface; /* interface */
|
||||
usbd_pipe_handle sc_intrpipe; /* interrupt pipe */
|
||||
int sc_ep_addr;
|
||||
|
||||
int sc_isize;
|
||||
int sc_osize;
|
||||
int sc_fsize;
|
||||
u_int8_t sc_iid;
|
||||
u_int8_t sc_oid;
|
||||
u_int8_t sc_fid;
|
||||
|
||||
char *sc_ibuf;
|
||||
char *sc_obuf;
|
||||
|
||||
void *sc_repdesc;
|
||||
int sc_repdesc_size;
|
||||
|
||||
struct clist sc_q;
|
||||
struct selinfo sc_rsel;
|
||||
u_char sc_state; /* driver state */
|
||||
#define UHID_OPEN 0x01 /* device is open */
|
||||
#define UHID_ASLP 0x02 /* waiting for mouse data */
|
||||
#define UHID_NEEDCLEAR 0x04 /* needs clearing endpoint stall */
|
||||
#define UHID_IMMED 0x08 /* return read data immediately */
|
||||
int sc_disconnected; /* device is gone */
|
||||
};
|
||||
|
||||
#define UHIDUNIT(dev) (minor(dev))
|
||||
#define UHID_CHUNK 128 /* chunk size for read */
|
||||
#define UHID_BSIZE 1020 /* buffer size */
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
int uhid_match __P((struct device *, struct cfdata *, void *));
|
||||
void uhid_attach __P((struct device *, struct device *, void *));
|
||||
#elif defined(__FreeBSD__)
|
||||
static device_probe_t uhid_match;
|
||||
static device_attach_t uhid_attach;
|
||||
#endif
|
||||
|
||||
int uhidopen __P((dev_t, int, int, struct proc *));
|
||||
int uhidclose __P((dev_t, int, int, struct proc *p));
|
||||
int uhidread __P((dev_t, struct uio *uio, int));
|
||||
int uhidwrite __P((dev_t, struct uio *uio, int));
|
||||
int uhidioctl __P((dev_t, u_long, caddr_t, int, struct proc *));
|
||||
int uhidpoll __P((dev_t, int, struct proc *));
|
||||
void uhid_intr __P((usbd_request_handle, usbd_private_handle, usbd_status));
|
||||
void uhid_disco __P((void *));
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
extern struct cfdriver uhid_cd;
|
||||
|
||||
struct cfattach uhid_ca = {
|
||||
sizeof(struct uhid_softc), uhid_match, uhid_attach
|
||||
};
|
||||
#elif defined(__FreeBSD__)
|
||||
|
||||
static devclass_t uhid_devclass;
|
||||
|
||||
static device_method_t uhid_methods[] = {
|
||||
DEVMETHOD(device_probe, uhid_match),
|
||||
DEVMETHOD(device_attach, uhid_attach),
|
||||
{0,0}
|
||||
};
|
||||
|
||||
static driver_t uhid_driver = {
|
||||
"uhid",
|
||||
uhid_methods,
|
||||
DRIVER_TYPE_MISC,
|
||||
sizeof(struct uhid_softc)
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
int
|
||||
uhid_match(parent, match, aux)
|
||||
struct device *parent;
|
||||
struct cfdata *match;
|
||||
void *aux;
|
||||
{
|
||||
struct usb_attach_arg *uaa = aux;
|
||||
#elif defined(__FreeBSD__)
|
||||
static int
|
||||
uhid_match(device_t device)
|
||||
{
|
||||
struct usb_attach_arg *uaa = device_get_ivars(device);
|
||||
#endif
|
||||
usb_interface_descriptor_t *id;
|
||||
|
||||
if (!uaa->iface)
|
||||
return (UMATCH_NONE);
|
||||
id = usbd_get_interface_descriptor(uaa->iface);
|
||||
if (!id || id->bInterfaceClass != UCLASS_HID)
|
||||
return (UMATCH_NONE);
|
||||
return (UMATCH_IFACECLASS_GENERIC);
|
||||
}
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
void
|
||||
uhid_attach(parent, self, aux)
|
||||
struct device *parent;
|
||||
struct device *self;
|
||||
void *aux;
|
||||
{
|
||||
struct uhid_softc *sc = (struct uhid_softc *)self;
|
||||
struct usb_attach_arg *uaa = aux;
|
||||
#elif defined(__FreeBSD__)
|
||||
static int
|
||||
uhid_attach(device_t self)
|
||||
{
|
||||
struct uhid_softc *sc = device_get_softc(self);
|
||||
struct usb_attach_arg *uaa = device_get_ivars(self);
|
||||
#endif
|
||||
usbd_interface_handle iface = uaa->iface;
|
||||
usb_interface_descriptor_t *id;
|
||||
usb_endpoint_descriptor_t *ed;
|
||||
int size;
|
||||
void *desc;
|
||||
usbd_status r;
|
||||
char devinfo[1024];
|
||||
|
||||
sc->sc_disconnected = 1;
|
||||
sc->sc_iface = iface;
|
||||
id = usbd_get_interface_descriptor(iface);
|
||||
usbd_devinfo(uaa->device, 0, devinfo);
|
||||
#if defined(__FreeBSD__)
|
||||
usb_device_set_desc(self, devinfo);
|
||||
printf("%s%d", device_get_name(self), device_get_unit(self));
|
||||
#endif
|
||||
printf(": %s (interface class %d/%d)\n", devinfo,
|
||||
id->bInterfaceClass, id->bInterfaceSubClass);
|
||||
sc->sc_dev = self;
|
||||
|
||||
ed = usbd_interface2endpoint_descriptor(iface, 0);
|
||||
if (!ed) {
|
||||
DEVICE_ERROR(sc->sc_dev, ("could not read endpoint descriptor\n"));
|
||||
ATTACH_ERROR_RETURN;
|
||||
}
|
||||
|
||||
DPRINTFN(10,("uhid_attach: \
|
||||
bLength=%d bDescriptorType=%d bEndpointAddress=%d-%s bmAttributes=%d wMaxPacketSize=%d bInterval=%d\n",
|
||||
ed->bLength, ed->bDescriptorType, ed->bEndpointAddress & UE_ADDR,
|
||||
ed->bEndpointAddress & UE_IN ? "in" : "out",
|
||||
ed->bmAttributes & UE_XFERTYPE,
|
||||
UGETW(ed->wMaxPacketSize), ed->bInterval));
|
||||
|
||||
if ((ed->bEndpointAddress & UE_IN) != UE_IN ||
|
||||
(ed->bmAttributes & UE_XFERTYPE) != UE_INTERRUPT) {
|
||||
DEVICE_ERROR(sc->sc_dev, ("unexpected endpoint\n"));
|
||||
ATTACH_ERROR_RETURN;
|
||||
}
|
||||
|
||||
sc->sc_ep_addr = ed->bEndpointAddress;
|
||||
sc->sc_disconnected = 0;
|
||||
|
||||
r = usbd_alloc_report_desc(uaa->iface, &desc, &size, M_USB);
|
||||
if (r != USBD_NORMAL_COMPLETION) {
|
||||
DEVICE_ERROR(sc->sc_dev, ("no report descriptor\n"));
|
||||
ATTACH_ERROR_RETURN;
|
||||
}
|
||||
|
||||
(void)usbd_set_idle(iface, 0, 0);
|
||||
|
||||
sc->sc_isize = hid_report_size(desc, size, hid_input, &sc->sc_iid);
|
||||
sc->sc_osize = hid_report_size(desc, size, hid_output, &sc->sc_oid);
|
||||
sc->sc_fsize = hid_report_size(desc, size, hid_feature, &sc->sc_fid);
|
||||
|
||||
sc->sc_repdesc = desc;
|
||||
sc->sc_repdesc_size = size;
|
||||
|
||||
ATTACH_SUCCESS_RETURN;
|
||||
}
|
||||
|
||||
void
|
||||
uhid_disco(p)
|
||||
void *p;
|
||||
{
|
||||
struct uhid_softc *sc = p;
|
||||
|
||||
DPRINTF(("ums_hid: sc=%p\n", sc));
|
||||
usbd_abort_pipe(sc->sc_intrpipe);
|
||||
sc->sc_disconnected = 1;
|
||||
}
|
||||
|
||||
void
|
||||
uhid_intr(reqh, addr, status)
|
||||
usbd_request_handle reqh;
|
||||
usbd_private_handle addr;
|
||||
usbd_status status;
|
||||
{
|
||||
struct uhid_softc *sc = addr;
|
||||
|
||||
DPRINTFN(5, ("uhid_intr: status=%d\n", status));
|
||||
DPRINTFN(5, ("uhid_intr: data = %02x %02x %02x\n",
|
||||
sc->sc_ibuf[0], sc->sc_ibuf[1], sc->sc_ibuf[2]));
|
||||
|
||||
if (status == USBD_CANCELLED)
|
||||
return;
|
||||
|
||||
if (status != USBD_NORMAL_COMPLETION) {
|
||||
DPRINTF(("uhid_intr: status=%d\n", status));
|
||||
sc->sc_state |= UHID_NEEDCLEAR;
|
||||
return;
|
||||
}
|
||||
|
||||
(void) b_to_q(sc->sc_ibuf, sc->sc_isize, &sc->sc_q);
|
||||
|
||||
if (sc->sc_state & UHID_ASLP) {
|
||||
sc->sc_state &= ~UHID_ASLP;
|
||||
DPRINTFN(5, ("uhid_intr: waking %p\n", sc));
|
||||
wakeup((caddr_t)sc);
|
||||
}
|
||||
selwakeup(&sc->sc_rsel);
|
||||
}
|
||||
|
||||
int
|
||||
uhidopen(dev, flag, mode, p)
|
||||
dev_t dev;
|
||||
int flag;
|
||||
int mode;
|
||||
struct proc *p;
|
||||
{
|
||||
usbd_status r;
|
||||
#if defined(__NetBSD__)
|
||||
struct uhid_softc *sc;
|
||||
int unit = UHIDUNIT(dev);
|
||||
|
||||
if (unit >= uhid_cd.cd_ndevs)
|
||||
return ENXIO;
|
||||
sc = uhid_cd.cd_devs[unit];
|
||||
#elif defined(__FreeBSD__)
|
||||
struct uhid_softc *sc = devclass_get_softc(uhid_devclass, UHIDUNIT(dev));
|
||||
#endif
|
||||
if (!sc)
|
||||
return ENXIO;
|
||||
|
||||
DPRINTF(("uhidopen: sc=%p, disco=%d\n", sc, sc->sc_disconnected));
|
||||
|
||||
if (sc->sc_disconnected)
|
||||
return (EIO);
|
||||
|
||||
if (sc->sc_state & UHID_OPEN)
|
||||
return EBUSY;
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
if (clalloc(&sc->sc_q, UHID_BSIZE, 0) == -1)
|
||||
return ENOMEM;
|
||||
#elif defined(__FreeBSD__)
|
||||
clist_alloc_cblocks(&sc->sc_q, UHID_BSIZE, 0);
|
||||
#endif
|
||||
|
||||
sc->sc_state |= UHID_OPEN;
|
||||
sc->sc_state &= ~UHID_IMMED;
|
||||
|
||||
sc->sc_ibuf = malloc(sc->sc_isize, M_USB, M_WAITOK);
|
||||
sc->sc_obuf = malloc(sc->sc_osize, M_USB, M_WAITOK);
|
||||
|
||||
/* Set up interrupt pipe. */
|
||||
r = usbd_open_pipe_intr(sc->sc_iface, sc->sc_ep_addr,
|
||||
USBD_SHORT_XFER_OK,
|
||||
&sc->sc_intrpipe, sc, sc->sc_ibuf,
|
||||
sc->sc_isize, uhid_intr);
|
||||
if (r != USBD_NORMAL_COMPLETION) {
|
||||
DPRINTF(("uhidopen: usbd_open_pipe_intr failed, error=%d\n",r));
|
||||
sc->sc_state &= ~UHID_OPEN;
|
||||
return (EIO);
|
||||
}
|
||||
usbd_set_disco(sc->sc_intrpipe, uhid_disco, sc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
uhidclose(dev, flag, mode, p)
|
||||
dev_t dev;
|
||||
int flag;
|
||||
int mode;
|
||||
struct proc *p;
|
||||
{
|
||||
#if defined(__NetBSD__)
|
||||
struct uhid_softc *sc;
|
||||
int unit = UHIDUNIT(dev);
|
||||
|
||||
if (unit >= uhid_cd.cd_ndevs)
|
||||
return ENXIO;
|
||||
sc = uhid_cd.cd_devs[unit];
|
||||
#elif defined(__FreeBSD__)
|
||||
struct uhid_softc *sc = devclass_get_softc(uhid_devclass, UHIDUNIT(dev));
|
||||
#endif
|
||||
|
||||
if (sc->sc_disconnected)
|
||||
return (EIO);
|
||||
|
||||
DPRINTF(("uhidclose: sc=%p\n", sc));
|
||||
|
||||
/* Disable interrupts. */
|
||||
usbd_abort_pipe(sc->sc_intrpipe);
|
||||
usbd_close_pipe(sc->sc_intrpipe);
|
||||
|
||||
sc->sc_state &= ~UHID_OPEN;
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
clfree(&sc->sc_q);
|
||||
#elif defined(__FreeBSD__)
|
||||
clist_free_cblocks(&sc->sc_q);
|
||||
#endif
|
||||
|
||||
free(sc->sc_ibuf, M_USB);
|
||||
free(sc->sc_obuf, M_USB);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
uhidread(dev, uio, flag)
|
||||
dev_t dev;
|
||||
struct uio *uio;
|
||||
int flag;
|
||||
{
|
||||
int s;
|
||||
int error = 0;
|
||||
size_t length;
|
||||
u_char buffer[UHID_CHUNK];
|
||||
usbd_status r;
|
||||
#if defined(__NetBSD__)
|
||||
struct uhid_softc *sc;
|
||||
int unit = UHIDUNIT(dev);
|
||||
|
||||
if (unit >= uhid_cd.cd_ndevs)
|
||||
return ENXIO;
|
||||
sc = uhid_cd.cd_devs[unit];
|
||||
#elif defined(__FreeBSD__)
|
||||
struct uhid_softc *sc = devclass_get_softc(uhid_devclass, UHIDUNIT(dev));
|
||||
#endif
|
||||
|
||||
if (sc->sc_disconnected)
|
||||
return (EIO);
|
||||
|
||||
DPRINTFN(1, ("uhidread\n"));
|
||||
if (sc->sc_state & UHID_IMMED) {
|
||||
DPRINTFN(1, ("uhidread immed\n"));
|
||||
|
||||
r = usbd_get_report(sc->sc_iface, UHID_INPUT_REPORT,
|
||||
sc->sc_iid, sc->sc_ibuf, sc->sc_isize);
|
||||
if (r != USBD_NORMAL_COMPLETION)
|
||||
return (EIO);
|
||||
return (uiomove(buffer, sc->sc_isize, uio));
|
||||
}
|
||||
|
||||
s = spltty();
|
||||
while (sc->sc_q.c_cc == 0) {
|
||||
if (flag & IO_NDELAY) {
|
||||
splx(s);
|
||||
return EWOULDBLOCK;
|
||||
}
|
||||
sc->sc_state |= UHID_ASLP;
|
||||
DPRINTFN(5, ("uhidread: sleep on %p\n", sc));
|
||||
error = tsleep((caddr_t)sc, PZERO | PCATCH, "uhidrea", 0);
|
||||
DPRINTFN(5, ("uhidread: woke, error=%d\n", error));
|
||||
if (error) {
|
||||
sc->sc_state &= ~UHID_ASLP;
|
||||
splx(s);
|
||||
return (error);
|
||||
}
|
||||
if (sc->sc_state & UHID_NEEDCLEAR) {
|
||||
DPRINTFN(-1,("uhidread: clearing stall\n"));
|
||||
sc->sc_state &= ~UHID_NEEDCLEAR;
|
||||
usbd_clear_endpoint_stall(sc->sc_intrpipe);
|
||||
}
|
||||
}
|
||||
splx(s);
|
||||
|
||||
/* Transfer as many chunks as possible. */
|
||||
while (sc->sc_q.c_cc > 0 && uio->uio_resid > 0) {
|
||||
length = min(sc->sc_q.c_cc, uio->uio_resid);
|
||||
if (length > sizeof(buffer))
|
||||
length = sizeof(buffer);
|
||||
|
||||
/* Remove a small chunk from the input queue. */
|
||||
(void) q_to_b(&sc->sc_q, buffer, length);
|
||||
DPRINTFN(5, ("uhidread: got %d chars\n", length));
|
||||
|
||||
/* Copy the data to the user process. */
|
||||
if ((error = uiomove(buffer, length, uio)) != 0)
|
||||
break;
|
||||
}
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
uhidwrite(dev, uio, flag)
|
||||
dev_t dev;
|
||||
struct uio *uio;
|
||||
int flag;
|
||||
{
|
||||
int error;
|
||||
int size;
|
||||
usbd_status r;
|
||||
#if defined(__NetBSD__)
|
||||
struct uhid_softc *sc;
|
||||
int unit = UHIDUNIT(dev);
|
||||
|
||||
if (unit >= uhid_cd.cd_ndevs)
|
||||
return ENXIO;
|
||||
sc = uhid_cd.cd_devs[unit];
|
||||
#elif defined(__FreeBSD__)
|
||||
struct uhid_softc *sc = devclass_get_softc(uhid_devclass, UHIDUNIT(dev));
|
||||
#endif
|
||||
|
||||
if (sc->sc_disconnected)
|
||||
return (EIO);
|
||||
|
||||
DPRINTFN(1, ("uhidwrite\n"));
|
||||
|
||||
size = sc->sc_osize;
|
||||
error = 0;
|
||||
while (uio->uio_resid > 0) {
|
||||
if (uio->uio_resid != size)
|
||||
return (0);
|
||||
if ((error = uiomove(sc->sc_obuf, size, uio)) != 0)
|
||||
break;
|
||||
if (sc->sc_oid)
|
||||
r = usbd_set_report(sc->sc_iface, UHID_OUTPUT_REPORT,
|
||||
sc->sc_obuf[0],
|
||||
sc->sc_obuf+1, size-1);
|
||||
else
|
||||
r = usbd_set_report(sc->sc_iface, UHID_OUTPUT_REPORT,
|
||||
0, sc->sc_obuf, size);
|
||||
if (r != USBD_NORMAL_COMPLETION) {
|
||||
error = EIO;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
uhidioctl(dev, cmd, addr, flag, p)
|
||||
dev_t dev;
|
||||
u_long cmd;
|
||||
caddr_t addr;
|
||||
int flag;
|
||||
struct proc *p;
|
||||
{
|
||||
struct usb_ctl_report_desc *rd;
|
||||
struct usb_ctl_report *re;
|
||||
int size, id;
|
||||
usbd_status r;
|
||||
#if defined(__NetBSD__)
|
||||
struct uhid_softc *sc;
|
||||
int unit = UHIDUNIT(dev);
|
||||
|
||||
if (unit >= uhid_cd.cd_ndevs)
|
||||
return ENXIO;
|
||||
sc = uhid_cd.cd_devs[unit];
|
||||
#elif defined(__FreeBSD__)
|
||||
struct uhid_softc *sc = devclass_get_softc(uhid_devclass, UHIDUNIT(dev));
|
||||
#endif
|
||||
|
||||
if (sc->sc_disconnected)
|
||||
return (EIO);
|
||||
|
||||
DPRINTFN(2, ("uhidioctl: cmd=%lx\n", cmd));
|
||||
switch (cmd) {
|
||||
case FIONBIO:
|
||||
/* All handled in the upper FS layer. */
|
||||
break;
|
||||
|
||||
case USB_GET_REPORT_DESC:
|
||||
rd = (struct usb_ctl_report_desc *)addr;
|
||||
size = min(sc->sc_repdesc_size, sizeof rd->data);
|
||||
rd->size = size;
|
||||
memcpy(rd->data, sc->sc_repdesc, size);
|
||||
break;
|
||||
|
||||
case USB_SET_IMMED:
|
||||
if (*(int *)addr)
|
||||
sc->sc_state |= UHID_IMMED;
|
||||
else
|
||||
sc->sc_state &= ~UHID_IMMED;
|
||||
break;
|
||||
|
||||
case USB_GET_REPORT:
|
||||
re = (struct usb_ctl_report *)addr;
|
||||
switch (re->report) {
|
||||
case UHID_INPUT_REPORT:
|
||||
size = sc->sc_isize;
|
||||
id = sc->sc_iid;
|
||||
break;
|
||||
case UHID_OUTPUT_REPORT:
|
||||
size = sc->sc_osize;
|
||||
id = sc->sc_oid;
|
||||
break;
|
||||
case UHID_FEATURE_REPORT:
|
||||
size = sc->sc_fsize;
|
||||
id = sc->sc_fid;
|
||||
break;
|
||||
default:
|
||||
return (EINVAL);
|
||||
}
|
||||
r = usbd_get_report(sc->sc_iface, re->report, id,
|
||||
re->data, size);
|
||||
if (r != USBD_NORMAL_COMPLETION)
|
||||
return (EIO);
|
||||
break;
|
||||
|
||||
default:
|
||||
return (EINVAL);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
uhidpoll(dev, events, p)
|
||||
dev_t dev;
|
||||
int events;
|
||||
struct proc *p;
|
||||
{
|
||||
int revents = 0;
|
||||
int s;
|
||||
#if defined(__NetBSD__)
|
||||
struct uhid_softc *sc;
|
||||
int unit = UHIDUNIT(dev);
|
||||
|
||||
if (unit >= uhid_cd.cd_ndevs)
|
||||
return ENXIO;
|
||||
sc = uhid_cd.cd_devs[unit];
|
||||
#elif defined(__FreeBSD__)
|
||||
struct uhid_softc *sc = devclass_get_softc(uhid_devclass, UHIDUNIT(dev));
|
||||
#endif
|
||||
|
||||
if (sc->sc_disconnected)
|
||||
return (EIO);
|
||||
|
||||
s = spltty();
|
||||
if (events & (POLLOUT | POLLWRNORM))
|
||||
revents |= events & (POLLOUT | POLLWRNORM);
|
||||
if (events & (POLLIN | POLLRDNORM)) {
|
||||
if (sc->sc_q.c_cc > 0)
|
||||
revents |= events & (POLLIN | POLLRDNORM);
|
||||
else
|
||||
selrecord(p, &sc->sc_rsel);
|
||||
}
|
||||
|
||||
splx(s);
|
||||
return (revents);
|
||||
}
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
DRIVER_MODULE(uhid, usb, uhid_driver, uhid_devclass, usb_driver_load, 0);
|
||||
#endif
|
490
sys/dev/usb/uhub.c
Normal file
490
sys/dev/usb/uhub.c
Normal file
@ -0,0 +1,490 @@
|
||||
/* $NetBSD: uhub.c,v 1.5 1998/08/02 22:30:52 augustss Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1998 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Lennart Augustsson <augustss@carlstedt.se>
|
||||
* 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 <dev/usb/usb_port.h>
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/malloc.h>
|
||||
#if defined(__NetBSD__)
|
||||
#include <sys/device.h>
|
||||
#elif defined(__FreeBSD__)
|
||||
#include <sys/module.h>
|
||||
#include <sys/bus.h>
|
||||
#endif
|
||||
#include <sys/proc.h>
|
||||
|
||||
#include <dev/usb/usb.h>
|
||||
|
||||
#include <dev/usb/usbdi.h>
|
||||
#include <dev/usb/usbdi_util.h>
|
||||
#include <dev/usb/usbdivar.h>
|
||||
|
||||
#ifdef USB_DEBUG
|
||||
#define DPRINTF(x) if (usbdebug) printf x
|
||||
#define DPRINTFN(n,x) if (usbdebug>(n)) printf x
|
||||
extern int usbdebug;
|
||||
#else
|
||||
#define DPRINTF(x)
|
||||
#define DPRINTFN(n,x)
|
||||
#endif
|
||||
|
||||
struct uhub_softc {
|
||||
bdevice sc_dev; /* base device */
|
||||
usbd_device_handle sc_hub; /* USB device */
|
||||
usbd_pipe_handle sc_ipipe; /* interrupt pipe */
|
||||
u_int8_t sc_status[1]; /* XXX more ports */
|
||||
u_char sc_running;
|
||||
};
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
int uhub_match __P((struct device *, struct cfdata *, void *));
|
||||
void uhub_attach __P((struct device *, struct device *, void *));
|
||||
#elif defined(__FreeBSD__)
|
||||
static device_probe_t uhub_match;
|
||||
static device_attach_t uhub_attach;
|
||||
#endif
|
||||
|
||||
usbd_status uhub_init_port __P((int, struct usbd_port *, usbd_device_handle));
|
||||
void uhub_disconnect __P((struct usbd_port *up, int portno));
|
||||
usbd_status uhub_explore __P((usbd_device_handle hub));
|
||||
void uhub_intr __P((usbd_request_handle, usbd_private_handle, usbd_status));
|
||||
|
||||
/*void uhub_disco __P((void *));*/
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
extern struct cfdriver uhub_cd;
|
||||
|
||||
struct cfattach uhub_ca = {
|
||||
sizeof(struct uhub_softc), uhub_match, uhub_attach
|
||||
};
|
||||
|
||||
struct cfattach uhub_uhub_ca = {
|
||||
sizeof(struct uhub_softc), uhub_match, uhub_attach
|
||||
};
|
||||
|
||||
#elif defined(__FreeBSD__)
|
||||
static devclass_t uhub_devclass;
|
||||
|
||||
static device_method_t uhub_methods[] = {
|
||||
DEVMETHOD(device_probe, uhub_match),
|
||||
DEVMETHOD(device_attach, uhub_attach),
|
||||
{0,0}
|
||||
};
|
||||
|
||||
static driver_t uhub_driver = {
|
||||
"usb", /* this is silly, but necessary. The uhub
|
||||
* implements a usb bus on top of a usb bus,
|
||||
* but the problem is that name of the driver
|
||||
* is used a the name of the device class it
|
||||
* implements.
|
||||
*/
|
||||
uhub_methods,
|
||||
DRIVER_TYPE_MISC,
|
||||
sizeof(struct uhub_softc)
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
int
|
||||
uhub_match(parent, match, aux)
|
||||
struct device *parent;
|
||||
struct cfdata *match;
|
||||
void *aux;
|
||||
{
|
||||
struct usb_attach_arg *uaa = aux;
|
||||
#elif defined(__FreeBSD__)
|
||||
static int
|
||||
uhub_match(device_t device)
|
||||
{
|
||||
struct usb_attach_arg *uaa = device_get_ivars(device);
|
||||
#endif
|
||||
usb_device_descriptor_t *dd = usbd_get_device_descriptor(uaa->device);
|
||||
|
||||
DPRINTFN(1,("uhub_match, dd=%p\n", dd));
|
||||
/*
|
||||
* The subclass for hubs seems to be 0 for some and 1 for others,
|
||||
* so we just ignore the subclass.
|
||||
*/
|
||||
if (uaa->iface == 0 && dd->bDeviceClass == UCLASS_HUB)
|
||||
return (UMATCH_DEVCLASS_DEVSUBCLASS);
|
||||
return (UMATCH_NONE);
|
||||
}
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
void
|
||||
uhub_attach(parent, self, aux)
|
||||
struct device *parent;
|
||||
struct device *self;
|
||||
void *aux;
|
||||
{
|
||||
struct uhub_softc *sc = (struct uhub_softc *)self;
|
||||
struct usb_attach_arg *uaa = aux;
|
||||
#elif defined(__FreeBSD__)
|
||||
static int
|
||||
uhub_attach(device_t self)
|
||||
{
|
||||
struct uhub_softc *sc = device_get_softc(self);
|
||||
struct usb_attach_arg *uaa = device_get_ivars(self);
|
||||
#endif
|
||||
usbd_device_handle dev = uaa->device;
|
||||
char devinfo[1024];
|
||||
usbd_status r;
|
||||
struct usbd_hub *hub;
|
||||
usb_device_request_t req;
|
||||
usb_hub_descriptor_t hubdesc;
|
||||
int port, nports;
|
||||
usbd_interface_handle iface;
|
||||
usb_endpoint_descriptor_t *ed;
|
||||
|
||||
DPRINTFN(10,("uhub_attach\n"));
|
||||
sc->sc_hub = dev;
|
||||
usbd_devinfo(dev, 1, devinfo);
|
||||
#if defined(__FreeBSD__)
|
||||
usb_device_set_desc(self, devinfo);
|
||||
printf("%s%d", device_get_name(self), device_get_unit(self));
|
||||
#endif
|
||||
printf(": %s\n", devinfo);
|
||||
sc->sc_dev = self;
|
||||
|
||||
r = usbd_set_config_no(dev, 0, 1);
|
||||
if (r != USBD_NORMAL_COMPLETION) {
|
||||
DEVICE_ERROR(sc->sc_dev, ("configuration failed, error=%d\n", r));
|
||||
ATTACH_ERROR_RETURN;
|
||||
}
|
||||
|
||||
if (dev->depth > USB_HUB_MAX_DEPTH) {
|
||||
DEVICE_ERROR(sc->sc_dev, ("hub depth (%d) exceeded, hub ignored\n",
|
||||
USB_HUB_MAX_DEPTH));
|
||||
ATTACH_ERROR_RETURN;
|
||||
}
|
||||
|
||||
/* Get hub descriptor. */
|
||||
req.bmRequestType = UT_READ_CLASS_DEVICE;
|
||||
req.bRequest = UR_GET_DESCRIPTOR;
|
||||
USETW(req.wValue, 0);
|
||||
USETW(req.wIndex, 0);
|
||||
USETW(req.wLength, USB_HUB_DESCRIPTOR_SIZE);
|
||||
DPRINTFN(1,("usb_init_hub: getting hub descriptor\n"));
|
||||
/* XXX not correct for hubs with >7 ports */
|
||||
r = usbd_do_request(dev, &req, &hubdesc);
|
||||
if (r != USBD_NORMAL_COMPLETION) {
|
||||
DEVICE_ERROR(sc->sc_dev, ("getting hub descriptor failed, error=%d\n", r));
|
||||
ATTACH_ERROR_RETURN;
|
||||
}
|
||||
|
||||
/* XXX block should be moved down to avoid memory leaking (or an overdose of free()'s) */
|
||||
nports = hubdesc.bNbrPorts;
|
||||
hub = malloc(sizeof(*hub) + (nports-1) * sizeof(struct usbd_port),
|
||||
M_USB, M_NOWAIT);
|
||||
if (hub == 0)
|
||||
ATTACH_ERROR_RETURN;
|
||||
dev->hub = hub;
|
||||
dev->hub->hubdata = sc;
|
||||
hub->explore = uhub_explore;
|
||||
hub->hubdesc = hubdesc;
|
||||
hub->nports = nports;
|
||||
|
||||
DPRINTFN(1,("usbhub_init_hub: selfpowered=%d, parent=%p, parent->selfpowered=%d\n",
|
||||
dev->self_powered, dev->powersrc->parent,
|
||||
dev->powersrc->parent ?
|
||||
dev->powersrc->parent->self_powered : 0));
|
||||
if (!dev->self_powered && dev->powersrc->parent &&
|
||||
!dev->powersrc->parent->self_powered) {
|
||||
DEVICE_ERROR(sc->sc_dev, ("bus powered hub connected to bus powered hub, ignored\n"));
|
||||
ATTACH_ERROR_RETURN;
|
||||
}
|
||||
|
||||
/* Set up interrupt pipe. */
|
||||
r = usbd_device2interface_handle(dev, 0, &iface);
|
||||
if (r != USBD_NORMAL_COMPLETION) {
|
||||
DEVICE_ERROR(sc->sc_dev, ("no interface handle\n"));
|
||||
ATTACH_ERROR_RETURN;
|
||||
}
|
||||
ed = usbd_interface2endpoint_descriptor(iface, 0);
|
||||
if (ed == 0) {
|
||||
DEVICE_ERROR(sc->sc_dev, ("no endpoint descriptor\n"));
|
||||
ATTACH_ERROR_RETURN;
|
||||
}
|
||||
if ((ed->bmAttributes & UE_XFERTYPE) != UE_INTERRUPT) {
|
||||
DEVICE_ERROR(sc->sc_dev, ("bad interrupt endpoint\n"));
|
||||
ATTACH_ERROR_RETURN;
|
||||
}
|
||||
|
||||
r = usbd_open_pipe_intr(iface, ed->bEndpointAddress,USBD_SHORT_XFER_OK,
|
||||
&sc->sc_ipipe, sc, sc->sc_status,
|
||||
sizeof(sc->sc_status),
|
||||
uhub_intr);
|
||||
if (r != USBD_NORMAL_COMPLETION) {
|
||||
DEVICE_ERROR(sc->sc_dev, ("cannot open interrupt pipe\n"));
|
||||
ATTACH_ERROR_RETURN;
|
||||
}
|
||||
|
||||
for (port = 1; port <= nports; port++) {
|
||||
r = uhub_init_port(port, &hub->ports[port-1], dev);
|
||||
if (r != USBD_NORMAL_COMPLETION)
|
||||
DEVICE_ERROR(sc->sc_dev, ("init of port %d failed\n", port));
|
||||
}
|
||||
sc->sc_running = 1;
|
||||
|
||||
ATTACH_SUCCESS_RETURN;
|
||||
}
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
static int
|
||||
uhub_detach(self)
|
||||
struct device *self;
|
||||
{
|
||||
struct uhub_softc *sc = (struct uhub_softc *)self;
|
||||
#elif defined(__FreeBSD__)
|
||||
static int
|
||||
uhub_detach(device_t self)
|
||||
{
|
||||
struct uhub_softc *sc = device_get_softc(self);
|
||||
#endif
|
||||
int nports = sc->sc_hub->hub->hubdesc.bNbrPorts;
|
||||
int port;
|
||||
|
||||
for (port = 1; port <= nports; port++) {
|
||||
if (sc->sc_hub->hub->ports[port-1].device)
|
||||
uhub_disconnect(&sc->sc_hub->hub->ports[port-1], port);
|
||||
}
|
||||
|
||||
free(sc->sc_hub->hub, M_USB);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
usbd_status
|
||||
uhub_init_port(port, uport, dev)
|
||||
int port;
|
||||
struct usbd_port *uport;
|
||||
usbd_device_handle dev;
|
||||
{
|
||||
usbd_status r;
|
||||
u_int16_t pstatus;
|
||||
|
||||
uport->device = 0;
|
||||
uport->parent = dev;
|
||||
r = usbd_get_port_status(dev, port, &uport->status);
|
||||
if (r != USBD_NORMAL_COMPLETION)
|
||||
return r;
|
||||
pstatus = UGETW(uport->status.wPortStatus);
|
||||
DPRINTF(("usbd_init_port: adding hub port=%d status=0x%04x change=0x%04x\n",
|
||||
port, pstatus, UGETW(uport->status.wPortChange)));
|
||||
if ((pstatus & UPS_PORT_POWER) == 0) {
|
||||
/* Port lacks power, turn it on */
|
||||
r = usbd_set_port_feature(dev, port, UHF_PORT_POWER);
|
||||
if (r != USBD_NORMAL_COMPLETION)
|
||||
return (r);
|
||||
r = usbd_get_port_status(dev, port, &uport->status);
|
||||
if (r != USBD_NORMAL_COMPLETION)
|
||||
return (r);
|
||||
DPRINTF(("usb_init_port: turn on port %d power status=0x%04x change=0x%04x\n",
|
||||
port, UGETW(uport->status.wPortStatus),
|
||||
UGETW(uport->status.wPortChange)));
|
||||
/* Wait for stable power. */
|
||||
usbd_delay_ms(dev->bus, dev->hub->hubdesc.bPwrOn2PwrGood *
|
||||
UHD_PWRON_FACTOR);
|
||||
}
|
||||
if (dev->self_powered)
|
||||
/* Self powered hub, give ports maximum current. */
|
||||
uport->power = USB_MAX_POWER;
|
||||
else
|
||||
uport->power = USB_MIN_POWER;
|
||||
return (USBD_NORMAL_COMPLETION);
|
||||
}
|
||||
|
||||
usbd_status
|
||||
uhub_explore(dev)
|
||||
usbd_device_handle dev;
|
||||
{
|
||||
usb_hub_descriptor_t *hd = &dev->hub->hubdesc;
|
||||
struct uhub_softc *sc = dev->hub->hubdata;
|
||||
struct usbd_port *up;
|
||||
usbd_status r;
|
||||
int port;
|
||||
int change, status;
|
||||
|
||||
DPRINTFN(10, ("uhub_explore dev=%p addr=%d\n", dev, dev->address));
|
||||
|
||||
if (!sc->sc_running)
|
||||
return (USBD_NOT_STARTED);
|
||||
|
||||
/* Ignore hubs that are too deep. */
|
||||
if (dev->depth > USB_HUB_MAX_DEPTH)
|
||||
return (USBD_TOO_DEEP);
|
||||
|
||||
for(port = 1; port <= hd->bNbrPorts; port++) {
|
||||
up = &dev->hub->ports[port-1];
|
||||
r = usbd_get_port_status(dev, port, &up->status);
|
||||
if (r != USBD_NORMAL_COMPLETION) {
|
||||
DPRINTF(("uhub_explore: get port status failed, error=%d\n",
|
||||
r));
|
||||
continue;
|
||||
}
|
||||
status = UGETW(up->status.wPortStatus);
|
||||
change = UGETW(up->status.wPortChange);
|
||||
DPRINTFN(5, ("uhub_explore: port %d status 0x%04x 0x%04x\n",
|
||||
port, status, change));
|
||||
if (!(change & UPS_CURRENT_CONNECT_STATUS)) {
|
||||
/* No status change, just do recursive explore. */
|
||||
if (up->device && up->device->hub)
|
||||
up->device->hub->explore(up->device);
|
||||
continue;
|
||||
}
|
||||
DPRINTF(("uhub_explore: status change hub=%d port=%d\n",
|
||||
dev->address, port));
|
||||
usbd_clear_port_feature(dev, port, UHF_C_PORT_CONNECTION);
|
||||
usbd_clear_port_feature(dev, port, UHF_C_PORT_ENABLE);
|
||||
/*
|
||||
* If there is already a device on the port the change status
|
||||
* must mean that is has disconnected. Looking at the
|
||||
* current connect status is not enough to figure this out
|
||||
* since a new unit may have been connected before we handle
|
||||
* the disconnect.
|
||||
*/
|
||||
if (up->device) {
|
||||
/* Disconnected */
|
||||
DPRINTF(("uhub_explore: device %d disappeared on port %d\n",
|
||||
up->device->address, port));
|
||||
uhub_disconnect(up, port);
|
||||
usbd_clear_port_feature(dev, port,
|
||||
UHF_C_PORT_CONNECTION);
|
||||
}
|
||||
if (!(status & UPS_CURRENT_CONNECT_STATUS))
|
||||
continue;
|
||||
|
||||
/* Connected */
|
||||
/* Wait for maximum device power up time. */
|
||||
usbd_delay_ms(dev->bus, USB_PORT_POWERUP_DELAY);
|
||||
/* Reset port, which implies enabling it. */
|
||||
if (usbd_reset_port(dev, port, &up->status) !=
|
||||
USBD_NORMAL_COMPLETION)
|
||||
continue;
|
||||
|
||||
/* Wait for power to settle in device. */
|
||||
usbd_delay_ms(dev->bus, USB_POWER_SETTLE);
|
||||
|
||||
/* Get device info and set its address. */
|
||||
r = usbd_new_device(&sc->sc_dev, dev->bus,
|
||||
dev->depth + 1, status & UPS_LOW_SPEED,
|
||||
port, up);
|
||||
/* XXX retry a few times? */
|
||||
if (r != USBD_NORMAL_COMPLETION) {
|
||||
DPRINTFN(-1,("uhub_explore: usb_new_device failed, error=%d\n", r));
|
||||
/* Avoid addressing problems by disabling. */
|
||||
/* usbd_reset_port(dev, port, &up->status); */
|
||||
/* XXX
|
||||
* What should we do. The device may or may not be at its
|
||||
* assigned address. In any case we'd like to ignore it.
|
||||
* Maybe the port should be disabled until the device is
|
||||
* disconnected.
|
||||
*/
|
||||
if (r == USBD_SET_ADDR_FAILED || 1) {/* XXX */
|
||||
/* The unit refused to accept a new
|
||||
* address, and since we cannot leave
|
||||
* at 0 we have to disable the port
|
||||
* instead. */
|
||||
/*
|
||||
DEVICE_ERROR(*parent, ("device problem, disable port %d\n",
|
||||
port));
|
||||
*/
|
||||
usbd_clear_port_feature(dev, port,
|
||||
UHF_PORT_ENABLE);
|
||||
}
|
||||
} else {
|
||||
if (up->device->hub)
|
||||
up->device->hub->explore(up->device);
|
||||
}
|
||||
}
|
||||
return (USBD_NORMAL_COMPLETION);
|
||||
}
|
||||
|
||||
void
|
||||
uhub_disconnect(up, portno)
|
||||
struct usbd_port *up;
|
||||
int portno;
|
||||
{
|
||||
usbd_device_handle dev = up->device;
|
||||
usbd_pipe_handle p, n;
|
||||
usb_hub_descriptor_t *hd;
|
||||
struct usbd_port *spi;
|
||||
int i, port;
|
||||
|
||||
DPRINTFN(3,("uhub_disconnect: up=%p dev=%p port=%d\n",
|
||||
up, dev, portno));
|
||||
|
||||
DEVICE_MSG(dev->bdev, ("device addr %d%s on hub addr %d, port %d disconnected\n",
|
||||
dev->address, dev->hub ? " (hub)" : "", up->parent->address, portno));
|
||||
|
||||
for (i = 0; i < dev->cdesc->bNumInterface; i++) {
|
||||
for (p = LIST_FIRST(&dev->ifaces[i].pipes); p; p = n) {
|
||||
n = LIST_NEXT(p, next);
|
||||
if (p->disco)
|
||||
p->disco(p->discoarg);
|
||||
usbd_abort_pipe(p);
|
||||
usbd_close_pipe(p);
|
||||
}
|
||||
}
|
||||
|
||||
/* clean up the kindergarten, get rid of the kids */
|
||||
usbd_remove_device(dev, up);
|
||||
}
|
||||
|
||||
void
|
||||
uhub_intr(reqh, addr, status)
|
||||
usbd_request_handle reqh;
|
||||
usbd_private_handle addr;
|
||||
usbd_status status;
|
||||
{
|
||||
struct uhub_softc *sc = addr;
|
||||
|
||||
DPRINTFN(5,("uhub_intr: sc=%p\n", sc));
|
||||
#if 0
|
||||
if (status != USBD_NORMAL_COMPLETION)
|
||||
usbd_clear_endpoint_stall(sc->sc_ipipe);
|
||||
else
|
||||
#endif
|
||||
usb_needs_explore(sc->sc_hub->bus);
|
||||
}
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
DRIVER_MODULE(uhub, usb, uhub_driver, uhub_devclass, usb_driver_load, 0);
|
||||
#endif
|
651
sys/dev/usb/ukbd.c
Normal file
651
sys/dev/usb/ukbd.c
Normal file
@ -0,0 +1,651 @@
|
||||
/*
|
||||
* Copyright (c) 1998 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Lennart Augustsson <augustss@carlstedt.se>
|
||||
* 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 <dev/usb/usb_port.h>
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#if defined(__NetBSD__)
|
||||
#include <sys/device.h>
|
||||
#include <sys/ioctl.h>
|
||||
#elif defined(__FreeBSD__)
|
||||
#include <sys/ioccom.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/bus.h>
|
||||
#include <machine/clock.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/usbhid.h>
|
||||
#include <dev/usb/usbdi.h>
|
||||
#include <dev/usb/usbdivar.h>
|
||||
#include <dev/usb/usbdi_util.h>
|
||||
#include <dev/usb/usbdevs.h>
|
||||
#include <dev/usb/usb_quirks.h>
|
||||
#include <dev/usb/hid.h>
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
#include <dev/wscons/wsconsio.h>
|
||||
#include <dev/wscons/wskbdvar.h>
|
||||
#include <dev/wscons/wsksymdef.h>
|
||||
#include <dev/wscons/wsksymvar.h>
|
||||
#include <dev/wscons/wskbdmap_mfii.h>
|
||||
|
||||
#include "opt_pckbd_layout.h"
|
||||
#include "opt_wsdisplay_compat.h"
|
||||
#endif
|
||||
|
||||
#ifdef USB_DEBUG
|
||||
#define DPRINTF(x) if (ukbddebug) printf x
|
||||
#define DPRINTFN(n,x) if (ukbddebug>(n)) printf x
|
||||
int ukbddebug = 0;
|
||||
#elif defined(__FreeBSD__)
|
||||
#define DPRINTF(x)
|
||||
#define DPRINTFN(n,x)
|
||||
#endif
|
||||
|
||||
#define UPROTO_BOOT_KEYBOARD 1
|
||||
|
||||
#define NKEYCODE 6
|
||||
|
||||
#define NUM_LOCK 0x01
|
||||
#define CAPS_LOCK 0x02
|
||||
#define SCROLL_LOCK 0x04
|
||||
|
||||
struct ukbd_data {
|
||||
u_int8_t modifiers;
|
||||
#define MOD_CONTROL_L 0x01
|
||||
#define MOD_CONTROL_R 0x10
|
||||
#define MOD_SHIFT_L 0x02
|
||||
#define MOD_SHIFT_R 0x20
|
||||
#define MOD_ALT_L 0x04
|
||||
#define MOD_ALT_R 0x40
|
||||
#define MOD_WIN_L 0x08
|
||||
#define MOD_WIN_R 0x80
|
||||
u_int8_t reserved;
|
||||
u_int8_t keycode[NKEYCODE];
|
||||
};
|
||||
|
||||
#define PRESS 0
|
||||
#define RELEASE 0x100
|
||||
|
||||
#define NMOD 6
|
||||
static struct {
|
||||
int mask, key;
|
||||
} ukbd_mods[NMOD] = {
|
||||
{ MOD_CONTROL_L, 29 },
|
||||
{ MOD_CONTROL_R, 58 },
|
||||
{ MOD_SHIFT_L, 42 },
|
||||
{ MOD_SHIFT_R, 54 },
|
||||
{ MOD_ALT_L, 56 },
|
||||
{ MOD_ALT_R, 184 },
|
||||
};
|
||||
|
||||
#define NN 0 /* no translation */
|
||||
/* Translate USB keycodes to US keyboard AT scancodes. */
|
||||
static u_int8_t ukbd_trtab[256] = {
|
||||
0, 0, 0, 0, 30, 48, 46, 32, /* 00 - 07 */
|
||||
18, 33, 34, 35, 23, 36, 37, 38, /* 08 - 0F */
|
||||
50, 49, 24, 25, 16, 19, 31, 20, /* 10 - 17 */
|
||||
22, 47, 17, 45, 21, 44, 2, 3, /* 18 - 1F */
|
||||
4, 5, 6, 7, 8, 9, 10, 11, /* 20 - 27 */
|
||||
28, 1, 14, 15, 57, 12, 13, 26, /* 28 - 2F */
|
||||
27, 43, NN, 39, 40, 41, 51, 52, /* 30 - 37 */
|
||||
53, 58, 59, 60, 61, 62, 63, 64, /* 38 - 3F */
|
||||
65, 66, 67, 68, 87, 88, 170, 70, /* 40 - 47 */
|
||||
127, 210, 199, 201, 211, 207, 209, 205, /* 48 - 4F */
|
||||
203, 208, 200, 69, 181, 55, 74, 78, /* 50 - 57 */
|
||||
156, 79, 80, 81, 75, 76, 77, 71, /* 58 - 5F */
|
||||
72, 73, 82, 83, NN, NN, NN, NN, /* 60 - 67 */
|
||||
NN, NN, NN, NN, NN, NN, NN, NN, /* 68 - 6F */
|
||||
NN, NN, NN, NN, NN, NN, 221, NN, /* 70 - 77 */
|
||||
NN, NN, NN, NN, NN, NN, NN, NN, /* 78 - 7F */
|
||||
NN, NN, NN, NN, NN, NN, NN, NN, /* 80 - 87 */
|
||||
NN, NN, NN, NN, NN, NN, NN, NN, /* 88 - 8F */
|
||||
NN, NN, NN, NN, NN, NN, NN, NN, /* 90 - 97 */
|
||||
NN, NN, NN, NN, NN, NN, NN, NN, /* 98 - 9F */
|
||||
NN, NN, NN, NN, NN, NN, NN, NN, /* A0 - A7 */
|
||||
NN, NN, NN, NN, NN, NN, NN, NN, /* A8 - AF */
|
||||
NN, NN, NN, NN, NN, NN, NN, NN, /* B0 - B7 */
|
||||
NN, NN, NN, NN, NN, NN, NN, NN, /* B8 - BF */
|
||||
NN, NN, NN, NN, NN, NN, NN, NN, /* C0 - C7 */
|
||||
NN, NN, NN, NN, NN, NN, NN, NN, /* C8 - CF */
|
||||
NN, NN, NN, NN, NN, NN, NN, NN, /* D0 - D7 */
|
||||
NN, NN, NN, NN, NN, NN, NN, NN, /* D8 - DF */
|
||||
NN, NN, NN, NN, NN, NN, NN, NN, /* E0 - E7 */
|
||||
NN, NN, NN, 219, NN, NN, NN, 220, /* E8 - EF */
|
||||
NN, NN, NN, NN, NN, NN, NN, NN, /* F0 - F7 */
|
||||
NN, NN, NN, NN, NN, NN, NN, NN, /* F8 - FF */
|
||||
};
|
||||
|
||||
#define KEY_ERROR 0x01
|
||||
|
||||
struct ukbd_softc {
|
||||
bdevice sc_dev; /* base device */
|
||||
usbd_interface_handle sc_iface; /* interface */
|
||||
usbd_pipe_handle sc_intrpipe; /* interrupt pipe */
|
||||
int sc_ep_addr;
|
||||
|
||||
struct ukbd_data sc_ndata;
|
||||
struct ukbd_data sc_odata;
|
||||
|
||||
char sc_enabled;
|
||||
char sc_disconnected; /* device is gone */
|
||||
|
||||
int sc_leds;
|
||||
#if defined(__NetBSD__)
|
||||
struct device *sc_wskbddev;
|
||||
#ifdef WSDISPLAY_COMPAT_RAWKBD
|
||||
int sc_rawkbd;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
int sc_polling;
|
||||
int sc_pollchar;
|
||||
};
|
||||
|
||||
#define UKBDUNIT(dev) (minor(dev))
|
||||
#define UKBD_CHUNK 128 /* chunk size for read */
|
||||
#define UKBD_BSIZE 1020 /* buffer size */
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
int ukbd_match __P((struct device *, struct cfdata *, void *));
|
||||
void ukbd_attach __P((struct device *, struct device *, void *));
|
||||
#elif defined(__FreeBSD__)
|
||||
static device_probe_t ukbd_match;
|
||||
static device_attach_t ukbd_attach;
|
||||
static device_detach_t ukbd_detach;
|
||||
#endif
|
||||
|
||||
void ukbd_cngetc __P((void *, u_int *, int *));
|
||||
void ukbd_cnpollc __P((void *, int));
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
const struct wskbd_consops ukbd_consops = {
|
||||
ukbd_cngetc,
|
||||
ukbd_cnpollc,
|
||||
};
|
||||
#endif
|
||||
|
||||
void ukbd_intr __P((usbd_request_handle, usbd_private_handle, usbd_status));
|
||||
void ukbd_disco __P((void *));
|
||||
|
||||
int ukbd_enable __P((void *, int));
|
||||
void ukbd_set_leds __P((void *, int));
|
||||
#if defined(__NetBSD__)
|
||||
int ukbd_ioctl __P((void *, u_long, caddr_t, int, struct proc *));
|
||||
|
||||
const struct wskbd_accessops ukbd_accessops = {
|
||||
ukbd_enable,
|
||||
ukbd_set_leds,
|
||||
ukbd_ioctl,
|
||||
};
|
||||
|
||||
const struct wskbd_mapdata ukbd_keymapdata = {
|
||||
pckbd_keydesctab,
|
||||
#ifdef PCKBD_LAYOUT
|
||||
PCKBD_LAYOUT,
|
||||
#else
|
||||
KB_US,
|
||||
#endif
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
extern struct cfdriver ukbd_cd;
|
||||
|
||||
struct cfattach ukbd_ca = {
|
||||
sizeof(struct ukbd_softc), ukbd_match, ukbd_attach
|
||||
};
|
||||
#elif defined(__FreeBSD__)
|
||||
static devclass_t ukbd_devclass;
|
||||
|
||||
static device_method_t ukbd_methods[] = {
|
||||
DEVMETHOD(device_probe, ukbd_match),
|
||||
DEVMETHOD(device_attach, ukbd_attach),
|
||||
DEVMETHOD(device_detach, ukbd_detach),
|
||||
{0,0}
|
||||
};
|
||||
|
||||
static driver_t ukbd_driver = {
|
||||
"ukbd",
|
||||
ukbd_methods,
|
||||
DRIVER_TYPE_MISC,
|
||||
sizeof(struct ukbd_softc)
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
int
|
||||
ukbd_match(parent, match, aux)
|
||||
struct device *parent;
|
||||
struct cfdata *match;
|
||||
void *aux;
|
||||
{
|
||||
struct usb_attach_arg *uaa = (struct usb_attach_arg *)aux;
|
||||
#elif defined(__FreeBSD__)
|
||||
static int
|
||||
ukbd_match(device_t device)
|
||||
{
|
||||
struct usb_attach_arg *uaa = device_get_ivars(device);
|
||||
#endif
|
||||
usb_interface_descriptor_t *id;
|
||||
|
||||
/* Check that this is a keyboard that speaks the boot protocol. */
|
||||
if (!uaa->iface)
|
||||
return (UMATCH_NONE);
|
||||
id = usbd_get_interface_descriptor(uaa->iface);
|
||||
if (id->bInterfaceClass != UCLASS_HID ||
|
||||
id->bInterfaceSubClass != USUBCLASS_BOOT ||
|
||||
id->bInterfaceProtocol != UPROTO_BOOT_KEYBOARD)
|
||||
return (UMATCH_NONE);
|
||||
return (UMATCH_IFACECLASS_IFACESUBCLASS_IFACEPROTO);
|
||||
}
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
void
|
||||
ukbd_attach(parent, self, aux)
|
||||
struct device *parent;
|
||||
struct device *self;
|
||||
void *aux;
|
||||
{
|
||||
struct ukbd_softc *sc = (struct ukbd_softc *)self;
|
||||
struct usb_attach_arg *uaa = aux;
|
||||
#elif defined(__FreeBSD__)
|
||||
static int
|
||||
ukbd_attach(device_t self)
|
||||
{
|
||||
struct ukbd_softc *sc = device_get_softc(self);
|
||||
struct usb_attach_arg *uaa = device_get_ivars(self);
|
||||
#endif
|
||||
usbd_interface_handle iface = uaa->iface;
|
||||
usb_interface_descriptor_t *id;
|
||||
usb_endpoint_descriptor_t *ed;
|
||||
usbd_status r;
|
||||
char devinfo[1024];
|
||||
#if defined(__NetBSD__)
|
||||
struct wskbddev_attach_args a;
|
||||
#else
|
||||
int i;
|
||||
#endif
|
||||
|
||||
sc->sc_disconnected = 1;
|
||||
sc->sc_iface = iface;
|
||||
id = usbd_get_interface_descriptor(iface);
|
||||
usbd_devinfo(uaa->device, 0, devinfo);
|
||||
#if defined(__FreeBSD__)
|
||||
usb_device_set_desc(self, devinfo);
|
||||
printf("%s%d", device_get_name(self), device_get_unit(self));
|
||||
#endif
|
||||
printf(": %s (interface class %d/%d)\n", devinfo,
|
||||
id->bInterfaceClass, id->bInterfaceSubClass);
|
||||
sc->sc_dev = self;
|
||||
ed = usbd_interface2endpoint_descriptor(iface, 0);
|
||||
if (!ed) {
|
||||
DEVICE_ERROR(sc->sc_dev, ("could not read endpoint descriptor\n"));
|
||||
ATTACH_ERROR_RETURN;
|
||||
}
|
||||
|
||||
DPRINTFN(10,("ukbd_attach: \
|
||||
bLength=%d bDescriptorType=%d bEndpointAddress=%d-%s bmAttributes=%d wMaxPacketSize=%d bInterval=%d\n",
|
||||
ed->bLength, ed->bDescriptorType, ed->bEndpointAddress & UE_ADDR,
|
||||
ed->bEndpointAddress & UE_IN ? "in" : "out",
|
||||
ed->bmAttributes & UE_XFERTYPE,
|
||||
UGETW(ed->wMaxPacketSize), ed->bInterval));
|
||||
|
||||
if ((ed->bEndpointAddress & UE_IN) != UE_IN ||
|
||||
(ed->bmAttributes & UE_XFERTYPE) != UE_INTERRUPT) {
|
||||
DEVICE_ERROR(sc->sc_dev, ("unexpected endpoint\n"));
|
||||
ATTACH_ERROR_RETURN;
|
||||
}
|
||||
|
||||
if ((usbd_get_quirks(uaa->device)->uq_flags & UQ_NO_SET_PROTO) == 0) {
|
||||
r = usbd_set_protocol(iface, 0);
|
||||
DPRINTFN(5, ("ukbd_attach: protocol set\n"));
|
||||
if (r != USBD_NORMAL_COMPLETION) {
|
||||
DEVICE_ERROR(sc->sc_dev, ("set protocol failed\n"));
|
||||
ATTACH_ERROR_RETURN;
|
||||
}
|
||||
}
|
||||
/* Ignore if SETIDLE fails since it is not crucial. */
|
||||
usbd_set_idle(iface, 0, 0);
|
||||
|
||||
sc->sc_ep_addr = ed->bEndpointAddress;
|
||||
sc->sc_disconnected = 0;
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
a.console = 0; /* XXX */
|
||||
|
||||
a.keymap = &ukbd_keymapdata;
|
||||
|
||||
a.accessops = &ukbd_accessops;
|
||||
a.accesscookie = sc;
|
||||
|
||||
sc->sc_wskbddev = config_found(self, &a, wskbddevprint);
|
||||
|
||||
#elif defined(__FreeBSD__)
|
||||
/* it's alive! IT'S ALIVE! */
|
||||
ukbd_set_leds(sc, NUM_LOCK);
|
||||
DELAY(15000);
|
||||
ukbd_set_leds(sc, CAPS_LOCK);
|
||||
DELAY(20000);
|
||||
ukbd_set_leds(sc, SCROLL_LOCK);
|
||||
DELAY(30000);
|
||||
ukbd_set_leds(sc, CAPS_LOCK);
|
||||
DELAY(50000);
|
||||
ukbd_set_leds(sc, NUM_LOCK);
|
||||
|
||||
ukbd_enable(sc, 1);
|
||||
#endif
|
||||
|
||||
ATTACH_SUCCESS_RETURN;
|
||||
}
|
||||
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
int
|
||||
ukbd_detach(device_t self)
|
||||
{
|
||||
struct ukbd_softc *sc = device_get_softc(self);
|
||||
char *devinfo = (char *) device_get_desc(self);
|
||||
|
||||
if (sc->sc_enabled)
|
||||
return ENXIO;
|
||||
|
||||
if (devinfo) {
|
||||
device_set_desc(self, NULL);
|
||||
free(devinfo, M_USB);
|
||||
}
|
||||
|
||||
/* good bye, and thanks for all the fish */
|
||||
ukbd_set_leds(sc, NUM_LOCK);
|
||||
DELAY(50000);
|
||||
ukbd_set_leds(sc, CAPS_LOCK);
|
||||
DELAY(30000);
|
||||
ukbd_set_leds(sc, SCROLL_LOCK);
|
||||
DELAY(20000);
|
||||
ukbd_set_leds(sc, CAPS_LOCK);
|
||||
DELAY(15000);
|
||||
ukbd_set_leds(sc, NUM_LOCK);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void
|
||||
ukbd_disco(p)
|
||||
void *p;
|
||||
{
|
||||
struct ukbd_softc *sc = p;
|
||||
|
||||
DPRINTF(("ukbd_disco: sc=%p\n", sc));
|
||||
usbd_abort_pipe(sc->sc_intrpipe);
|
||||
sc->sc_disconnected = 1;
|
||||
}
|
||||
|
||||
int
|
||||
ukbd_enable(v, on)
|
||||
void *v;
|
||||
int on;
|
||||
{
|
||||
struct ukbd_softc *sc = v;
|
||||
usbd_status r;
|
||||
|
||||
if (on) {
|
||||
/* Set up interrupt pipe. */
|
||||
if (sc->sc_enabled)
|
||||
return EBUSY;
|
||||
|
||||
sc->sc_enabled = 1;
|
||||
r = usbd_open_pipe_intr(sc->sc_iface, sc->sc_ep_addr,
|
||||
USBD_SHORT_XFER_OK,
|
||||
&sc->sc_intrpipe, sc, &sc->sc_ndata,
|
||||
sizeof(sc->sc_ndata), ukbd_intr);
|
||||
if (r != USBD_NORMAL_COMPLETION)
|
||||
return (EIO);
|
||||
usbd_set_disco(sc->sc_intrpipe, ukbd_disco, sc);
|
||||
} else {
|
||||
/* Disable interrupts. */
|
||||
usbd_abort_pipe(sc->sc_intrpipe);
|
||||
usbd_close_pipe(sc->sc_intrpipe);
|
||||
|
||||
sc->sc_enabled = 0;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
ukbd_intr(reqh, addr, status)
|
||||
usbd_request_handle reqh;
|
||||
usbd_private_handle addr;
|
||||
usbd_status status;
|
||||
{
|
||||
struct ukbd_softc *sc = addr;
|
||||
struct ukbd_data *ud = &sc->sc_ndata;
|
||||
int mod, omod;
|
||||
int ibuf[NMOD+2*NKEYCODE]; /* chars events */
|
||||
int nkeys, i, j;
|
||||
int key, c;
|
||||
#define ADDKEY(c) ibuf[nkeys++] = (c)
|
||||
|
||||
DPRINTFN(5, ("ukbd_intr: status=%d\n", status));
|
||||
if (status == USBD_CANCELLED)
|
||||
return;
|
||||
|
||||
if (status != USBD_NORMAL_COMPLETION) {
|
||||
DPRINTF(("ukbd_intr: status=%d\n", status));
|
||||
usbd_clear_endpoint_stall_async(sc->sc_intrpipe);
|
||||
return;
|
||||
}
|
||||
|
||||
DPRINTFN(5, (" mod=0x%02x key0=0x%02x key1=0x%02x\n",
|
||||
ud->modifiers, ud->keycode[0], ud->keycode[1]));
|
||||
|
||||
if (ud->keycode[0] == KEY_ERROR)
|
||||
return; /* ignore */
|
||||
nkeys = 0;
|
||||
mod = ud->modifiers;
|
||||
omod = sc->sc_odata.modifiers;
|
||||
if (mod != omod)
|
||||
for (i = 0; i < NMOD; i++)
|
||||
if (( mod & ukbd_mods[i].mask) !=
|
||||
(omod & ukbd_mods[i].mask))
|
||||
ADDKEY(ukbd_mods[i].key |
|
||||
(mod & ukbd_mods[i].mask
|
||||
? PRESS : RELEASE));
|
||||
if (memcmp(ud->keycode, sc->sc_odata.keycode, NKEYCODE) != 0) {
|
||||
/* Check for released keys. */
|
||||
for (i = 0; i < NKEYCODE; i++) {
|
||||
key = sc->sc_odata.keycode[i];
|
||||
if (key == 0)
|
||||
continue;
|
||||
for (j = 0; j < NKEYCODE; j++)
|
||||
if (key == ud->keycode[j])
|
||||
goto rfound;
|
||||
c = ukbd_trtab[key];
|
||||
if (c)
|
||||
ADDKEY(c | RELEASE);
|
||||
rfound:
|
||||
;
|
||||
}
|
||||
|
||||
/* Check for pressed keys. */
|
||||
for (i = 0; i < NKEYCODE; i++) {
|
||||
key = ud->keycode[i];
|
||||
if (key == 0)
|
||||
continue;
|
||||
for (j = 0; j < NKEYCODE; j++)
|
||||
if (key == sc->sc_odata.keycode[j])
|
||||
goto pfound;
|
||||
c = ukbd_trtab[key];
|
||||
DPRINTFN(2,("ukbd_intr: press key=0x%02x -> 0x%02x\n",
|
||||
key, c));
|
||||
if (c)
|
||||
ADDKEY(c | PRESS);
|
||||
pfound:
|
||||
;
|
||||
}
|
||||
}
|
||||
sc->sc_odata = *ud;
|
||||
|
||||
if (sc->sc_polling) {
|
||||
if (nkeys > 0)
|
||||
sc->sc_pollchar = ibuf[0]; /* XXX lost keys? */
|
||||
return;
|
||||
}
|
||||
for (i = 0; i < nkeys; i++) {
|
||||
c = ibuf[i];
|
||||
#if defined(__NetBSD__)
|
||||
wskbd_input(sc->sc_wskbddev,
|
||||
c & RELEASE ? WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN,
|
||||
c & 0xff);
|
||||
#elif defined(__FreeBSD__)
|
||||
printf("%c (%d) %s\n", ((c&0xff) < 32 || (c&0xff) > 126? '.':(c&0xff)), c,
|
||||
(c&RELEASE? "released":"pressed"));
|
||||
if (ud->modifiers)
|
||||
printf("0x%04x\n", ud->modifiers);
|
||||
for (i = 0; i < NKEYCODE; i++)
|
||||
if (ud->keycode[i])
|
||||
printf("%d ", ud->keycode[i]);
|
||||
printf("\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ukbd_set_leds(v, leds)
|
||||
void *v;
|
||||
int leds;
|
||||
{
|
||||
struct ukbd_softc *sc = v;
|
||||
u_int8_t res = leds;
|
||||
|
||||
DPRINTF(("ukbd_set_leds: sc=%p leds=%d\n", sc, leds));
|
||||
|
||||
sc->sc_leds = leds;
|
||||
#if defined(__NetBSD__)
|
||||
res = 0;
|
||||
if (leds & WSKBD_LED_SCROLL)
|
||||
res |= SCROLL_LOCK;
|
||||
if (leds & WSKBD_LED_NUM)
|
||||
res |= NUM_LOCK;
|
||||
if (leds & WSKBD_LED_CAPS)
|
||||
res |= CAPS_LOCK;
|
||||
#endif
|
||||
usbd_set_report_async(sc->sc_iface, UHID_OUTPUT_REPORT, 0, &res, 1);
|
||||
}
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
int
|
||||
ukbd_ioctl(v, cmd, data, flag, p)
|
||||
void *v;
|
||||
u_long cmd;
|
||||
caddr_t data;
|
||||
int flag;
|
||||
struct proc *p;
|
||||
{
|
||||
struct ukbd_softc *sc = v;
|
||||
|
||||
switch (cmd) {
|
||||
case WSKBDIO_GTYPE:
|
||||
*(int *)data = WSKBD_TYPE_PC_XT;
|
||||
return 0;
|
||||
case WSKBDIO_SETLEDS:
|
||||
ukbd_set_leds(v, *(int *)data);
|
||||
return 0;
|
||||
case WSKBDIO_GETLEDS:
|
||||
*(int *)data = sc->sc_leds;
|
||||
return (0);
|
||||
#ifdef WSDISPLAY_COMPAT_RAWKBD
|
||||
case WSKBDIO_SETMODE:
|
||||
sc->sc_rawkbd = *(int *)data == WSKBD_RAW;
|
||||
return (0);
|
||||
#endif
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Console interface. */
|
||||
/* XXX does not work. */
|
||||
void
|
||||
ukbd_cngetc(v, type, data)
|
||||
void *v;
|
||||
u_int *type;
|
||||
int *data;
|
||||
{
|
||||
struct ukbd_softc *sc = v;
|
||||
usbd_lock_token s;
|
||||
int c;
|
||||
|
||||
DPRINTFN(1,("ukbd_cngetc: enter\n"));
|
||||
s = usbd_lock();
|
||||
sc->sc_polling = 1;
|
||||
sc->sc_pollchar = -1;
|
||||
while(sc->sc_pollchar == -1)
|
||||
usbd_dopoll(sc->sc_iface);
|
||||
sc->sc_polling = 0;
|
||||
c = sc->sc_pollchar;
|
||||
*type = c & RELEASE ? WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN;
|
||||
*data = c & 0xff;
|
||||
usbd_unlock(s);
|
||||
DPRINTFN(1,("ukbd_cngetc: return 0x%02x\n", c));
|
||||
}
|
||||
|
||||
void
|
||||
ukbd_cnpollc(v, on)
|
||||
void *v;
|
||||
int on;
|
||||
{
|
||||
struct ukbd_softc *sc = v;
|
||||
|
||||
DPRINTFN(1,("ukbd_cnpollc: sc=%p on=%d\n", v, on));
|
||||
|
||||
usbd_set_polling(sc->sc_iface, on);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
DRIVER_MODULE(ukbd, usb, ukbd_driver, ukbd_devclass, usb_driver_load, 0);
|
||||
#endif
|
502
sys/dev/usb/ulpt.c
Normal file
502
sys/dev/usb/ulpt.c
Normal file
@ -0,0 +1,502 @@
|
||||
/* $NetBSD: ulpt.c,v 1.2 1998/07/25 15:19:09 augustss Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1998 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Lennart Augustsson <augustss@carlstedt.se>
|
||||
* 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 <dev/usb/usb_port.h>
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/proc.h>
|
||||
#if defined(__NetBSD__)
|
||||
#include <sys/user.h>
|
||||
#endif
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/kernel.h>
|
||||
#if defined(__NetBSD__)
|
||||
#include <sys/device.h>
|
||||
#include <sys/ioctl.h>
|
||||
#elif defined(__FreeBSD__)
|
||||
#include <sys/ioccom.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/bus.h>
|
||||
#endif
|
||||
#include <sys/uio.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/syslog.h>
|
||||
|
||||
#include <dev/usb/usb.h>
|
||||
#include <dev/usb/usbdi.h>
|
||||
#include <dev/usb/usbdivar.h>
|
||||
#include <dev/usb/usbdi_util.h>
|
||||
#include <dev/usb/usbdevs.h>
|
||||
#include <dev/usb/usb_quirks.h>
|
||||
|
||||
#define TIMEOUT hz*16 /* wait up to 16 seconds for a ready */
|
||||
#define STEP hz/4
|
||||
|
||||
#define LPTPRI (PZERO+8)
|
||||
#define ULPT_BSIZE 1024
|
||||
|
||||
#ifdef USB_DEBUG
|
||||
#define DPRINTF(x) if (ulptdebug) printf x
|
||||
#define DPRINTFN(n,x) if (ulptdebug>(n)) printf x
|
||||
int ulptdebug = 0;
|
||||
#else
|
||||
#define DPRINTF(x)
|
||||
#define DPRINTFN(n,x)
|
||||
#endif
|
||||
|
||||
#define UR_GET_DEVICE_ID 0
|
||||
#define UR_GET_PORT_STATUS 1
|
||||
#define UR_SOFT_RESET 2
|
||||
|
||||
#define LPS_NERR 0x08 /* printer no error */
|
||||
#define LPS_SELECT 0x10 /* printer selected */
|
||||
#define LPS_NOPAPER 0x20 /* printer out of paper */
|
||||
#define LPS_INVERT (LPS_SELECT|LPS_NERR)
|
||||
#define LPS_MASK (LPS_SELECT|LPS_NERR|LPS_NOPAPER)
|
||||
|
||||
struct ulpt_softc {
|
||||
bdevice sc_dev;
|
||||
usbd_device_handle sc_udev; /* device */
|
||||
usbd_interface_handle sc_iface; /* interface */
|
||||
int sc_ifaceno;
|
||||
usbd_pipe_handle sc_bulkpipe; /* bulk pipe */
|
||||
int sc_bulk;
|
||||
|
||||
u_char sc_state;
|
||||
#define ULPT_OPEN 0x01 /* device is open */
|
||||
#define ULPT_OBUSY 0x02 /* printer is busy doing output */
|
||||
#define ULPT_INIT 0x04 /* waiting to initialize for open */
|
||||
u_char sc_flags;
|
||||
#define ULPT_NOPRIME 0x40 /* don't prime on open */
|
||||
u_char sc_laststatus;
|
||||
};
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
int ulpt_match __P((struct device *, struct cfdata *, void *));
|
||||
void ulpt_attach __P((struct device *, struct device *, void *));
|
||||
#elif defined(__FreeBSD__)
|
||||
static device_probe_t ulpt_match;
|
||||
static device_attach_t ulpt_attach;
|
||||
#endif
|
||||
|
||||
int ulptopen __P((dev_t, int, int, struct proc *));
|
||||
int ulptclose __P((dev_t, int, int, struct proc *p));
|
||||
int ulptwrite __P((dev_t, struct uio *uio, int));
|
||||
int ulptioctl __P((dev_t, u_long, caddr_t, int, struct proc *));
|
||||
void ulpt_disco __P((void *));
|
||||
|
||||
int ulpt_status __P((struct ulpt_softc *));
|
||||
void ulpt_reset __P((struct ulpt_softc *));
|
||||
int ulpt_statusmsg __P((u_char, struct ulpt_softc *));
|
||||
|
||||
#define ULPTUNIT(s) (minor(s) & 0x1f)
|
||||
#define ULPTFLAGS(s) (minor(s) & 0xe0)
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
extern struct cfdriver ulpt_cd;
|
||||
|
||||
struct cfattach ulpt_ca = {
|
||||
sizeof(struct ulpt_softc), ulpt_match, ulpt_attach
|
||||
};
|
||||
#elif defined(__FreeBSD__)
|
||||
static devclass_t ulpt_devclass;
|
||||
|
||||
static device_method_t ulpt_methods[] = {
|
||||
DEVMETHOD(device_probe, ulpt_match),
|
||||
DEVMETHOD(device_attach, ulpt_attach),
|
||||
{0,0}
|
||||
};
|
||||
|
||||
static driver_t ulpt_driver = {
|
||||
"ulpt",
|
||||
ulpt_methods,
|
||||
DRIVER_TYPE_MISC,
|
||||
sizeof(struct ulpt_softc)
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
int
|
||||
ulpt_match(parent, match, aux)
|
||||
struct device *parent;
|
||||
struct cfdata *match;
|
||||
void *aux;
|
||||
{
|
||||
struct usb_attach_arg *uaa = aux;
|
||||
#elif defined(__FreeBSD__)
|
||||
static int
|
||||
ulpt_match(device_t device)
|
||||
{
|
||||
struct usb_attach_arg *uaa = device_get_ivars(device);
|
||||
#endif
|
||||
usb_interface_descriptor_t *id;
|
||||
|
||||
DPRINTFN(10,("ulpt_match\n"));
|
||||
if (!uaa->iface)
|
||||
return (UMATCH_NONE);
|
||||
id = usbd_get_interface_descriptor(uaa->iface);
|
||||
if (id->bInterfaceClass == UCLASS_PRINTER &&
|
||||
id->bInterfaceSubClass == USUBCLASS_PRINTER &&
|
||||
(id->bInterfaceProtocol == UPROTO_PRINTER_UNI ||
|
||||
id->bInterfaceProtocol == UPROTO_PRINTER_BI))
|
||||
return (UMATCH_IFACECLASS_IFACESUBCLASS_IFACEPROTO);
|
||||
return (UMATCH_NONE);
|
||||
}
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
void
|
||||
ulpt_attach(parent, self, aux)
|
||||
struct device *parent;
|
||||
struct device *self;
|
||||
void *aux;
|
||||
{
|
||||
struct ulpt_softc *sc = (struct ulpt_softc *)self;
|
||||
struct usb_attach_arg *uaa = aux;
|
||||
#elif defined(__FreeBSD__)
|
||||
static int
|
||||
ulpt_attach(device_t self)
|
||||
{
|
||||
struct ulpt_softc *sc = device_get_softc(self);
|
||||
struct usb_attach_arg *uaa = device_get_ivars(self);
|
||||
#endif
|
||||
usbd_device_handle dev = uaa->device;
|
||||
usbd_interface_handle iface = uaa->iface;
|
||||
usb_interface_descriptor_t *id = usbd_get_interface_descriptor(iface);
|
||||
#if 0
|
||||
usb_config_descriptor_t *cd = usbd_get_config_descriptor(dev);
|
||||
usb_device_request_t req;
|
||||
#endif
|
||||
char devinfo[1024];
|
||||
usb_endpoint_descriptor_t *ed;
|
||||
usbd_status r;
|
||||
|
||||
DPRINTFN(10,("ulpt_attach: sc=%p\n", sc));
|
||||
usbd_devinfo(dev, 0, devinfo);
|
||||
#if defined(__FreeBSD__)
|
||||
usb_device_set_desc(self, devinfo);
|
||||
printf("%s%d", device_get_name(self), device_get_unit(self));
|
||||
#endif
|
||||
printf(": %s (interface class %d/%d)\n", devinfo,
|
||||
id->bInterfaceClass, id->bInterfaceSubClass);
|
||||
sc->sc_dev = self;
|
||||
|
||||
/* Figure out which endpoint is the bulk out endpoint. */
|
||||
ed = usbd_interface2endpoint_descriptor(iface, 0);
|
||||
if (!ed)
|
||||
goto nobulk;
|
||||
if ((ed->bEndpointAddress & UE_IN) != UE_OUT ||
|
||||
(ed->bmAttributes & UE_XFERTYPE) != UE_BULK) {
|
||||
/* In case we are using a bidir protocol... */
|
||||
ed = usbd_interface2endpoint_descriptor(iface, 1);
|
||||
if (!ed)
|
||||
goto nobulk;
|
||||
if ((ed->bEndpointAddress & UE_IN) != UE_OUT ||
|
||||
(ed->bmAttributes & UE_XFERTYPE) != UE_BULK)
|
||||
goto nobulk;
|
||||
}
|
||||
sc->sc_bulk = ed->bEndpointAddress;
|
||||
DPRINTFN(10, ("ulpt_attach: bulk=%d\n", sc->sc_bulk));
|
||||
|
||||
sc->sc_iface = iface;
|
||||
r = usbd_interface2device_handle(iface, &sc->sc_udev);
|
||||
if (r != USBD_NORMAL_COMPLETION)
|
||||
ATTACH_ERROR_RETURN;
|
||||
sc->sc_ifaceno = id->bInterfaceNumber;
|
||||
|
||||
#if 0
|
||||
XXX needs a different way to read the id string since the length
|
||||
is unknown. usbd_do_request() returns error on a short transfer.
|
||||
req.bmRequestType = UT_READ_CLASS_INTERFACE;
|
||||
req.bRequest = UR_GET_DEVICE_ID;
|
||||
USETW(req.wValue, cd->bConfigurationValue);
|
||||
USETW2(req.wIndex, id->bInterfaceNumber, id->bAlternateSetting);
|
||||
USETW(req.wLength, sizeof devinfo - 1);
|
||||
r = usbd_do_request(dev, &req, devinfo);
|
||||
if (r == USBD_NORMAL_COMPLETION) {
|
||||
int len;
|
||||
char *idstr;
|
||||
len = (devinfo[0] << 8) | (devinfo[1] & 0xff);
|
||||
/* devinfo now contains an IEEE-1284 device ID */
|
||||
idstr = devinfo+2;
|
||||
idstr[len] = 0;
|
||||
DEVICE_ERROR(sc->sc_dev, ("device id <%s>\n", idstr));
|
||||
} else {
|
||||
printf("%s: \n", sc->sc_dev.dv_xname);
|
||||
DEVICE_ERROR(sc->sc_dev, ("cannot get device id"));
|
||||
}
|
||||
#endif
|
||||
|
||||
ATTACH_SUCCESS_RETURN;
|
||||
|
||||
nobulk:
|
||||
DEVICE_ERROR(sc->sc_dev, ("could not find bulk endpoint\n"));
|
||||
ATTACH_ERROR_RETURN;
|
||||
}
|
||||
|
||||
int
|
||||
ulpt_status(sc)
|
||||
struct ulpt_softc *sc;
|
||||
{
|
||||
usb_device_request_t req;
|
||||
usbd_status r;
|
||||
u_char status;
|
||||
|
||||
req.bmRequestType = UT_READ_CLASS_INTERFACE;
|
||||
req.bRequest = UR_GET_PORT_STATUS;
|
||||
USETW(req.wValue, 0);
|
||||
USETW(req.wIndex, sc->sc_ifaceno);
|
||||
USETW(req.wLength, 1);
|
||||
r = usbd_do_request(sc->sc_udev, &req, &status);
|
||||
DPRINTFN(1, ("ulpt_status: status=0x%02x r=%d\n", status, r));
|
||||
if (r == USBD_NORMAL_COMPLETION)
|
||||
return (status);
|
||||
else
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
ulpt_reset(sc)
|
||||
struct ulpt_softc *sc;
|
||||
{
|
||||
usb_device_request_t req;
|
||||
|
||||
DPRINTFN(1, ("ulpt_reset\n"));
|
||||
req.bmRequestType = UT_WRITE_CLASS_OTHER;
|
||||
req.bRequest = UR_SOFT_RESET;
|
||||
USETW(req.wValue, 0);
|
||||
USETW(req.wIndex, sc->sc_ifaceno);
|
||||
USETW(req.wLength, 0);
|
||||
(void)usbd_do_request(sc->sc_udev, &req, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset the printer, then wait until it's selected and not busy.
|
||||
*/
|
||||
int
|
||||
ulptopen(dev, flag, mode, p)
|
||||
dev_t dev;
|
||||
int flag;
|
||||
int mode;
|
||||
struct proc *p;
|
||||
{
|
||||
u_char flags = ULPTFLAGS(dev);
|
||||
usbd_status r;
|
||||
int spin, error;
|
||||
#if defined(__NetBSD__)
|
||||
int unit = ULPTUNIT(dev);
|
||||
struct ulpt_softc *sc;
|
||||
|
||||
if (unit >= ulpt_cd.cd_ndevs)
|
||||
return ENXIO;
|
||||
sc = ulpt_cd.cd_devs[unit];
|
||||
#elif defined(__FreeBSD__)
|
||||
struct ulpt_softc *sc = devclass_get_softc(ulpt_devclass, ULPTUNIT(dev));
|
||||
#endif
|
||||
|
||||
if (!sc || !sc->sc_iface)
|
||||
return ENXIO;
|
||||
|
||||
if (sc->sc_state)
|
||||
return EBUSY;
|
||||
|
||||
sc->sc_state = ULPT_INIT;
|
||||
sc->sc_flags = flags;
|
||||
DPRINTF(("ulptopen: flags=0x%x\n", (unsigned)flags));
|
||||
|
||||
if ((flags & ULPT_NOPRIME) == 0)
|
||||
ulpt_reset(sc);
|
||||
|
||||
for (spin = 0; (ulpt_status(sc) & LPS_SELECT) == 0; spin += STEP) {
|
||||
if (spin >= TIMEOUT) {
|
||||
sc->sc_state = 0;
|
||||
return EBUSY;
|
||||
}
|
||||
|
||||
/* wait 1/4 second, give up if we get a signal */
|
||||
error = tsleep((caddr_t)sc, LPTPRI | PCATCH, "ulptop", STEP);
|
||||
if (error != EWOULDBLOCK) {
|
||||
sc->sc_state = 0;
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
r = usbd_open_pipe(sc->sc_iface, sc->sc_bulk, 0, &sc->sc_bulkpipe);
|
||||
if (r != USBD_NORMAL_COMPLETION) {
|
||||
sc->sc_state = 0;
|
||||
return (EIO);
|
||||
}
|
||||
|
||||
sc->sc_state = ULPT_OPEN;
|
||||
|
||||
DPRINTF(("ulptopen: done\n"));
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
ulpt_statusmsg(status, sc)
|
||||
u_char status;
|
||||
struct ulpt_softc *sc;
|
||||
{
|
||||
u_char new;
|
||||
|
||||
status = (status ^ LPS_INVERT) & LPS_MASK;
|
||||
new = status & ~sc->sc_laststatus;
|
||||
sc->sc_laststatus = status;
|
||||
|
||||
/* XXX should be tidied up into one block and a definition in usb_ports.h
|
||||
*/
|
||||
#if defined(__NetBSD__)
|
||||
if (new & LPS_SELECT)
|
||||
log(LOG_NOTICE, "%s: offline\n", sc->sc_dev.dv_xname);
|
||||
else if (new & LPS_NOPAPER)
|
||||
log(LOG_NOTICE, "%s: out of paper\n", sc->sc_dev.dv_xname);
|
||||
else if (new & LPS_NERR)
|
||||
log(LOG_NOTICE, "%s: output error\n", sc->sc_dev.dv_xname);
|
||||
#elif defined(__FreeBSD__)
|
||||
if (new & LPS_SELECT)
|
||||
log(LOG_NOTICE, "%s%d: offline\n",
|
||||
device_get_name(sc->sc_dev), device_get_unit(sc->sc_dev));
|
||||
else if (new & LPS_NOPAPER)
|
||||
log(LOG_NOTICE, "%s%d: out of paper\n",
|
||||
device_get_name(sc->sc_dev), device_get_unit(sc->sc_dev));
|
||||
else if (new & LPS_NERR)
|
||||
log(LOG_NOTICE, "%s%d: output error\n",
|
||||
device_get_name(sc->sc_dev), device_get_unit(sc->sc_dev));
|
||||
#endif
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int
|
||||
ulptclose(dev, flag, mode, p)
|
||||
dev_t dev;
|
||||
int flag;
|
||||
int mode;
|
||||
struct proc *p;
|
||||
{
|
||||
#if defined(__NetBSD__)
|
||||
int unit = ULPTUNIT(dev);
|
||||
struct ulpt_softc *sc;
|
||||
|
||||
if (unit >= ulpt_cd.cd_ndevs)
|
||||
return (ENXIO);
|
||||
sc = ulpt_cd.cd_devs[unit];
|
||||
#elif defined(__FreeBSD__)
|
||||
struct ulpt_softc *sc = devclass_get_softc(ulpt_devclass, ULPTUNIT(dev));
|
||||
#endif
|
||||
|
||||
usbd_close_pipe(sc->sc_bulkpipe);
|
||||
|
||||
sc->sc_state = 0;
|
||||
|
||||
DPRINTF(("ulptclose: closed\n"));
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
ulptwrite(dev, uio, flags)
|
||||
dev_t dev;
|
||||
struct uio *uio;
|
||||
int flags;
|
||||
{
|
||||
size_t n;
|
||||
int error = 0;
|
||||
char buf[ULPT_BSIZE];
|
||||
usbd_request_handle reqh;
|
||||
usbd_status r;
|
||||
#if defined(__NetBSD__)
|
||||
int unit = ULPTUNIT(dev);
|
||||
struct ulpt_softc *sc;
|
||||
|
||||
if (unit >= ulpt_cd.cd_ndevs)
|
||||
return (ENXIO);
|
||||
sc = ulpt_cd.cd_devs[unit];
|
||||
#elif defined(__FreeBSD__)
|
||||
struct ulpt_softc *sc = devclass_get_softc(ulpt_devclass, ULPTUNIT(dev));
|
||||
#endif
|
||||
|
||||
DPRINTF(("ulptwrite\n"));
|
||||
reqh = usbd_alloc_request();
|
||||
if (reqh == 0)
|
||||
return (EIO);
|
||||
while ((n = min(ULPT_BSIZE, uio->uio_resid)) != 0) {
|
||||
ulpt_statusmsg(ulpt_status(sc), sc);
|
||||
uiomove(buf, n, uio);
|
||||
/* XXX use callback to enable interrupt? */
|
||||
r = usbd_setup_request(reqh, sc->sc_bulkpipe, 0, buf, n,
|
||||
0, USBD_NO_TIMEOUT, 0);
|
||||
if (r != USBD_NORMAL_COMPLETION) {
|
||||
error = EIO;
|
||||
break;
|
||||
}
|
||||
DPRINTFN(1, ("ulptwrite: transfer %d bytes\n", n));
|
||||
r = usbd_sync_transfer(reqh);
|
||||
if (r != USBD_NORMAL_COMPLETION) {
|
||||
DPRINTF(("ulptwrite: error=%d\n", r));
|
||||
usbd_clear_endpoint_stall(sc->sc_bulkpipe);
|
||||
error = EIO;
|
||||
break;
|
||||
}
|
||||
}
|
||||
usbd_free_request(reqh);
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
ulptioctl(dev, cmd, data, flag, p)
|
||||
dev_t dev;
|
||||
u_long cmd;
|
||||
caddr_t data;
|
||||
int flag;
|
||||
struct proc *p;
|
||||
{
|
||||
int error = 0;
|
||||
|
||||
switch (cmd) {
|
||||
default:
|
||||
error = ENODEV;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
DRIVER_MODULE(ulpt, usb, ulpt_driver, ulpt_devclass, usb_driver_load, 0);
|
||||
#endif
|
812
sys/dev/usb/ums.c
Normal file
812
sys/dev/usb/ums.c
Normal file
@ -0,0 +1,812 @@
|
||||
/* $NetBSD: ums.c,v 1.8 1998/08/01 20:11:39 augustss Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1998 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Lennart Augustsson <augustss@carlstedt.se>
|
||||
* 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 <dev/usb/usb_port.h>
|
||||
|
||||
#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>
|
||||
#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/usbhid.h>
|
||||
|
||||
#include <dev/usb/usbdi.h>
|
||||
#include <dev/usb/usbdivar.h>
|
||||
#include <dev/usb/usbdi_util.h>
|
||||
#include <dev/usb/usbdevs.h>
|
||||
#include <dev/usb/usb_quirks.h>
|
||||
#include <dev/usb/hid.h>
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
#include <dev/wscons/wsconsio.h>
|
||||
#include <dev/wscons/wsmousevar.h>
|
||||
#elif defined(__FreeBSD__)
|
||||
#include <machine/mouse.h>
|
||||
#endif
|
||||
|
||||
#ifdef USB_DEBUG
|
||||
#define DPRINTF(x) if (umsdebug) printf x
|
||||
#define DPRINTFN(n,x) if (umsdebug>(n)) printf x
|
||||
int umsdebug = 1;
|
||||
#else
|
||||
#define DPRINTF(x)
|
||||
#define DPRINTFN(n,x)
|
||||
#endif
|
||||
|
||||
#define UMSUNIT(s) (minor(s)&0x1f)
|
||||
|
||||
#define PS2LBUTMASK x01
|
||||
#define PS2RBUTMASK x02
|
||||
#define PS2MBUTMASK x04
|
||||
#define PS2BUTMASK 0x0f
|
||||
|
||||
#define QUEUE_BUFSIZE 240 /* MUST be dividable by 3 _and_ 4 */
|
||||
|
||||
struct ums_softc {
|
||||
bdevice sc_dev; /* base device */
|
||||
usbd_interface_handle sc_iface; /* interface */
|
||||
usbd_pipe_handle sc_intrpipe; /* interrupt pipe */
|
||||
int sc_ep_addr;
|
||||
|
||||
u_char *sc_ibuf;
|
||||
u_int8_t sc_iid;
|
||||
int sc_isize;
|
||||
struct hid_location sc_loc_x, sc_loc_y, sc_loc_z;
|
||||
struct hid_location *sc_loc_btn;
|
||||
|
||||
int sc_enabled;
|
||||
int sc_disconnected; /* device is gone */
|
||||
|
||||
int flags; /* device configuration */
|
||||
# define UMS_Z 0x01 /* z direction available */
|
||||
int nbuttons;
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
u_char sc_buttons; /* mouse button status */
|
||||
struct device *sc_wsmousedev;
|
||||
#elif defined(__FreeBSD__)
|
||||
u_char qbuf[QUEUE_BUFSIZE];
|
||||
u_char dummy[100]; /* just for safety and for now */
|
||||
int qcount, qhead, qtail;
|
||||
mousehw_t hw;
|
||||
mousemode_t mode;
|
||||
mousestatus_t status;
|
||||
|
||||
int state;
|
||||
# define UMS_ASLEEP 0x01 /* readFromDevice is waiting */
|
||||
# define UMS_SELECT 0x02 /* select is waiting */
|
||||
struct selinfo rsel; /* process waiting in select */
|
||||
#endif
|
||||
};
|
||||
|
||||
#define MOUSE_FLAGS_MASK (HIO_CONST|HIO_RELATIVE)
|
||||
#define MOUSE_FLAGS (HIO_RELATIVE)
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
int ums_match __P((struct device *, struct cfdata *, void *));
|
||||
void ums_attach __P((struct device *, struct device *, void *));
|
||||
#elif defined(__FreeBSD__)
|
||||
static device_probe_t ums_match;
|
||||
static device_attach_t ums_attach;
|
||||
static device_detach_t ums_detach;
|
||||
#endif
|
||||
|
||||
void ums_intr __P((usbd_request_handle, usbd_private_handle, usbd_status));
|
||||
void ums_disco __P((void *));
|
||||
|
||||
static int ums_enable __P((void *));
|
||||
static void ums_disable __P((void *));
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
static int ums_ioctl __P((void *, u_long, caddr_t, int, struct proc *));
|
||||
#elif defined(__FreeBSD__)
|
||||
static d_open_t ums_open;
|
||||
static d_close_t ums_close;
|
||||
static d_read_t ums_read;
|
||||
static d_ioctl_t ums_ioctl;
|
||||
static d_poll_t ums_poll;
|
||||
|
||||
#define UMS_CDEV_MAJOR 138 /* XXX NWH should be requested */
|
||||
|
||||
static struct cdevsw ums_cdevsw = {
|
||||
ums_open, ums_close, ums_read, nowrite,
|
||||
ums_ioctl, nostop, nullreset, nodevtotty,
|
||||
ums_poll, nommap,
|
||||
NULL, "ums_", NULL, -1
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
const struct wsmouse_accessops ums_accessops = {
|
||||
ums_enable,
|
||||
ums_ioctl,
|
||||
ums_disable,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
extern struct cfdriver ums_cd;
|
||||
|
||||
struct cfattach ums_ca = {
|
||||
sizeof(struct ums_softc), ums_match, ums_attach
|
||||
};
|
||||
#elif defined(__FreeBSD__)
|
||||
static devclass_t ums_devclass;
|
||||
|
||||
static device_method_t ums_methods[] = {
|
||||
DEVMETHOD(device_probe, ums_match),
|
||||
DEVMETHOD(device_attach, ums_attach),
|
||||
DEVMETHOD(device_detach, ums_detach),
|
||||
{0,0}
|
||||
};
|
||||
|
||||
static driver_t ums_driver = {
|
||||
"ums",
|
||||
ums_methods,
|
||||
DRIVER_TYPE_MISC,
|
||||
sizeof(struct ums_softc)
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
int
|
||||
ums_match(parent, match, aux)
|
||||
struct device *parent;
|
||||
struct cfdata *match;
|
||||
void *aux;
|
||||
{
|
||||
struct usb_attach_arg *uaa = aux;
|
||||
#elif defined(__FreeBSD__)
|
||||
static int
|
||||
ums_match(device_t device)
|
||||
{
|
||||
struct usb_attach_arg *uaa = device_get_ivars(device);
|
||||
#endif
|
||||
usb_interface_descriptor_t *id;
|
||||
int size, ret;
|
||||
void *desc;
|
||||
usbd_status r;
|
||||
|
||||
if (!uaa->iface)
|
||||
return (UMATCH_NONE);
|
||||
id = usbd_get_interface_descriptor(uaa->iface);
|
||||
if (id->bInterfaceClass != UCLASS_HID)
|
||||
return (UMATCH_NONE);
|
||||
|
||||
r = usbd_alloc_report_desc(uaa->iface, &desc, &size, M_TEMP);
|
||||
if (r != USBD_NORMAL_COMPLETION)
|
||||
return (UMATCH_NONE);
|
||||
|
||||
if (hid_is_collection(desc, size,
|
||||
HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_MOUSE)))
|
||||
ret = UMATCH_IFACECLASS;
|
||||
else
|
||||
ret = UMATCH_NONE;
|
||||
|
||||
free(desc, M_TEMP);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
void
|
||||
ums_attach(parent, self, aux)
|
||||
struct device *parent;
|
||||
struct device *self;
|
||||
void *aux;
|
||||
{
|
||||
struct ums_softc *sc = (struct ums_softc *)self;
|
||||
struct usb_attach_arg *uaa = aux;
|
||||
#elif defined(__FreeBSD__)
|
||||
static int
|
||||
ums_attach(device_t self)
|
||||
{
|
||||
struct ums_softc *sc = device_get_softc(self);
|
||||
struct usb_attach_arg *uaa = device_get_ivars(self);
|
||||
#endif
|
||||
usbd_interface_handle iface = uaa->iface;
|
||||
usb_interface_descriptor_t *id;
|
||||
usb_endpoint_descriptor_t *ed;
|
||||
#if defined(__NetBSD__)
|
||||
struct wsmousedev_attach_args a;
|
||||
#endif
|
||||
char devinfo[1024];
|
||||
int size;
|
||||
void *desc;
|
||||
usbd_status r;
|
||||
u_int32_t flags;
|
||||
struct hid_location loc_btn;
|
||||
int i;
|
||||
|
||||
sc->sc_disconnected = 1;
|
||||
sc->sc_iface = iface;
|
||||
id = usbd_get_interface_descriptor(iface);
|
||||
usbd_devinfo(uaa->device, 0, devinfo);
|
||||
#if defined(__FreeBSD__)
|
||||
usb_device_set_desc(self, devinfo);
|
||||
printf("%s%d", device_get_name(self), device_get_unit(self));
|
||||
#endif
|
||||
printf(": %s (interface class %d/%d)\n", devinfo,
|
||||
id->bInterfaceClass, id->bInterfaceSubClass);
|
||||
sc->sc_dev = self;
|
||||
ed = usbd_interface2endpoint_descriptor(iface, 0);
|
||||
if (!ed) {
|
||||
DEVICE_ERROR(sc->sc_dev, ("could not read endpoint descriptor\n"));
|
||||
ATTACH_ERROR_RETURN;
|
||||
}
|
||||
|
||||
DPRINTFN(10,("ums_attach: bLength=%d bDescriptorType=%d "
|
||||
"bEndpointAddress=%d-%s bmAttributes=%d wMaxPacketSize=%d "
|
||||
"bInterval=%d\n",
|
||||
ed->bLength, ed->bDescriptorType, ed->bEndpointAddress & UE_ADDR,
|
||||
ed->bEndpointAddress & UE_IN ? "in" : "out",
|
||||
ed->bmAttributes & UE_XFERTYPE,
|
||||
UGETW(ed->wMaxPacketSize), ed->bInterval));
|
||||
|
||||
if ((ed->bEndpointAddress & UE_IN) != UE_IN ||
|
||||
(ed->bmAttributes & UE_XFERTYPE) != UE_INTERRUPT) {
|
||||
DEVICE_ERROR(sc->sc_dev, ("unexpected endpoint\n"));
|
||||
ATTACH_ERROR_RETURN;
|
||||
}
|
||||
|
||||
r = usbd_alloc_report_desc(uaa->iface, &desc, &size, M_TEMP);
|
||||
if (r != USBD_NORMAL_COMPLETION)
|
||||
ATTACH_ERROR_RETURN;
|
||||
|
||||
if (!hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_X),
|
||||
hid_input, &sc->sc_loc_x, &flags)) {
|
||||
DEVICE_ERROR(sc->sc_dev, ("mouse has no X report\n"));
|
||||
ATTACH_ERROR_RETURN;
|
||||
}
|
||||
if ((flags & MOUSE_FLAGS_MASK) != MOUSE_FLAGS)
|
||||
DEVICE_ERROR(sc->sc_dev, ("X report 0x%04x not supported\n",
|
||||
flags));
|
||||
|
||||
if (!hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Y),
|
||||
hid_input, &sc->sc_loc_y, &flags)) {
|
||||
DEVICE_ERROR(sc->sc_dev, ("mouse has no Y report\n"));
|
||||
ATTACH_ERROR_RETURN;
|
||||
}
|
||||
if ((flags & MOUSE_FLAGS_MASK) != MOUSE_FLAGS)
|
||||
DEVICE_ERROR(sc->sc_dev, ("Y report 0x%04x not supported\n",
|
||||
flags));
|
||||
|
||||
#ifndef USBVERBOSE
|
||||
if (bootverbose)
|
||||
#endif
|
||||
{
|
||||
if (hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Z),
|
||||
hid_input, &sc->sc_loc_z, &flags))
|
||||
DEVICE_MSG(sc->sc_dev, ("Device has Z axis\n"));
|
||||
if (hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_SLIDER),
|
||||
hid_input, &sc->sc_loc_z, &flags))
|
||||
DEVICE_MSG(sc->sc_dev, ("Device has Slider\n"));
|
||||
if (hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_DIAL),
|
||||
hid_input, &sc->sc_loc_z, &flags))
|
||||
DEVICE_MSG(sc->sc_dev, ("Device has Dial\n"));
|
||||
if (hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_WHEEL),
|
||||
hid_input, &sc->sc_loc_z, &flags))
|
||||
DEVICE_MSG(sc->sc_dev, ("Device has Wheel\n"));
|
||||
if (hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_HAT_SWITCH),
|
||||
hid_input, &sc->sc_loc_z, &flags))
|
||||
DEVICE_MSG(sc->sc_dev, ("Device has Hat Switch\n"));
|
||||
}
|
||||
|
||||
/* try to guess the Z activator: first check Z, then WHEEL */
|
||||
if (hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Z),
|
||||
hid_input, &sc->sc_loc_z, &flags) ||
|
||||
hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_WHEEL),
|
||||
hid_input, &sc->sc_loc_z, &flags)) {
|
||||
if ((flags & MOUSE_FLAGS_MASK) != MOUSE_FLAGS) {
|
||||
sc->sc_loc_z.size = 0; /* Bad Z coord, ignore it */
|
||||
#if !defined(__FreeBSD__) /* FIXME */
|
||||
/* IntelliMouse protocol is not properly implemented yet.
|
||||
* Probably the wisest to use the sysmouse protocol
|
||||
*/
|
||||
} else {
|
||||
sc->flags |= UMS_Z;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* figure out the number of buttons, 7 is an arbitrary limit */
|
||||
for (i = 1; i <= 7; i++)
|
||||
if (!hid_locate(desc, size, HID_USAGE2(HUP_BUTTON, i),
|
||||
hid_input, &loc_btn, 0))
|
||||
break;
|
||||
sc->nbuttons = i - 1;
|
||||
sc->sc_loc_btn = malloc(sizeof(struct hid_location)*sc->nbuttons, M_USBDEV, M_NOWAIT);
|
||||
if (!sc->sc_loc_btn)
|
||||
ATTACH_ERROR_RETURN;
|
||||
|
||||
#ifndef USBVERBOSE
|
||||
if (bootverbose)
|
||||
#endif
|
||||
DEVICE_MSG(sc->sc_dev, ("%d buttons%s\n",
|
||||
sc->nbuttons, (sc->flags & UMS_Z? " and Z dir.":"")));
|
||||
|
||||
for (i = 1; i <= sc->nbuttons; i++)
|
||||
hid_locate(desc, size, HID_USAGE2(HUP_BUTTON, i),
|
||||
hid_input, &sc->sc_loc_btn[i-1], 0);
|
||||
|
||||
sc->sc_isize = hid_report_size(desc, size, hid_input, &sc->sc_iid);
|
||||
sc->sc_ibuf = malloc(sc->sc_isize, M_USB, M_NOWAIT);
|
||||
if (!sc->sc_ibuf) {
|
||||
free(sc->sc_loc_btn, M_USB);
|
||||
ATTACH_ERROR_RETURN;
|
||||
}
|
||||
|
||||
sc->sc_ep_addr = ed->bEndpointAddress;
|
||||
sc->sc_disconnected = 0;
|
||||
free(desc, M_TEMP);
|
||||
|
||||
#ifdef USB_DEBUG
|
||||
DPRINTF(("ums_attach: sc=%p\n", sc));
|
||||
DPRINTF(("ums_attach: X\t%d/%d\n",
|
||||
sc->sc_loc_x.pos, sc->sc_loc_x.size));
|
||||
DPRINTF(("ums_attach: Y\t%d/%d\n",
|
||||
sc->sc_loc_x.pos, sc->sc_loc_x.size));
|
||||
if (sc->flags & UMS_Z)
|
||||
DPRINTF(("ums_attach: Z\t%d/%d\n",
|
||||
sc->sc_loc_z.pos, sc->sc_loc_z.size));
|
||||
for (i = 1; i <= sc->nbuttons; i++) {
|
||||
DPRINTF(("ums_attach: B%d\t%d/%d\n",
|
||||
i, sc->sc_loc_btn[i-1].pos,sc->sc_loc_btn[i-1].size));
|
||||
}
|
||||
DPRINTF(("ums_attach: size=%d, id=%d\n", sc->sc_isize, sc->sc_iid));
|
||||
#endif
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
a.accessops = &ums_accessops;
|
||||
a.accesscookie = sc;
|
||||
|
||||
sc->sc_wsmousedev = config_found(self, &a, wsmousedevprint);
|
||||
#elif defined(__FreeBSD__)
|
||||
sc->hw.buttons = 2; /* XXX hw&mode values are bogus */
|
||||
sc->hw.iftype = MOUSE_IF_PS2;
|
||||
sc->hw.type = MOUSE_MOUSE;
|
||||
if (sc->flags & UMS_Z)
|
||||
sc->hw.model = MOUSE_MODEL_INTELLI;
|
||||
else
|
||||
sc->hw.model = MOUSE_MODEL_GENERIC;
|
||||
sc->hw.hwid = 0;
|
||||
sc->mode.protocol = MOUSE_PROTO_PS2;
|
||||
sc->mode.rate = -1;
|
||||
sc->mode.resolution = MOUSE_RES_DEFAULT;
|
||||
sc->mode.accelfactor = 1;
|
||||
sc->mode.level = 0;
|
||||
if (sc->flags & UMS_Z) {
|
||||
sc->mode.packetsize = MOUSE_INTELLI_PACKETSIZE;
|
||||
sc->mode.syncmask[0] = 0xc8;
|
||||
} else {
|
||||
sc->mode.packetsize = MOUSE_PS2_PACKETSIZE;
|
||||
sc->mode.syncmask[0] = 0xc0;
|
||||
}
|
||||
sc->mode.syncmask[1] = 0;
|
||||
|
||||
sc->status.flags = 0;
|
||||
sc->status.button = sc->status.obutton = 0;
|
||||
sc->status.dx = sc->status.dy = sc->status.dz = 0;
|
||||
|
||||
sc->rsel.si_flags = 0;
|
||||
sc->rsel.si_pid = 0;
|
||||
#endif
|
||||
|
||||
ATTACH_SUCCESS_RETURN;
|
||||
}
|
||||
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
static int
|
||||
ums_detach(device_t self)
|
||||
{
|
||||
struct ums_softc *sc = device_get_softc(self);
|
||||
char *devinfo = (char *) device_get_desc(self);
|
||||
|
||||
if (devinfo) {
|
||||
device_set_desc(self, NULL);
|
||||
free(devinfo, M_USB);
|
||||
}
|
||||
free(sc->sc_loc_btn, M_USB);
|
||||
free(sc->sc_ibuf, M_USB);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
ums_disco(p)
|
||||
void *p;
|
||||
{
|
||||
struct ums_softc *sc = p;
|
||||
|
||||
DPRINTF(("ums_disco: sc=%p\n", sc));
|
||||
usbd_abort_pipe(sc->sc_intrpipe);
|
||||
sc->sc_disconnected = 1;
|
||||
}
|
||||
|
||||
void
|
||||
ums_intr(reqh, addr, status)
|
||||
usbd_request_handle reqh;
|
||||
usbd_private_handle addr;
|
||||
usbd_status status;
|
||||
{
|
||||
struct ums_softc *sc = addr;
|
||||
u_char *ibuf;
|
||||
int dx, dy, dz;
|
||||
u_char buttons = 0;
|
||||
int i;
|
||||
|
||||
DPRINTFN(5, ("ums_intr: sc=%p status=%d\n", sc, status));
|
||||
DPRINTFN(5, ("ums_intr: data = %02x %02x %02x\n",
|
||||
sc->sc_ibuf[0], sc->sc_ibuf[1], sc->sc_ibuf[2]));
|
||||
|
||||
if (status == USBD_CANCELLED)
|
||||
return;
|
||||
|
||||
if (status != USBD_NORMAL_COMPLETION) {
|
||||
DPRINTF(("ums_intr: status=%d\n", status));
|
||||
usbd_clear_endpoint_stall_async(sc->sc_intrpipe);
|
||||
return;
|
||||
}
|
||||
|
||||
ibuf = sc->sc_ibuf;
|
||||
if (sc->sc_iid) {
|
||||
if (*ibuf++ != sc->sc_iid)
|
||||
return;
|
||||
}
|
||||
dx = hid_get_data(ibuf, &sc->sc_loc_x);
|
||||
dy = -hid_get_data(ibuf, &sc->sc_loc_y);
|
||||
dz = hid_get_data(ibuf, &sc->sc_loc_z);
|
||||
/* NWH Why are you modifying the button assignments here?
|
||||
* That's the purpose of a high level mouse driver
|
||||
*/
|
||||
for (i = 1; i <= sc->nbuttons; i++)
|
||||
if (hid_get_data(ibuf, &sc->sc_loc_btn[i-1]))
|
||||
buttons |= (1 << (i-1));
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
if (dx || dy || buttons != sc->sc_buttons) {
|
||||
DPRINTFN(10, ("ums_intr: x:%d y:%d z:%d buttons:0x%x\n",
|
||||
dx, dy, dz, buttons));
|
||||
sc->sc_buttons = buttons;
|
||||
if (sc->sc_wsmousedev)
|
||||
wsmouse_input(sc->sc_wsmousedev, buttons, dx, dy, dz);
|
||||
#elif defined(__FreeBSD__)
|
||||
if (dx || dy || buttons != sc->status.button) {
|
||||
DPRINTFN(10, ("ums_intr: x:%d y:%d z:%d buttons:0x%x\n",
|
||||
dx, dy, dz, buttons));
|
||||
|
||||
sc->status.button = buttons;
|
||||
sc->status.dx += dx;
|
||||
sc->status.dy += dy;
|
||||
sc->status.dz += dz;
|
||||
|
||||
/* Discard data in case of full buffer */
|
||||
if (sc->qcount == sizeof(sc->qbuf)) {
|
||||
DPRINTF(("Buffer full, discarded packet"));
|
||||
return;
|
||||
}
|
||||
|
||||
sc->qbuf[sc->qhead] = MOUSE_PS2_SYNC;
|
||||
if (dx < 0)
|
||||
sc->qbuf[sc->qhead] |= MOUSE_PS2_XNEG;
|
||||
if (dx > 255 || dx < -255)
|
||||
sc->qbuf[sc->qhead] |= MOUSE_PS2_XOVERFLOW;
|
||||
if (dy < 0)
|
||||
sc->qbuf[sc->qhead] |= MOUSE_PS2_YNEG;
|
||||
if (dy > 255 || dy < -255)
|
||||
sc->qbuf[sc->qhead] |= MOUSE_PS2_YOVERFLOW;
|
||||
sc->qbuf[sc->qhead++] |= buttons;
|
||||
sc->qbuf[sc->qhead++] = dx;
|
||||
sc->qbuf[sc->qhead++] = dy;
|
||||
sc->qcount += 3;
|
||||
if (sc->flags & UMS_Z) {
|
||||
sc->qbuf[sc->qhead++] = dz;
|
||||
sc->qcount++;
|
||||
}
|
||||
#ifdef USB_DEBUG
|
||||
if (sc->qhead > sizeof(sc->qbuf))
|
||||
DPRINTF(("Buffer overrun! %d %d\n", sc->qhead, sizeof(sc->qbuf)));
|
||||
#endif
|
||||
if (sc->qhead >= sizeof(sc->qbuf)) /* wrap round at end of buffer */
|
||||
sc->qhead = 0;
|
||||
|
||||
if (sc->state & UMS_ASLEEP) /* someone waiting for data */
|
||||
wakeup(sc);
|
||||
selwakeup(&sc->rsel); /* wake up any pending selects */
|
||||
sc->state &= ~UMS_SELECT;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
ums_enable(v)
|
||||
void *v;
|
||||
{
|
||||
struct ums_softc *sc = v;
|
||||
|
||||
usbd_status r;
|
||||
|
||||
if (sc->sc_enabled)
|
||||
return EBUSY;
|
||||
|
||||
sc->sc_enabled = 1;
|
||||
#if defined(__NetBSD__)
|
||||
sc->sc_buttons = 0;
|
||||
#elif defined(__FreeBSD__)
|
||||
sc->qcount = 0;
|
||||
sc->qhead = sc->qtail = 0;
|
||||
#ifdef USB_DEBUG
|
||||
if (sizeof(sc->qbuf) % 4 || sizeof(sc->qbuf) % 3) {
|
||||
DPRINTF(("Buffer size not dividable by 3 or 4\n"));
|
||||
return ENXIO;
|
||||
}
|
||||
#endif
|
||||
sc->status.flags = 0;
|
||||
sc->status.button = sc->status.obutton = 0;
|
||||
sc->status.dx = sc->status.dy = sc->status.dz = 0;
|
||||
#endif
|
||||
|
||||
/* Set up interrupt pipe. */
|
||||
r = usbd_open_pipe_intr(sc->sc_iface, sc->sc_ep_addr,
|
||||
USBD_SHORT_XFER_OK, &sc->sc_intrpipe, sc,
|
||||
sc->sc_ibuf, sc->sc_isize, ums_intr);
|
||||
if (r != USBD_NORMAL_COMPLETION) {
|
||||
DPRINTF(("ums_enable: usbd_open_pipe_intr failed, error=%d\n",
|
||||
r));
|
||||
sc->sc_enabled = 0;
|
||||
return (EIO);
|
||||
}
|
||||
usbd_set_disco(sc->sc_intrpipe, ums_disco, sc);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
ums_disable(v)
|
||||
void *v;
|
||||
{
|
||||
struct ums_softc *sc = v;
|
||||
|
||||
/* Disable interrupts. */
|
||||
usbd_abort_pipe(sc->sc_intrpipe);
|
||||
usbd_close_pipe(sc->sc_intrpipe);
|
||||
|
||||
sc->sc_enabled = 0;
|
||||
|
||||
#if defined(USBVERBOSE) && defined(__FreeBSD__)
|
||||
if (sc->qcount != 0)
|
||||
DPRINTF(("Discarded %d bytes in queue\n", sc->qcount));
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
static int
|
||||
ums_ioctl(v, cmd, data, flag, p)
|
||||
void *v;
|
||||
u_long cmd;
|
||||
caddr_t data;
|
||||
int flag;
|
||||
struct proc *p;
|
||||
|
||||
{
|
||||
switch (cmd) {
|
||||
case WSMOUSEIO_GTYPE:
|
||||
*(u_int *)data = WSMOUSE_TYPE_PS2;
|
||||
return (0);
|
||||
}
|
||||
|
||||
return (-1); /* NWH XXX ??? */
|
||||
}
|
||||
|
||||
#elif defined(__FreeBSD__)
|
||||
static int
|
||||
ums_open(dev_t dev, int flag, int fmt, struct proc *p)
|
||||
{
|
||||
struct ums_softc *sc = devclass_get_softc(ums_devclass, UMSUNIT(dev));
|
||||
|
||||
if (!sc) {
|
||||
DPRINTF(("sc not found at open"));
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
return ums_enable(sc);
|
||||
}
|
||||
|
||||
static int
|
||||
ums_close(dev_t dev, int flag, int fmt, struct proc *p)
|
||||
{
|
||||
struct ums_softc *sc = devclass_get_softc(ums_devclass, UMSUNIT(dev));
|
||||
|
||||
if (!sc) {
|
||||
DPRINTF(("sc not found at close"));
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
if (sc->sc_enabled)
|
||||
ums_disable(sc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ums_read(dev_t dev, struct uio *uio, int flag)
|
||||
{
|
||||
struct ums_softc *sc = devclass_get_softc(ums_devclass, UMSUNIT(dev));
|
||||
int s;
|
||||
char buf[sizeof(sc->qbuf)];
|
||||
int l = 0;
|
||||
int error;
|
||||
|
||||
if (!sc || !sc->sc_enabled) {
|
||||
DPRINTF(("sc not found at read"));
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
s = splusb();
|
||||
while (sc->qcount == 0 ) {
|
||||
/* NWH XXX non blocking I/O ??
|
||||
if (non blocking I/O ) {
|
||||
splx(s);
|
||||
return EWOULDBLOCK;
|
||||
} else {
|
||||
*/
|
||||
sc->state |= UMS_ASLEEP;
|
||||
error = tsleep(sc, PZERO | PCATCH, "umsrea", 0);
|
||||
sc->state &= ~UMS_ASLEEP;
|
||||
if (error) {
|
||||
splx(s);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
while ((sc->qcount > 0) && (uio->uio_resid > 0)) {
|
||||
l = (sc->qcount < uio->uio_resid? sc->qcount:uio->uio_resid);
|
||||
if (l > sizeof(buf))
|
||||
l = sizeof(buf);
|
||||
if (l > sizeof(sc->qbuf) - sc->qtail) /* transfer till end of buf */
|
||||
l = sizeof(sc->qbuf) - sc->qtail;
|
||||
|
||||
splx(s);
|
||||
uiomove(&sc->qbuf[sc->qtail], l, uio);
|
||||
s = splusb();
|
||||
|
||||
if ( sc->qcount - l < 0 ) {
|
||||
DPRINTF(("qcount below 0, count=%d l=%d\n", sc->qcount, l));
|
||||
sc->qcount = l;
|
||||
}
|
||||
sc->qcount -= l; /* remove the bytes from the buffer */
|
||||
sc->qtail = (sc->qtail + l) % sizeof(sc->qbuf);
|
||||
}
|
||||
splx(s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ums_poll(dev_t dev, int events, struct proc *p)
|
||||
{
|
||||
struct ums_softc *sc = devclass_get_softc(ums_devclass, UMSUNIT(dev));
|
||||
int revents = 0;
|
||||
int s;
|
||||
|
||||
if (!sc) {
|
||||
DPRINTF(("sc not found at poll"));
|
||||
return 0; /* just to make sure */
|
||||
}
|
||||
|
||||
s = splusb();
|
||||
if (events & (POLLIN | POLLRDNORM))
|
||||
if (sc->qcount) {
|
||||
revents = events & (POLLIN | POLLRDNORM);
|
||||
} else {
|
||||
sc->state |= UMS_SELECT;
|
||||
selrecord(p, &sc->rsel);
|
||||
}
|
||||
splx(s);
|
||||
|
||||
return revents;
|
||||
}
|
||||
|
||||
int
|
||||
ums_ioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
|
||||
{
|
||||
struct ums_softc *sc = devclass_get_softc(ums_devclass, UMSUNIT(dev));
|
||||
int error = 0;
|
||||
int s;
|
||||
|
||||
if (!sc) {
|
||||
DPRINTF(("sc not found at ioctl"));
|
||||
return ENOENT;
|
||||
}
|
||||
|
||||
switch(cmd) {
|
||||
case MOUSE_GETHWINFO:
|
||||
*(mousehw_t *)addr = sc->hw;
|
||||
break;
|
||||
case MOUSE_GETMODE:
|
||||
*(mousemode_t *)addr = sc->mode;
|
||||
break;
|
||||
case MOUSE_GETLEVEL:
|
||||
*(int *)addr = sc->mode.level;
|
||||
break;
|
||||
case MOUSE_GETSTATUS: {
|
||||
mousestatus_t *status = (mousestatus_t *) addr;
|
||||
|
||||
s = splusb();
|
||||
*status = sc->status;
|
||||
sc->status.obutton = sc->status.button;
|
||||
sc->status.button = 0;
|
||||
sc->status.dx = sc->status.dy = sc->status.dz = 0;
|
||||
splx(s);
|
||||
|
||||
if (status->dx || status->dy || status->dz)
|
||||
status->flags |= MOUSE_POSCHANGED;
|
||||
if (status->button != status->obutton)
|
||||
status->flags |= MOUSE_BUTTONSCHANGED;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
error = ENOTTY;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
CDEV_DRIVER_MODULE(ums, usb, ums_driver, ums_devclass,
|
||||
UMS_CDEV_MAJOR, ums_cdevsw, usb_driver_load, 0);
|
||||
#endif
|
||||
|
603
sys/dev/usb/usb.c
Normal file
603
sys/dev/usb/usb.c
Normal file
@ -0,0 +1,603 @@
|
||||
/* $NetBSD: usb.c,v 1.3 1998/08/01 18:16:20 augustss Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1998 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Lennart Augustsson <augustss@carlstedt.se>
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* USB spec: http://www.teleport.com/cgi-bin/mailmerge.cgi/~usb/cgiform.tpl
|
||||
* More USB specs at http://www.usb.org/developers/index.shtml
|
||||
*/
|
||||
|
||||
#include <dev/usb/usb_port.h>
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/malloc.h>
|
||||
#if defined(__NetBSD__)
|
||||
#include <sys/device.h>
|
||||
#else
|
||||
#include <sys/module.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/ioccom.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/conf.h>
|
||||
#endif
|
||||
#include <sys/poll.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/select.h>
|
||||
|
||||
#include <dev/usb/usb.h>
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
MALLOC_DEFINE(M_USB, "USB", "USB");
|
||||
MALLOC_DEFINE(M_USBDEV, "USBdev", "USB device");
|
||||
#endif
|
||||
|
||||
#include <dev/usb/usbdi.h>
|
||||
#include <dev/usb/usbdivar.h>
|
||||
#include <dev/usb/usb_quirks.h>
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
#include "usb_if.h"
|
||||
#endif
|
||||
|
||||
#ifdef USB_DEBUG
|
||||
#define DPRINTF(x) if (usbdebug) printf x
|
||||
#define DPRINTFN(n,x) if (usbdebug>(n)) printf x
|
||||
int usbdebug = 2;
|
||||
int uhcidebug = 2;
|
||||
int ohcidebug = 2;
|
||||
#else
|
||||
#define DPRINTF(x)
|
||||
#define DPRINTFN(n,x)
|
||||
#endif
|
||||
|
||||
#define USBUNIT(dev) (minor(dev))
|
||||
|
||||
struct usb_softc {
|
||||
bdevice sc_dev; /* base device */
|
||||
usbd_bus_handle sc_bus; /* USB controller */
|
||||
struct usbd_port sc_port; /* dummy port for root hub */
|
||||
char sc_running;
|
||||
char sc_exploring;
|
||||
struct selinfo sc_consel; /* waiting for connect change */
|
||||
};
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
int usb_match __P((struct device *, struct cfdata *, void *));
|
||||
void usb_attach __P((struct device *, struct device *, void *));
|
||||
|
||||
int usbopen __P((dev_t, int, int, struct proc *));
|
||||
int usbclose __P((dev_t, int, int, struct proc *));
|
||||
int usbioctl __P((dev_t, u_long, caddr_t, int, struct proc *));
|
||||
int usbpoll __P((dev_t, int, struct proc *));
|
||||
|
||||
#else
|
||||
static device_probe_t usb_match;
|
||||
static device_attach_t usb_attach;
|
||||
static bus_print_child_t usb_print_child;
|
||||
|
||||
d_open_t usbopen;
|
||||
d_close_t usbclose;
|
||||
d_ioctl_t usbioctl;
|
||||
int usbpoll __P((dev_t, int, struct proc *));
|
||||
|
||||
struct cdevsw usb_cdevsw = {
|
||||
usbopen, usbclose, noread, nowrite,
|
||||
usbioctl, nullstop, nullreset, nodevtotty,
|
||||
seltrue, nommap, nostrat,
|
||||
"usb", NULL, -1
|
||||
};
|
||||
#endif
|
||||
|
||||
usbd_status usb_discover __P((struct usb_softc *));
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
extern struct cfdriver usb_cd;
|
||||
|
||||
struct cfattach usb_ca = {
|
||||
sizeof(struct usb_softc), usb_match, usb_attach
|
||||
};
|
||||
#else
|
||||
static devclass_t usb_devclass = NULL;
|
||||
|
||||
static device_method_t usb_methods[] = {
|
||||
DEVMETHOD(device_probe, usb_match),
|
||||
DEVMETHOD(device_attach, usb_attach),
|
||||
|
||||
DEVMETHOD(bus_print_child, usb_print_child),
|
||||
{0, 0}
|
||||
};
|
||||
|
||||
static driver_t usb_driver = {
|
||||
"usb",
|
||||
usb_methods,
|
||||
DRIVER_TYPE_MISC,
|
||||
sizeof(struct usb_softc),
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
int
|
||||
usb_match(parent, match, aux)
|
||||
struct device *parent;
|
||||
struct cfdata *match;
|
||||
void *aux;
|
||||
#else
|
||||
static int
|
||||
usb_match(device_t device)
|
||||
#endif
|
||||
{
|
||||
DPRINTF(("usbd_match\n"));
|
||||
#if defined(__NetBSD__)
|
||||
return (1);
|
||||
#else
|
||||
return (0);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
void
|
||||
usb_attach(parent, self, aux)
|
||||
struct device *parent;
|
||||
struct device *self;
|
||||
void *aux;
|
||||
{
|
||||
struct usb_softc *sc = (struct usb_softc *)self;
|
||||
#else
|
||||
static int
|
||||
usb_attach(device_t device)
|
||||
{
|
||||
struct usb_softc *sc = device_get_softc(device);
|
||||
void *aux = device_get_ivars(device);
|
||||
#endif
|
||||
usbd_device_handle dev;
|
||||
usbd_status r;
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
printf("\n");
|
||||
#endif
|
||||
|
||||
DPRINTF(("usbd_attach\n"));
|
||||
usbd_init();
|
||||
sc->sc_bus = aux;
|
||||
sc->sc_bus->usbctl = sc;
|
||||
sc->sc_running = 1;
|
||||
sc->sc_bus->use_polling = 1;
|
||||
sc->sc_port.power = USB_MAX_POWER;
|
||||
#if defined(__FreeBSD__)
|
||||
sc->sc_dev = device;
|
||||
#endif
|
||||
r = usbd_new_device(&sc->sc_dev, sc->sc_bus, 0, 0, 0, &sc->sc_port);
|
||||
|
||||
if (r == USBD_NORMAL_COMPLETION) {
|
||||
dev = sc->sc_port.device;
|
||||
if (!dev->hub) {
|
||||
sc->sc_running = 0;
|
||||
DEVICE_ERROR(sc->sc_dev, ("root device is not a hub\n"));
|
||||
ATTACH_ERROR_RETURN;
|
||||
}
|
||||
sc->sc_bus->root_hub = dev;
|
||||
dev->hub->explore(sc->sc_bus->root_hub);
|
||||
} else {
|
||||
DEVICE_ERROR(sc->sc_dev, ("root hub problem, error=%d\n", r));
|
||||
sc->sc_running = 0;
|
||||
}
|
||||
sc->sc_bus->use_polling = 0;
|
||||
|
||||
ATTACH_SUCCESS_RETURN;
|
||||
}
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
int
|
||||
usbctlprint(aux, pnp)
|
||||
void *aux;
|
||||
const char *pnp;
|
||||
{
|
||||
/* only "usb"es can attach to host controllers */
|
||||
if (pnp)
|
||||
printf("usb at %s", pnp);
|
||||
|
||||
return (UNCONF);
|
||||
}
|
||||
|
||||
#else
|
||||
static void
|
||||
usb_print_child(device_t parent, device_t child)
|
||||
{
|
||||
struct usb_softc *sc = device_get_softc(child);
|
||||
|
||||
printf(" at %s%d", device_get_name(parent), device_get_unit(parent));
|
||||
|
||||
/* How do we get to the usbd_device_handle???
|
||||
usbd_device_handle dev = invalidadosch;
|
||||
|
||||
printf(" addr %d", dev->addr);
|
||||
|
||||
if (bootverbose) {
|
||||
if (dev->lowspeed)
|
||||
printf(", lowspeed");
|
||||
if (dev->self_powered)
|
||||
printf(", self powered");
|
||||
else
|
||||
printf(", %dmA", dev->power);
|
||||
printf(", config %d", dev->config);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
/* Reconfigure all the USB busses in the system
|
||||
*/
|
||||
|
||||
int
|
||||
usb_driver_load(module_t mod, modeventtype_t what, void *arg)
|
||||
{
|
||||
/* subroutine is there but inactive at the moment
|
||||
* the reconfiguration process has not been thought through yet.
|
||||
*/
|
||||
devclass_t ugen_devclass = devclass_find("ugen");
|
||||
device_t *devlist;
|
||||
int devcount;
|
||||
int error;
|
||||
|
||||
switch (what) {
|
||||
case MOD_LOAD:
|
||||
case MOD_UNLOAD:
|
||||
if (!usb_devclass)
|
||||
return 0; /* just ignore call */
|
||||
|
||||
if (ugen_devclass) {
|
||||
/* detach devices from generic driver if possible
|
||||
*/
|
||||
error = devclass_get_devices(ugen_devclass, &devlist,
|
||||
&devcount);
|
||||
if (!error)
|
||||
for (devcount--; devcount >= 0; devcount--)
|
||||
(void) DEVICE_DETACH(devlist[devcount]);
|
||||
}
|
||||
|
||||
error = devclass_get_devices(usb_devclass, &devlist, &devcount);
|
||||
if (error)
|
||||
return 0; /* XXX maybe transient, or error? */
|
||||
|
||||
for (devcount--; devcount >= 0; devcount--)
|
||||
USB_RECONFIGURE(devlist[devcount]);
|
||||
|
||||
free(devlist, M_TEMP);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0; /* nothing to do by us */
|
||||
}
|
||||
|
||||
/* Set the description of the device including a malloc and copy
|
||||
*/
|
||||
void
|
||||
usb_device_set_desc(device_t device, char *devinfo)
|
||||
{
|
||||
size_t l;
|
||||
char *desc;
|
||||
|
||||
if ( devinfo ) {
|
||||
l = strlen(devinfo);
|
||||
desc = malloc(l+1, M_USB, M_NOWAIT);
|
||||
if (desc)
|
||||
memcpy(desc, devinfo, l+1);
|
||||
} else
|
||||
desc = NULL;
|
||||
|
||||
device_set_desc(device, desc);
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
usbopen(dev, flag, mode, p)
|
||||
dev_t dev;
|
||||
int flag, mode;
|
||||
struct proc *p;
|
||||
{
|
||||
#if defined(__NetBSD__)
|
||||
int unit = USBUNIT(dev);
|
||||
struct usb_softc *sc;
|
||||
|
||||
if (unit >= usb_cd.cd_ndevs)
|
||||
return (ENXIO);
|
||||
sc = usb_cd.cd_devs[unit];
|
||||
#else
|
||||
device_t device = devclass_get_device(usb_devclass, USBUNIT(dev));
|
||||
struct usb_softc *sc = device_get_softc(device);
|
||||
#endif
|
||||
|
||||
if (sc == 0 || !sc->sc_running)
|
||||
return (ENXIO);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
usbclose(dev, flag, mode, p)
|
||||
dev_t dev;
|
||||
int flag, mode;
|
||||
struct proc *p;
|
||||
{
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
usbioctl(dev, cmd, data, flag, p)
|
||||
dev_t dev;
|
||||
u_long cmd;
|
||||
caddr_t data;
|
||||
int flag;
|
||||
struct proc *p;
|
||||
{
|
||||
#if defined(__NetBSD__)
|
||||
int unit = USBUNIT(dev);
|
||||
struct usb_softc *sc;
|
||||
|
||||
if (unit >= usb_cd.cd_ndevs)
|
||||
return (ENXIO);
|
||||
sc = usb_cd.cd_devs[unit];
|
||||
#else
|
||||
device_t device = devclass_get_device(usb_devclass, USBUNIT(dev));
|
||||
struct usb_softc *sc = device_get_softc(device);
|
||||
#endif
|
||||
|
||||
if (sc == 0 || !sc->sc_running)
|
||||
return (ENXIO);
|
||||
switch (cmd) {
|
||||
#ifdef USB_DEBUG
|
||||
case USB_SETDEBUG:
|
||||
usbdebug = uhcidebug = ohcidebug = *(int *)data;
|
||||
break;
|
||||
#endif
|
||||
case USB_DISCOVER:
|
||||
usb_discover(sc);
|
||||
break;
|
||||
case USB_REQUEST:
|
||||
{
|
||||
struct usb_ctl_request *ur = (void *)data;
|
||||
int len = UGETW(ur->request.wLength);
|
||||
struct iovec iov;
|
||||
struct uio uio;
|
||||
void *ptr = 0;
|
||||
int addr = ur->addr;
|
||||
usbd_status r;
|
||||
int error = 0;
|
||||
|
||||
if (len < 0 || len > 32768)
|
||||
return EINVAL;
|
||||
if (addr < 0 || addr >= USB_MAX_DEVICES ||
|
||||
sc->sc_bus->devices[addr] == 0)
|
||||
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(sc->sc_bus->devices[addr],
|
||||
&ur->request, ptr);
|
||||
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);
|
||||
break;
|
||||
}
|
||||
|
||||
case USB_DEVICEINFO:
|
||||
{
|
||||
struct usb_device_info *di = (void *)data;
|
||||
int addr = di->addr;
|
||||
usbd_device_handle dev;
|
||||
struct usbd_port *p;
|
||||
int i, r, s;
|
||||
|
||||
if (addr < 1 || addr >= USB_MAX_DEVICES)
|
||||
return (EINVAL);
|
||||
dev = sc->sc_bus->devices[addr];
|
||||
if (dev == 0)
|
||||
return (ENXIO);
|
||||
di->config = dev->config;
|
||||
usbd_devinfo_vp(dev, di->product, di->vendor);
|
||||
usbd_printBCD(di->revision, UGETW(dev->ddesc.bcdDevice));
|
||||
di->class = dev->ddesc.bDeviceClass;
|
||||
di->power = dev->self_powered ? 0 : dev->power;
|
||||
di->lowspeed = dev->lowspeed;
|
||||
if (dev->hub) {
|
||||
for (i = 0;
|
||||
i < sizeof(di->ports) / sizeof(di->ports[0]) &&
|
||||
i < dev->hub->hubdesc.bNbrPorts;
|
||||
i++) {
|
||||
p = &dev->hub->ports[i];
|
||||
if (p->device)
|
||||
r = p->device->address;
|
||||
else {
|
||||
s = UGETW(p->status.wPortStatus);
|
||||
if (s & UPS_PORT_ENABLED)
|
||||
r = USB_PORT_ENABLED;
|
||||
else if (s & UPS_SUSPEND)
|
||||
r = USB_PORT_SUSPENDED;
|
||||
else if (s & UPS_PORT_POWER)
|
||||
r = USB_PORT_POWERED;
|
||||
else
|
||||
r = USB_PORT_DISABLED;
|
||||
}
|
||||
di->ports[i] = r;
|
||||
}
|
||||
di->nports = dev->hub->hubdesc.bNbrPorts;
|
||||
} else
|
||||
di->nports = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case USB_DEVICESTATS:
|
||||
*(struct usb_device_stats *)data = sc->sc_bus->stats;
|
||||
break;
|
||||
|
||||
default:
|
||||
return (ENXIO);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
usbpoll(dev, events, p)
|
||||
dev_t dev;
|
||||
int events;
|
||||
struct proc *p;
|
||||
{
|
||||
int revents, s;
|
||||
#if defined(__NetBSD__)
|
||||
int unit = USBUNIT(dev);
|
||||
struct usb_softc *sc;
|
||||
|
||||
if (unit >= usb_cd.cd_ndevs)
|
||||
return (ENXIO);
|
||||
sc = usb_cd.cd_devs[unit];
|
||||
#else
|
||||
device_t device = devclass_get_device(usb_devclass, USBUNIT(dev));
|
||||
struct usb_softc *sc = device_get_softc(device);
|
||||
#endif
|
||||
|
||||
DPRINTFN(2, ("usbpoll: sc=%p events=0x%x\n", sc, events));
|
||||
s = splusb();
|
||||
revents = 0;
|
||||
if (events & (POLLOUT | POLLWRNORM))
|
||||
if (sc->sc_bus->needs_explore)
|
||||
revents |= events & (POLLOUT | POLLWRNORM);
|
||||
DPRINTFN(2, ("usbpoll: revents=0x%x\n", revents));
|
||||
if (revents == 0) {
|
||||
if (events & (POLLOUT | POLLWRNORM)) {
|
||||
DPRINTFN(2, ("usbpoll: selrecord\n"));
|
||||
selrecord(p, &sc->sc_consel);
|
||||
}
|
||||
}
|
||||
splx(s);
|
||||
return (revents);
|
||||
}
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
/* See remarks on this in usbdi.c
|
||||
*/
|
||||
int
|
||||
usb_bus_count()
|
||||
{
|
||||
int i, n;
|
||||
|
||||
for (i = n = 0; i < usb_cd.cd_ndevs; i++)
|
||||
if (usb_cd.cd_devs[i])
|
||||
n++;
|
||||
return (n);
|
||||
}
|
||||
|
||||
usbd_status
|
||||
usb_get_bus_handle(n, h)
|
||||
int n;
|
||||
usbd_bus_handle *h;
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < usb_cd.cd_ndevs; i++)
|
||||
if (usb_cd.cd_devs[i] && n-- == 0) {
|
||||
*h = usb_cd.cd_devs[i];
|
||||
return (USBD_NORMAL_COMPLETION);
|
||||
}
|
||||
return (USBD_INVAL);
|
||||
}
|
||||
#endif
|
||||
|
||||
usbd_status
|
||||
usb_discover(sc)
|
||||
struct usb_softc *sc;
|
||||
{
|
||||
int s;
|
||||
|
||||
/* Explore device tree from the root */
|
||||
/* We need mutual exclusion while traversing the device tree. */
|
||||
s = splusb();
|
||||
while (sc->sc_exploring)
|
||||
tsleep(&sc->sc_exploring, PRIBIO, "usbdis", 0);
|
||||
sc->sc_exploring = 1;
|
||||
sc->sc_bus->needs_explore = 0;
|
||||
splx(s);
|
||||
|
||||
sc->sc_bus->root_hub->hub->explore(sc->sc_bus->root_hub);
|
||||
|
||||
s = splusb();
|
||||
sc->sc_exploring = 0;
|
||||
wakeup(&sc->sc_exploring);
|
||||
splx(s);
|
||||
/* XXX should we start over if sc_needsexplore is set again? */
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
usb_needs_explore(bus)
|
||||
usbd_bus_handle bus;
|
||||
{
|
||||
bus->needs_explore = 1;
|
||||
selwakeup(&bus->usbctl->sc_consel);
|
||||
}
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
DRIVER_MODULE(usb, root, usb_driver, usb_devclass, 0, 0);
|
||||
#endif
|
387
sys/dev/usb/usb.h
Normal file
387
sys/dev/usb/usb.h
Normal file
@ -0,0 +1,387 @@
|
||||
/* $NetBSD: usb.h,v 1.3 1998/07/25 15:22:11 augustss Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1998 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Lennart Augustsson <augustss@carlstedt.se>
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _USB_H_
|
||||
#define _USB_H_
|
||||
|
||||
#include <sys/types.h>
|
||||
#if defined(__NetBSD__)
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
#include <sys/malloc.h>
|
||||
|
||||
MALLOC_DECLARE(M_USB);
|
||||
MALLOC_DECLARE(M_USBDEV);
|
||||
#endif
|
||||
|
||||
#define USB_MAX_DEVICES 128
|
||||
#define USB_START_ADDR 0
|
||||
|
||||
#define USB_CONTROL_ENDPOINT 0
|
||||
#define USB_MAX_ENDPOINTS 16
|
||||
|
||||
/*
|
||||
* The USB records contain some unaligned little-endian word
|
||||
* components. The U[SG]ETW macros take care of both the alignment
|
||||
* and endian problem and should always be used to access 16 bit
|
||||
* values.
|
||||
*/
|
||||
typedef u_int8_t uByte;
|
||||
typedef u_int8_t uWord[2];
|
||||
#define UGETW(w) ((w)[0] | ((w)[1] << 8))
|
||||
#define USETW(w,v) ((w)[0] = (u_int8_t)(v), (w)[1] = (u_int8_t)((v) >> 8))
|
||||
#define USETW2(w,h,l) ((w)[0] = (u_int8_t)(l), (w)[1] = (u_int8_t)(h))
|
||||
/*
|
||||
* On little-endian machines that can handle unanliged accesses
|
||||
* (e.g. i386) these macros can be replaced by the following.
|
||||
*/
|
||||
#if 0
|
||||
#define UGETW(w) (*(u_int16_t *)(w))
|
||||
#define USETW(w,v) (*(u_int16_t *)(w) = (v))
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
uByte bmRequestType;
|
||||
uByte bRequest;
|
||||
uWord wValue;
|
||||
uWord wIndex;
|
||||
uWord wLength;
|
||||
} usb_device_request_t;
|
||||
|
||||
#define UT_WRITE 0x00
|
||||
#define UT_READ 0x80
|
||||
#define UT_STANDARD 0x00
|
||||
#define UT_CLASS 0x20
|
||||
#define UT_VENDOR 0x40
|
||||
#define UT_DEVICE 0x00
|
||||
#define UT_INTERFACE 0x01
|
||||
#define UT_ENDPOINT 0x02
|
||||
#define UT_OTHER 0x03
|
||||
|
||||
#define UT_READ_DEVICE (UT_READ | UT_STANDARD | UT_DEVICE)
|
||||
#define UT_READ_INTERFACE (UT_READ | UT_STANDARD | UT_INTERFACE)
|
||||
#define UT_READ_ENDPOINT (UT_READ | UT_STANDARD | UT_ENDPOINT)
|
||||
#define UT_WRITE_DEVICE (UT_WRITE | UT_STANDARD | UT_DEVICE)
|
||||
#define UT_WRITE_INTERFACE (UT_WRITE | UT_STANDARD | UT_INTERFACE)
|
||||
#define UT_WRITE_ENDPOINT (UT_WRITE | UT_STANDARD | UT_ENDPOINT)
|
||||
#define UT_READ_CLASS_DEVICE (UT_READ | UT_CLASS | UT_DEVICE)
|
||||
#define UT_READ_CLASS_INTERFACE (UT_READ | UT_CLASS | UT_INTERFACE)
|
||||
#define UT_READ_CLASS_OTHER (UT_READ | UT_CLASS | UT_OTHER)
|
||||
#define UT_WRITE_CLASS_DEVICE (UT_WRITE | UT_CLASS | UT_DEVICE)
|
||||
#define UT_WRITE_CLASS_INTERFACE (UT_WRITE | UT_CLASS | UT_INTERFACE)
|
||||
#define UT_WRITE_CLASS_OTHER (UT_WRITE | UT_CLASS | UT_OTHER)
|
||||
|
||||
/* Requests */
|
||||
#define UR_GET_STATUS 0x00
|
||||
#define UR_CLEAR_FEATURE 0x01
|
||||
#define UR_SET_FEATURE 0x03
|
||||
#define UR_SET_ADDRESS 0x05
|
||||
#define UR_GET_DESCRIPTOR 0x06
|
||||
#define UDESC_DEVICE 1
|
||||
#define UDESC_CONFIG 2
|
||||
#define UDESC_STRING 3
|
||||
#define UDESC_INTERFACE 4
|
||||
#define UDESC_ENDPOINT 5
|
||||
#define UR_SET_DESCRIPTOR 0x07
|
||||
#define UR_GET_CONFIG 0x08
|
||||
#define UR_SET_CONFIG 0x09
|
||||
#define UR_GET_INTERFACE 0x0a
|
||||
#define UR_SET_INTERFACE 0x0b
|
||||
#define UR_SYNCH_FRAME 0x0c
|
||||
|
||||
/* Feature numbers */
|
||||
#define UF_ENDPOINT_STALL 0
|
||||
#define UF_DEVICE_REMOTE_WAKEUP 1
|
||||
|
||||
#define USB_MAX_IPACKET 8 /* maximum size of the initial packet */
|
||||
|
||||
typedef struct {
|
||||
uByte bLength;
|
||||
uByte bDescriptorType;
|
||||
uByte bDescriptorSubtype;
|
||||
} usb_descriptor_t;
|
||||
|
||||
typedef struct {
|
||||
uByte bLength;
|
||||
uByte bDescriptorType;
|
||||
uWord bcdUSB;
|
||||
uByte bDeviceClass;
|
||||
uByte bDeviceSubClass;
|
||||
uByte bDeviceProtocol;
|
||||
uByte bMaxPacketSize;
|
||||
/* The fields below are not part of the initial descriptor. */
|
||||
uWord idVendor;
|
||||
uWord idProduct;
|
||||
uWord bcdDevice;
|
||||
uByte iManufacturer;
|
||||
uByte iProduct;
|
||||
uByte iSerialNumber;
|
||||
uByte bNumConfigurations;
|
||||
} usb_device_descriptor_t;
|
||||
#define USB_DEVICE_DESCRIPTOR_SIZE 18
|
||||
|
||||
typedef struct {
|
||||
uByte bLength;
|
||||
uByte bDescriptorType;
|
||||
uWord wTotalLength;
|
||||
uByte bNumInterface;
|
||||
uByte bConfigurationValue;
|
||||
uByte iConfiguration;
|
||||
uByte bmAttributes;
|
||||
#define UC_BUS_POWERED 0x80
|
||||
#define UC_SELF_POWERED 0x40
|
||||
#define UC_REMOTE_WAKEUP 0x20
|
||||
uByte bMaxPower; /* max current in 2 mA units */
|
||||
#define UC_POWER_FACTOR 2
|
||||
} usb_config_descriptor_t;
|
||||
#define USB_CONFIG_DESCRIPTOR_SIZE 9
|
||||
|
||||
typedef struct {
|
||||
uByte bLength;
|
||||
uByte bDescriptorType;
|
||||
uByte bInterfaceNumber;
|
||||
uByte bAlternateSetting;
|
||||
uByte bNumEndpoints;
|
||||
uByte bInterfaceClass;
|
||||
uByte bInterfaceSubClass;
|
||||
uByte bInterfaceProtocol;
|
||||
uByte iInterface;
|
||||
} usb_interface_descriptor_t;
|
||||
#define USB_INTERFACE_DESCRIPTOR_SIZE 9
|
||||
|
||||
typedef struct {
|
||||
uByte bLength;
|
||||
uByte bDescriptorType;
|
||||
uByte bEndpointAddress;
|
||||
#define UE_IN 0x80
|
||||
#define UE_OUT 0x00
|
||||
#define UE_ADDR 0x0f
|
||||
#define UE_GET_IN(a) (((a) >> 7) & 1)
|
||||
uByte bmAttributes;
|
||||
#define UE_CONTROL 0x00
|
||||
#define UE_ISOCHRONOUS 0x01
|
||||
#define UE_BULK 0x02
|
||||
#define UE_INTERRUPT 0x03
|
||||
#define UE_XFERTYPE 0x03
|
||||
uWord wMaxPacketSize;
|
||||
uByte bInterval;
|
||||
} usb_endpoint_descriptor_t;
|
||||
#define USB_ENDPOINT_DESCRIPTOR_SIZE 7
|
||||
|
||||
typedef struct {
|
||||
uByte bLength;
|
||||
uByte bDescriptorType;
|
||||
uWord bString[127];
|
||||
} usb_string_descriptor_t;
|
||||
#define USB_MAX_STRING_LEN 128
|
||||
|
||||
/* Hub specific request */
|
||||
#define UR_GET_BUS_STATE 0x02
|
||||
|
||||
/* Hub features */
|
||||
#define UHF_C_HUB_LOCAL_POWER 0
|
||||
#define UHF_C_HUB_OVER_CURRENT 1
|
||||
#define UHF_PORT_CONNECTION 0
|
||||
#define UHF_PORT_ENABLE 1
|
||||
#define UHF_PORT_SUSPEND 2
|
||||
#define UHF_PORT_OVER_CURRENT 3
|
||||
#define UHF_PORT_RESET 4
|
||||
#define UHF_PORT_POWER 8
|
||||
#define UHF_PORT_LOW_SPEED 9
|
||||
#define UHF_C_PORT_CONNECTION 16
|
||||
#define UHF_C_PORT_ENABLE 17
|
||||
#define UHF_C_PORT_SUSPEND 18
|
||||
#define UHF_C_PORT_OVER_CURRENT 19
|
||||
#define UHF_C_PORT_RESET 20
|
||||
|
||||
typedef struct {
|
||||
uByte bDescLength;
|
||||
uByte bDescriptorType;
|
||||
uByte bNbrPorts;
|
||||
uWord bHubCharacteristics;
|
||||
#define UHD_PWR 0x03
|
||||
#define UHD_PWR_GANGED 0x00
|
||||
#define UHD_PWR_INDIVIDUAL 0x01
|
||||
#define UHD_PWR_NO_SWITCH 0x02
|
||||
#define UHD_COMPOUND 0x04
|
||||
#define UHD_OC 0x18
|
||||
#define UHD_OC_GLOBAL 0x00
|
||||
#define UHD_OC_INDIVIDUAL 0x08
|
||||
#define UHD_OC_NONE 0x10
|
||||
uByte bPwrOn2PwrGood; /* delay in 2 ms units */
|
||||
#define UHD_PWRON_FACTOR 2
|
||||
uByte bHubContrCurrent;
|
||||
uByte DeviceRemovable[1];
|
||||
/* this is only correct with 1-7 ports on the hub */
|
||||
uByte PortPowerCtrlMask[3];
|
||||
} usb_hub_descriptor_t;
|
||||
#define USB_HUB_DESCRIPTOR_SIZE 9
|
||||
|
||||
typedef struct {
|
||||
uWord wStatus;
|
||||
/* Device status flags */
|
||||
#define UDS_SELF_POWERED 0x0001
|
||||
#define UDS_REMOTE_WAKEUP 0x0002
|
||||
} usb_status_t;
|
||||
|
||||
typedef struct {
|
||||
uWord wHubStatus;
|
||||
#define UHS_LOCAL_POWER 0x0001
|
||||
#define UHS_OVER_CURRENT 0x0002
|
||||
uWord wHubChange;
|
||||
} usb_hub_status_t;
|
||||
|
||||
typedef struct {
|
||||
uWord wPortStatus;
|
||||
#define UPS_CURRENT_CONNECT_STATUS 0x0001
|
||||
#define UPS_PORT_ENABLED 0x0002
|
||||
#define UPS_SUSPEND 0x0004
|
||||
#define UPS_OVERCURRENT_INDICATOR 0x0008
|
||||
#define UPS_RESET 0x0010
|
||||
#define UPS_PORT_POWER 0x0100
|
||||
#define UPS_LOW_SPEED 0x0200
|
||||
uWord wPortChange;
|
||||
#define UPS_C_CONNECT_STATUS 0x0001
|
||||
#define UPS_C_PORT_ENABLED 0x0002
|
||||
#define UPS_C_SUSPEND 0x0004
|
||||
#define UPS_C_OVERCURRENT_INDICATOR 0x0008
|
||||
#define UPS_C_PORT_RESET 0x0010
|
||||
} usb_port_status_t;
|
||||
|
||||
#define UDESC_CS_DEVICE 0x21
|
||||
#define UDESC_CS_CONFIG 0x22
|
||||
#define UDESC_CS_STRING 0x23
|
||||
#define UDESC_CS_INTERFACE 0x24
|
||||
#define UDESC_CS_ENDPOINT 0x25
|
||||
|
||||
#define UDESC_HUB 0x29
|
||||
|
||||
#define UCLASS_UNSPEC 0
|
||||
#define UCLASS_AUDIO 1
|
||||
#define USUBCLASS_AUDIOCONTROL 1
|
||||
#define USUBCLASS_AUDIOSTREAM 2
|
||||
#define UCLASS_HID 3
|
||||
#define USUBCLASS_BOOT 1
|
||||
#define UCLASS_PRINTER 7
|
||||
#define USUBCLASS_PRINTER 1
|
||||
#define UPROTO_PRINTER_UNI 1
|
||||
#define UPROTO_PRINTER_BI 2
|
||||
#define UCLASS_HUB 9
|
||||
#define USUBCLASS_HUB 1
|
||||
|
||||
#define USB_HUB_MAX_DEPTH 5
|
||||
|
||||
#define USB_PORT_RESET_DELAY 10 /* ms */
|
||||
#define USB_PORT_POWERUP_DELAY 100 /* ms */
|
||||
#define USB_POWER_SETTLE 100 /* ms */
|
||||
|
||||
#define USB_MIN_POWER 100 /* mA */
|
||||
#define USB_MAX_POWER 500 /* mA */
|
||||
|
||||
|
||||
#define USB_RESET_DELAY 100 /* ms XXX?*/
|
||||
#define USB_RESUME_DELAY 10 /* ms XXX?*/
|
||||
|
||||
/*** ioctl() related stuff ***/
|
||||
|
||||
struct usb_ctl_request {
|
||||
int addr;
|
||||
usb_device_request_t request;
|
||||
void *data;
|
||||
};
|
||||
|
||||
struct usb_all_desc {
|
||||
u_char data[1024]; /* filled data size will vary */
|
||||
};
|
||||
|
||||
struct usb_ctl_report_desc {
|
||||
int size;
|
||||
u_char data[1024]; /* filled data size will vary */
|
||||
};
|
||||
|
||||
struct usb_device_info {
|
||||
uByte addr; /* device address */
|
||||
char product[USB_MAX_STRING_LEN];
|
||||
char vendor[USB_MAX_STRING_LEN];
|
||||
char revision[8];
|
||||
uByte class;
|
||||
uByte config;
|
||||
uByte lowspeed;
|
||||
int power; /* power consumption in mA, 0 if selfpowered */
|
||||
int nports;
|
||||
uByte ports[16]; /* hub only: addresses of devices on ports */
|
||||
#define USB_PORT_ENABLED 0xff
|
||||
#define USB_PORT_SUSPENDED 0xfe
|
||||
#define USB_PORT_POWERED 0xfd
|
||||
#define USB_PORT_DISABLED 0xfc
|
||||
};
|
||||
|
||||
struct usb_ctl_report {
|
||||
int report;
|
||||
u_char data[1024]; /* filled data size will vary */
|
||||
};
|
||||
|
||||
struct usb_device_stats {
|
||||
u_long requests[4]; /* indexed by transfer type UE_* */
|
||||
};
|
||||
|
||||
/* USB controller */
|
||||
#define USB_REQUEST _IOWR('U', 1, struct usb_ctl_request)
|
||||
#define USB_SETDEBUG _IOW ('U', 2, int)
|
||||
#define USB_DISCOVER _IO ('U', 3)
|
||||
#define USB_DEVICEINFO _IOWR('U', 4, struct usb_device_info)
|
||||
#define USB_DEVICESTATS _IOR ('U', 5, struct usb_device_stats)
|
||||
|
||||
/* Generic HID device */
|
||||
#define USB_GET_REPORT_DESC _IOR ('U', 21, struct usb_ctl_report_desc)
|
||||
#define USB_SET_IMMED _IOW ('U', 22, int)
|
||||
#define USB_GET_REPORT _IOWR('U', 23, struct usb_ctl_report)
|
||||
|
||||
/* Generic USB device */
|
||||
#define USB_SET_CONFIG _IOW ('U', 100, int)
|
||||
#define USB_SET_INTERFACE _IOW ('U', 101, int)
|
||||
#define USB_GET_DEVICE_DESC _IOR ('U', 102, usb_device_descriptor_t)
|
||||
#define USB_GET_CONFIG_DESC _IOR ('U', 103, usb_config_descriptor_t)
|
||||
#define USB_GET_INTERFACE_DESC _IOR ('U', 104, usb_interface_descriptor_t)
|
||||
#define USB_GET_ALL_DESC _IOR ('U', 105, struct usb_all_desc)
|
||||
|
||||
|
||||
#endif /* _USB_H_ */
|
11
sys/dev/usb/usb_if.m
Normal file
11
sys/dev/usb/usb_if.m
Normal file
@ -0,0 +1,11 @@
|
||||
# USB interface description
|
||||
#
|
||||
|
||||
INTERFACE usb;
|
||||
|
||||
# The device should start probing for new children again
|
||||
#
|
||||
METHOD int reconfigure {
|
||||
device_t dev;
|
||||
};
|
||||
|
91
sys/dev/usb/usb_mem.h
Normal file
91
sys/dev/usb/usb_mem.h
Normal file
@ -0,0 +1,91 @@
|
||||
/* $NetBSD: usb_mem.h,v 1.1 1998/07/24 21:09:08 augustss Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1998 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Lennart Augustsson <augustss@carlstedt.se>
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
typedef struct usb_block_dma {
|
||||
bus_dma_tag_t tag;
|
||||
bus_dmamap_t map;
|
||||
caddr_t kaddr;
|
||||
bus_dma_segment_t segs[1];
|
||||
int nsegs;
|
||||
size_t size;
|
||||
size_t align;
|
||||
int fullblock;
|
||||
LIST_ENTRY(usb_block_dma) next;
|
||||
} usb_dma_block_t;
|
||||
|
||||
typedef struct {
|
||||
usb_dma_block_t *block;
|
||||
u_int offs;
|
||||
} usb_dma_t;
|
||||
|
||||
#define DMAADDR(dma) ((dma)->block->segs[0].ds_addr + (dma)->offs)
|
||||
#define KERNADDR(dma) ((void *)((dma)->block->kaddr + (dma)->offs))
|
||||
|
||||
usbd_status usb_allocmem __P((bus_dma_tag_t, size_t, size_t, usb_dma_t *));
|
||||
void usb_freemem __P((bus_dma_tag_t, usb_dma_t *));
|
||||
|
||||
#else
|
||||
|
||||
/* FreeBSD does not have special functions for dma memory, so let's keep it
|
||||
* simple for now.
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/buf.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <vm/vm.h>
|
||||
#include <vm/pmap.h>
|
||||
|
||||
#include <machine/pmap.h> /* for vtophys */
|
||||
|
||||
|
||||
|
||||
typedef void * usb_dma_t;
|
||||
|
||||
#define usb_allocmem(t,s,a,p) (*(p) = malloc(s, M_USB, M_NOWAIT), (*(p) == NULL? USBD_NOMEM: USBD_NORMAL_COMPLETION))
|
||||
#define usb_freemem(t,p) (free(*(p), M_USB))
|
||||
|
||||
#define DMAADDR(dma) (vtophys(*(dma)))
|
||||
#define KERNADDR(dma) ((void *) *(dma))
|
||||
#endif
|
||||
|
79
sys/dev/usb/usb_port.h
Normal file
79
sys/dev/usb/usb_port.h
Normal file
@ -0,0 +1,79 @@
|
||||
/* Macro's to cope with the differences between NetBSD and FreeBSD
|
||||
*/
|
||||
|
||||
/*
|
||||
* NetBSD
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
#include "opt_usbverbose.h"
|
||||
|
||||
#define DEVICE_NAME(bdev) \
|
||||
printf("%s: ", (bdev).dv_xname)
|
||||
#define DEVICE_MSG(bdev
|
||||
|
||||
typedef struct device bdevice; /* base device */
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* FreeBSD
|
||||
*
|
||||
*/
|
||||
|
||||
#elif defined(__FreeBSD__)
|
||||
#include "opt_usb.h"
|
||||
#define DEVICE_NAME(bdev) \
|
||||
printf("%s%d: ", \
|
||||
device_get_name(bdev), device_get_unit(bdev))
|
||||
|
||||
/* XXX Change this when FreeBSD has memset
|
||||
*/
|
||||
#define memset(d, v, s) \
|
||||
do{ \
|
||||
if ((v) == 0) \
|
||||
bzero((d), (s)); \
|
||||
else \
|
||||
panic("Non zero filler for memset, cannot handle!"); \
|
||||
} while (0)
|
||||
|
||||
/* XXX can't we put this somehow into a typedef? */
|
||||
#define bdevice device_t /* base device */
|
||||
|
||||
#define USB_MODULE(name, driver, devclass) \
|
||||
DRIVER_MODULE((name), "usb", (driver), (devclass), usb_driver_load, 0)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* General
|
||||
*
|
||||
*/
|
||||
|
||||
#define DEVICE_MSG(bdev, s) (DEVICE_NAME(bdev), printf s)
|
||||
#define DEVICE_ERROR(bdev, s) DEVICE_MSG(bdev, s)
|
||||
|
||||
|
||||
/* Returns from attach for NetBSD vs. FreeBSD
|
||||
*/
|
||||
|
||||
/* Error returns */
|
||||
#if defined(__NetBSD__)
|
||||
#define ATTACH_ERROR_RETURN return
|
||||
#define ATTACH_SUCCESS_RETURN return
|
||||
#elif defined(__FreeBSD__)
|
||||
#define ATTACH_ERROR_RETURN return ENXIO
|
||||
#define ATTACH_SUCCESS_RETURN return 0
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* The debugging subsystem
|
||||
*/
|
||||
|
||||
/* XXX to be filled in
|
||||
*/
|
||||
|
89
sys/dev/usb/usb_quirks.c
Normal file
89
sys/dev/usb/usb_quirks.c
Normal file
@ -0,0 +1,89 @@
|
||||
/* $NetBSD: usb_quirks.c,v 1.1 1998/07/12 19:52:00 augustss Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1998 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Lennart Augustsson <augustss@carlstedt.se>
|
||||
* 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 <dev/usb/usb_port.h>
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#if defined(__NetBSD__)
|
||||
#include <sys/device.h>
|
||||
#endif
|
||||
#include <sys/select.h>
|
||||
|
||||
#include <dev/usb/usb.h>
|
||||
|
||||
#include <dev/usb/usbdevs.h>
|
||||
#include <dev/usb/usb_quirks.h>
|
||||
|
||||
struct usbd_quirk_entry {
|
||||
u_int16_t idVendor;
|
||||
u_int16_t idProduct;
|
||||
u_int16_t bcdDevice;
|
||||
struct usbd_quirks quirks;
|
||||
} quirks[] = {
|
||||
{ USB_VENDOR_GENIUS, USB_PRODUCT_GENIUS_NICHE, 0x100, { UQ_NO_SET_PROTO}},
|
||||
{ USB_VENDOR_INSIDEOUT,USB_PRODUCT_INSIDEOUT_EDGEPORT4,
|
||||
0x094, { UQ_SWAP_UNICODE}},
|
||||
{ USB_VENDOR_UNIXTAR, USB_PRODUCT_UNIXTAR_UTUSB41, 0x100, { UQ_HUB_POWER }},
|
||||
{ 0, 0, 0, { 0 } }
|
||||
};
|
||||
|
||||
struct usbd_quirks usbd_no_quirk = { 0 };
|
||||
|
||||
struct usbd_quirks *
|
||||
usbd_find_quirk(d)
|
||||
usb_device_descriptor_t *d;
|
||||
{
|
||||
struct usbd_quirk_entry *t;
|
||||
|
||||
for (t = quirks; t->idVendor != 0; t++) {
|
||||
if (t->idVendor == UGETW(d->idVendor) &&
|
||||
t->idProduct == UGETW(d->idProduct) &&
|
||||
t->bcdDevice == UGETW(d->bcdDevice))
|
||||
break;
|
||||
}
|
||||
#ifdef USB_DEBUG
|
||||
{ extern int usbdebug;
|
||||
if (usbdebug && t->quirks.uq_flags)
|
||||
printf("quirk %d/%d/%x: %d\n",
|
||||
UGETW(d->idVendor), UGETW(d->idProduct),
|
||||
UGETW(d->bcdDevice), t->quirks.uq_flags);
|
||||
}
|
||||
#endif
|
||||
return (&t->quirks);
|
||||
}
|
49
sys/dev/usb/usb_quirks.h
Normal file
49
sys/dev/usb/usb_quirks.h
Normal file
@ -0,0 +1,49 @@
|
||||
/* $NetBSD: usb_quirks.h,v 1.1 1998/07/12 19:52:00 augustss Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1998 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Lennart Augustsson <augustss@carlstedt.se>
|
||||
* 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.
|
||||
*/
|
||||
|
||||
struct usbd_quirks {
|
||||
u_int32_t uq_flags; /* Device problems: */
|
||||
#define UQ_NO_SET_PROTO 0x01 /* cannot handle SET PROTOCOL */
|
||||
#define UQ_SWAP_UNICODE 0x02 /* has some Unicode strings swapped. */
|
||||
#define UQ_HUB_POWER 0x04 /* does not respond correctly to get
|
||||
device status; use get hub status. */
|
||||
};
|
||||
|
||||
extern struct usbd_quirks usbd_no_quirk;
|
||||
|
||||
struct usbd_quirks *usbd_find_quirk __P((usb_device_descriptor_t *));
|
880
sys/dev/usb/usb_subr.c
Normal file
880
sys/dev/usb/usb_subr.c
Normal file
@ -0,0 +1,880 @@
|
||||
/* $NetBSD: usb_subr.c,v 1.7 1998/08/02 22:30:53 augustss Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1998 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Lennart Augustsson <augustss@carlstedt.se>
|
||||
* 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 <dev/usb/usb_port.h>
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/malloc.h>
|
||||
#if defined(__NetBSD__)
|
||||
#include <sys/device.h>
|
||||
#elif defined(__FreeBSD__)
|
||||
#include <sys/module.h>
|
||||
#include <sys/bus.h>
|
||||
#endif
|
||||
#include <sys/proc.h>
|
||||
#include <sys/select.h>
|
||||
|
||||
#include <dev/usb/usb.h>
|
||||
|
||||
#include <dev/usb/usbdi.h>
|
||||
#include <dev/usb/usbdi_util.h>
|
||||
#include <dev/usb/usbdivar.h>
|
||||
#include <dev/usb/usbdevs.h>
|
||||
#include <dev/usb/usb_quirks.h>
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
#include <machine/clock.h>
|
||||
#define delay(d) DELAY(d)
|
||||
#endif
|
||||
|
||||
#ifdef USB_DEBUG
|
||||
#define DPRINTF(x) if (usbdebug) printf x
|
||||
#define DPRINTFN(n,x) if (usbdebug>(n)) printf x
|
||||
extern int usbdebug;
|
||||
#else
|
||||
#define DPRINTF(x)
|
||||
#define DPRINTFN(n,x)
|
||||
#endif
|
||||
|
||||
static usbd_status usbd_set_config __P((usbd_device_handle, int));
|
||||
char *usbd_get_string __P((usbd_device_handle, int, char *));
|
||||
int usbd_getnewaddr __P((usbd_bus_handle bus));
|
||||
int usbd_print __P((void *aux, const char *pnp));
|
||||
#if defined(__NetBSD__)
|
||||
int usbd_submatch __P((struct device *, struct cfdata *cf, void *));
|
||||
#endif
|
||||
usb_interface_descriptor_t *usbd_find_idesc __P((usb_config_descriptor_t *cd,
|
||||
int ino, int ano));
|
||||
usbd_status usbd_fill_iface_data __P((usbd_device_handle dev, int i, int a));
|
||||
void usbd_free_iface_data __P((usbd_device_handle dev, int ifcno));
|
||||
void usbd_kill_pipe __P((usbd_pipe_handle));
|
||||
static usbd_status usbd_probe_and_attach(bdevice *parent, usbd_device_handle dev);
|
||||
|
||||
#ifdef USBVERBOSE
|
||||
typedef u_int16_t usb_vendor_id_t;
|
||||
typedef u_int16_t usb_product_id_t;
|
||||
|
||||
/*
|
||||
* Descriptions of of known vendors and devices ("products").
|
||||
*/
|
||||
struct usb_knowndev {
|
||||
usb_vendor_id_t vendor;
|
||||
usb_product_id_t product;
|
||||
int flags;
|
||||
char *vendorname, *productname;
|
||||
};
|
||||
#define USB_KNOWNDEV_NOPROD 0x01 /* match on vendor only */
|
||||
|
||||
#include <dev/usb/usbdevs_data.h>
|
||||
#endif /* USBVERBOSE */
|
||||
|
||||
|
||||
char *
|
||||
usbd_get_string(dev, si, buf)
|
||||
usbd_device_handle dev;
|
||||
int si;
|
||||
char *buf;
|
||||
{
|
||||
int swap = dev->quirks->uq_flags & UQ_SWAP_UNICODE;
|
||||
usb_device_request_t req;
|
||||
usb_string_descriptor_t us;
|
||||
char *s;
|
||||
int i, n;
|
||||
u_int16_t c;
|
||||
usbd_status r;
|
||||
int lang; /* NWH */
|
||||
|
||||
if (si == 0)
|
||||
return 0;
|
||||
|
||||
/* NWH added fetching of language
|
||||
* See 9.6.5 (spec v1.0)
|
||||
*/
|
||||
req.bmRequestType = UT_READ_DEVICE;
|
||||
req.bRequest = UR_GET_DESCRIPTOR;
|
||||
USETW2(req.wValue, UDESC_STRING, 0);
|
||||
USETW(req.wIndex, 0);
|
||||
USETW(req.wLength, 4); /* only first word in bString */
|
||||
r = usbd_do_request(dev, &req, &us);
|
||||
if (r != USBD_NORMAL_COMPLETION)
|
||||
return 0;
|
||||
lang = UGETW(us.bString[0]);
|
||||
/* NWH end */
|
||||
|
||||
req.bmRequestType = UT_READ_DEVICE;
|
||||
req.bRequest = UR_GET_DESCRIPTOR;
|
||||
USETW2(req.wValue, UDESC_STRING, si);
|
||||
USETW(req.wIndex, lang);
|
||||
USETW(req.wLength, 1); /* only size byte first */
|
||||
r = usbd_do_request(dev, &req, &us);
|
||||
if (r != USBD_NORMAL_COMPLETION)
|
||||
return 0;
|
||||
USETW(req.wLength, us.bLength); /* the whole string */
|
||||
r = usbd_do_request(dev, &req, &us);
|
||||
if (r != USBD_NORMAL_COMPLETION)
|
||||
return 0;
|
||||
s = buf;
|
||||
n = us.bLength / 2 - 1;
|
||||
for (i = 0; i < n; i++) {
|
||||
c = UGETW(us.bString[i]);
|
||||
/* Convert from Unicode, handle buggy strings. */
|
||||
if ((c & 0xff00) == 0)
|
||||
*s++ = c;
|
||||
else if ((c & 0x00ff) == 0 && swap)
|
||||
*s++ = c >> 8;
|
||||
else
|
||||
*s++ = '?';
|
||||
}
|
||||
*s++ = 0;
|
||||
return buf;
|
||||
}
|
||||
|
||||
void
|
||||
usbd_devinfo_vp(dev, v, p)
|
||||
usbd_device_handle dev;
|
||||
char *v, *p;
|
||||
{
|
||||
usb_device_descriptor_t *udd = &dev->ddesc;
|
||||
char *vendor = 0, *product = 0;
|
||||
#ifdef USBVERBOSE
|
||||
struct usb_knowndev *kdp;
|
||||
#endif
|
||||
|
||||
if (!dev) {
|
||||
DPRINTF(("usbd_devinfo_vp: dev not set\n"));
|
||||
return;
|
||||
}
|
||||
if (!v) {
|
||||
DPRINTF(("usbd_devinfo_vp: v not set\n"));
|
||||
return;
|
||||
}
|
||||
if (!p) {
|
||||
DPRINTF(("usbd_devinfo_vp: p not set\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
vendor = usbd_get_string(dev, udd->iManufacturer, v);
|
||||
product = usbd_get_string(dev, udd->iProduct, p);
|
||||
#ifdef USBVERBOSE
|
||||
if (!vendor) {
|
||||
for(kdp = usb_knowndevs;
|
||||
kdp->vendorname != NULL;
|
||||
kdp++) {
|
||||
if (kdp->vendor == UGETW(udd->idVendor) &&
|
||||
(kdp->product == UGETW(udd->idProduct) ||
|
||||
(kdp->flags & USB_KNOWNDEV_NOPROD) != 0))
|
||||
break;
|
||||
}
|
||||
if (kdp->vendorname == NULL)
|
||||
vendor = product = NULL;
|
||||
else {
|
||||
vendor = kdp->vendorname;
|
||||
product = (kdp->flags & USB_KNOWNDEV_NOPROD) == 0 ?
|
||||
kdp->productname : NULL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (vendor)
|
||||
strcpy(v, vendor);
|
||||
else
|
||||
sprintf(v, "vendor 0x%04x", UGETW(udd->idVendor));
|
||||
if (product)
|
||||
strcpy(p, product);
|
||||
else
|
||||
sprintf(p, "product 0x%04x", UGETW(udd->idProduct));
|
||||
}
|
||||
|
||||
int
|
||||
usbd_printBCD(cp, bcd)
|
||||
char *cp;
|
||||
int bcd;
|
||||
{
|
||||
return (sprintf(cp, "%x.%02x", bcd >> 8, bcd & 0xff));
|
||||
}
|
||||
|
||||
void
|
||||
usbd_devinfo(dev, showclass, cp)
|
||||
usbd_device_handle dev;
|
||||
int showclass;
|
||||
char *cp;
|
||||
{
|
||||
usb_device_descriptor_t *udd = &dev->ddesc;
|
||||
char vendor[USB_MAX_STRING_LEN];
|
||||
char product[USB_MAX_STRING_LEN];
|
||||
int bcdDevice, bcdUSB;
|
||||
|
||||
usbd_devinfo_vp(dev, vendor, product);
|
||||
cp += sprintf(cp, "%s", vendor);
|
||||
cp += sprintf(cp, " %s", product);
|
||||
if (showclass)
|
||||
cp += sprintf(cp, " (class %d/%d)",
|
||||
udd->bDeviceClass, udd->bDeviceSubClass);
|
||||
bcdUSB = UGETW(udd->bcdUSB);
|
||||
bcdDevice = UGETW(udd->bcdDevice);
|
||||
cp += sprintf(cp, " (rev ");
|
||||
cp += usbd_printBCD(cp, bcdUSB);
|
||||
*cp++ = '/';
|
||||
cp += usbd_printBCD(cp, bcdDevice);
|
||||
*cp++ = ')';
|
||||
cp += sprintf(cp, " (addr %d)", dev->address);
|
||||
}
|
||||
|
||||
/* Delay for a certain number of ms */
|
||||
void
|
||||
usbd_delay_ms(bus, ms)
|
||||
usbd_bus_handle bus;
|
||||
int ms;
|
||||
{
|
||||
/* Wait at least two clock ticks so we know the time has passed. */
|
||||
if (bus->use_polling)
|
||||
delay((ms+1) * 1000);
|
||||
else
|
||||
tsleep(&ms, PRIBIO, "usbdly", (ms*hz+999)/1000 + 1);
|
||||
}
|
||||
|
||||
usbd_status
|
||||
usbd_reset_port(dev, port, ps)
|
||||
usbd_device_handle dev;
|
||||
int port;
|
||||
usb_port_status_t *ps;
|
||||
{
|
||||
usb_device_request_t req;
|
||||
usbd_status r;
|
||||
int n;
|
||||
|
||||
req.bmRequestType = UT_WRITE_CLASS_OTHER;
|
||||
req.bRequest = UR_SET_FEATURE;
|
||||
USETW(req.wValue, UHF_PORT_RESET);
|
||||
USETW(req.wIndex, port);
|
||||
USETW(req.wLength, 0);
|
||||
r = usbd_do_request(dev, &req, 0);
|
||||
DPRINTFN(1,("usbd_reset_port: port %d reset done, error=%d\n",
|
||||
port, r));
|
||||
if (r != USBD_NORMAL_COMPLETION)
|
||||
return (r);
|
||||
n = 10;
|
||||
do {
|
||||
/* Wait for device to recover from reset. */
|
||||
usbd_delay_ms(dev->bus, USB_PORT_RESET_DELAY);
|
||||
r = usbd_get_port_status(dev, port, ps);
|
||||
if (r != USBD_NORMAL_COMPLETION) {
|
||||
DPRINTF(("usbd_reset_port: get status failed %d\n",r));
|
||||
return (r);
|
||||
}
|
||||
} while ((UGETW(ps->wPortChange) & UPS_C_PORT_RESET) == 0 && --n > 0);
|
||||
if (n == 0) {
|
||||
printf("usbd_reset_port: timeout\n");
|
||||
return (USBD_IOERROR);
|
||||
}
|
||||
r = usbd_clear_port_feature(dev, port, UHF_C_PORT_RESET);
|
||||
#ifdef USB_DEBUG
|
||||
if (r != USBD_NORMAL_COMPLETION)
|
||||
DPRINTF(("usbd_reset_port: clear port feature failed %d\n",r));
|
||||
#endif
|
||||
return (r);
|
||||
}
|
||||
|
||||
usb_interface_descriptor_t *
|
||||
usbd_find_idesc(cd, ino, ano)
|
||||
usb_config_descriptor_t *cd;
|
||||
int ino;
|
||||
int ano;
|
||||
{
|
||||
char *p = (char *)cd;
|
||||
char *end = p + UGETW(cd->wTotalLength);
|
||||
usb_interface_descriptor_t *d;
|
||||
|
||||
for (; p < end; p += d->bLength) {
|
||||
d = (usb_interface_descriptor_t *)p;
|
||||
if (p + d->bLength <= end &&
|
||||
d->bDescriptorType == UDESC_INTERFACE &&
|
||||
d->bInterfaceNumber == ino && d->bAlternateSetting == ano)
|
||||
return (d);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
usbd_status
|
||||
usbd_fill_iface_data(dev, ino, ano)
|
||||
usbd_device_handle dev;
|
||||
int ino;
|
||||
int ano;
|
||||
{
|
||||
usbd_interface_handle ifc = &dev->ifaces[ino];
|
||||
usb_endpoint_descriptor_t *ed;
|
||||
char *p, *end;
|
||||
int endpt, nendpt;
|
||||
usbd_status r;
|
||||
|
||||
DPRINTFN(5,("usbd_fill_iface_data: ino=%d ano=%d\n", ino, ano));
|
||||
ifc->device = dev;
|
||||
ifc->state = USBD_INTERFACE_ACTIVE;
|
||||
ifc->idesc = usbd_find_idesc(dev->cdesc, ino, ano);
|
||||
if (ifc->idesc == 0)
|
||||
return (USBD_INVAL);
|
||||
nendpt = ifc->idesc->bNumEndpoints;
|
||||
DPRINTFN(10,("usbd_fill_iface_data: found idesc n=%d\n", nendpt));
|
||||
if (nendpt != 0) {
|
||||
ifc->endpoints = malloc(nendpt * sizeof(struct usbd_endpoint),
|
||||
M_USB, M_NOWAIT);
|
||||
if (ifc->endpoints == 0)
|
||||
return (USBD_NOMEM);
|
||||
} else
|
||||
ifc->endpoints = 0;
|
||||
ifc->priv = 0;
|
||||
p = (char *)ifc->idesc + ifc->idesc->bLength;
|
||||
end = (char *)dev->cdesc + UGETW(dev->cdesc->wTotalLength);
|
||||
for (endpt = 0; endpt < nendpt; endpt++) {
|
||||
DPRINTFN(10,("usbd_fill_iface_data: endpt=%d\n", endpt));
|
||||
for (; p < end; p += ed->bLength) {
|
||||
ed = (usb_endpoint_descriptor_t *)p;
|
||||
DPRINTFN(10,("usbd_fill_iface_data: p=%p end=%p len=%d type=%d\n",
|
||||
p, end, ed->bLength, ed->bDescriptorType));
|
||||
if (p + ed->bLength <= end &&
|
||||
ed->bDescriptorType == UDESC_ENDPOINT)
|
||||
goto found;
|
||||
if (ed->bDescriptorType == UDESC_INTERFACE)
|
||||
break;
|
||||
}
|
||||
r = USBD_INVAL;
|
||||
goto bad;
|
||||
found:
|
||||
ifc->endpoints[endpt].edesc = ed;
|
||||
ifc->endpoints[endpt].state = USBD_ENDPOINT_ACTIVE;
|
||||
ifc->endpoints[endpt].refcnt = 0;
|
||||
ifc->endpoints[endpt].toggle = 0;
|
||||
}
|
||||
LIST_INIT(&ifc->pipes);
|
||||
return (USBD_NORMAL_COMPLETION);
|
||||
bad:
|
||||
free(ifc->endpoints, M_USB);
|
||||
return (r);
|
||||
}
|
||||
|
||||
void
|
||||
usbd_free_iface_data(dev, ifcno)
|
||||
usbd_device_handle dev;
|
||||
int ifcno;
|
||||
{
|
||||
usbd_interface_handle ifc = &dev->ifaces[ifcno];
|
||||
if (ifc->endpoints)
|
||||
free(ifc->endpoints, M_USB);
|
||||
}
|
||||
|
||||
static usbd_status
|
||||
usbd_set_config(dev, conf)
|
||||
usbd_device_handle dev;
|
||||
int conf;
|
||||
{
|
||||
usb_device_request_t req;
|
||||
|
||||
req.bmRequestType = UT_WRITE_DEVICE;
|
||||
req.bRequest = UR_SET_CONFIG;
|
||||
USETW(req.wValue, conf);
|
||||
USETW(req.wIndex, 0);
|
||||
USETW(req.wLength, 0);
|
||||
return (usbd_do_request(dev, &req, 0));
|
||||
}
|
||||
|
||||
usbd_status
|
||||
usbd_set_config_no(dev, no, msg)
|
||||
usbd_device_handle dev;
|
||||
int no;
|
||||
int msg;
|
||||
{
|
||||
usb_status_t ds;
|
||||
usb_hub_status_t hs;
|
||||
usb_config_descriptor_t cd, *cdp;
|
||||
usbd_status r;
|
||||
int ifcno, nifc, len, selfpowered, power;
|
||||
|
||||
DPRINTFN(5, ("usbd_set_config_no: dev=%p no=%d\n", dev, no));
|
||||
|
||||
/* XXX check that all interfaces are idle */
|
||||
if (dev->config != 0) {
|
||||
DPRINTF(("usbd_set_config_no: free old config\n"));
|
||||
/* Free all configuration data structures. */
|
||||
nifc = dev->cdesc->bNumInterface;
|
||||
for (ifcno = 0; ifcno < nifc; ifcno++)
|
||||
usbd_free_iface_data(dev, ifcno);
|
||||
free(dev->ifaces, M_USB);
|
||||
free(dev->cdesc, M_USB);
|
||||
dev->ifaces = 0;
|
||||
dev->cdesc = 0;
|
||||
dev->config = 0;
|
||||
dev->state = USBD_DEVICE_ADDRESSED;
|
||||
}
|
||||
|
||||
/* Figure out what config number to use. */
|
||||
r = usbd_get_config_desc(dev, no, &cd);
|
||||
if (r != USBD_NORMAL_COMPLETION)
|
||||
return (r);
|
||||
len = UGETW(cd.wTotalLength);
|
||||
cdp = malloc(len, M_USB, M_NOWAIT);
|
||||
if (cdp == 0)
|
||||
return (USBD_NOMEM);
|
||||
r = usbd_get_desc(dev, UDESC_CONFIG, no, len, cdp);
|
||||
if (r != USBD_NORMAL_COMPLETION)
|
||||
goto bad;
|
||||
selfpowered = 0;
|
||||
if (cdp->bmAttributes & UC_SELF_POWERED) {
|
||||
/* May be self powered. */
|
||||
if (cdp->bmAttributes & UC_BUS_POWERED) {
|
||||
/* Must ask device. */
|
||||
if (dev->quirks->uq_flags & UQ_HUB_POWER) {
|
||||
/* Buggy hub, use hub descriptor. */
|
||||
r = usbd_get_hub_status(dev, &hs);
|
||||
if (r == USBD_NORMAL_COMPLETION &&
|
||||
!(UGETW(hs.wHubStatus) & UHS_LOCAL_POWER))
|
||||
selfpowered = 1;
|
||||
} else {
|
||||
r = usbd_get_device_status(dev, &ds);
|
||||
if (r == USBD_NORMAL_COMPLETION &&
|
||||
(UGETW(ds.wStatus) & UDS_SELF_POWERED))
|
||||
selfpowered = 1;
|
||||
}
|
||||
DPRINTF(("usbd_set_config_no: status=0x%04x, error=%d\n",
|
||||
UGETW(ds.wStatus), r));
|
||||
} else
|
||||
selfpowered = 1;
|
||||
}
|
||||
DPRINTF(("usbd_set_config_no: (addr %d) attr=0x%02x, selfpowered=%d, power=%d, powerquirk=%x\n",
|
||||
dev->address, cdp->bmAttributes,
|
||||
selfpowered, cdp->bMaxPower * 2,
|
||||
dev->quirks->uq_flags & UQ_HUB_POWER));
|
||||
#ifdef USB_DEBUG
|
||||
if (!dev->powersrc) {
|
||||
printf("usbd_set_config_no: No power source?\n");
|
||||
return (EIO);
|
||||
}
|
||||
#endif
|
||||
power = cdp->bMaxPower * 2;
|
||||
if (power > dev->powersrc->power) {
|
||||
/* XXX print nicer message. */
|
||||
if (msg)
|
||||
DEVICE_ERROR(dev->bus->bdev,
|
||||
("device addr %d (config %d) exceeds power budget, %d mA > %d mA\n",
|
||||
dev->address,
|
||||
cdp->bConfigurationValue,
|
||||
power, dev->powersrc->power));
|
||||
r = USBD_NO_POWER;
|
||||
goto bad;
|
||||
}
|
||||
dev->power = power;
|
||||
dev->self_powered = selfpowered;
|
||||
|
||||
r = usbd_set_config(dev, cdp->bConfigurationValue);
|
||||
if (r != USBD_NORMAL_COMPLETION) {
|
||||
DPRINTF(("usbd_set_config_no: setting config=%d failed, error=%d\n",
|
||||
cdp->bConfigurationValue, r));
|
||||
goto bad;
|
||||
}
|
||||
DPRINTF(("usbd_set_config_no: setting new config %d\n",
|
||||
cdp->bConfigurationValue));
|
||||
nifc = cdp->bNumInterface;
|
||||
dev->ifaces = malloc(nifc * sizeof(struct usbd_interface),
|
||||
M_USB, M_NOWAIT);
|
||||
if (dev->ifaces == 0) {
|
||||
r = USBD_NOMEM;
|
||||
goto bad;
|
||||
}
|
||||
DPRINTFN(5,("usbd_set_config_no: dev=%p cdesc=%p\n", dev, cdp));
|
||||
dev->cdesc = cdp;
|
||||
dev->config = cdp->bConfigurationValue;
|
||||
dev->state = USBD_DEVICE_CONFIGURED;
|
||||
for (ifcno = 0; ifcno < nifc; ifcno++) {
|
||||
r = usbd_fill_iface_data(dev, ifcno, 0);
|
||||
if (r != USBD_NORMAL_COMPLETION) {
|
||||
while (--ifcno >= 0)
|
||||
usbd_free_iface_data(dev, ifcno);
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
|
||||
return (USBD_NORMAL_COMPLETION);
|
||||
|
||||
bad:
|
||||
free(cdp, M_USB);
|
||||
return (r);
|
||||
}
|
||||
|
||||
/* XXX add function for alternate settings */
|
||||
|
||||
usbd_status
|
||||
usbd_setup_pipe(dev, iface, ep, pipe)
|
||||
usbd_device_handle dev;
|
||||
usbd_interface_handle iface;
|
||||
struct usbd_endpoint *ep;
|
||||
usbd_pipe_handle *pipe;
|
||||
{
|
||||
usbd_pipe_handle p;
|
||||
usbd_status r;
|
||||
|
||||
*pipe = NULL;
|
||||
|
||||
DPRINTFN(1,("usbd_setup_pipe: dev=%p iface=%p ep=%p pipe=%p\n",
|
||||
dev, iface, ep, pipe));
|
||||
p = malloc(dev->bus->pipe_size, M_USB, M_NOWAIT);
|
||||
if (p == 0)
|
||||
return (USBD_NOMEM);
|
||||
p->device = dev;
|
||||
p->iface = iface;
|
||||
p->state = USBD_PIPE_ACTIVE;
|
||||
p->endpoint = ep;
|
||||
ep->refcnt++;
|
||||
p->refcnt = 1;
|
||||
p->intrreqh = 0;
|
||||
p->running = 0;
|
||||
SIMPLEQ_INIT(&p->queue);
|
||||
r = dev->bus->open_pipe(p);
|
||||
if (r != USBD_NORMAL_COMPLETION) {
|
||||
DPRINTF(("usbd_setup_pipe: endpoint=%d failed, error=%d\n",
|
||||
ep->edesc->bEndpointAddress, r));
|
||||
free(p, M_USB);
|
||||
return (r);
|
||||
}
|
||||
*pipe = p;
|
||||
return (USBD_NORMAL_COMPLETION);
|
||||
}
|
||||
|
||||
/* Abort the device control pipe. */
|
||||
void
|
||||
usbd_kill_pipe(pipe)
|
||||
usbd_pipe_handle pipe;
|
||||
{
|
||||
pipe->methods->close(pipe);
|
||||
pipe->endpoint->refcnt--;
|
||||
free(pipe, M_USB);
|
||||
}
|
||||
|
||||
int
|
||||
usbd_getnewaddr(bus)
|
||||
usbd_bus_handle bus;
|
||||
{
|
||||
int addr;
|
||||
|
||||
for (addr = 1; addr < USB_MAX_DEVICES; addr++)
|
||||
if (bus->devices[addr] == 0)
|
||||
return (addr);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
|
||||
/* NWH separated out the probe and attach code
|
||||
*/
|
||||
static usbd_status
|
||||
usbd_probe_and_attach(parent, dev)
|
||||
bdevice *parent;
|
||||
usbd_device_handle dev;
|
||||
{
|
||||
struct usb_attach_arg uaa;
|
||||
usb_device_descriptor_t *dd = &dev->ddesc;
|
||||
int r, found, i, confi;
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
dev->bdev = device_add_child(*parent, NULL, -1, &uaa);
|
||||
if (!dev->bdev) {
|
||||
DEVICE_ERROR(dev->bus->bdev, ("Device creation failed\n"));
|
||||
return ENXIO;
|
||||
}
|
||||
#endif
|
||||
|
||||
uaa.device = dev;
|
||||
uaa.iface = 0;
|
||||
uaa.usegeneric = 0;
|
||||
|
||||
/* First try with device specific drivers. */
|
||||
#if defined(__NetBSD__)
|
||||
if (config_found_sm(parent, &uaa, usbd_print, usbd_submatch) != 0)
|
||||
#elif defined(__FreeBSD__)
|
||||
if (device_probe_and_attach(dev->bdev) == 0)
|
||||
#endif
|
||||
return (USBD_NORMAL_COMPLETION);
|
||||
|
||||
DPRINTF(("usbd_new_device: no device driver found\n"));
|
||||
|
||||
/* Next try with interface drivers. */
|
||||
for (confi = 0; confi < dd->bNumConfigurations; confi++) {
|
||||
r = usbd_set_config_no(dev, confi, 1);
|
||||
if (r != USBD_NORMAL_COMPLETION) {
|
||||
DEVICE_ERROR(*parent, ("set config failed, r=%d\n", r));
|
||||
return r;
|
||||
}
|
||||
for (found = i = 0; i < dev->cdesc->bNumInterface; i++) {
|
||||
uaa.iface = &dev->ifaces[i];
|
||||
#if defined(__NetBSD__)
|
||||
if (config_found_sm(parent, &uaa, usbd_print,
|
||||
usbd_submatch))
|
||||
#elif defined(__FreeBSD__)
|
||||
if (device_probe_and_attach(dev->bdev) == 0)
|
||||
#endif
|
||||
found++;
|
||||
}
|
||||
if (found != 0)
|
||||
return (USBD_NORMAL_COMPLETION);
|
||||
}
|
||||
/* No interfaces were attach in any of the configurations. */
|
||||
if (dd->bNumConfigurations > 0)
|
||||
usbd_set_config_no(dev, 0, 0);
|
||||
|
||||
DPRINTF(("usbd_new_device: no interface drivers found\n"));
|
||||
|
||||
/* Finally try the generic driver. */
|
||||
uaa.iface = 0;
|
||||
uaa.usegeneric = 1;
|
||||
#if defined(__NetBSD__)
|
||||
if (config_found_sm(parent, &uaa, usbd_print, usbd_submatch) != 0)
|
||||
return (USBD_NORMAL_COMPLETION);
|
||||
#elif defined(__FreeBSD__)
|
||||
if (device_probe_and_attach(dev->bdev) == 0)
|
||||
return (USBD_NORMAL_COMPLETION);
|
||||
#endif
|
||||
|
||||
/* generic attach failed, but leave the device as it is
|
||||
* we just did not find any drivers, that's all. the device is
|
||||
* fully operational and not harming anyone
|
||||
*/
|
||||
DPRINTF(("usbd_new_device: generic attach failed\n"));
|
||||
return USBD_NORMAL_COMPLETION;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Called when a new device has been put in the powered state,
|
||||
* but not yet in the addressed state.
|
||||
* Get initial descriptor, set the address, get full descriptor,
|
||||
* and attach a driver.
|
||||
*/
|
||||
usbd_status
|
||||
usbd_new_device(parent, bus, depth, lowspeed, port, up)
|
||||
bdevice *parent;
|
||||
usbd_bus_handle bus;
|
||||
int depth;
|
||||
int lowspeed;
|
||||
int port;
|
||||
struct usbd_port *up;
|
||||
{
|
||||
usbd_device_handle dev;
|
||||
usb_device_descriptor_t *dd;
|
||||
usbd_status r;
|
||||
int addr;
|
||||
int i;
|
||||
|
||||
DPRINTF(("usbd_new_device bus=%p depth=%d lowspeed=%d\n",
|
||||
bus, depth, lowspeed));
|
||||
addr = usbd_getnewaddr(bus);
|
||||
if (addr < 0) {
|
||||
DEVICE_ERROR(bus->bdev, ("No free USB addresses, new device ignored.\n"));
|
||||
return (USBD_NO_ADDR);
|
||||
}
|
||||
|
||||
dev = malloc(sizeof *dev, M_USB, M_NOWAIT);
|
||||
if (dev == 0)
|
||||
return (USBD_NOMEM);
|
||||
memset(dev, 0, sizeof(*dev));
|
||||
|
||||
dev->bus = bus;
|
||||
|
||||
/* Set up default endpoint handle. */
|
||||
dev->def_ep.edesc = &dev->def_ep_desc;
|
||||
dev->def_ep.state = USBD_ENDPOINT_ACTIVE;
|
||||
dev->def_ep.refcnt = 0;
|
||||
dev->def_ep.toggle = 0; /* XXX */
|
||||
|
||||
/* Set up default endpoint descriptor. */
|
||||
dev->def_ep_desc.bLength = USB_ENDPOINT_DESCRIPTOR_SIZE;
|
||||
dev->def_ep_desc.bDescriptorType = UDESC_ENDPOINT;
|
||||
dev->def_ep_desc.bEndpointAddress = USB_CONTROL_ENDPOINT;
|
||||
dev->def_ep_desc.bmAttributes = UE_CONTROL;
|
||||
USETW(dev->def_ep_desc.wMaxPacketSize, USB_MAX_IPACKET);
|
||||
dev->def_ep_desc.bInterval = 0;
|
||||
|
||||
dev->state = USBD_DEVICE_DEFAULT;
|
||||
dev->quirks = &usbd_no_quirk;
|
||||
dev->address = USB_START_ADDR;
|
||||
dev->ddesc.bMaxPacketSize = 0;
|
||||
dev->lowspeed = lowspeed != 0;
|
||||
dev->depth = depth;
|
||||
dev->powersrc = up;
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
dev->bdev = NULL;
|
||||
#endif
|
||||
|
||||
/* Establish the the default pipe. */
|
||||
r = usbd_setup_pipe(dev, 0, &dev->def_ep, &dev->default_pipe);
|
||||
if (r != USBD_NORMAL_COMPLETION) {
|
||||
usbd_remove_device(dev, up);
|
||||
return r;
|
||||
}
|
||||
|
||||
up->device = dev;
|
||||
dd = &dev->ddesc;
|
||||
/* Try a few times in case the device is slow (i.e. outside specs.) */
|
||||
for (i = 0; i < 5; i++) {
|
||||
/* Get the first 8 bytes of the device descriptor. */
|
||||
r = usbd_get_desc(dev, UDESC_DEVICE, 0, USB_MAX_IPACKET, dd);
|
||||
if (r == USBD_NORMAL_COMPLETION)
|
||||
break;
|
||||
usbd_delay_ms(dev->bus, 200);
|
||||
}
|
||||
if (r != USBD_NORMAL_COMPLETION) {
|
||||
DPRINTFN(-1, ("usbd_new_device: addr=%d, getting first desc failed\n",
|
||||
addr));
|
||||
usbd_remove_device(dev, up);
|
||||
return r;
|
||||
}
|
||||
|
||||
DPRINTF(("usbd_new_device: adding unit addr=%d, rev=%02x, class=%d, subclass=%d, protocol=%d, maxpacket=%d, ls=%d\n",
|
||||
addr, UGETW(dd->bcdUSB), dd->bDeviceClass, dd->bDeviceSubClass,
|
||||
dd->bDeviceProtocol, dd->bMaxPacketSize, dev->lowspeed));
|
||||
|
||||
USETW(dev->def_ep_desc.wMaxPacketSize, dd->bMaxPacketSize);
|
||||
|
||||
/* Get the full device descriptor. */
|
||||
r = usbd_get_device_desc(dev, dd);
|
||||
if (r != USBD_NORMAL_COMPLETION) {
|
||||
DPRINTFN(-1, ("usbd_new_device: addr=%d, getting full desc failed\n", addr));
|
||||
usbd_remove_device(dev, up);
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Figure out what's wrong with this device. */
|
||||
dev->quirks = usbd_find_quirk(dd);
|
||||
|
||||
/* Set the address */
|
||||
r = usbd_set_address(dev, addr);
|
||||
if (r != USBD_NORMAL_COMPLETION) {
|
||||
DPRINTFN(-1,("usbd_new_device: set address %d failed\n",addr));
|
||||
usbd_remove_device(dev, up);
|
||||
return USBD_SET_ADDR_FAILED;
|
||||
}
|
||||
dev->address = addr; /* New device address now */
|
||||
dev->state = USBD_DEVICE_ADDRESSED;
|
||||
bus->devices[addr] = dev;
|
||||
|
||||
/* Assume 100mA bus powered for now. Changed when configured. */
|
||||
dev->power = USB_MIN_POWER;
|
||||
dev->self_powered = 0;
|
||||
|
||||
DPRINTF(("usbd_new_device: new dev (addr %d), dev=%p, parent=%p\n",
|
||||
addr, dev, parent));
|
||||
|
||||
r = usbd_probe_and_attach(parent, dev);
|
||||
if (r) {
|
||||
usbd_remove_device(dev, up);
|
||||
return r;
|
||||
}
|
||||
|
||||
return (USBD_NORMAL_COMPLETION);
|
||||
}
|
||||
|
||||
void
|
||||
usbd_remove_device(dev, up)
|
||||
usbd_device_handle dev;
|
||||
struct usbd_port *up;
|
||||
{
|
||||
DPRINTF(("usbd_remove_device: %p\n", dev));
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
/* XXX bit of a hack, only for hubs the detach is called
|
||||
* the code should register a detach function and use that one
|
||||
* to detach a device porperly
|
||||
*/
|
||||
if (dev->bdev && dev->hub)
|
||||
uhub_detach(dev->hub->hubdata);
|
||||
#elif defined(__FreeBSD__)
|
||||
if (dev->bdev)
|
||||
device_delete_child(device_get_parent(dev->bdev), dev->bdev);
|
||||
#endif
|
||||
|
||||
if (dev->default_pipe)
|
||||
usbd_kill_pipe(dev->default_pipe);
|
||||
up->device = 0;
|
||||
dev->bus->devices[dev->address] = 0;
|
||||
|
||||
free(dev, M_USB);
|
||||
}
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
int
|
||||
usbd_print(aux, pnp)
|
||||
void *aux;
|
||||
const char *pnp;
|
||||
{
|
||||
struct usb_attach_arg *uaa = aux;
|
||||
char devinfo[1024];
|
||||
|
||||
DPRINTFN(15, ("usbd_print dev=%p\n", uaa->device));
|
||||
if (pnp) {
|
||||
if (!uaa->usegeneric)
|
||||
return (QUIET);
|
||||
usbd_devinfo(uaa->device, 1, devinfo);
|
||||
printf("%s at %s", devinfo, pnp);
|
||||
}
|
||||
if (uaa->port != 0)
|
||||
printf(" port %d", uaa->port);
|
||||
return (UNCONF);
|
||||
}
|
||||
|
||||
int
|
||||
usbd_submatch(parent, cf, aux)
|
||||
struct device *parent;
|
||||
struct cfdata *cf;
|
||||
void *aux;
|
||||
{
|
||||
struct usb_attach_arg *uaa = aux;
|
||||
|
||||
if (uaa->port != 0 &&
|
||||
cf->uhubcf_port != UHUB_UNK_PORT &&
|
||||
cf->uhubcf_port != uaa->port)
|
||||
return 0;
|
||||
return ((*cf->cf_attach->ca_match)(parent, cf, aux));
|
||||
}
|
||||
|
||||
#elif defined(__FreeBSD__)
|
||||
static void
|
||||
usbd_bus_print_child(device_t bus, device_t dev)
|
||||
{
|
||||
/* FIXME print the device address and the configuration used
|
||||
*/
|
||||
}
|
||||
#endif
|
121
sys/dev/usb/usbdevs.h
Normal file
121
sys/dev/usb/usbdevs.h
Normal file
@ -0,0 +1,121 @@
|
||||
/* $NetBSD: usbdevs.h,v 1.6 1998/10/05 02:31:13 mark Exp $ */
|
||||
|
||||
/*
|
||||
* THIS FILE AUTOMATICALLY GENERATED. DO NOT EDIT.
|
||||
*
|
||||
* generated from:
|
||||
* NetBSD: usbdevs,v 1.5 1998/10/05 02:30:17 mark Exp
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 1998 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Lennart Augustsson <augustss@carlstedt.se>
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* List of known USB vendors
|
||||
*/
|
||||
|
||||
#define USB_VENDOR_NEC 0x0409 /* NEC */
|
||||
#define USB_VENDOR_KODAK 0x040a /* Eastman Kodak */
|
||||
#define USB_VENDOR_NANAO 0x0440 /* Nanao */
|
||||
#define USB_VENDOR_UNIXTAR 0x0451 /* Unixtar */
|
||||
#define USB_VENDOR_GENIUS 0x0458 /* Genius */
|
||||
#define USB_VENDOR_CHERRY 0x046a /* Cherry */
|
||||
#define USB_VENDOR_PHILIPS 0x0471 /* Philips */
|
||||
#define USB_VENDOR_CONNECTIX 0x0478 /* Connectix */
|
||||
#define USB_VENDOR_CYPRESS 0x04b4 /* Cypress Semicondutor */
|
||||
#define USB_VENDOR_EIZO 0x056d /* EIZO */
|
||||
#define USB_VENDOR_BELKIN 0x05ab /* Belkin */
|
||||
#define USB_VENDOR_EIZONANAO 0x05e7 /* EIZO Nanao */
|
||||
#define USB_VENDOR_CHIC 0x05fe /* Chic Technology */
|
||||
#define USB_VENDOR_PLX 0x10b5 /* PLX */
|
||||
#define USB_VENDOR_INSIDEOUT 0x1608 /* Inside Out Networks */
|
||||
#define USB_VENDOR_INTEL 0x8086 /* Intel */
|
||||
|
||||
/*
|
||||
* List of known products. Grouped by vendor.
|
||||
*/
|
||||
|
||||
/* NEC products */
|
||||
#define USB_PRODUCT_NEC_HUB 0x55aa /* hub */
|
||||
|
||||
/* Kodak products */
|
||||
#define USB_PRODUCT_KODAK_DC260 0x0110 /* Digital Science DC260 */
|
||||
|
||||
/* Nanao products */
|
||||
#define USB_PRODUCT_NANAO_HUB 0x0000 /* hub */
|
||||
#define USB_PRODUCT_NANAO_MONITOR 0x0001 /* monitor */
|
||||
|
||||
/* Unixtar products */
|
||||
#define USB_PRODUCT_UNIXTAR_UTUSB41 0x1446 /* UT-USB41 */
|
||||
|
||||
/* Genius products */
|
||||
#define USB_PRODUCT_GENIUS_NICHE 0x0001 /* Niche mouse */
|
||||
#define USB_PRODUCT_GENIUS_FLIGHT2000 0x1004 /* Flight 2000 joystick */
|
||||
|
||||
/* Cherry products */
|
||||
#define USB_PRODUCT_CHERRY_MY3000KBD 0x0001 /* My3000 keyboard */
|
||||
#define USB_PRODUCT_CHERRY_MY3000HUB 0x0003 /* My3000 hub */
|
||||
|
||||
/* Philips products */
|
||||
#define USB_PRODUCT_PHILIPS_DSS 0x0101 /* DSS 350 Digital Speaker System */
|
||||
#define USB_PRODUCT_PHILIPS_HUB 0x0201 /* hub */
|
||||
|
||||
/* Connectix products */
|
||||
#define USB_PRODUCT_CONNECTIX_QUICKCAM 0x0001 /* QuickCam */
|
||||
|
||||
/* Cypress Semiconduuctor products */
|
||||
#define USB_PRODUCT_CYPRESS_MOUSE 0x0001 /* mouse */
|
||||
|
||||
/* Belkin products */
|
||||
#define USB_PRODUCT_BELKIN_F5U002 0x0002 /* Parallel printer adapter */
|
||||
|
||||
/* EIZO Nanao products */
|
||||
#define USB_PRODUCT_EIZO_HUB 0x0000 /* hub */
|
||||
#define USB_PRODUCT_EIZO_MONITOR 0x0001 /* monitor */
|
||||
#define USB_PRODUCT_EIZONANAO_HUB 0x0000 /* hub */
|
||||
#define USB_PRODUCT_EIZONANAO_MONITOR 0x0001 /* monitor */
|
||||
|
||||
/* Chic Technology */
|
||||
#define USB_PRODUCT_CHIC_MOUSE1 0x0001 /* mouse */
|
||||
|
||||
/* PLX products */
|
||||
#define USB_PRODUCT_PLX_TESTBOARD 0x9060 /* test board */
|
||||
|
||||
/* Inside Out Networks products */
|
||||
#define USB_PRODUCT_INSIDEOUT_EDGEPORT4 0x0001 /* EdgePort/4 */
|
||||
|
||||
/* Intel products */
|
||||
#define USB_PRODUCT_INTEL_TESTBOARD 0x9890 /* 82930 test board */
|
276
sys/dev/usb/usbdevs_data.h
Normal file
276
sys/dev/usb/usbdevs_data.h
Normal file
@ -0,0 +1,276 @@
|
||||
/* $NetBSD: usbdevs_data.h,v 1.6 1998/10/05 02:31:14 mark Exp $ */
|
||||
|
||||
/*
|
||||
* THIS FILE AUTOMATICALLY GENERATED. DO NOT EDIT.
|
||||
*
|
||||
* generated from:
|
||||
* NetBSD: usbdevs,v 1.5 1998/10/05 02:30:17 mark Exp
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 1998 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Lennart Augustsson <augustss@carlstedt.se>
|
||||
* 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.
|
||||
*/
|
||||
|
||||
struct usb_knowndev usb_knowndevs[] = {
|
||||
{
|
||||
USB_VENDOR_NEC, USB_PRODUCT_NEC_HUB,
|
||||
0,
|
||||
"NEC",
|
||||
"hub",
|
||||
},
|
||||
{
|
||||
USB_VENDOR_KODAK, USB_PRODUCT_KODAK_DC260,
|
||||
0,
|
||||
"Eastman Kodak",
|
||||
"Digital Science DC260",
|
||||
},
|
||||
{
|
||||
USB_VENDOR_NANAO, USB_PRODUCT_NANAO_HUB,
|
||||
0,
|
||||
"Nanao",
|
||||
"hub",
|
||||
},
|
||||
{
|
||||
USB_VENDOR_NANAO, USB_PRODUCT_NANAO_MONITOR,
|
||||
0,
|
||||
"Nanao",
|
||||
"monitor",
|
||||
},
|
||||
{
|
||||
USB_VENDOR_UNIXTAR, USB_PRODUCT_UNIXTAR_UTUSB41,
|
||||
0,
|
||||
"Unixtar",
|
||||
"UT-USB41",
|
||||
},
|
||||
{
|
||||
USB_VENDOR_GENIUS, USB_PRODUCT_GENIUS_NICHE,
|
||||
0,
|
||||
"Genius",
|
||||
"Niche mouse",
|
||||
},
|
||||
{
|
||||
USB_VENDOR_GENIUS, USB_PRODUCT_GENIUS_FLIGHT2000,
|
||||
0,
|
||||
"Genius",
|
||||
"Flight 2000 joystick",
|
||||
},
|
||||
{
|
||||
USB_VENDOR_CHERRY, USB_PRODUCT_CHERRY_MY3000KBD,
|
||||
0,
|
||||
"Cherry",
|
||||
"My3000 keyboard",
|
||||
},
|
||||
{
|
||||
USB_VENDOR_CHERRY, USB_PRODUCT_CHERRY_MY3000HUB,
|
||||
0,
|
||||
"Cherry",
|
||||
"My3000 hub",
|
||||
},
|
||||
{
|
||||
USB_VENDOR_PHILIPS, USB_PRODUCT_PHILIPS_DSS,
|
||||
0,
|
||||
"Philips",
|
||||
"DSS 350 Digital Speaker System",
|
||||
},
|
||||
{
|
||||
USB_VENDOR_PHILIPS, USB_PRODUCT_PHILIPS_HUB,
|
||||
0,
|
||||
"Philips",
|
||||
"hub",
|
||||
},
|
||||
{
|
||||
USB_VENDOR_CONNECTIX, USB_PRODUCT_CONNECTIX_QUICKCAM,
|
||||
0,
|
||||
"Connectix",
|
||||
"QuickCam",
|
||||
},
|
||||
{
|
||||
USB_VENDOR_CYPRESS, USB_PRODUCT_CYPRESS_MOUSE,
|
||||
0,
|
||||
"Cypress Semicondutor",
|
||||
"mouse",
|
||||
},
|
||||
{
|
||||
USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5U002,
|
||||
0,
|
||||
"Belkin",
|
||||
"Parallel printer adapter",
|
||||
},
|
||||
{
|
||||
USB_VENDOR_EIZO, USB_PRODUCT_EIZO_HUB,
|
||||
0,
|
||||
"EIZO",
|
||||
"hub",
|
||||
},
|
||||
{
|
||||
USB_VENDOR_EIZO, USB_PRODUCT_EIZO_MONITOR,
|
||||
0,
|
||||
"EIZO",
|
||||
"monitor",
|
||||
},
|
||||
{
|
||||
USB_VENDOR_EIZONANAO, USB_PRODUCT_EIZONANAO_HUB,
|
||||
0,
|
||||
"EIZO Nanao",
|
||||
"hub",
|
||||
},
|
||||
{
|
||||
USB_VENDOR_EIZONANAO, USB_PRODUCT_EIZONANAO_MONITOR,
|
||||
0,
|
||||
"EIZO Nanao",
|
||||
"monitor",
|
||||
},
|
||||
{
|
||||
USB_VENDOR_CHIC, USB_PRODUCT_CHIC_MOUSE1,
|
||||
0,
|
||||
"Chic Technology",
|
||||
"mouse",
|
||||
},
|
||||
{
|
||||
USB_VENDOR_PLX, USB_PRODUCT_PLX_TESTBOARD,
|
||||
0,
|
||||
"PLX",
|
||||
"test board",
|
||||
},
|
||||
{
|
||||
USB_VENDOR_INSIDEOUT, USB_PRODUCT_INSIDEOUT_EDGEPORT4,
|
||||
0,
|
||||
"Inside Out Networks",
|
||||
"EdgePort/4",
|
||||
},
|
||||
{
|
||||
USB_VENDOR_INTEL, USB_PRODUCT_INTEL_TESTBOARD,
|
||||
0,
|
||||
"Intel",
|
||||
"82930 test board",
|
||||
},
|
||||
{
|
||||
USB_VENDOR_NEC, 0,
|
||||
USB_KNOWNDEV_NOPROD,
|
||||
"NEC",
|
||||
NULL,
|
||||
},
|
||||
{
|
||||
USB_VENDOR_KODAK, 0,
|
||||
USB_KNOWNDEV_NOPROD,
|
||||
"Eastman Kodak",
|
||||
NULL,
|
||||
},
|
||||
{
|
||||
USB_VENDOR_NANAO, 0,
|
||||
USB_KNOWNDEV_NOPROD,
|
||||
"Nanao",
|
||||
NULL,
|
||||
},
|
||||
{
|
||||
USB_VENDOR_UNIXTAR, 0,
|
||||
USB_KNOWNDEV_NOPROD,
|
||||
"Unixtar",
|
||||
NULL,
|
||||
},
|
||||
{
|
||||
USB_VENDOR_GENIUS, 0,
|
||||
USB_KNOWNDEV_NOPROD,
|
||||
"Genius",
|
||||
NULL,
|
||||
},
|
||||
{
|
||||
USB_VENDOR_CHERRY, 0,
|
||||
USB_KNOWNDEV_NOPROD,
|
||||
"Cherry",
|
||||
NULL,
|
||||
},
|
||||
{
|
||||
USB_VENDOR_PHILIPS, 0,
|
||||
USB_KNOWNDEV_NOPROD,
|
||||
"Philips",
|
||||
NULL,
|
||||
},
|
||||
{
|
||||
USB_VENDOR_CONNECTIX, 0,
|
||||
USB_KNOWNDEV_NOPROD,
|
||||
"Connectix",
|
||||
NULL,
|
||||
},
|
||||
{
|
||||
USB_VENDOR_CYPRESS, 0,
|
||||
USB_KNOWNDEV_NOPROD,
|
||||
"Cypress Semicondutor",
|
||||
NULL,
|
||||
},
|
||||
{
|
||||
USB_VENDOR_EIZO, 0,
|
||||
USB_KNOWNDEV_NOPROD,
|
||||
"EIZO",
|
||||
NULL,
|
||||
},
|
||||
{
|
||||
USB_VENDOR_BELKIN, 0,
|
||||
USB_KNOWNDEV_NOPROD,
|
||||
"Belkin",
|
||||
NULL,
|
||||
},
|
||||
{
|
||||
USB_VENDOR_EIZONANAO, 0,
|
||||
USB_KNOWNDEV_NOPROD,
|
||||
"EIZO Nanao",
|
||||
NULL,
|
||||
},
|
||||
{
|
||||
USB_VENDOR_CHIC, 0,
|
||||
USB_KNOWNDEV_NOPROD,
|
||||
"Chic Technology",
|
||||
NULL,
|
||||
},
|
||||
{
|
||||
USB_VENDOR_PLX, 0,
|
||||
USB_KNOWNDEV_NOPROD,
|
||||
"PLX",
|
||||
NULL,
|
||||
},
|
||||
{
|
||||
USB_VENDOR_INSIDEOUT, 0,
|
||||
USB_KNOWNDEV_NOPROD,
|
||||
"Inside Out Networks",
|
||||
NULL,
|
||||
},
|
||||
{
|
||||
USB_VENDOR_INTEL, 0,
|
||||
USB_KNOWNDEV_NOPROD,
|
||||
"Intel",
|
||||
NULL,
|
||||
},
|
||||
{ 0, 0, 0, NULL, NULL, }
|
||||
};
|
1112
sys/dev/usb/usbdi.c
Normal file
1112
sys/dev/usb/usbdi.c
Normal file
File diff suppressed because it is too large
Load Diff
303
sys/dev/usb/usbdi.h
Normal file
303
sys/dev/usb/usbdi.h
Normal file
@ -0,0 +1,303 @@
|
||||
/* $NetBSD: usbdi.h,v 1.6 1998/08/02 22:30:53 augustss Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1998 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Lennart Augustsson <augustss@carlstedt.se>
|
||||
* 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.
|
||||
*/
|
||||
|
||||
typedef struct usbd_bus *usbd_bus_handle;
|
||||
typedef struct usbd_device *usbd_device_handle;
|
||||
typedef struct usbd_interface *usbd_interface_handle;
|
||||
typedef struct usbd_pipe *usbd_pipe_handle;
|
||||
typedef struct usbd_request *usbd_request_handle;
|
||||
typedef void *usbd_private_handle;
|
||||
|
||||
typedef enum {
|
||||
USBD_ENDPOINT_ACTIVE,
|
||||
USBD_ENDPOINT_STALLED,
|
||||
} usbd_endpoint_state;
|
||||
|
||||
typedef enum {
|
||||
USBD_PIPE_ACTIVE,
|
||||
USBD_PIPE_STALLED,
|
||||
USBD_PIPE_IDLE,
|
||||
} usbd_pipe_state;
|
||||
|
||||
typedef enum {
|
||||
USBD_INTERFACE_ACTIVE,
|
||||
USBD_INTERFACE_STALLED,
|
||||
USBD_INTERFACE_IDLE,
|
||||
} usbd_interface_state;
|
||||
|
||||
typedef enum {
|
||||
USBD_DEVICE_ATTACHED,
|
||||
USBD_DEVICE_POWERED,
|
||||
USBD_DEVICE_DEFAULT,
|
||||
USBD_DEVICE_ADDRESSED,
|
||||
USBD_DEVICE_CONFIGURED,
|
||||
USBD_DEVICE_SUSPENDED,
|
||||
} usbd_device_state;
|
||||
|
||||
typedef enum {
|
||||
USBD_NORMAL_COMPLETION = 0,
|
||||
USBD_IN_PROGRESS,
|
||||
/* errors */
|
||||
USBD_PENDING_REQUESTS,
|
||||
USBD_NOT_STARTED,
|
||||
USBD_INVAL,
|
||||
USBD_IS_IDLE,
|
||||
USBD_NOMEM,
|
||||
USBD_CANCELLED,
|
||||
USBD_BAD_ADDRESS,
|
||||
USBD_IN_USE,
|
||||
USBD_INTERFACE_NOT_ACTIVE,
|
||||
USBD_NO_ADDR,
|
||||
USBD_SET_ADDR_FAILED,
|
||||
USBD_NO_POWER,
|
||||
USBD_TOO_DEEP,
|
||||
USBD_IOERROR,
|
||||
USBD_NOT_CONFIGURED,
|
||||
USBD_TIMEOUT,
|
||||
USBD_SHORT_XFER,
|
||||
USBD_STALLED,
|
||||
|
||||
USBD_XXX,
|
||||
} usbd_status;
|
||||
|
||||
typedef int usbd_lock_token;
|
||||
|
||||
typedef void (*usbd_callback) __P((usbd_request_handle, usbd_private_handle,
|
||||
usbd_status));
|
||||
|
||||
/* Open flags */
|
||||
#define USBD_EXCLUSIVE_USE 0x01
|
||||
|
||||
/* Request flags */
|
||||
#define USBD_XFER_OUT 0x01
|
||||
#define USBD_XFER_IN 0x02
|
||||
#define USBD_SHORT_XFER_OK 0x04
|
||||
|
||||
#define USBD_NO_TIMEOUT 0
|
||||
#define USBD_DEFAULT_TIMEOUT 5000 /* ms = 5 s */
|
||||
|
||||
usbd_status usbd_open_pipe
|
||||
__P((usbd_interface_handle iface, u_int8_t address,
|
||||
u_int8_t flags, usbd_pipe_handle *pipe));
|
||||
usbd_status usbd_close_pipe __P((usbd_pipe_handle pipe));
|
||||
usbd_status usbd_transfer __P((usbd_request_handle req));
|
||||
usbd_request_handle usbd_alloc_request __P((void));
|
||||
usbd_status usbd_free_request __P((usbd_request_handle reqh));
|
||||
usbd_status usbd_setup_request
|
||||
__P((usbd_request_handle reqh, usbd_pipe_handle pipe,
|
||||
usbd_private_handle priv, void *buffer,
|
||||
u_int32_t length, u_int16_t flags, u_int32_t timeout,
|
||||
usbd_callback));
|
||||
usbd_status usbd_setup_device_request
|
||||
__P((usbd_request_handle reqh, usb_device_request_t *req));
|
||||
usbd_status usbd_setup_default_request
|
||||
__P((usbd_request_handle reqh, usbd_device_handle dev,
|
||||
usbd_private_handle priv, u_int32_t timeout,
|
||||
usb_device_request_t *req, void *buffer,
|
||||
u_int32_t length, u_int16_t flags, usbd_callback));
|
||||
usbd_status usbd_set_request_timeout
|
||||
__P((usbd_request_handle reqh, u_int32_t timeout));
|
||||
usbd_status usbd_get_request_status
|
||||
__P((usbd_request_handle reqh, usbd_private_handle *priv,
|
||||
void **buffer, u_int32_t *count, usbd_status *status));
|
||||
usbd_status usbd_request_device_data
|
||||
__P((usbd_request_handle reqh, usb_device_request_t *req));
|
||||
usb_descriptor_t *usbd_get_descriptor
|
||||
__P((usbd_interface_handle *iface, u_int8_t desc_type));
|
||||
usb_endpoint_descriptor_t *usbd_interface2endpoint_descriptor
|
||||
__P((usbd_interface_handle iface, u_int8_t address));
|
||||
usbd_status usbd_set_configuration
|
||||
__P((usbd_device_handle dev, u_int16_t conf));
|
||||
usbd_status usbd_retry_request
|
||||
__P((usbd_request_handle reqh, u_int32_t retry_count));
|
||||
usbd_status usbd_abort_pipe __P((usbd_pipe_handle pipe));
|
||||
usbd_status usbd_abort_interface __P((usbd_interface_handle iface));
|
||||
usbd_status usbd_reset_pipe __P((usbd_pipe_handle pipe));
|
||||
usbd_status usbd_reset_interface __P((usbd_interface_handle iface));
|
||||
usbd_status usbd_clear_endpoint_stall __P((usbd_pipe_handle pipe));
|
||||
usbd_status usbd_clear_endpoint_stall_async __P((usbd_pipe_handle pipe));
|
||||
usbd_status usbd_set_pipe_state
|
||||
__P((usbd_pipe_handle pipe, usbd_pipe_state state));
|
||||
usbd_status usbd_get_pipe_state
|
||||
__P((usbd_pipe_handle pipe, usbd_pipe_state *state,
|
||||
u_int32_t *endpoint_state, u_int32_t *request_count));
|
||||
usbd_status usbd_set_interface_state
|
||||
__P((usbd_interface_handle iface, usbd_interface_state state));
|
||||
usbd_status usbd_get_interface_state
|
||||
__P((usbd_interface_handle iface, usbd_interface_state *state));
|
||||
usbd_status usbd_get_device_state
|
||||
__P((usbd_device_handle dev, usbd_device_state *state));
|
||||
usbd_status usbd_set_device_state
|
||||
__P((usbd_device_handle dev, usbd_device_state state));
|
||||
usbd_status usbd_device_address
|
||||
__P((usbd_device_handle dev, u_int8_t *address));
|
||||
usbd_status usbd_endpoint_address
|
||||
__P((usbd_pipe_handle dev, u_int8_t *address));
|
||||
usbd_status usbd_endpoint_count
|
||||
__P((usbd_interface_handle dev, u_int8_t *count));
|
||||
usbd_status usbd_interface_count
|
||||
__P((usbd_device_handle dev, u_int8_t *count));
|
||||
u_int8_t usbd_bus_count __P((void));
|
||||
usbd_status usbd_get_bus_handle __P((u_int8_t index, usbd_bus_handle *bus));
|
||||
usbd_status usbd_get_root_hub
|
||||
__P((usbd_bus_handle bus, usbd_device_handle *dev));
|
||||
usbd_status usbd_port_count __P((usbd_device_handle hub, u_int8_t *nports));
|
||||
usbd_status usbd_hub2device_handle
|
||||
__P((usbd_device_handle hub, u_int8_t port, usbd_device_handle *dev));
|
||||
usbd_status usbd_request2pipe_handle
|
||||
__P((usbd_request_handle reqh, usbd_pipe_handle *pipe));
|
||||
usbd_status usbd_pipe2interface_handle
|
||||
__P((usbd_pipe_handle pipe, usbd_interface_handle *iface));
|
||||
usbd_status usbd_interface2device_handle
|
||||
__P((usbd_interface_handle iface, usbd_device_handle *dev));
|
||||
usbd_status usbd_device2bus_handle
|
||||
__P((usbd_device_handle dev, usbd_bus_handle *bus));
|
||||
usbd_status usbd_device2interface_handle
|
||||
__P((usbd_device_handle dev, u_int8_t ifaceno,
|
||||
usbd_interface_handle *iface));
|
||||
usbd_status usbd_set_interface_private_handle
|
||||
__P((usbd_interface_handle iface, usbd_private_handle priv));
|
||||
usbd_status usbd_get_interface_private_handle
|
||||
__P((usbd_interface_handle iface, usbd_private_handle *priv));
|
||||
usbd_status usbd_reference_pipe __P((usbd_pipe_handle pipe));
|
||||
usbd_status usbd_dereference_pipe __P((usbd_pipe_handle pipe));
|
||||
usbd_lock_token usbd_lock __P((void));
|
||||
void usbd_unlock __P((usbd_lock_token tok));
|
||||
|
||||
/* Non-standard */
|
||||
usbd_status usbd_sync_transfer __P((usbd_request_handle req));
|
||||
usbd_status usbd_open_pipe_intr
|
||||
__P((usbd_interface_handle iface, u_int8_t address,
|
||||
u_int8_t flags, usbd_pipe_handle *pipe,
|
||||
usbd_private_handle priv, void *buffer,
|
||||
u_int32_t length, usbd_callback));
|
||||
usbd_status usbd_open_pipe_iso
|
||||
__P((usbd_interface_handle iface, u_int8_t address,
|
||||
u_int8_t flags, usbd_pipe_handle *pipe,
|
||||
usbd_private_handle priv, u_int32_t bufsize, u_int32_t nbuf,
|
||||
usbd_callback));
|
||||
usbd_status usbd_do_request
|
||||
__P((usbd_device_handle pipe, usb_device_request_t *req, void *data));
|
||||
usbd_status usbd_do_request_async
|
||||
__P((usbd_device_handle pipe, usb_device_request_t *req, void *data));
|
||||
usb_interface_descriptor_t *usbd_get_interface_descriptor
|
||||
__P((usbd_interface_handle iface));
|
||||
usb_config_descriptor_t *usbd_get_config_descriptor
|
||||
__P((usbd_device_handle dev));
|
||||
usb_device_descriptor_t *usbd_get_device_descriptor
|
||||
__P((usbd_device_handle dev));
|
||||
usbd_status usbd_set_interface __P((usbd_interface_handle, int));
|
||||
|
||||
void usbd_dopoll __P((usbd_interface_handle));
|
||||
void usbd_set_polling __P((usbd_interface_handle iface, int on));
|
||||
|
||||
/* NetBSD attachment information */
|
||||
|
||||
/* Attach data */
|
||||
struct usb_attach_arg {
|
||||
struct usbd_device *device;
|
||||
struct usbd_interface *iface;
|
||||
int usegeneric;
|
||||
};
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
/* Match codes. */
|
||||
/* First five codes is for a whole device. */
|
||||
#define UMATCH_VENDOR_PRODUCT_REV 14
|
||||
#define UMATCH_VENDOR_PRODUCT 13
|
||||
#define UMATCH_VENDOR_DEVCLASS_DEVPROTO 12
|
||||
#define UMATCH_DEVCLASS_DEVSUBCLASS_DEVPROTO 11
|
||||
#define UMATCH_DEVCLASS_DEVSUBCLASS 10
|
||||
/* Next six codes are for interfaces. */
|
||||
#define UMATCH_VENDOR_PRODUCT_REV_CONF_IFACE 9
|
||||
#define UMATCH_VENDOR_PRODUCT_CONF_IFACE 8
|
||||
#define UMATCH_VENDOR_IFACESUBCLASS_IFACEPROTO 7
|
||||
#define UMATCH_VENDOR_IFACESUBCLASS 6
|
||||
#define UMATCH_IFACECLASS_IFACESUBCLASS_IFACEPROTO 5
|
||||
#define UMATCH_IFACECLASS_IFACESUBCLASS 4
|
||||
#define UMATCH_IFACECLASS 3
|
||||
#define UMATCH_IFACECLASS_GENERIC 2
|
||||
/* Generic driver */
|
||||
#define UMATCH_GENERIC 1
|
||||
/* No match */
|
||||
#define UMATCH_NONE 0
|
||||
|
||||
#elif defined(__FreeBSD__)
|
||||
/* FreeBSD needs values less than zero */
|
||||
/* for the moment disabled
|
||||
#define UMATCH_VENDOR_PRODUCT_REV -14
|
||||
#define UMATCH_VENDOR_PRODUCT -13
|
||||
#define UMATCH_VENDOR_DEVCLASS_DEVPROTO -12
|
||||
#define UMATCH_DEVCLASS_DEVSUBCLASS_DEVPROTO -11
|
||||
#define UMATCH_DEVCLASS_DEVSUBCLASS -10
|
||||
#define UMATCH_VENDOR_PRODUCT_REV_CONF_IFACE -9
|
||||
#define UMATCH_VENDOR_PRODUCT_CONF_IFACE -8
|
||||
#define UMATCH_VENDOR_IFACESUBCLASS_IFACEPROTO -7
|
||||
#define UMATCH_VENDOR_IFACESUBCLASS -6
|
||||
#define UMATCH_IFACECLASS_IFACESUBCLASS_IFACEPROTO -5
|
||||
#define UMATCH_IFACECLASS_IFACESUBCLASS -4
|
||||
#define UMATCH_IFACECLASS -3
|
||||
#define UMATCH_IFACECLASS_GENERIC -2
|
||||
#define UMATCH_GENERIC -1
|
||||
#define UMATCH_NONE ENXIO
|
||||
|
||||
* For the moment we use Yes/No answers with appropriate
|
||||
* sorting in the config file
|
||||
*/
|
||||
#define UMATCH_VENDOR_PRODUCT_REV 0
|
||||
#define UMATCH_VENDOR_PRODUCT 0
|
||||
#define UMATCH_VENDOR_DEVCLASS_DEVPROTO 0
|
||||
#define UMATCH_DEVCLASS_DEVSUBCLASS_DEVPROTO 0
|
||||
#define UMATCH_DEVCLASS_DEVSUBCLASS 0
|
||||
#define UMATCH_VENDOR_PRODUCT_REV_CONF_IFACE 0
|
||||
#define UMATCH_VENDOR_PRODUCT_CONF_IFACE 0
|
||||
#define UMATCH_VENDOR_IFACESUBCLASS_IFACEPROTO 0
|
||||
#define UMATCH_VENDOR_IFACESUBCLASS 0
|
||||
#define UMATCH_IFACECLASS_IFACESUBCLASS_IFACEPROTO 0
|
||||
#define UMATCH_IFACECLASS_IFACESUBCLASS 0
|
||||
#define UMATCH_IFACECLASS 0
|
||||
#define UMATCH_IFACECLASS_GENERIC 0
|
||||
#define UMATCH_GENERIC 0
|
||||
#define UMATCH_NONE ENXIO
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
void usbd_devinfo __P((usbd_device_handle, int, char *));
|
||||
struct usbd_quirks *usbd_get_quirks __P((usbd_device_handle));
|
||||
void usbd_set_disco __P((usbd_pipe_handle, void (*)(void *), void *));
|
416
sys/dev/usb/usbdi_util.c
Normal file
416
sys/dev/usb/usbdi_util.c
Normal file
@ -0,0 +1,416 @@
|
||||
/* $NetBSD: usbdi_util.c,v 1.4 1998/08/02 22:30:53 augustss Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1998 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Lennart Augustsson <augustss@carlstedt.se>
|
||||
* 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 <dev/usb/usb_port.h>
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/malloc.h>
|
||||
#if defined(__NetBSD__)
|
||||
#include <sys/device.h>
|
||||
#endif
|
||||
#include <sys/proc.h>
|
||||
#include <sys/select.h>
|
||||
|
||||
#include <dev/usb/usb.h>
|
||||
#include <dev/usb/usbhid.h>
|
||||
|
||||
#include <dev/usb/usbdi.h>
|
||||
#include <dev/usb/usbdi_util.h>
|
||||
|
||||
#ifdef USB_DEBUG
|
||||
#define DPRINTF(x) if (usbdebug) printf x
|
||||
#define DPRINTFN(n,x) if (usbdebug>(n)) printf x
|
||||
extern int usbdebug;
|
||||
#else
|
||||
#define DPRINTF(x)
|
||||
#define DPRINTFN(n,x)
|
||||
#endif
|
||||
|
||||
usbd_status
|
||||
usbd_get_desc(dev, type, index, len, desc)
|
||||
usbd_device_handle dev;
|
||||
int type, index;
|
||||
int len;
|
||||
void *desc;
|
||||
{
|
||||
usb_device_request_t req;
|
||||
|
||||
req.bmRequestType = UT_READ_DEVICE;
|
||||
req.bRequest = UR_GET_DESCRIPTOR;
|
||||
USETW2(req.wValue, type, index);
|
||||
USETW(req.wIndex, 0);
|
||||
USETW(req.wLength, len);
|
||||
return (usbd_do_request(dev, &req, desc));
|
||||
}
|
||||
|
||||
usbd_status
|
||||
usbd_get_config_desc(dev, conf, d)
|
||||
usbd_device_handle dev;
|
||||
int conf;
|
||||
usb_config_descriptor_t *d;
|
||||
{
|
||||
DPRINTFN(3,("usbd_get_config_desc: conf=%d\n", conf));
|
||||
return (usbd_get_desc(dev, UDESC_CONFIG,
|
||||
conf, USB_CONFIG_DESCRIPTOR_SIZE, d));
|
||||
}
|
||||
|
||||
usbd_status
|
||||
usbd_get_config_desc_full(dev, conf, d, size)
|
||||
usbd_device_handle dev;
|
||||
int conf;
|
||||
void *d;
|
||||
int size;
|
||||
{
|
||||
DPRINTFN(3,("usbd_get_config_desc_full: conf=%d\n", conf));
|
||||
return (usbd_get_desc(dev, UDESC_CONFIG, conf, size, d));
|
||||
}
|
||||
|
||||
usbd_status
|
||||
usbd_get_device_desc(dev, d)
|
||||
usbd_device_handle dev;
|
||||
usb_device_descriptor_t *d;
|
||||
{
|
||||
DPRINTFN(3,("usbd_get_device_desc:\n"));
|
||||
return (usbd_get_desc(dev, UDESC_DEVICE,
|
||||
0, USB_DEVICE_DESCRIPTOR_SIZE, d));
|
||||
}
|
||||
|
||||
usbd_status
|
||||
usbd_get_device_status(dev, st)
|
||||
usbd_device_handle dev;
|
||||
usb_status_t *st;
|
||||
{
|
||||
usb_device_request_t req;
|
||||
|
||||
req.bmRequestType = UT_READ_DEVICE;
|
||||
req.bRequest = UR_GET_STATUS;
|
||||
USETW(req.wValue, 0);
|
||||
USETW(req.wIndex, 0);
|
||||
USETW(req.wLength, sizeof(usb_status_t));
|
||||
return (usbd_do_request(dev, &req, st));
|
||||
}
|
||||
|
||||
usbd_status
|
||||
usbd_get_hub_status(dev, st)
|
||||
usbd_device_handle dev;
|
||||
usb_hub_status_t *st;
|
||||
{
|
||||
usb_device_request_t req;
|
||||
|
||||
req.bmRequestType = UT_READ_CLASS_DEVICE;
|
||||
req.bRequest = UR_GET_STATUS;
|
||||
USETW(req.wValue, 0);
|
||||
USETW(req.wIndex, 0);
|
||||
USETW(req.wLength, sizeof(usb_hub_status_t));
|
||||
return (usbd_do_request(dev, &req, st));
|
||||
}
|
||||
|
||||
usbd_status
|
||||
usbd_set_address(dev, addr)
|
||||
usbd_device_handle dev;
|
||||
int addr;
|
||||
{
|
||||
usb_device_request_t req;
|
||||
|
||||
req.bmRequestType = UT_WRITE_DEVICE;
|
||||
req.bRequest = UR_SET_ADDRESS;
|
||||
USETW(req.wValue, addr);
|
||||
USETW(req.wIndex, 0);
|
||||
USETW(req.wLength, 0);
|
||||
return usbd_do_request(dev, &req, 0);
|
||||
}
|
||||
|
||||
usbd_status
|
||||
usbd_get_port_status(dev, port, ps)
|
||||
usbd_device_handle dev;
|
||||
int port;
|
||||
usb_port_status_t *ps;
|
||||
{
|
||||
usb_device_request_t req;
|
||||
|
||||
req.bmRequestType = UT_READ_CLASS_OTHER;
|
||||
req.bRequest = UR_GET_STATUS;
|
||||
USETW(req.wValue, 0);
|
||||
USETW(req.wIndex, port);
|
||||
USETW(req.wLength, sizeof *ps);
|
||||
return (usbd_do_request(dev, &req, ps));
|
||||
}
|
||||
|
||||
usbd_status
|
||||
usbd_clear_port_feature(dev, port, sel)
|
||||
usbd_device_handle dev;
|
||||
int port, sel;
|
||||
{
|
||||
usb_device_request_t req;
|
||||
|
||||
req.bmRequestType = UT_WRITE_CLASS_OTHER;
|
||||
req.bRequest = UR_CLEAR_FEATURE;
|
||||
USETW(req.wValue, sel);
|
||||
USETW(req.wIndex, port);
|
||||
USETW(req.wLength, 0);
|
||||
return (usbd_do_request(dev, &req, 0));
|
||||
}
|
||||
|
||||
usbd_status
|
||||
usbd_set_port_feature(dev, port, sel)
|
||||
usbd_device_handle dev;
|
||||
int port, sel;
|
||||
{
|
||||
usb_device_request_t req;
|
||||
|
||||
req.bmRequestType = UT_WRITE_CLASS_OTHER;
|
||||
req.bRequest = UR_SET_FEATURE;
|
||||
USETW(req.wValue, sel);
|
||||
USETW(req.wIndex, port);
|
||||
USETW(req.wLength, 0);
|
||||
return (usbd_do_request(dev, &req, 0));
|
||||
}
|
||||
|
||||
|
||||
usbd_status
|
||||
usbd_set_protocol(iface, report)
|
||||
usbd_interface_handle iface;
|
||||
int report;
|
||||
{
|
||||
usb_interface_descriptor_t *id = usbd_get_interface_descriptor(iface);
|
||||
usbd_device_handle dev;
|
||||
usb_device_request_t req;
|
||||
usbd_status r;
|
||||
|
||||
DPRINTFN(4, ("usbd_set_protocol: iface=%p, report=%d, endpt=%d\n",
|
||||
iface, report, id->bInterfaceNumber));
|
||||
r = usbd_interface2device_handle(iface, &dev);
|
||||
if (r != USBD_NORMAL_COMPLETION)
|
||||
return (r);
|
||||
if (!id)
|
||||
return (USBD_INVAL);
|
||||
req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
|
||||
req.bRequest = UR_SET_PROTOCOL;
|
||||
USETW(req.wValue, report);
|
||||
USETW(req.wIndex, id->bInterfaceNumber);
|
||||
USETW(req.wLength, 0);
|
||||
return (usbd_do_request(dev, &req, 0));
|
||||
}
|
||||
|
||||
usbd_status
|
||||
usbd_set_report(iface, type, id, data, len)
|
||||
usbd_interface_handle iface;
|
||||
int type;
|
||||
int id;
|
||||
void *data;
|
||||
int len;
|
||||
{
|
||||
usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface);
|
||||
usbd_device_handle dev;
|
||||
usb_device_request_t req;
|
||||
usbd_status r;
|
||||
|
||||
DPRINTFN(4, ("usbd_set_report: len=%d\n", len));
|
||||
r = usbd_interface2device_handle(iface, &dev);
|
||||
if (r != USBD_NORMAL_COMPLETION)
|
||||
return (r);
|
||||
if (!ifd)
|
||||
return (USBD_INVAL);
|
||||
req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
|
||||
req.bRequest = UR_SET_REPORT;
|
||||
USETW2(req.wValue, type, id);
|
||||
USETW(req.wIndex, ifd->bInterfaceNumber);
|
||||
USETW(req.wLength, len);
|
||||
return (usbd_do_request(dev, &req, data));
|
||||
}
|
||||
|
||||
usbd_status
|
||||
usbd_set_report_async(iface, type, id, data, len)
|
||||
usbd_interface_handle iface;
|
||||
int type;
|
||||
int id;
|
||||
void *data;
|
||||
int len;
|
||||
{
|
||||
usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface);
|
||||
usbd_device_handle dev;
|
||||
usb_device_request_t req;
|
||||
usbd_status r;
|
||||
|
||||
DPRINTFN(4, ("usbd_set_report_async: len=%d\n", len));
|
||||
r = usbd_interface2device_handle(iface, &dev);
|
||||
if (r != USBD_NORMAL_COMPLETION)
|
||||
return (r);
|
||||
if (!ifd)
|
||||
return (USBD_INVAL);
|
||||
req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
|
||||
req.bRequest = UR_SET_REPORT;
|
||||
USETW2(req.wValue, type, id);
|
||||
USETW(req.wIndex, ifd->bInterfaceNumber);
|
||||
USETW(req.wLength, len);
|
||||
return (usbd_do_request_async(dev, &req, data));
|
||||
}
|
||||
|
||||
usbd_status
|
||||
usbd_get_report(iface, type, id, data, len)
|
||||
usbd_interface_handle iface;
|
||||
int type;
|
||||
int id;
|
||||
void *data;
|
||||
int len;
|
||||
{
|
||||
usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface);
|
||||
usbd_device_handle dev;
|
||||
usb_device_request_t req;
|
||||
usbd_status r;
|
||||
|
||||
DPRINTFN(4, ("usbd_set_report: len=%d\n", len));
|
||||
r = usbd_interface2device_handle(iface, &dev);
|
||||
if (r != USBD_NORMAL_COMPLETION)
|
||||
return (r);
|
||||
if (!ifd)
|
||||
return (USBD_INVAL);
|
||||
req.bmRequestType = UT_READ_CLASS_INTERFACE;
|
||||
req.bRequest = UR_GET_REPORT;
|
||||
USETW2(req.wValue, type, id);
|
||||
USETW(req.wIndex, ifd->bInterfaceNumber);
|
||||
USETW(req.wLength, len);
|
||||
return (usbd_do_request(dev, &req, data));
|
||||
}
|
||||
|
||||
usbd_status
|
||||
usbd_set_idle(iface, duration, id)
|
||||
usbd_interface_handle iface;
|
||||
int duration;
|
||||
int id;
|
||||
{
|
||||
usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface);
|
||||
usbd_device_handle dev;
|
||||
usb_device_request_t req;
|
||||
usbd_status r;
|
||||
|
||||
DPRINTFN(4, ("usbd_set_idle: %d %d\n", duration, id));
|
||||
r = usbd_interface2device_handle(iface, &dev);
|
||||
if (r != USBD_NORMAL_COMPLETION)
|
||||
return (r);
|
||||
if (!ifd)
|
||||
return (USBD_INVAL);
|
||||
req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
|
||||
req.bRequest = UR_SET_IDLE;
|
||||
USETW2(req.wValue, duration, id);
|
||||
USETW(req.wIndex, ifd->bInterfaceNumber);
|
||||
USETW(req.wLength, 0);
|
||||
return (usbd_do_request(dev, &req, 0));
|
||||
}
|
||||
|
||||
usbd_status
|
||||
usbd_get_report_descriptor(dev, i, size, d)
|
||||
usbd_device_handle dev;
|
||||
int i;
|
||||
int size;
|
||||
void *d;
|
||||
{
|
||||
usb_device_request_t req;
|
||||
|
||||
req.bmRequestType = UT_READ_INTERFACE;
|
||||
req.bRequest = UR_GET_DESCRIPTOR;
|
||||
USETW2(req.wValue, UDESC_REPORT, 0);
|
||||
USETW(req.wIndex, i);
|
||||
USETW(req.wLength, size);
|
||||
return (usbd_do_request(dev, &req, d));
|
||||
}
|
||||
|
||||
usb_hid_descriptor_t *
|
||||
usbd_get_hid_descriptor(ifc)
|
||||
usbd_interface_handle ifc;
|
||||
{
|
||||
usb_interface_descriptor_t *idesc = usbd_get_interface_descriptor(ifc);
|
||||
usbd_device_handle dev;
|
||||
usb_config_descriptor_t *cdesc;
|
||||
usb_hid_descriptor_t *hd;
|
||||
char *p, *end;
|
||||
usbd_status r;
|
||||
|
||||
r = usbd_interface2device_handle(ifc, &dev);
|
||||
if (r != USBD_NORMAL_COMPLETION)
|
||||
return (0);
|
||||
cdesc = usbd_get_config_descriptor(dev);
|
||||
|
||||
p = (char *)idesc + idesc->bLength;
|
||||
end = (char *)cdesc + UGETW(cdesc->wTotalLength);
|
||||
|
||||
for (; p < end; p += hd->bLength) {
|
||||
hd = (usb_hid_descriptor_t *)p;
|
||||
if (p + hd->bLength <= end && hd->bDescriptorType == UDESC_HID)
|
||||
return (hd);
|
||||
if (hd->bDescriptorType == UDESC_INTERFACE)
|
||||
break;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
usbd_status
|
||||
usbd_alloc_report_desc(ifc, descp, sizep, mem)
|
||||
usbd_interface_handle ifc;
|
||||
void **descp;
|
||||
int *sizep;
|
||||
#if defined(__NetBSD__)
|
||||
int mem;
|
||||
#elif defined(__FreeBSD__)
|
||||
struct malloc_type *mem;
|
||||
#endif
|
||||
|
||||
{
|
||||
usb_hid_descriptor_t *hid;
|
||||
usbd_device_handle dev;
|
||||
usbd_status r;
|
||||
|
||||
r = usbd_interface2device_handle(ifc, &dev);
|
||||
if (r != USBD_NORMAL_COMPLETION)
|
||||
return (r);
|
||||
hid = usbd_get_hid_descriptor(ifc);
|
||||
if (!hid)
|
||||
return (USBD_IOERROR);
|
||||
*sizep = UGETW(hid->descrs[0].wDescriptorLength);
|
||||
*descp = malloc(*sizep, mem, M_NOWAIT);
|
||||
if (!*descp)
|
||||
return (USBD_NOMEM);
|
||||
r = usbd_get_report_descriptor(dev, 0, *sizep, *descp);
|
||||
if (r != USBD_NORMAL_COMPLETION) {
|
||||
free(*descp, mem);
|
||||
return (r);
|
||||
}
|
||||
return (USBD_NORMAL_COMPLETION);
|
||||
}
|
74
sys/dev/usb/usbdi_util.h
Normal file
74
sys/dev/usb/usbdi_util.h
Normal file
@ -0,0 +1,74 @@
|
||||
/* $NetBSD: usbdi_util.h,v 1.4 1998/08/02 22:30:53 augustss Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1998 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Lennart Augustsson <augustss@carlstedt.se>
|
||||
* 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.
|
||||
*/
|
||||
|
||||
usbd_status usbd_get_desc __P((usbd_device_handle dev, int type,
|
||||
int index, int len, void *desc));
|
||||
usbd_status usbd_get_config_desc __P((usbd_device_handle, int,
|
||||
usb_config_descriptor_t *));
|
||||
usbd_status usbd_get_config_desc_full __P((usbd_device_handle, int,
|
||||
void *, int));
|
||||
usbd_status usbd_get_device_desc __P((usbd_device_handle dev,
|
||||
usb_device_descriptor_t *d));
|
||||
usbd_status usbd_set_address __P((usbd_device_handle dev, int addr));
|
||||
usbd_status usbd_get_port_status __P((usbd_device_handle,
|
||||
int, usb_port_status_t *));
|
||||
usbd_status usbd_set_port_feature __P((usbd_device_handle dev, int, int));
|
||||
usbd_status usbd_clear_port_feature __P((usbd_device_handle, int, int));
|
||||
usbd_status usbd_get_device_status __P((usbd_device_handle,usb_status_t*));
|
||||
usbd_status usbd_get_hub_status __P((usbd_device_handle dev,
|
||||
usb_hub_status_t *st));
|
||||
usbd_status usbd_set_protocol __P((usbd_interface_handle dev, int report));
|
||||
usbd_status usbd_get_report_descriptor
|
||||
__P((usbd_device_handle dev, int i, int size, void *d));
|
||||
struct usb_hid_descriptor *usbd_get_hid_descriptor
|
||||
__P((usbd_interface_handle ifc));
|
||||
usbd_status usbd_set_report
|
||||
__P((usbd_interface_handle iface,int type,int id,void *data,int len));
|
||||
usbd_status usbd_set_report_async
|
||||
__P((usbd_interface_handle iface,int type,int id,void *data,int len));
|
||||
usbd_status usbd_get_report
|
||||
__P((usbd_interface_handle iface,int type,int id,void *data,int len));
|
||||
usbd_status usbd_set_idle
|
||||
__P((usbd_interface_handle iface, int duration, int id));
|
||||
#if defined(__NetBSD__)
|
||||
usbd_status usbd_alloc_report_desc
|
||||
__P((usbd_interface_handle ifc, void **descp, int *sizep, int mem));
|
||||
#elif defined(__FreeBSD__)
|
||||
usbd_status usbd_alloc_report_desc
|
||||
__P((usbd_interface_handle ifc, void **descp, int *sizep, struct malloc_type * mem));
|
||||
#endif
|
231
sys/dev/usb/usbdivar.h
Normal file
231
sys/dev/usb/usbdivar.h
Normal file
@ -0,0 +1,231 @@
|
||||
/*
|
||||
* Copyright (c) 1998 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Lennart Augustsson <augustss@carlstedt.se>
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
/* conversiom from one type of queue to the other */
|
||||
#define SIMPLEQ_REMOVE_HEAD STAILQ_REMOVE_HEAD_QUEUE
|
||||
#define SIMPLEQ_INSERT_HEAD STAILQ_INSERT_HEAD
|
||||
#define SIMPLEQ_INSERT_TAIL STAILQ_INSERT_TAIL
|
||||
#define SIMPLEQ_NEXT STAILQ_NEXT
|
||||
#define SIMPLEQ_FIRST STAILQ_FIRST
|
||||
#define SIMPLEQ_HEAD STAILQ_HEAD
|
||||
#define SIMPLEQ_INIT STAILQ_INIT
|
||||
#define SIMPLEQ_ENTRY STAILQ_ENTRY
|
||||
#endif
|
||||
|
||||
struct usbd_request;
|
||||
struct usbd_pipe;
|
||||
|
||||
struct usbd_endpoint {
|
||||
usb_endpoint_descriptor_t *edesc;
|
||||
usbd_endpoint_state state;
|
||||
int refcnt;
|
||||
int toggle; /* XXX */
|
||||
};
|
||||
|
||||
typedef void (*usbd_xfercb)__P((usbd_request_handle req));
|
||||
|
||||
struct usbd_methods {
|
||||
usbd_status (*transfer)__P((usbd_request_handle reqh));
|
||||
void (*abort)__P((usbd_request_handle reqh));
|
||||
void (*close)__P((usbd_pipe_handle pipe));
|
||||
usbd_status (*isobuf)__P((usbd_pipe_handle pipe,
|
||||
u_int32_t bufsize,u_int32_t nbuf));
|
||||
};
|
||||
|
||||
struct usbd_port {
|
||||
usb_port_status_t status;
|
||||
int power; /* mA of current on port */
|
||||
struct usbd_device *device;
|
||||
struct usbd_device *parent; /* The ports hub */
|
||||
};
|
||||
|
||||
struct usbd_hub {
|
||||
usbd_status (*explore)__P((usbd_device_handle hub));
|
||||
void *hubdata;
|
||||
usb_hub_descriptor_t hubdesc;
|
||||
int nports;
|
||||
struct usbd_port ports[1];
|
||||
};
|
||||
|
||||
struct usb_softc;
|
||||
|
||||
/*****/
|
||||
|
||||
struct usbd_bus {
|
||||
/* Filled by HC driver */
|
||||
bdevice bdev; /* base device, host adapter */
|
||||
usbd_status (*open_pipe)__P((struct usbd_pipe *pipe));
|
||||
u_int32_t pipe_size; /* size of a pipe struct */
|
||||
void (*do_poll)__P((struct usbd_bus *));
|
||||
/* Filled by usb driver */
|
||||
struct usbd_device *root_hub;
|
||||
usbd_device_handle devices[USB_MAX_DEVICES];
|
||||
char needs_explore;/* a hub a signalled a change */
|
||||
char use_polling;
|
||||
struct usb_softc *usbctl;
|
||||
struct usb_device_stats stats;
|
||||
};
|
||||
|
||||
struct usbd_device {
|
||||
struct usbd_bus *bus;
|
||||
usbd_device_state state;
|
||||
struct usbd_pipe *default_pipe;
|
||||
u_int8_t address;
|
||||
u_int8_t depth;
|
||||
u_int8_t lowspeed;
|
||||
u_int16_t power;
|
||||
u_int8_t self_powered;
|
||||
int config;
|
||||
struct usbd_port *powersrc;
|
||||
struct usbd_endpoint def_ep; /* for pipe 0 */
|
||||
usb_endpoint_descriptor_t def_ep_desc; /* for pipe 0 */
|
||||
struct usbd_interface *ifaces;
|
||||
usb_device_descriptor_t ddesc;
|
||||
usb_config_descriptor_t *cdesc; /* full config descr */
|
||||
struct usbd_quirks *quirks;
|
||||
struct usbd_hub *hub; /* only if this is a hub */
|
||||
#if defined(__FreeBSD__)
|
||||
bdevice bdev; /* base device */
|
||||
#endif
|
||||
};
|
||||
|
||||
struct usbd_interface {
|
||||
struct usbd_device *device;
|
||||
usbd_interface_state state;
|
||||
usb_interface_descriptor_t *idesc;
|
||||
struct usbd_endpoint *endpoints;
|
||||
void *priv;
|
||||
LIST_HEAD(, usbd_pipe) pipes;
|
||||
};
|
||||
|
||||
struct usbd_pipe {
|
||||
struct usbd_interface *iface;
|
||||
struct usbd_device *device;
|
||||
struct usbd_endpoint *endpoint;
|
||||
usbd_pipe_state state;
|
||||
int32_t refcnt;
|
||||
char running;
|
||||
SIMPLEQ_HEAD(, usbd_request) queue;
|
||||
LIST_ENTRY(usbd_pipe) next;
|
||||
|
||||
void (*disco) __P((void *));
|
||||
void *discoarg;
|
||||
|
||||
usbd_request_handle intrreqh; /* used for repeating requests */
|
||||
usbd_request_handle curreqh; /* currently running request */
|
||||
|
||||
/* Filled by HC driver. */
|
||||
struct usbd_methods *methods;
|
||||
};
|
||||
|
||||
struct usbd_request {
|
||||
struct usbd_pipe *pipe;
|
||||
void *priv;
|
||||
void *buffer;
|
||||
u_int32_t length;
|
||||
u_int32_t actlen;
|
||||
u_int16_t flags;
|
||||
u_int32_t timeout;
|
||||
usbd_status status;
|
||||
usbd_callback callback;
|
||||
usbd_xfercb xfercb;
|
||||
u_int32_t retries;
|
||||
char done;
|
||||
|
||||
usb_device_request_t request;
|
||||
u_int8_t isreq;
|
||||
|
||||
SIMPLEQ_ENTRY(usbd_request) next;
|
||||
|
||||
void *hcpriv; /* XXX private use by the HC driver */
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
struct callout_handle callout_handler;
|
||||
#endif
|
||||
};
|
||||
|
||||
void usbd_init __P((void));
|
||||
|
||||
/* Routines from usb_subr.c */
|
||||
int usbctlprint __P((void *, const char *));
|
||||
void usbd_delay_ms __P((usbd_bus_handle, int));
|
||||
void usbd_devinfo_vp __P((usbd_device_handle, char *, char *));
|
||||
usbd_status usbd_set_config_no __P((usbd_device_handle, int, int));
|
||||
usbd_status usbd_reset_port __P((usbd_device_handle dev,
|
||||
int port, usb_port_status_t *ps));
|
||||
usbd_status usbd_setup_pipe __P((usbd_device_handle dev,
|
||||
usbd_interface_handle iface,
|
||||
struct usbd_endpoint *,
|
||||
usbd_pipe_handle *pipe));
|
||||
usbd_status usbd_new_device __P((bdevice *parent,
|
||||
usbd_bus_handle bus, int depth,
|
||||
int lowspeed, int port,
|
||||
struct usbd_port *));
|
||||
void usbd_remove_device __P((usbd_device_handle,
|
||||
struct usbd_port *));
|
||||
int usbd_printBCD __P((char *cp, int bcd));
|
||||
|
||||
/* Routines from usb.c */
|
||||
int usb_bus_count __P((void));
|
||||
usbd_status usb_get_bus_handle __P((int, usbd_bus_handle *));
|
||||
void usb_needs_explore __P((usbd_bus_handle));
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
int usb_driver_load __P((module_t mod, modeventtype_t what,
|
||||
void *arg));
|
||||
void usb_device_set_desc __P((device_t device, char *devinfo));
|
||||
#endif
|
||||
|
||||
extern int usbd_use_polling;
|
||||
|
||||
/* Locator stuff. */
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
/* NWH File not found anywhere in NetBSD sources... */
|
||||
#include "locators.h"
|
||||
#endif
|
||||
|
||||
#define uhubcf_port cf_loc[UHUBCF_PORT]
|
||||
#define UHUB_UNK_PORT UHUBCF_PORT_DEFAULT /* wildcarded 'port' */
|
||||
|
||||
/* Junk. */
|
||||
|
||||
/* XXX */
|
||||
#define splusb splbio
|
||||
#define IPL_USB IPL_BIO
|
||||
/* XXX */
|
||||
|
133
sys/dev/usb/usbhid.h
Normal file
133
sys/dev/usb/usbhid.h
Normal file
@ -0,0 +1,133 @@
|
||||
/* $NetBSD: usbhid.h,v 1.1 1998/07/12 19:52:01 augustss Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1998 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Lennart Augustsson <augustss@carlstedt.se>
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _USBHID_H_
|
||||
#define _USBHID_H_
|
||||
|
||||
#define UR_GET_HID_DESCRIPTOR 0x06
|
||||
#define UDESC_HID 0x21
|
||||
#define UDESC_REPORT 0x22
|
||||
#define UDESC_PHYSICAL 0x23
|
||||
#define UR_SET_HID_DESCRIPTOR 0x07
|
||||
#define UR_GET_REPORT 0x01
|
||||
#define UR_SET_REPORT 0x09
|
||||
#define UR_GET_IDLE 0x02
|
||||
#define UR_SET_IDLE 0x0a
|
||||
#define UR_GET_PROTOCOL 0x03
|
||||
#define UR_SET_PROTOCOL 0x0b
|
||||
|
||||
typedef struct usb_hid_descriptor {
|
||||
uByte bLength;
|
||||
uByte bDescriptorType;
|
||||
uWord bcdHID;
|
||||
uByte bCountryCode;
|
||||
uByte bNumDescriptors;
|
||||
struct {
|
||||
uByte bDescriptorType;
|
||||
uWord wDescriptorLength;
|
||||
} descrs[1];
|
||||
} usb_hid_descriptor_t;
|
||||
#define USB_HID_DESCRIPTOR_SIZE(n) (9+(n)*3)
|
||||
|
||||
/* Usage pages */
|
||||
#define HUP_GENERIC_DESKTOP 0x0001
|
||||
#define HUP_SIMULATION 0x0002
|
||||
#define HUP_LEDS 0x0008
|
||||
#define HUP_BUTTON 0x0009
|
||||
|
||||
/* Usages, generic desktop */
|
||||
#define HUG_POINTER 0x0001
|
||||
#define HUG_MOUSE 0x0002
|
||||
#define HUG_JOYSTICK 0x0004
|
||||
#define HUG_GAME_PAD 0x0005
|
||||
#define HUG_KEYBOARD 0x0006
|
||||
#define HUG_KEYPAD 0x0007
|
||||
#define HUG_X 0x0030
|
||||
#define HUG_Y 0x0031
|
||||
#define HUG_Z 0x0032
|
||||
#define HUG_RX 0x0033
|
||||
#define HUG_RY 0x0034
|
||||
#define HUG_RZ 0x0035
|
||||
#define HUG_SLIDER 0x0036
|
||||
#define HUG_DIAL 0x0037
|
||||
#define HUG_WHEEL 0x0038
|
||||
#define HUG_HAT_SWITCH 0x0039
|
||||
#define HUG_COUNTED_BUFFER 0x003a
|
||||
#define HUG_BYTE_COUNT 0x003b
|
||||
#define HUG_MOTION_WAKEUP 0x003c
|
||||
#define HUG_VX 0x0040
|
||||
#define HUG_VY 0x0041
|
||||
#define HUG_VZ 0x0042
|
||||
#define HUG_VBRX 0x0043
|
||||
#define HUG_VBRY 0x0044
|
||||
#define HUG_VBRZ 0x0045
|
||||
#define HUG_VNO 0x0046
|
||||
#define HUG_SYSTEM_CONTROL 0x0080
|
||||
#define HUG_SYSTEM_POWER_DOWN 0x0081
|
||||
#define HUG_SYSTEM_SLEEP 0x0082
|
||||
#define HUG_SYSTEM_WAKEUP 0x0083
|
||||
#define HUG_SYSTEM_CONTEXT_MENU 0x0084
|
||||
#define HUG_SYSTEM_MAIN_MENU 0x0085
|
||||
#define HUG_SYSTEM_APP_MENU 0x0086
|
||||
#define HUG_SYSTEM_MENU_HELP 0x0087
|
||||
#define HUG_SYSTEM_MENU_EXIT 0x0088
|
||||
#define HUG_SYSTEM_MENU_SELECT 0x0089
|
||||
#define HUG_SYSTEM_MENU_RIGHT 0x008a
|
||||
#define HUG_SYSTEM_MENU_LEFT 0x008b
|
||||
#define HUG_SYSTEM_MENU_UP 0x008c
|
||||
#define HUG_SYSTEM_MENU_DOWN 0x008d
|
||||
|
||||
#define HID_USAGE2(p,u) (((p) << 16) | u)
|
||||
|
||||
#define UHID_INPUT_REPORT 0x01
|
||||
#define UHID_OUTPUT_REPORT 0x02
|
||||
#define UHID_FEATURE_REPORT 0x03
|
||||
|
||||
/* Bits in the input/output/feature items */
|
||||
#define HIO_CONST 0x001
|
||||
#define HIO_VARIABLE 0x002
|
||||
#define HIO_RELATIVE 0x004
|
||||
#define HIO_WRAP 0x008
|
||||
#define HIO_NONLINEAR 0x010
|
||||
#define HIO_NOPREF 0x020
|
||||
#define HIO_NULLSTATE 0x040
|
||||
#define HIO_VOLATILE 0x080
|
||||
#define HIO_BUFBYTES 0x100
|
||||
|
||||
#endif /* _USBHID_H_ */
|
@ -11,7 +11,7 @@
|
||||
# device lines is present in the ./LINT configuration file. If you are
|
||||
# in doubt as to the purpose or necessity of a line, check first in LINT.
|
||||
#
|
||||
# $Id: GENERIC,v 1.130 1998/11/03 22:01:21 des Exp $
|
||||
# $Id: GENERIC,v 1.131 1998/11/12 11:29:28 obrien Exp $
|
||||
|
||||
machine "i386"
|
||||
cpu "I386_CPU"
|
||||
@ -179,3 +179,22 @@ options SYSVSHM
|
||||
# option. The number of devices determines the maximum number of
|
||||
# simultaneous BPF clients programs runnable.
|
||||
#pseudo-device bpfilter 4 #Berkeley packet filter
|
||||
|
||||
|
||||
# USB support
|
||||
#controller uhci0
|
||||
#controller usb0
|
||||
#
|
||||
# for the moment we have to specify the priorities of the device
|
||||
# drivers explicitly by the ordering in the list below. This will
|
||||
# be changed in the future.
|
||||
#
|
||||
#device ums0
|
||||
#device ukbd0
|
||||
#device ulpt0
|
||||
#device uhub0
|
||||
#device hid0
|
||||
#device ugen0
|
||||
#
|
||||
#options USB_DEBUG
|
||||
#options USBVERBOSE
|
||||
|
15
usr.sbin/usbd/Makefile
Normal file
15
usr.sbin/usbd/Makefile
Normal file
@ -0,0 +1,15 @@
|
||||
# FIXME have a look at all the other files and align it
|
||||
|
||||
PROG= usbd
|
||||
MAN= usbd.8
|
||||
|
||||
# for FreeBSD we need MAN8 instead of MAN
|
||||
MAN8= usbd.8
|
||||
|
||||
# This hard coded path is not necessary as soon as we are in the
|
||||
# base FreeBSD system. The .h files will be in /usr/include by then.
|
||||
#
|
||||
CFLAGS += -I../../sys
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
.include <bsd.subdir.mk>
|
80
usr.sbin/usbd/usbd.8
Normal file
80
usr.sbin/usbd/usbd.8
Normal file
@ -0,0 +1,80 @@
|
||||
.\" $NetBSD: usbd.8,v 1.2 1998/07/13 11:01:50 augustss Exp $
|
||||
.\" Copyright (c) 1998 The NetBSD Foundation, Inc.
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" Author: Lennart Augustsson
|
||||
.\"
|
||||
.\" 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.
|
||||
.\"
|
||||
.Dd July 12, 1998
|
||||
.Dt USBD 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm usbd
|
||||
.Nd supervise USB attach/detach
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl d
|
||||
.Op Fl f Ar device
|
||||
.Op Fl t Ar timeout
|
||||
.Op Fl v
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
handles the USB device attachment and detachment.
|
||||
.Pp
|
||||
The options are as follows:
|
||||
.Bl -tag -width Ds
|
||||
.It Fl d
|
||||
Enable debugging to the standard output,
|
||||
and do not disassociate from the controlling terminal.
|
||||
.It Fl e
|
||||
Do one device tree exploration and then exit.
|
||||
.It Fl f Ar device
|
||||
Specify the pathname of a USB controller device file.
|
||||
The flag may be repeated to watch more than one USB controller.
|
||||
The default is
|
||||
.Pa /dev/usb0 ,
|
||||
.Pa /dev/usb1 ,
|
||||
.Pa /dev/usb2 ,
|
||||
and
|
||||
.Pa /dev/usb3 .
|
||||
.It Fl t Ar timeout
|
||||
Set the timeout interval (in seconds) before an exploration happens
|
||||
without being triggered by a connect or disconnect.
|
||||
A timeout of 0 means that there is no timeout. The default is 30.
|
||||
.It Fl v
|
||||
Be verbose.
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr usb 4
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm
|
||||
command appeared in
|
||||
.Nx 1.4 .
|
183
usr.sbin/usbd/usbd.c
Normal file
183
usr.sbin/usbd/usbd.c
Normal file
@ -0,0 +1,183 @@
|
||||
/* $NetBSD: usbd.c,v 1.2 1998/07/23 18:39:53 augustss Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1998 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Lennart Augustsson
|
||||
*
|
||||
* 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 <err.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#if defined(__FreeBSD__)
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/malloc.h>
|
||||
#endif
|
||||
#include <dev/usb/usb.h>
|
||||
|
||||
#define USBDEV "/dev/usb"
|
||||
#define MAXUSBDEV 4
|
||||
|
||||
extern char *__progname;
|
||||
|
||||
void usage(void);
|
||||
|
||||
void
|
||||
usage(void)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s [-d] [-e] [-f dev] [-t timeout] [-v]\n",
|
||||
__progname);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#define NDEVS 20 /* maximum number of usb controllers */
|
||||
|
||||
/*
|
||||
* Sometimes a device does not respond in time for interrupt
|
||||
* driven explore to find it. Therefore we run an exploration
|
||||
* at regular intervals to catch those.
|
||||
*/
|
||||
#define TIMEOUT 30
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int r, i;
|
||||
char *devs[NDEVS];
|
||||
int ndevs = 0;
|
||||
int fds[NDEVS];
|
||||
fd_set fdset;
|
||||
int ch, verbose = 0;
|
||||
int debug = 0;
|
||||
int explore = 0;
|
||||
int itimo = TIMEOUT;
|
||||
int maxfd;
|
||||
char buf[50];
|
||||
struct timeval timo;
|
||||
extern char *optarg;
|
||||
extern int optind;
|
||||
|
||||
while ((ch = getopt(argc, argv, "def:t:v")) != -1) {
|
||||
switch(ch) {
|
||||
case 'd':
|
||||
debug++;
|
||||
break;
|
||||
case 'e':
|
||||
explore++;
|
||||
break;
|
||||
case 'f':
|
||||
if (ndevs < NDEVS)
|
||||
devs[ndevs++] = optarg;
|
||||
break;
|
||||
case 't':
|
||||
itimo = atoi(optarg);
|
||||
break;
|
||||
case 'v':
|
||||
verbose++;
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
maxfd = 0;
|
||||
if (ndevs == 0) {
|
||||
for (i = 0; i < MAXUSBDEV; i++) {
|
||||
sprintf(buf, "%s%d", USBDEV, i);
|
||||
fds[ndevs] = open(buf, O_RDWR);
|
||||
if (fds[ndevs] >= 0) {
|
||||
devs[ndevs] = strdup(buf);
|
||||
if (verbose)
|
||||
printf("%s: opening %s\n",
|
||||
__progname, devs[ndevs]);
|
||||
if (fds[ndevs] > maxfd)
|
||||
maxfd = fds[ndevs];
|
||||
ndevs++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < ndevs; i++) {
|
||||
fds[i] = open(devs[i], O_RDWR);
|
||||
if (fds[i] < 0)
|
||||
err(1, "%s", devs[i]);
|
||||
else if (fds[i] > maxfd)
|
||||
maxfd = fds[i];
|
||||
}
|
||||
}
|
||||
if (ndevs == 0) {
|
||||
if (verbose)
|
||||
printf("%s: no USB controllers found\n", __progname);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (explore) {
|
||||
for (i = 0; i < ndevs; i++) {
|
||||
r = ioctl(fds[i], USB_DISCOVER);
|
||||
if (r < 0)
|
||||
err(1, "USB_DISCOVER");
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (!debug)
|
||||
daemon(0, 0);
|
||||
|
||||
|
||||
|
||||
FD_ZERO(&fdset);
|
||||
for (;;) {
|
||||
for (i = 0; i < ndevs; i++)
|
||||
FD_SET(fds[i], &fdset);
|
||||
timo.tv_usec = 0;
|
||||
timo.tv_sec = itimo;
|
||||
r = select(maxfd+1, &fdset, &fdset, 0, itimo ? &timo : 0);
|
||||
if (r < 0)
|
||||
warn("select failed\n");
|
||||
for (i = 0; i < ndevs; i++)
|
||||
if (r == 0 || FD_ISSET(fds[i], &fdset)) {
|
||||
if (verbose)
|
||||
printf("%s: doing %sdiscovery on %s\n",
|
||||
__progname, r ? "" : "timeout ",
|
||||
devs[i]);
|
||||
if (ioctl(fds[i], USB_DISCOVER) < 0)
|
||||
err(1, "USB_DISCOVER");
|
||||
}
|
||||
}
|
||||
}
|
8
usr.sbin/usbdevs/Makefile
Normal file
8
usr.sbin/usbdevs/Makefile
Normal file
@ -0,0 +1,8 @@
|
||||
# $NetBSD: Makefile,v 1.2 1998/07/12 20:40:45 augustss Exp $
|
||||
|
||||
PROG= usbdevs
|
||||
MAN8= usbdevs.8
|
||||
CFLAGS+=-I../..//sys
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
.include <bsd.subdir.mk>
|
67
usr.sbin/usbdevs/usbdevs.8
Normal file
67
usr.sbin/usbdevs/usbdevs.8
Normal file
@ -0,0 +1,67 @@
|
||||
.\" $NetBSD: usbdevs.8,v 1.3 1998/07/23 13:57:51 augustss Exp $
|
||||
.\" Copyright (c) 1998 The NetBSD Foundation, Inc.
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" Author: Lennart Augustsson
|
||||
.\"
|
||||
.\" 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.
|
||||
.\"
|
||||
.Dd July 12, 1998
|
||||
.Dt USBDEVS 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm usbdevs
|
||||
.Nd show USB devices connected to the system
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl a Ar addr
|
||||
.Op Fl f Ar dev
|
||||
.Op Fl v
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
prints a listing of all USB devices connected to the system
|
||||
with some information about each device.
|
||||
The indentation of each line indicates its distance from the root.
|
||||
.Pp
|
||||
The options are as follows:
|
||||
.Bl -tag -width Ds
|
||||
.It Fl a Ar addr
|
||||
only print information about the device at the given address.
|
||||
.It Fl f Ar dev
|
||||
only print information for the given USB controller.
|
||||
.It Fl v
|
||||
Be verbose.
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr usb 4
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm
|
||||
command appeared in
|
||||
.Nx 1.4 .
|
212
usr.sbin/usbdevs/usbdevs.c
Normal file
212
usr.sbin/usbdevs/usbdevs.c
Normal file
@ -0,0 +1,212 @@
|
||||
/* $NetBSD: usbdevs.c,v 1.4 1998/07/23 13:57:51 augustss Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1998 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Lennart Augustsson
|
||||
*
|
||||
* 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <dev/usb/usb.h>
|
||||
#if defined(__FreeBSD__)
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
#define USBDEV "/dev/usb"
|
||||
|
||||
int verbose;
|
||||
|
||||
void usage __P((void));
|
||||
void usbdev __P((int f, int a, int rec));
|
||||
void usbdump __P((int f));
|
||||
void dumpone __P((char *name, int f, int addr));
|
||||
int main __P((int, char **));
|
||||
|
||||
extern char *__progname;
|
||||
|
||||
void
|
||||
usage()
|
||||
{
|
||||
fprintf(stderr, "Usage: %s [-a addr] [-f dev] [-v]\n", __progname);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
char done[USB_MAX_DEVICES];
|
||||
int indent;
|
||||
|
||||
void
|
||||
usbdev(f, a, rec)
|
||||
int f;
|
||||
int a;
|
||||
int rec;
|
||||
{
|
||||
struct usb_device_info di;
|
||||
int e, p;
|
||||
|
||||
di.addr = a;
|
||||
e = ioctl(f, USB_DEVICEINFO, &di);
|
||||
if (e)
|
||||
return;
|
||||
done[a] = 1;
|
||||
printf("addr %d: ", di.addr);
|
||||
if (verbose) {
|
||||
if (di.lowspeed)
|
||||
printf("low speed, ");
|
||||
if (di.power)
|
||||
printf("power %d mA, ", di.power);
|
||||
else
|
||||
printf("self powered, ");
|
||||
if (di.config)
|
||||
printf("config %d, ", di.config);
|
||||
else
|
||||
printf("unconfigured, ");
|
||||
}
|
||||
printf("%s, %s", di.product, di.vendor);
|
||||
if (verbose)
|
||||
printf(", rev %s", di.revision);
|
||||
printf("\n");
|
||||
if (!rec)
|
||||
return;
|
||||
for (p = 0; p < di.nports; p++) {
|
||||
int s = di.ports[p];
|
||||
if (s >= USB_MAX_DEVICES) {
|
||||
if (verbose) {
|
||||
printf("%*sport %d %s\n", indent+1, "", p+1,
|
||||
s == USB_PORT_ENABLED ? "enabled" :
|
||||
s == USB_PORT_SUSPENDED ? "suspended" :
|
||||
s == USB_PORT_POWERED ? "powered" :
|
||||
s == USB_PORT_DISABLED ? "disabled" :
|
||||
"???");
|
||||
|
||||
}
|
||||
continue;
|
||||
}
|
||||
indent++;
|
||||
printf("%*s", indent, "");
|
||||
if (verbose)
|
||||
printf("port %d ", p+1);
|
||||
usbdev(f, di.ports[p], 1);
|
||||
indent--;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
usbdump(f)
|
||||
int f;
|
||||
{
|
||||
int a;
|
||||
|
||||
for (a = 1; a < USB_MAX_DEVICES; a++) {
|
||||
if (!done[a])
|
||||
usbdev(f, a, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
dumpone(name, f, addr)
|
||||
char *name;
|
||||
int f;
|
||||
int addr;
|
||||
{
|
||||
if (verbose)
|
||||
printf("Controller %s:\n", name);
|
||||
indent = 0;
|
||||
memset(done, 0, sizeof done);
|
||||
if (addr)
|
||||
usbdev(f, addr, 0);
|
||||
else
|
||||
usbdump(f);
|
||||
}
|
||||
|
||||
int
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
int ch, i, f;
|
||||
char buf[50];
|
||||
extern int optind;
|
||||
extern char *optarg;
|
||||
char *dev = 0;
|
||||
int addr = 0;
|
||||
int ncont;
|
||||
|
||||
while ((ch = getopt(argc, argv, "a:f:v")) != -1) {
|
||||
switch(ch) {
|
||||
case 'a':
|
||||
addr = atoi(optarg);
|
||||
break;
|
||||
case 'f':
|
||||
dev = optarg;
|
||||
break;
|
||||
case 'v':
|
||||
verbose = 1;
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (dev == 0) {
|
||||
for (ncont = 0, i = 0; i < 10; i++) {
|
||||
sprintf(buf, "%s%d", USBDEV, i);
|
||||
f = open(buf, O_RDONLY);
|
||||
if (f >= 0) {
|
||||
ncont++;
|
||||
dumpone(buf, f, addr);
|
||||
close(f);
|
||||
} else {
|
||||
if (errno == EACCES)
|
||||
warn("%s", buf);
|
||||
}
|
||||
}
|
||||
if (verbose && ncont == 0)
|
||||
printf("%s: no USB controllers found\n", __progname);
|
||||
} else {
|
||||
f = open(dev, O_RDONLY);
|
||||
if (f >= 0)
|
||||
dumpone(dev, f, addr);
|
||||
else
|
||||
err(1, "%s", dev);
|
||||
}
|
||||
exit(0);
|
||||
}
|
Loading…
Reference in New Issue
Block a user