Initial commit of ported NetBSD USB stack

This commit is contained in:
Nick Hibma 1998-11-26 23:13:13 +00:00
parent 48ecb15bdc
commit 0cec007c5f
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=41366
41 changed files with 12720 additions and 3 deletions

View File

@ -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

View File

@ -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

View File

@ -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
View 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
View 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
View 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
View 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
View 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

View 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
View 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

File diff suppressed because it is too large Load Diff

184
sys/dev/usb/uhcireg.h Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

303
sys/dev/usb/usbdi.h Normal file
View 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
View 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
View 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
View 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
View 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_ */

View File

@ -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
View 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
View 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
View 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");
}
}
}

View 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>

View 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
View 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);
}