summaryrefslogtreecommitdiffstats
path: root/sys/dev/usb
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/usb')
-rw-r--r--sys/dev/usb/input/atp.c2
-rw-r--r--sys/dev/usb/input/uep.c21
-rw-r--r--sys/dev/usb/input/uhid.c38
-rw-r--r--sys/dev/usb/input/ukbd.c630
-rw-r--r--sys/dev/usb/input/ums.c7
-rw-r--r--sys/dev/usb/misc/udbp.c41
-rw-r--r--sys/dev/usb/misc/ufm.c18
-rw-r--r--sys/dev/usb/net/if_aue.c2
-rw-r--r--sys/dev/usb/net/if_axe.c122
-rw-r--r--sys/dev/usb/net/if_axereg.h29
-rw-r--r--sys/dev/usb/net/if_cdce.c10
-rw-r--r--sys/dev/usb/net/if_cue.c2
-rw-r--r--sys/dev/usb/net/if_ipheth.c2
-rw-r--r--sys/dev/usb/net/if_kue.c2
-rw-r--r--sys/dev/usb/net/if_mos.c2
-rw-r--r--sys/dev/usb/net/if_rue.c2
-rw-r--r--sys/dev/usb/net/if_udav.c3
-rw-r--r--sys/dev/usb/net/if_usie.c1586
-rw-r--r--sys/dev/usb/net/if_usievar.h256
-rw-r--r--sys/dev/usb/net/uhso.c3
-rw-r--r--sys/dev/usb/quirk/usb_quirk.c2
-rw-r--r--sys/dev/usb/quirk/usb_quirk.h1
-rw-r--r--sys/dev/usb/serial/u3g.c2
-rw-r--r--sys/dev/usb/serial/uark.c2
-rw-r--r--sys/dev/usb/serial/ubsa.c2
-rw-r--r--sys/dev/usb/serial/uchcom.c2
-rw-r--r--sys/dev/usb/serial/ucycom.c2
-rw-r--r--sys/dev/usb/serial/ufoma.c30
-rw-r--r--sys/dev/usb/serial/uftdi.c2
-rw-r--r--sys/dev/usb/serial/ugensa.c2
-rw-r--r--sys/dev/usb/serial/uipaq.c2
-rw-r--r--sys/dev/usb/serial/ulpt.c35
-rw-r--r--sys/dev/usb/serial/umcs.c2
-rw-r--r--sys/dev/usb/serial/umct.c2
-rw-r--r--sys/dev/usb/serial/umodem.c11
-rw-r--r--sys/dev/usb/serial/umoscom.c2
-rw-r--r--sys/dev/usb/serial/uplcom.c2
-rw-r--r--sys/dev/usb/serial/uslcom.c2
-rw-r--r--sys/dev/usb/serial/uvisor.c2
-rw-r--r--sys/dev/usb/serial/uvscom.c2
-rw-r--r--sys/dev/usb/storage/umass.c5
-rw-r--r--sys/dev/usb/storage/urio.c21
-rw-r--r--sys/dev/usb/template/usb_template.c48
-rw-r--r--sys/dev/usb/template/usb_template.h14
-rw-r--r--sys/dev/usb/template/usb_template_audio.c405
-rw-r--r--sys/dev/usb/template/usb_template_cdce.c2
-rw-r--r--sys/dev/usb/template/usb_template_kbd.c224
-rw-r--r--sys/dev/usb/template/usb_template_modem.c252
-rw-r--r--sys/dev/usb/template/usb_template_mouse.c222
-rw-r--r--sys/dev/usb/template/usb_template_msc.c4
-rw-r--r--sys/dev/usb/template/usb_template_mtp.c4
-rw-r--r--sys/dev/usb/usb_device.c41
-rw-r--r--sys/dev/usb/usb_hid.c37
-rw-r--r--sys/dev/usb/usb_hub.c6
-rw-r--r--sys/dev/usb/usb_ioctl.h14
-rw-r--r--sys/dev/usb/usb_lookup.c114
-rw-r--r--sys/dev/usb/usb_msctest.c19
-rw-r--r--sys/dev/usb/usb_request.c35
-rw-r--r--sys/dev/usb/usbdevs7
-rw-r--r--sys/dev/usb/usbdi.h20
-rw-r--r--sys/dev/usb/usbhid.h2
-rw-r--r--sys/dev/usb/wlan/if_rum.c2
-rw-r--r--sys/dev/usb/wlan/if_run.c2
-rw-r--r--sys/dev/usb/wlan/if_uath.c3
-rw-r--r--sys/dev/usb/wlan/if_upgt.c4
-rw-r--r--sys/dev/usb/wlan/if_ural.c2
-rw-r--r--sys/dev/usb/wlan/if_urtw.c4
-rw-r--r--sys/dev/usb/wlan/if_zyd.c2
68 files changed, 4054 insertions, 348 deletions
diff --git a/sys/dev/usb/input/atp.c b/sys/dev/usb/input/atp.c
index fab60a2..9a17950 100644
--- a/sys/dev/usb/input/atp.c
+++ b/sys/dev/usb/input/atp.c
@@ -240,7 +240,7 @@ struct atp_dev_params {
},
};
-static const struct usb_device_id atp_devs[] = {
+static const STRUCT_USB_HOST_ID atp_devs[] = {
/* Core Duo MacBook & MacBook Pro */
{ USB_VPI(USB_VENDOR_APPLE, 0x0217, ATP_DEV_PARAMS_0) },
{ USB_VPI(USB_VENDOR_APPLE, 0x0218, ATP_DEV_PARAMS_0) },
diff --git a/sys/dev/usb/input/uep.c b/sys/dev/usb/input/uep.c
index 048452d..e90298b 100644
--- a/sys/dev/usb/input/uep.c
+++ b/sys/dev/usb/input/uep.c
@@ -288,6 +288,12 @@ static const struct usb_config uep_config[UEP_N_TRANSFER] = {
},
};
+static const STRUCT_USB_HOST_ID uep_devs[] = {
+ {USB_VPI(USB_VENDOR_EGALAX, USB_PRODUCT_EGALAX_TPANEL, 0)},
+ {USB_VPI(USB_VENDOR_EGALAX, USB_PRODUCT_EGALAX_TPANEL2, 0)},
+ {USB_VPI(USB_VENDOR_EGALAX2, USB_PRODUCT_EGALAX2_TPANEL, 0)},
+};
+
static int
uep_probe(device_t dev)
{
@@ -295,17 +301,12 @@ uep_probe(device_t dev)
if (uaa->usb_mode != USB_MODE_HOST)
return (ENXIO);
+ if (uaa->info.bConfigIndex != 0)
+ return (ENXIO);
+ if (uaa->info.bIfaceIndex != 0)
+ return (ENXIO);
- if ((uaa->info.idVendor == USB_VENDOR_EGALAX) &&
- ((uaa->info.idProduct == USB_PRODUCT_EGALAX_TPANEL) ||
- (uaa->info.idProduct == USB_PRODUCT_EGALAX_TPANEL2)))
- return (BUS_PROBE_SPECIFIC);
-
- if ((uaa->info.idVendor == USB_VENDOR_EGALAX2) &&
- (uaa->info.idProduct == USB_PRODUCT_EGALAX2_TPANEL))
- return (BUS_PROBE_SPECIFIC);
-
- return (ENXIO);
+ return (usbd_lookup_id_by_uaa(uep_devs, sizeof(uep_devs), uaa));
}
static int
diff --git a/sys/dev/usb/input/uhid.c b/sys/dev/usb/input/uhid.c
index a7fd899..1b810e3 100644
--- a/sys/dev/usb/input/uhid.c
+++ b/sys/dev/usb/input/uhid.c
@@ -607,29 +607,45 @@ uhid_ioctl(struct usb_fifo *fifo, u_long cmd, void *addr,
return (error);
}
+static const STRUCT_USB_HOST_ID uhid_devs[] = {
+ /* generic HID class */
+ {USB_IFACE_CLASS(UICLASS_HID),},
+ /* the Xbox 360 gamepad doesn't use the HID class */
+ {USB_IFACE_CLASS(UICLASS_VENDOR),
+ USB_IFACE_SUBCLASS(UISUBCLASS_XBOX360_CONTROLLER),
+ USB_IFACE_PROTOCOL(UIPROTO_XBOX360_GAMEPAD),},
+};
+
static int
uhid_probe(device_t dev)
{
struct usb_attach_arg *uaa = device_get_ivars(dev);
+ int error;
DPRINTFN(11, "\n");
- if (uaa->usb_mode != USB_MODE_HOST) {
+ if (uaa->usb_mode != USB_MODE_HOST)
return (ENXIO);
- }
- if (uaa->info.bInterfaceClass != UICLASS_HID) {
- /* the Xbox 360 gamepad doesn't use the HID class */
+ error = usbd_lookup_id_by_uaa(uhid_devs, sizeof(uhid_devs), uaa);
+ if (error)
+ return (error);
- if ((uaa->info.bInterfaceClass != UICLASS_VENDOR) ||
- (uaa->info.bInterfaceSubClass != UISUBCLASS_XBOX360_CONTROLLER) ||
- (uaa->info.bInterfaceProtocol != UIPROTO_XBOX360_GAMEPAD)) {
- return (ENXIO);
- }
- }
- if (usb_test_quirk(uaa, UQ_HID_IGNORE)) {
+ if (usb_test_quirk(uaa, UQ_HID_IGNORE))
+ return (ENXIO);
+
+ /*
+ * Don't attach to mouse and keyboard devices, hence then no
+ * "nomatch" event is generated and then ums and ukbd won't
+ * attach properly when loaded.
+ */
+ if ((uaa->info.bInterfaceClass == UICLASS_HID) &&
+ (uaa->info.bInterfaceSubClass == UISUBCLASS_BOOT) &&
+ ((uaa->info.bInterfaceProtocol == UIPROTO_BOOT_KEYBOARD) ||
+ (uaa->info.bInterfaceProtocol == UIPROTO_MOUSE))) {
return (ENXIO);
}
+
return (BUS_PROBE_GENERIC);
}
diff --git a/sys/dev/usb/input/ukbd.c b/sys/dev/usb/input/ukbd.c
index 9182663..bf3ecd7 100644
--- a/sys/dev/usb/input/ukbd.c
+++ b/sys/dev/usb/input/ukbd.c
@@ -59,6 +59,8 @@ __FBSDID("$FreeBSD$");
#include <sys/callout.h>
#include <sys/malloc.h>
#include <sys/priv.h>
+#include <sys/proc.h>
+#include <sys/sched.h>
#include <sys/kdb.h>
#include <dev/usb/usb.h>
@@ -108,9 +110,10 @@ TUNABLE_INT("hw.usb.ukbd.no_leds", &ukbd_no_leds);
#define UKBD_IN_BUF_SIZE (2*(UKBD_NMOD + (2*UKBD_NKEYCODE))) /* bytes */
#define UKBD_IN_BUF_FULL (UKBD_IN_BUF_SIZE / 2) /* bytes */
#define UKBD_NFKEY (sizeof(fkey_tab)/sizeof(fkey_tab[0])) /* units */
+#define UKBD_BUFFER_SIZE 64 /* bytes */
struct ukbd_data {
- uint8_t modifiers;
+ uint16_t modifiers;
#define MOD_CONTROL_L 0x01
#define MOD_CONTROL_R 0x10
#define MOD_SHIFT_L 0x02
@@ -119,9 +122,10 @@ struct ukbd_data {
#define MOD_ALT_R 0x40
#define MOD_WIN_L 0x08
#define MOD_WIN_R 0x80
- uint8_t reserved;
+/* internal */
+#define MOD_EJECT 0x0100
+#define MOD_FN 0x0200
uint8_t keycode[UKBD_NKEYCODE];
- uint8_t exten[8];
};
enum {
@@ -137,6 +141,18 @@ struct ukbd_softc {
fkeytab_t sc_fkeymap[UKBD_NFKEY];
struct hid_location sc_loc_apple_eject;
struct hid_location sc_loc_apple_fn;
+ struct hid_location sc_loc_ctrl_l;
+ struct hid_location sc_loc_ctrl_r;
+ struct hid_location sc_loc_shift_l;
+ struct hid_location sc_loc_shift_r;
+ struct hid_location sc_loc_alt_l;
+ struct hid_location sc_loc_alt_r;
+ struct hid_location sc_loc_win_l;
+ struct hid_location sc_loc_win_r;
+ struct hid_location sc_loc_events;
+ struct hid_location sc_loc_numlock;
+ struct hid_location sc_loc_capslock;
+ struct hid_location sc_loc_scrolllock;
struct usb_callout sc_callout;
struct ukbd_data sc_ndata;
struct ukbd_data sc_odata;
@@ -155,31 +171,64 @@ struct ukbd_softc {
uint32_t sc_buffered_char[2];
#endif
uint32_t sc_flags; /* flags */
-#define UKBD_FLAG_COMPOSE 0x0001
-#define UKBD_FLAG_POLLING 0x0002
-#define UKBD_FLAG_SET_LEDS 0x0004
-#define UKBD_FLAG_ATTACHED 0x0010
-#define UKBD_FLAG_GONE 0x0020
-#define UKBD_FLAG_APPLE_EJECT 0x0040
-#define UKBD_FLAG_APPLE_FN 0x0080
-#define UKBD_FLAG_APPLE_SWAP 0x0100
-#define UKBD_FLAG_TIMER_RUNNING 0x0200
+#define UKBD_FLAG_COMPOSE 0x00000001
+#define UKBD_FLAG_POLLING 0x00000002
+#define UKBD_FLAG_SET_LEDS 0x00000004
+#define UKBD_FLAG_ATTACHED 0x00000010
+#define UKBD_FLAG_GONE 0x00000020
+
+#define UKBD_FLAG_HID_MASK 0x003fffc0
+#define UKBD_FLAG_APPLE_EJECT 0x00000040
+#define UKBD_FLAG_APPLE_FN 0x00000080
+#define UKBD_FLAG_APPLE_SWAP 0x00000100
+#define UKBD_FLAG_TIMER_RUNNING 0x00000200
+#define UKBD_FLAG_CTRL_L 0x00000400
+#define UKBD_FLAG_CTRL_R 0x00000800
+#define UKBD_FLAG_SHIFT_L 0x00001000
+#define UKBD_FLAG_SHIFT_R 0x00002000
+#define UKBD_FLAG_ALT_L 0x00004000
+#define UKBD_FLAG_ALT_R 0x00008000
+#define UKBD_FLAG_WIN_L 0x00010000
+#define UKBD_FLAG_WIN_R 0x00020000
+#define UKBD_FLAG_EVENTS 0x00040000
+#define UKBD_FLAG_NUMLOCK 0x00080000
+#define UKBD_FLAG_CAPSLOCK 0x00100000
+#define UKBD_FLAG_SCROLLLOCK 0x00200000
int sc_mode; /* input mode (K_XLATE,K_RAW,K_CODE) */
int sc_state; /* shift/lock key state */
int sc_accents; /* accent key index (> 0) */
int sc_poll_tick_last;
+ int sc_led_size;
+ int sc_kbd_size;
uint16_t sc_inputs;
uint16_t sc_inputhead;
uint16_t sc_inputtail;
+ uint16_t sc_modifiers;
uint8_t sc_leds; /* store for async led requests */
uint8_t sc_iface_index;
uint8_t sc_iface_no;
+ uint8_t sc_id_apple_eject;
+ uint8_t sc_id_apple_fn;
+ uint8_t sc_id_ctrl_l;
+ uint8_t sc_id_ctrl_r;
+ uint8_t sc_id_shift_l;
+ uint8_t sc_id_shift_r;
+ uint8_t sc_id_alt_l;
+ uint8_t sc_id_alt_r;
+ uint8_t sc_id_win_l;
+ uint8_t sc_id_win_r;
+ uint8_t sc_id_event;
+ uint8_t sc_id_numlock;
+ uint8_t sc_id_capslock;
+ uint8_t sc_id_scrolllock;
+ uint8_t sc_id_events;
uint8_t sc_kbd_id;
- uint8_t sc_led_id;
+
uint8_t sc_poll_detected;
+ uint8_t sc_buffer[UKBD_BUFFER_SIZE];
};
#define KEY_ERROR 0x01
@@ -261,6 +310,22 @@ static const uint8_t ukbd_trtab[256] = {
NN, NN, NN, NN, NN, NN, NN, NN, /* F8 - FF */
};
+static const uint8_t ukbd_boot_desc[] = {
+ 0x05, 0x01, 0x09, 0x06, 0xa1,
+ 0x01, 0x05, 0x07, 0x19, 0xe0,
+ 0x29, 0xe7, 0x15, 0x00, 0x25,
+ 0x01, 0x75, 0x01, 0x95, 0x08,
+ 0x81, 0x02, 0x95, 0x01, 0x75,
+ 0x08, 0x81, 0x01, 0x95, 0x03,
+ 0x75, 0x01, 0x05, 0x08, 0x19,
+ 0x01, 0x29, 0x03, 0x91, 0x02,
+ 0x95, 0x05, 0x75, 0x01, 0x91,
+ 0x01, 0x95, 0x06, 0x75, 0x08,
+ 0x15, 0x00, 0x26, 0xff, 0x00,
+ 0x05, 0x07, 0x19, 0x00, 0x2a,
+ 0xff, 0x00, 0x81, 0x00, 0xc0
+};
+
/* prototypes */
static void ukbd_timeout(void *);
static void ukbd_set_leds(struct ukbd_softc *, uint8_t);
@@ -323,6 +388,33 @@ ukbd_put_key(struct ukbd_softc *sc, uint32_t key)
}
static void
+ukbd_yield(void)
+{
+ struct thread *td = curthread;
+ uint32_t old_prio;
+
+ DROP_GIANT();
+
+ thread_lock(td);
+
+ /* get current priority */
+ old_prio = td->td_base_pri;
+
+ /* set new priority */
+ sched_prio(td, td->td_user_pri);
+
+ /* cause a task switch */
+ mi_switch(SW_INVOL | SWT_RELINQUISH, NULL);
+
+ /* restore priority */
+ sched_prio(td, old_prio);
+
+ thread_unlock(td);
+
+ PICKUP_GIANT();
+}
+
+static void
ukbd_do_poll(struct ukbd_softc *sc, uint8_t wait)
{
DPRINTFN(2, "polling\n");
@@ -333,8 +425,9 @@ ukbd_do_poll(struct ukbd_softc *sc, uint8_t wait)
if (kdb_active == 0) {
while (sc->sc_inputs == 0) {
- /* make sure the USB code gets a chance to run */
- pause("UKBD", 1);
+
+ /* give USB threads a chance to run */
+ ukbd_yield();
/* check if we should wait */
if (!wait)
@@ -561,8 +654,6 @@ ukbd_intr_callback(struct usb_xfer *xfer, usb_error_t error)
uint8_t i;
uint8_t offset;
uint8_t id;
- uint8_t apple_fn;
- uint8_t apple_eject;
int len;
usbd_xfer_status(xfer, &len, NULL, NULL, NULL);
@@ -580,73 +671,145 @@ ukbd_intr_callback(struct usb_xfer *xfer, usb_error_t error)
if (sc->sc_kbd_id != 0) {
/* check and remove HID ID byte */
usbd_copy_out(pc, 0, &id, 1);
- if (id != sc->sc_kbd_id) {
- DPRINTF("wrong HID ID\n");
- goto tr_setup;
- }
offset = 1;
len--;
+ if (len == 0) {
+ DPRINTF("zero length data\n");
+ goto tr_setup;
+ }
} else {
offset = 0;
+ id = 0;
}
- if (len > sizeof(sc->sc_ndata)) {
- len = sizeof(sc->sc_ndata);
- }
+ if (len > UKBD_BUFFER_SIZE)
+ len = UKBD_BUFFER_SIZE;
- if (len) {
- memset(&sc->sc_ndata, 0, sizeof(sc->sc_ndata));
- usbd_copy_out(pc, offset, &sc->sc_ndata, len);
+ /* get data */
+ usbd_copy_out(pc, offset, sc->sc_buffer, len);
- if ((sc->sc_flags & UKBD_FLAG_APPLE_EJECT) &&
- hid_get_data((uint8_t *)&sc->sc_ndata,
- len, &sc->sc_loc_apple_eject))
- apple_eject = 1;
- else
- apple_eject = 0;
+ /* clear temporary storage */
+ memset(&sc->sc_ndata, 0, sizeof(sc->sc_ndata));
- if ((sc->sc_flags & UKBD_FLAG_APPLE_FN) &&
- hid_get_data((uint8_t *)&sc->sc_ndata,
- len, &sc->sc_loc_apple_fn))
- apple_fn = 1;
+ /* scan through HID data */
+ if ((sc->sc_flags & UKBD_FLAG_APPLE_EJECT) &&
+ (id == sc->sc_id_apple_eject)) {
+ if (hid_get_data(sc->sc_buffer, len, &sc->sc_loc_apple_eject))
+ sc->sc_modifiers |= MOD_EJECT;
else
- apple_fn = 0;
-#ifdef USB_DEBUG
- DPRINTF("apple_eject=%u apple_fn=%u\n",
- apple_eject, apple_fn);
+ sc->sc_modifiers &= ~MOD_EJECT;
+ }
+ if ((sc->sc_flags & UKBD_FLAG_APPLE_FN) &&
+ (id == sc->sc_id_apple_fn)) {
+ if (hid_get_data(sc->sc_buffer, len, &sc->sc_loc_apple_fn))
+ sc->sc_modifiers |= MOD_FN;
+ else
+ sc->sc_modifiers &= ~MOD_FN;
+ }
+ if ((sc->sc_flags & UKBD_FLAG_CTRL_L) &&
+ (id == sc->sc_id_ctrl_l)) {
+ if (hid_get_data(sc->sc_buffer, len, &sc->sc_loc_ctrl_l))
+ sc-> sc_modifiers |= MOD_CONTROL_L;
+ else
+ sc-> sc_modifiers &= ~MOD_CONTROL_L;
+ }
+ if ((sc->sc_flags & UKBD_FLAG_CTRL_R) &&
+ (id == sc->sc_id_ctrl_r)) {
+ if (hid_get_data(sc->sc_buffer, len, &sc->sc_loc_ctrl_r))
+ sc->sc_modifiers |= MOD_CONTROL_R;
+ else
+ sc->sc_modifiers &= ~MOD_CONTROL_R;
+ }
+ if ((sc->sc_flags & UKBD_FLAG_SHIFT_L) &&
+ (id == sc->sc_id_shift_l)) {
+ if (hid_get_data(sc->sc_buffer, len, &sc->sc_loc_shift_l))
+ sc->sc_modifiers |= MOD_SHIFT_L;
+ else
+ sc->sc_modifiers &= ~MOD_SHIFT_L;
+ }
+ if ((sc->sc_flags & UKBD_FLAG_SHIFT_R) &&
+ (id == sc->sc_id_shift_r)) {
+ if (hid_get_data(sc->sc_buffer, len, &sc->sc_loc_shift_r))
+ sc->sc_modifiers |= MOD_SHIFT_R;
+ else
+ sc->sc_modifiers &= ~MOD_SHIFT_R;
+ }
+ if ((sc->sc_flags & UKBD_FLAG_ALT_L) &&
+ (id == sc->sc_id_alt_l)) {
+ if (hid_get_data(sc->sc_buffer, len, &sc->sc_loc_alt_l))
+ sc->sc_modifiers |= MOD_ALT_L;
+ else
+ sc->sc_modifiers &= ~MOD_ALT_L;
+ }
+ if ((sc->sc_flags & UKBD_FLAG_ALT_R) &&
+ (id == sc->sc_id_alt_r)) {
+ if (hid_get_data(sc->sc_buffer, len, &sc->sc_loc_alt_r))
+ sc->sc_modifiers |= MOD_ALT_R;
+ else
+ sc->sc_modifiers &= ~MOD_ALT_R;
+ }
+ if ((sc->sc_flags & UKBD_FLAG_WIN_L) &&
+ (id == sc->sc_id_win_l)) {
+ if (hid_get_data(sc->sc_buffer, len, &sc->sc_loc_win_l))
+ sc->sc_modifiers |= MOD_WIN_L;
+ else
+ sc->sc_modifiers &= ~MOD_WIN_L;
+ }
+ if ((sc->sc_flags & UKBD_FLAG_WIN_R) &&
+ (id == sc->sc_id_win_r)) {
+ if (hid_get_data(sc->sc_buffer, len, &sc->sc_loc_win_r))
+ sc->sc_modifiers |= MOD_WIN_R;
+ else
+ sc->sc_modifiers &= ~MOD_WIN_R;
+ }
- if (sc->sc_ndata.modifiers) {
- DPRINTF("mod: 0x%04x\n", sc->sc_ndata.modifiers);
+ sc->sc_ndata.modifiers = sc->sc_modifiers;
+
+ if ((sc->sc_flags & UKBD_FLAG_EVENTS) &&
+ (id == sc->sc_id_events)) {
+ i = sc->sc_loc_events.count;
+ if (i > UKBD_NKEYCODE)
+ i = UKBD_NKEYCODE;
+ if (i > len)
+ i = len;
+ while (i--) {
+ sc->sc_ndata.keycode[i] =
+ hid_get_data(sc->sc_buffer + i, len - i,
+ &sc->sc_loc_events);
}
- for (i = 0; i < UKBD_NKEYCODE; i++) {
- if (sc->sc_ndata.keycode[i]) {
- DPRINTF("[%d] = %d\n", i, sc->sc_ndata.keycode[i]);
- }
- }
-#endif /* USB_DEBUG */
+ }
- if (apple_fn) {
- for (i = 0; i < UKBD_NKEYCODE; i++) {
- sc->sc_ndata.keycode[i] =
- ukbd_apple_fn(sc->sc_ndata.keycode[i]);
- }
+#ifdef USB_DEBUG
+ DPRINTF("modifiers = 0x%04x\n", (int)sc->sc_modifiers);
+ for (i = 0; i < UKBD_NKEYCODE; i++) {
+ if (sc->sc_ndata.keycode[i]) {
+ DPRINTF("[%d] = 0x%02x\n",
+ (int)i, (int)sc->sc_ndata.keycode[i]);
+ }
+ }
+#endif
+ if (sc->sc_modifiers & MOD_FN) {
+ for (i = 0; i < UKBD_NKEYCODE; i++) {
+ sc->sc_ndata.keycode[i] =
+ ukbd_apple_fn(sc->sc_ndata.keycode[i]);
}
+ }
- if (sc->sc_flags & UKBD_FLAG_APPLE_SWAP) {
- for (i = 0; i < UKBD_NKEYCODE; i++) {
- sc->sc_ndata.keycode[i] =
- ukbd_apple_swap(sc->sc_ndata.keycode[i]);
- }
+ if (sc->sc_flags & UKBD_FLAG_APPLE_SWAP) {
+ for (i = 0; i < UKBD_NKEYCODE; i++) {
+ sc->sc_ndata.keycode[i] =
+ ukbd_apple_swap(sc->sc_ndata.keycode[i]);
}
+ }
- ukbd_interrupt(sc);
+ ukbd_interrupt(sc);
- if (!(sc->sc_flags & UKBD_FLAG_TIMER_RUNNING)) {
- if (ukbd_any_key_pressed(sc)) {
- ukbd_start_timer(sc);
- }
+ if (!(sc->sc_flags & UKBD_FLAG_TIMER_RUNNING)) {
+ if (ukbd_any_key_pressed(sc)) {
+ ukbd_start_timer(sc);
}
}
+
case USB_ST_SETUP:
tr_setup:
if (sc->sc_inputs < UKBD_IN_BUF_FULL) {
@@ -672,10 +835,12 @@ tr_setup:
static void
ukbd_set_leds_callback(struct usb_xfer *xfer, usb_error_t error)
{
+ struct ukbd_softc *sc = usbd_xfer_softc(xfer);
struct usb_device_request req;
struct usb_page_cache *pc;
- uint8_t buf[2];
- struct ukbd_softc *sc = usbd_xfer_softc(xfer);
+ uint8_t id;
+ uint8_t any;
+ int len;
#ifdef USB_DEBUG
if (ukbd_no_leds)
@@ -685,37 +850,83 @@ ukbd_set_leds_callback(struct usb_xfer *xfer, usb_error_t error)
switch (USB_GET_STATE(xfer)) {
case USB_ST_TRANSFERRED:
case USB_ST_SETUP:
- if (sc->sc_flags & UKBD_FLAG_SET_LEDS) {
- sc->sc_flags &= ~UKBD_FLAG_SET_LEDS;
-
- req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
- req.bRequest = UR_SET_REPORT;
- USETW2(req.wValue, UHID_OUTPUT_REPORT, 0);
- req.wIndex[0] = sc->sc_iface_no;
- req.wIndex[1] = 0;
- req.wLength[1] = 0;
-
- /* check if we need to prefix an ID byte */
- if (sc->sc_led_id != 0) {
- req.wLength[0] = 2;
- buf[0] = sc->sc_led_id;
- buf[1] = sc->sc_leds;
- } else {
- req.wLength[0] = 1;
- buf[0] = sc->sc_leds;
- buf[1] = 0;
+ if (!(sc->sc_flags & UKBD_FLAG_SET_LEDS))
+ break;
+ sc->sc_flags &= ~UKBD_FLAG_SET_LEDS;
+
+ req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
+ req.bRequest = UR_SET_REPORT;
+ USETW2(req.wValue, UHID_OUTPUT_REPORT, 0);
+ req.wIndex[0] = sc->sc_iface_no;
+ req.wIndex[1] = 0;
+ req.wLength[1] = 0;
+
+ memset(sc->sc_buffer, 0, UKBD_BUFFER_SIZE);
+
+ id = 0;
+ any = 0;
+
+ /* Assumption: All led bits must be in the same ID. */
+
+ if (sc->sc_flags & UKBD_FLAG_NUMLOCK) {
+ if (sc->sc_leds & NLKED) {
+ hid_put_data_unsigned(sc->sc_buffer + 1, UKBD_BUFFER_SIZE - 1,
+ &sc->sc_loc_numlock, 1);
}
+ id = sc->sc_id_numlock;
+ any = 1;
+ }
- pc = usbd_xfer_get_frame(xfer, 0);
- usbd_copy_in(pc, 0, &req, sizeof(req));
- pc = usbd_xfer_get_frame(xfer, 1);
- usbd_copy_in(pc, 0, buf, sizeof(buf));
+ if (sc->sc_flags & UKBD_FLAG_SCROLLLOCK) {
+ if (sc->sc_leds & SLKED) {
+ hid_put_data_unsigned(sc->sc_buffer + 1, UKBD_BUFFER_SIZE - 1,
+ &sc->sc_loc_scrolllock, 1);
+ }
+ id = sc->sc_id_scrolllock;
+ any = 1;
+ }
- usbd_xfer_set_frame_len(xfer, 0, sizeof(req));
- usbd_xfer_set_frame_len(xfer, 1, req.wLength[0]);
- usbd_xfer_set_frames(xfer, 2);
- usbd_transfer_submit(xfer);
+ if (sc->sc_flags & UKBD_FLAG_CAPSLOCK) {
+ if (sc->sc_leds & CLKED) {
+ hid_put_data_unsigned(sc->sc_buffer + 1, UKBD_BUFFER_SIZE - 1,
+ &sc->sc_loc_capslock, 1);
+ }
+ id = sc->sc_id_capslock;
+ any = 1;
}
+
+ /* if no leds, nothing to do */
+ if (!any)
+ break;
+
+ /* range check output report length */
+ len = sc->sc_led_size;
+ if (len > (UKBD_BUFFER_SIZE - 1))
+ len = (UKBD_BUFFER_SIZE - 1);
+
+ /* check if we need to prefix an ID byte */
+ sc->sc_buffer[0] = id;
+
+ pc = usbd_xfer_get_frame(xfer, 1);
+ if (id != 0) {
+ len++;
+ usbd_copy_in(pc, 0, sc->sc_buffer, len);
+ } else {
+ usbd_copy_in(pc, 0, sc->sc_buffer + 1, len);
+ }
+ req.wLength[0] = len;
+ usbd_xfer_set_frame_len(xfer, 1, len);
+
+ DPRINTF("len=%d, id=%d\n", len, id);
+
+ /* setup control request last */
+ pc = usbd_xfer_get_frame(xfer, 0);
+ usbd_copy_in(pc, 0, &req, sizeof(req));
+ usbd_xfer_set_frame_len(xfer, 0, sizeof(req));
+
+ /* start data transfer */
+ usbd_xfer_set_frames(xfer, 2);
+ usbd_transfer_submit(xfer);
break;
default: /* Error */
@@ -739,12 +950,19 @@ static const struct usb_config ukbd_config[UKBD_N_TRANSFER] = {
.type = UE_CONTROL,
.endpoint = 0x00, /* Control pipe */
.direction = UE_DIR_ANY,
- .bufsize = sizeof(struct usb_device_request) + 8,
+ .bufsize = sizeof(struct usb_device_request) + UKBD_BUFFER_SIZE,
.callback = &ukbd_set_leds_callback,
.timeout = 1000, /* 1 second */
},
};
+/* A match on these entries will load ukbd */
+static const STRUCT_USB_HOST_ID __used ukbd_devs[] = {
+ {USB_IFACE_CLASS(UICLASS_HID),
+ USB_IFACE_SUBCLASS(UISUBCLASS_BOOT),
+ USB_IFACE_PROTOCOL(UIPROTO_BOOT_KEYBOARD),},
+};
+
static int
ukbd_probe(device_t dev)
{
@@ -801,6 +1019,140 @@ ukbd_probe(device_t dev)
return (error);
}
+static void
+ukbd_parse_hid(struct ukbd_softc *sc, const uint8_t *ptr, uint32_t len)
+{
+ uint32_t flags;
+
+ /* reset detected bits */
+ sc->sc_flags &= ~UKBD_FLAG_HID_MASK;
+
+ /* check if there is an ID byte */
+ sc->sc_kbd_size = hid_report_size(ptr, len,
+ hid_input, &sc->sc_kbd_id);
+
+ /* investigate if this is an Apple Keyboard */
+ if (hid_locate(ptr, len,
+ HID_USAGE2(HUP_CONSUMER, HUG_APPLE_EJECT),
+ hid_input, 0, &sc->sc_loc_apple_eject, &flags,
+ &sc->sc_id_apple_eject)) {
+ if (flags & HIO_VARIABLE)
+ sc->sc_flags |= UKBD_FLAG_APPLE_EJECT |
+ UKBD_FLAG_APPLE_SWAP;
+ DPRINTFN(1, "Found Apple eject-key\n");
+ }
+ if (hid_locate(ptr, len,
+ HID_USAGE2(0xFFFF, 0x0003),
+ hid_input, 0, &sc->sc_loc_apple_fn, &flags,
+ &sc->sc_id_apple_fn)) {
+ if (flags & HIO_VARIABLE)
+ sc->sc_flags |= UKBD_FLAG_APPLE_FN;
+ DPRINTFN(1, "Found Apple FN-key\n");
+ }
+ /* figure out some keys */
+ if (hid_locate(ptr, len,
+ HID_USAGE2(HUP_KEYBOARD, 0xE0),
+ hid_input, 0, &sc->sc_loc_ctrl_l, &flags,
+ &sc->sc_id_ctrl_l)) {
+ if (flags & HIO_VARIABLE)
+ sc->sc_flags |= UKBD_FLAG_CTRL_L;
+ DPRINTFN(1, "Found left control\n");
+ }
+ if (hid_locate(ptr, len,
+ HID_USAGE2(HUP_KEYBOARD, 0xE4),
+ hid_input, 0, &sc->sc_loc_ctrl_r, &flags,
+ &sc->sc_id_ctrl_r)) {
+ if (flags & HIO_VARIABLE)
+ sc->sc_flags |= UKBD_FLAG_CTRL_R;
+ DPRINTFN(1, "Found right control\n");
+ }
+ if (hid_locate(ptr, len,
+ HID_USAGE2(HUP_KEYBOARD, 0xE1),
+ hid_input, 0, &sc->sc_loc_shift_l, &flags,
+ &sc->sc_id_shift_l)) {
+ if (flags & HIO_VARIABLE)
+ sc->sc_flags |= UKBD_FLAG_SHIFT_L;
+ DPRINTFN(1, "Found left shift\n");
+ }
+ if (hid_locate(ptr, len,
+ HID_USAGE2(HUP_KEYBOARD, 0xE5),
+ hid_input, 0, &sc->sc_loc_shift_r, &flags,
+ &sc->sc_id_shift_r)) {
+ if (flags & HIO_VARIABLE)
+ sc->sc_flags |= UKBD_FLAG_SHIFT_R;
+ DPRINTFN(1, "Found right shift\n");
+ }
+ if (hid_locate(ptr, len,
+ HID_USAGE2(HUP_KEYBOARD, 0xE2),
+ hid_input, 0, &sc->sc_loc_alt_l, &flags,
+ &sc->sc_id_alt_l)) {
+ if (flags & HIO_VARIABLE)
+ sc->sc_flags |= UKBD_FLAG_ALT_L;
+ DPRINTFN(1, "Found left alt\n");
+ }
+ if (hid_locate(ptr, len,
+ HID_USAGE2(HUP_KEYBOARD, 0xE6),
+ hid_input, 0, &sc->sc_loc_alt_r, &flags,
+ &sc->sc_id_alt_r)) {
+ if (flags & HIO_VARIABLE)
+ sc->sc_flags |= UKBD_FLAG_ALT_R;
+ DPRINTFN(1, "Found right alt\n");
+ }
+ if (hid_locate(ptr, len,
+ HID_USAGE2(HUP_KEYBOARD, 0xE3),
+ hid_input, 0, &sc->sc_loc_win_l, &flags,
+ &sc->sc_id_win_l)) {
+ if (flags & HIO_VARIABLE)
+ sc->sc_flags |= UKBD_FLAG_WIN_L;
+ DPRINTFN(1, "Found left GUI\n");
+ }
+ if (hid_locate(ptr, len,
+ HID_USAGE2(HUP_KEYBOARD, 0xE7),
+ hid_input, 0, &sc->sc_loc_win_r, &flags,
+ &sc->sc_id_win_r)) {
+ if (flags & HIO_VARIABLE)
+ sc->sc_flags |= UKBD_FLAG_WIN_R;
+ DPRINTFN(1, "Found right GUI\n");
+ }
+ /* figure out event buffer */
+ if (hid_locate(ptr, len,
+ HID_USAGE2(HUP_KEYBOARD, 0x00),
+ hid_input, 0, &sc->sc_loc_events, &flags,
+ &sc->sc_id_events)) {
+ sc->sc_flags |= UKBD_FLAG_EVENTS;
+ DPRINTFN(1, "Found keyboard events\n");
+ }
+
+ /* figure out leds on keyboard */
+ sc->sc_led_size = hid_report_size(ptr, len,
+ hid_output, NULL);
+
+ if (hid_locate(ptr, len,
+ HID_USAGE2(HUP_LEDS, 0x01),
+ hid_output, 0, &sc->sc_loc_numlock, &flags,
+ &sc->sc_id_numlock)) {
+ if (flags & HIO_VARIABLE)
+ sc->sc_flags |= UKBD_FLAG_NUMLOCK;
+ DPRINTFN(1, "Found keyboard numlock\n");
+ }
+ if (hid_locate(ptr, len,
+ HID_USAGE2(HUP_LEDS, 0x02),
+ hid_output, 0, &sc->sc_loc_capslock, &flags,
+ &sc->sc_id_capslock)) {
+ if (flags & HIO_VARIABLE)
+ sc->sc_flags |= UKBD_FLAG_CAPSLOCK;
+ DPRINTFN(1, "Found keyboard capslock\n");
+ }
+ if (hid_locate(ptr, len,
+ HID_USAGE2(HUP_LEDS, 0x03),
+ hid_output, 0, &sc->sc_loc_scrolllock, &flags,
+ &sc->sc_id_scrolllock)) {
+ if (flags & HIO_VARIABLE)
+ sc->sc_flags |= UKBD_FLAG_SCROLLLOCK;
+ DPRINTFN(1, "Found keyboard scrolllock\n");
+ }
+}
+
static int
ukbd_attach(device_t dev)
{
@@ -810,7 +1162,6 @@ ukbd_attach(device_t dev)
keyboard_t *kbd = &sc->sc_kbd;
void *hid_ptr = NULL;
usb_error_t err;
- uint32_t flags;
uint16_t n;
uint16_t hid_len;
@@ -857,64 +1208,38 @@ ukbd_attach(device_t dev)
*/
KBD_PROBE_DONE(kbd);
- /*
- * Set boot protocol if we need the quirk.
- */
- if (usb_test_quirk(uaa, UQ_KBD_BOOTPROTO)) {
- err = usbd_req_set_protocol(sc->sc_udev, NULL,
- sc->sc_iface_index, 0);
- if (err != USB_ERR_NORMAL_COMPLETION) {
- DPRINTF("set protocol error=%s\n", usbd_errstr(err));
- goto detach;
- }
- }
-
- /* figure out if there is an ID byte in the data */
+ /* get HID descriptor */
err = usbd_req_get_hid_desc(uaa->device, NULL, &hid_ptr,
&hid_len, M_TEMP, uaa->info.bIfaceIndex);
+
if (err == 0) {
- uint8_t apple_keys = 0;
- uint8_t temp_id;
-
- /* investigate if this is an Apple Keyboard */
- if (hid_locate(hid_ptr, hid_len,
- HID_USAGE2(HUP_CONSUMER, HUG_APPLE_EJECT),
- hid_input, 0, &sc->sc_loc_apple_eject, &flags,
- &temp_id)) {
- if (flags & HIO_VARIABLE)
- sc->sc_flags |= UKBD_FLAG_APPLE_EJECT |
- UKBD_FLAG_APPLE_SWAP;
- DPRINTFN(1, "Found Apple eject-key\n");
- apple_keys = 1;
- sc->sc_kbd_id = temp_id;
- }
- if (hid_locate(hid_ptr, hid_len,
- HID_USAGE2(0xFFFF, 0x0003),
- hid_input, 0, &sc->sc_loc_apple_fn, &flags,
- &temp_id)) {
- if (flags & HIO_VARIABLE)
- sc->sc_flags |= UKBD_FLAG_APPLE_FN;
- DPRINTFN(1, "Found Apple FN-key\n");
- apple_keys = 1;
- sc->sc_kbd_id = temp_id;
- }
- if (apple_keys == 0) {
- /*
- * Assume the first HID ID contains the
- * keyboard data
- */
- hid_report_size(hid_ptr, hid_len,
- hid_input, &sc->sc_kbd_id);
- }
+ DPRINTF("Parsing HID descriptor of %d bytes\n",
+ (int)hid_len);
- /* investigate if we need an ID-byte for the leds */
- hid_report_size(hid_ptr, hid_len, hid_output, &sc->sc_led_id);
+ ukbd_parse_hid(sc, hid_ptr, hid_len);
free(hid_ptr, M_TEMP);
}
+ /* check if we should use the boot protocol */
+ if (usb_test_quirk(uaa, UQ_KBD_BOOTPROTO) ||
+ (err != 0) || (!(sc->sc_flags & UKBD_FLAG_EVENTS))) {
+
+ DPRINTF("Forcing boot protocol\n");
+
+ err = usbd_req_set_protocol(sc->sc_udev, NULL,
+ sc->sc_iface_index, 0);
+
+ if (err != 0) {
+ DPRINTF("Set protocol error=%s (ignored)\n",
+ usbd_errstr(err));
+ }
+
+ ukbd_parse_hid(sc, ukbd_boot_desc, sizeof(ukbd_boot_desc));
+ }
+
/* ignore if SETIDLE fails, hence it is not crucial */
- err = usbd_req_set_idle(sc->sc_udev, NULL, sc->sc_iface_index, 0, 0);
+ usbd_req_set_idle(sc->sc_udev, NULL, sc->sc_iface_index, 0, 0);
mtx_lock(&Giant);
@@ -1461,10 +1786,6 @@ errkey:
static int
ukbd_ioctl(keyboard_t *kbd, u_long cmd, caddr_t arg)
{
- /* translate LED_XXX bits into the device specific bits */
- static const uint8_t ledmap[8] = {
- 0, 2, 1, 3, 4, 6, 5, 7,
- };
struct ukbd_softc *sc = kbd->kb_data;
int i;
@@ -1540,10 +1861,11 @@ ukbd_ioctl(keyboard_t *kbd, u_long cmd, caddr_t arg)
#endif
case KDSETLED: /* set keyboard LED */
/* NOTE: lock key state in "sc_state" won't be changed */
- if (*(int *)arg & ~LOCK_MASK) {
+ if (*(int *)arg & ~LOCK_MASK)
return (EINVAL);
- }
+
i = *(int *)arg;
+
/* replace CAPS LED with ALTGR LED for ALTGR keyboards */
if (sc->sc_mode == K_XLATE &&
kbd->kb_keymap->n_keys > ALTGR_OFFSET) {
@@ -1552,9 +1874,9 @@ ukbd_ioctl(keyboard_t *kbd, u_long cmd, caddr_t arg)
else
i &= ~CLKED;
}
- if (KBD_HAS_DEVICE(kbd)) {
- ukbd_set_leds(sc, ledmap[i & LED_MASK]);
- }
+ if (KBD_HAS_DEVICE(kbd))
+ ukbd_set_leds(sc, i);
+
KBD_LED_VAL(kbd) = *(int *)arg;
break;
case KDGKBSTATE: /* get lock key state */
@@ -1607,6 +1929,8 @@ ukbd_ioctl(keyboard_t *kbd, u_long cmd, caddr_t arg)
return (ukbd_set_typematic(kbd, *(int *)arg));
case PIO_KEYMAP: /* set keyboard translation table */
+ case OPIO_KEYMAP: /* set keyboard translation table
+ * (compat) */
case PIO_KEYMAPENT: /* set keyboard translation table
* entry */
case PIO_DEADKEYMAP: /* set accent key translation table */
diff --git a/sys/dev/usb/input/ums.c b/sys/dev/usb/input/ums.c
index af9aa1f..3c4f36e 100644
--- a/sys/dev/usb/input/ums.c
+++ b/sys/dev/usb/input/ums.c
@@ -355,6 +355,13 @@ static const struct usb_config ums_config[UMS_N_TRANSFER] = {
},
};
+/* A match on these entries will load ums */
+static const STRUCT_USB_HOST_ID __used ums_devs[] = {
+ {USB_IFACE_CLASS(UICLASS_HID),
+ USB_IFACE_SUBCLASS(UISUBCLASS_BOOT),
+ USB_IFACE_PROTOCOL(UIPROTO_MOUSE),},
+};
+
static int
ums_probe(device_t dev)
{
diff --git a/sys/dev/usb/misc/udbp.c b/sys/dev/usb/misc/udbp.c
index 38a4fee..1a72cae 100644
--- a/sys/dev/usb/misc/udbp.c
+++ b/sys/dev/usb/misc/udbp.c
@@ -288,40 +288,27 @@ udbp_modload(module_t mod, int event, void *data)
return (error);
}
+static const STRUCT_USB_HOST_ID udbp_devs[] = {
+ {USB_VPI(USB_VENDOR_NETCHIP, USB_PRODUCT_NETCHIP_TURBOCONNECT, 0)},
+ {USB_VPI(USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2301, 0)},
+ {USB_VPI(USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2302, 0)},
+ {USB_VPI(USB_VENDOR_ANCHOR, USB_PRODUCT_ANCHOR_EZLINK, 0)},
+ {USB_VPI(USB_VENDOR_GENESYS, USB_PRODUCT_GENESYS_GL620USB, 0)},
+};
+
static int
udbp_probe(device_t dev)
{
struct usb_attach_arg *uaa = device_get_ivars(dev);
- if (uaa->usb_mode != USB_MODE_HOST) {
+ if (uaa->usb_mode != USB_MODE_HOST)
+ return (ENXIO);
+ if (uaa->info.bConfigIndex != 0)
+ return (ENXIO);
+ if (uaa->info.bIfaceIndex != 0)
return (ENXIO);
- }
- /*
- * XXX Julian, add the id of the device if you have one to test
- * things with. run 'usbdevs -v' and note the 3 ID's that appear.
- * The Vendor Id and Product Id are in hex and the Revision Id is in
- * bcd. But as usual if the revision is 0x101 then you should
- * compare the revision id in the device descriptor with 0x101 Or go
- * search the file usbdevs.h. Maybe the device is already in there.
- */
- if (((uaa->info.idVendor == USB_VENDOR_NETCHIP) &&
- (uaa->info.idProduct == USB_PRODUCT_NETCHIP_TURBOCONNECT)))
- return (0);
-
- if (((uaa->info.idVendor == USB_VENDOR_PROLIFIC) &&
- ((uaa->info.idProduct == USB_PRODUCT_PROLIFIC_PL2301) ||
- (uaa->info.idProduct == USB_PRODUCT_PROLIFIC_PL2302))))
- return (0);
-
- if ((uaa->info.idVendor == USB_VENDOR_ANCHOR) &&
- (uaa->info.idProduct == USB_PRODUCT_ANCHOR_EZLINK))
- return (0);
-
- if ((uaa->info.idVendor == USB_VENDOR_GENESYS) &&
- (uaa->info.idProduct == USB_PRODUCT_GENESYS_GL620USB))
- return (0);
- return (ENXIO);
+ return (usbd_lookup_id_by_uaa(udbp_devs, sizeof(udbp_devs), uaa));
}
static int
diff --git a/sys/dev/usb/misc/ufm.c b/sys/dev/usb/misc/ufm.c
index 75e2b7f..11bea65 100644
--- a/sys/dev/usb/misc/ufm.c
+++ b/sys/dev/usb/misc/ufm.c
@@ -118,19 +118,23 @@ DRIVER_MODULE(ufm, uhub, ufm_driver, ufm_devclass, NULL, 0);
MODULE_DEPEND(ufm, usb, 1, 1, 1);
MODULE_VERSION(ufm, 1);
+static const STRUCT_USB_HOST_ID ufm_devs[] = {
+ {USB_VPI(USB_VENDOR_CYPRESS, USB_PRODUCT_CYPRESS_FMRADIO, 0)},
+};
+
static int
ufm_probe(device_t dev)
{
struct usb_attach_arg *uaa = device_get_ivars(dev);
- if (uaa->usb_mode != USB_MODE_HOST) {
+ if (uaa->usb_mode != USB_MODE_HOST)
return (ENXIO);
- }
- if ((uaa->info.idVendor == USB_VENDOR_CYPRESS) &&
- (uaa->info.idProduct == USB_PRODUCT_CYPRESS_FMRADIO)) {
- return (0);
- }
- return (ENXIO);
+ if (uaa->info.bConfigIndex != 0)
+ return (ENXIO);
+ if (uaa->info.bIfaceIndex != 0)
+ return (ENXIO);
+
+ return (usbd_lookup_id_by_uaa(ufm_devs, sizeof(ufm_devs), uaa));
}
static int
diff --git a/sys/dev/usb/net/if_aue.c b/sys/dev/usb/net/if_aue.c
index 3716844..71871de 100644
--- a/sys/dev/usb/net/if_aue.c
+++ b/sys/dev/usb/net/if_aue.c
@@ -110,7 +110,7 @@ SYSCTL_INT(_hw_usb_aue, OID_AUTO, debug, CTLFLAG_RW, &aue_debug, 0,
/*
* Various supported device vendors/products.
*/
-static const struct usb_device_id aue_devs[] = {
+static const STRUCT_USB_HOST_ID aue_devs[] = {
#define AUE_DEV(v,p,i) { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, i) }
AUE_DEV(3COM, 3C460B, AUE_FLAG_PII),
AUE_DEV(ABOCOM, DSB650TX_PNA, 0),
diff --git a/sys/dev/usb/net/if_axe.c b/sys/dev/usb/net/if_axe.c
index 00d1c0b..b4e27f8 100644
--- a/sys/dev/usb/net/if_axe.c
+++ b/sys/dev/usb/net/if_axe.c
@@ -133,7 +133,7 @@ SYSCTL_INT(_hw_usb_axe, OID_AUTO, debug, CTLFLAG_RW, &axe_debug, 0,
/*
* Various supported device vendors/products.
*/
-static const struct usb_device_id axe_devs[] = {
+static const STRUCT_USB_HOST_ID axe_devs[] = {
#define AXE_DEV(v,p,i) { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, i) }
AXE_DEV(ABOCOM, UF200, 0),
AXE_DEV(ACERCM, EP1427X2, 0),
@@ -142,6 +142,7 @@ static const struct usb_device_id axe_devs[] = {
AXE_DEV(ASIX, AX88178, AXE_FLAG_178),
AXE_DEV(ASIX, AX88772, AXE_FLAG_772),
AXE_DEV(ASIX, AX88772A, AXE_FLAG_772A),
+ AXE_DEV(ASIX, AX88772B, AXE_FLAG_772B),
AXE_DEV(ATEN, UC210T, 0),
AXE_DEV(BELKIN, F5D5055, AXE_FLAG_178),
AXE_DEV(BILLIONTON, USB2AR, 0),
@@ -190,7 +191,9 @@ static void axe_ifmedia_sts(struct ifnet *, struct ifmediareq *);
static int axe_cmd(struct axe_softc *, int, int, int, void *);
static void axe_ax88178_init(struct axe_softc *);
static void axe_ax88772_init(struct axe_softc *);
+static void axe_ax88772_phywake(struct axe_softc *);
static void axe_ax88772a_init(struct axe_softc *);
+static void axe_ax88772b_init(struct axe_softc *);
static int axe_get_phyno(struct axe_softc *, int);
static const struct usb_config axe_config[AXE_N_TRANSFER] = {
@@ -217,6 +220,17 @@ static const struct usb_config axe_config[AXE_N_TRANSFER] = {
},
};
+static const struct ax88772b_mfb ax88772b_mfb_table[] = {
+ { 0x8000, 0x8001, 2048 },
+ { 0x8100, 0x8147, 4096},
+ { 0x8200, 0x81EB, 6144},
+ { 0x8300, 0x83D7, 8192},
+ { 0x8400, 0x851E, 16384},
+ { 0x8500, 0x8666, 20480},
+ { 0x8600, 0x87AE, 24576},
+ { 0x8700, 0x8A3D, 32768}
+};
+
static device_method_t axe_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, axe_probe),
@@ -669,16 +683,11 @@ axe_ax88772_init(struct axe_softc *sc)
}
static void
-axe_ax88772a_init(struct axe_softc *sc)
+axe_ax88772_phywake(struct axe_softc *sc)
{
struct usb_ether *ue;
- uint16_t eeprom;
ue = &sc->sc_ue;
- axe_cmd(sc, AXE_CMD_SROM_READ, 0, 0x0017, &eeprom);
- eeprom = le16toh(eeprom);
- /* Reload EEPROM. */
- AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM, hz / 32);
if (sc->sc_phyno == AXE_772_PHY_NO_EPHY) {
/* Manually select internal(embedded) PHY - MAC mode. */
axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, AXE_SW_PHY_SELECT_SS_ENB |
@@ -704,6 +713,55 @@ axe_ax88772a_init(struct axe_softc *sc)
uether_pause(&sc->sc_ue, hz / 32);
axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_IPRL, NULL);
uether_pause(&sc->sc_ue, hz / 32);
+}
+
+static void
+axe_ax88772a_init(struct axe_softc *sc)
+{
+ struct usb_ether *ue;
+
+ ue = &sc->sc_ue;
+ /* Reload EEPROM. */
+ AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM, hz / 32);
+ axe_ax88772_phywake(sc);
+ /* Stop MAC. */
+ axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, 0, NULL);
+}
+
+static void
+axe_ax88772b_init(struct axe_softc *sc)
+{
+ struct usb_ether *ue;
+ uint16_t eeprom;
+ uint8_t *eaddr;
+ int i;
+
+ ue = &sc->sc_ue;
+ /* Reload EEPROM. */
+ AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM, hz / 32);
+ /*
+ * Save PHY power saving configuration(high byte) and
+ * clear EEPROM checksum value(low byte).
+ */
+ axe_cmd(sc, AXE_CMD_SROM_READ, 0, AXE_EEPROM_772B_PHY_PWRCFG, &eeprom);
+ sc->sc_pwrcfg = le16toh(eeprom) & 0xFF00;
+
+ /*
+ * Auto-loaded default station address from internal ROM is
+ * 00:00:00:00:00:00 such that an explicit access to EEPROM
+ * is required to get real station address.
+ */
+ eaddr = ue->ue_eaddr;
+ for (i = 0; i < ETHER_ADDR_LEN / 2; i++) {
+ axe_cmd(sc, AXE_CMD_SROM_READ, 0, AXE_EEPROM_772B_NODE_ID + i,
+ &eeprom);
+ eeprom = le16toh(eeprom);
+ *eaddr++ = (uint8_t)(eeprom & 0xFF);
+ *eaddr++ = (uint8_t)((eeprom >> 8) & 0xFF);
+ }
+ /* Wakeup PHY. */
+ axe_ax88772_phywake(sc);
+ /* Stop MAC. */
axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, 0, NULL);
}
@@ -732,6 +790,8 @@ axe_reset(struct axe_softc *sc)
axe_ax88772_init(sc);
else if (sc->sc_flags & AXE_FLAG_772A)
axe_ax88772a_init(sc);
+ else if (sc->sc_flags & AXE_FLAG_772B)
+ axe_ax88772b_init(sc);
}
static void
@@ -755,29 +815,29 @@ axe_attach_post(struct usb_ether *ue)
sc->sc_phyno = 0;
}
+ /* Initialize controller and get station address. */
if (sc->sc_flags & AXE_FLAG_178) {
axe_ax88178_init(sc);
sc->sc_tx_bufsz = 16 * 1024;
+ axe_cmd(sc, AXE_178_CMD_READ_NODEID, 0, 0, ue->ue_eaddr);
} else if (sc->sc_flags & AXE_FLAG_772) {
axe_ax88772_init(sc);
sc->sc_tx_bufsz = 8 * 1024;
+ axe_cmd(sc, AXE_178_CMD_READ_NODEID, 0, 0, ue->ue_eaddr);
} else if (sc->sc_flags & AXE_FLAG_772A) {
axe_ax88772a_init(sc);
sc->sc_tx_bufsz = 8 * 1024;
- }
-
- /*
- * Get station address.
- */
- if (AXE_IS_178_FAMILY(sc))
axe_cmd(sc, AXE_178_CMD_READ_NODEID, 0, 0, ue->ue_eaddr);
- else
+ } else if (sc->sc_flags & AXE_FLAG_772B) {
+ axe_ax88772b_init(sc);
+ sc->sc_tx_bufsz = 8 * 1024;
+ } else
axe_cmd(sc, AXE_172_CMD_READ_NODEID, 0, 0, ue->ue_eaddr);
/*
* Fetch IPG values.
*/
- if (sc->sc_flags & AXE_FLAG_772A) {
+ if (sc->sc_flags & (AXE_FLAG_772A | AXE_FLAG_772B)) {
/* Set IPG values. */
sc->sc_ipgs[0] = 0x15;
sc->sc_ipgs[1] = 0x16;
@@ -1104,18 +1164,30 @@ axe_init(struct usb_ether *ue)
axe_cmd(sc, AXE_172_CMD_WRITE_IPG2, 0, sc->sc_ipgs[2], NULL);
}
- /* Enable receiver, set RX mode */
+ /* AX88772B uses different maximum frame burst configuration. */
+ if (sc->sc_flags & AXE_FLAG_772B)
+ axe_cmd(sc, AXE_772B_CMD_RXCTL_WRITE_CFG,
+ ax88772b_mfb_table[AX88772B_MFB_16K].threshold,
+ ax88772b_mfb_table[AX88772B_MFB_16K].byte_cnt, NULL);
+
+ /* Enable receiver, set RX mode. */
rxmode = (AXE_RXCMD_MULTICAST | AXE_RXCMD_ENABLE);
if (AXE_IS_178_FAMILY(sc)) {
-#if 0
- rxmode |= AXE_178_RXCMD_MFB_2048; /* chip default */
-#else
- /*
- * Default Rx buffer size is too small to get
- * maximum performance.
- */
- rxmode |= AXE_178_RXCMD_MFB_16384;
-#endif
+ if (sc->sc_flags & AXE_FLAG_772B) {
+ /*
+ * Select RX header format type 1. Aligning IP
+ * header on 4 byte boundary is not needed
+ * because we always copy the received frame in
+ * RX handler.
+ */
+ rxmode |= AXE_772B_RXCMD_HDR_TYPE_1;
+ } else {
+ /*
+ * Default Rx buffer size is too small to get
+ * maximum performance.
+ */
+ rxmode |= AXE_178_RXCMD_MFB_16384;
+ }
} else {
rxmode |= AXE_172_RXCMD_UNICAST;
}
diff --git a/sys/dev/usb/net/if_axereg.h b/sys/dev/usb/net/if_axereg.h
index 6772911..6e08997 100644
--- a/sys/dev/usb/net/if_axereg.h
+++ b/sys/dev/usb/net/if_axereg.h
@@ -96,6 +96,8 @@
#define AXE_CMD_READ_VLAN_CTRL 0x4027
#define AXE_CMD_WRITE_VLAN_CTRL 0x4028
+#define AXE_772B_CMD_RXCTL_WRITE_CFG 0x012A
+
#define AXE_SW_RESET_CLEAR 0x00
#define AXE_SW_RESET_RR 0x01
#define AXE_SW_RESET_RT 0x02
@@ -132,12 +134,18 @@
#define AXE_178_RXCMD_KEEP_INVALID_CRC 0x0004
#define AXE_RXCMD_BROADCAST 0x0008
#define AXE_RXCMD_MULTICAST 0x0010
+#define AXE_RXCMD_ACCEPT_RUNT 0x0040 /* AX88772B */
#define AXE_RXCMD_ENABLE 0x0080
#define AXE_178_RXCMD_MFB_MASK 0x0300
#define AXE_178_RXCMD_MFB_2048 0x0000
#define AXE_178_RXCMD_MFB_4096 0x0100
#define AXE_178_RXCMD_MFB_8192 0x0200
#define AXE_178_RXCMD_MFB_16384 0x0300
+#define AXE_772B_RXCMD_HDR_TYPE_0 0x0000
+#define AXE_772B_RXCMD_HDR_TYPE_1 0x0100
+#define AXE_772B_RXCMD_IPHDR_ALIGN 0x0200
+#define AXE_772B_RXCMD_ADD_CHKSUM 0x0400
+#define AXE_RXCMD_LOOPBACK 0x1000 /* AX88772A/AX88772B */
#define AXE_PHY_SEL_PRI 1
#define AXE_PHY_SEL_SEC 0
@@ -176,7 +184,7 @@
#define AXE_PHY_MODE_REALTEK_8251CL 0x0E
#define AXE_PHY_MODE_ATTANSIC 0x40
-/* AX88772A only. */
+/* AX88772A/AX88772B only. */
#define AXE_SW_PHY_SELECT_EXT 0x0000
#define AXE_SW_PHY_SELECT_EMBEDDED 0x0001
#define AXE_SW_PHY_SELECT_AUTO 0x0002
@@ -199,6 +207,24 @@
#define AXE_CONFIG_IDX 0 /* config number 1 */
#define AXE_IFACE_IDX 0
+/* EEPROM Map. */
+#define AXE_EEPROM_772B_NODE_ID 0x04
+#define AXE_EEPROM_772B_PHY_PWRCFG 0x18
+
+struct ax88772b_mfb {
+ int byte_cnt;
+ int threshold;
+ int size;
+};
+#define AX88772B_MFB_2K 0
+#define AX88772B_MFB_4K 1
+#define AX88772B_MFB_6K 2
+#define AX88772B_MFB_8K 3
+#define AX88772B_MFB_16K 4
+#define AX88772B_MFB_20K 5
+#define AX88772B_MFB_24K 6
+#define AX88772B_MFB_32K 7
+
struct axe_sframe_hdr {
uint16_t len;
uint16_t ilen;
@@ -228,6 +254,7 @@ struct axe_softc {
uint8_t sc_ipgs[3];
uint8_t sc_phyaddrs[2];
+ uint16_t sc_pwrcfg;
int sc_tx_bufsz;
};
diff --git a/sys/dev/usb/net/if_cdce.c b/sys/dev/usb/net/if_cdce.c
index b48e79d..12e6f67 100644
--- a/sys/dev/usb/net/if_cdce.c
+++ b/sys/dev/usb/net/if_cdce.c
@@ -263,7 +263,7 @@ static const struct usb_ether_methods cdce_ue_methods = {
.ue_setpromisc = cdce_setpromisc,
};
-static const struct usb_device_id cdce_devs[] = {
+static const STRUCT_USB_HOST_ID cdce_host_devs[] = {
{USB_VPI(USB_VENDOR_ACERLABS, USB_PRODUCT_ACERLABS_M5632, CDCE_FLAG_NO_UNION)},
{USB_VPI(USB_VENDOR_AMBIT, USB_PRODUCT_AMBIT_NTL_250, CDCE_FLAG_NO_UNION)},
{USB_VPI(USB_VENDOR_COMPAQ, USB_PRODUCT_COMPAQ_IPAQLINUX, CDCE_FLAG_NO_UNION)},
@@ -277,7 +277,9 @@ static const struct usb_device_id cdce_devs[] = {
{USB_VPI(USB_VENDOR_SHARP, USB_PRODUCT_SHARP_SLA300, CDCE_FLAG_ZAURUS | CDCE_FLAG_NO_UNION)},
{USB_VPI(USB_VENDOR_SHARP, USB_PRODUCT_SHARP_SLC700, CDCE_FLAG_ZAURUS | CDCE_FLAG_NO_UNION)},
{USB_VPI(USB_VENDOR_SHARP, USB_PRODUCT_SHARP_SLC750, CDCE_FLAG_ZAURUS | CDCE_FLAG_NO_UNION)},
+};
+static const STRUCT_USB_DUAL_ID cdce_dual_devs[] = {
{USB_IF_CSI(UICLASS_CDC, UISUBCLASS_ETHERNET_NETWORKING_CONTROL_MODEL, 0)},
{USB_IF_CSI(UICLASS_CDC, UISUBCLASS_MOBILE_DIRECT_LINE_MODEL, 0)},
{USB_IF_CSI(UICLASS_CDC, UISUBCLASS_NETWORK_CONTROL_MODEL, 0)},
@@ -472,8 +474,12 @@ static int
cdce_probe(device_t dev)
{
struct usb_attach_arg *uaa = device_get_ivars(dev);
+ int error;
- return (usbd_lookup_id_by_uaa(cdce_devs, sizeof(cdce_devs), uaa));
+ error = usbd_lookup_id_by_uaa(cdce_host_devs, sizeof(cdce_host_devs), uaa);
+ if (error)
+ error = usbd_lookup_id_by_uaa(cdce_dual_devs, sizeof(cdce_dual_devs), uaa);
+ return (error);
}
static void
diff --git a/sys/dev/usb/net/if_cue.c b/sys/dev/usb/net/if_cue.c
index fae8f70..90a18f3 100644
--- a/sys/dev/usb/net/if_cue.c
+++ b/sys/dev/usb/net/if_cue.c
@@ -88,7 +88,7 @@ __FBSDID("$FreeBSD$");
/* Belkin F5U111 adapter covered by NETMATE entry */
-static const struct usb_device_id cue_devs[] = {
+static const STRUCT_USB_HOST_ID cue_devs[] = {
#define CUE_DEV(v,p) { USB_VP(USB_VENDOR_##v, USB_PRODUCT_##v##_##p) }
CUE_DEV(CATC, NETMATE),
CUE_DEV(CATC, NETMATE2),
diff --git a/sys/dev/usb/net/if_ipheth.c b/sys/dev/usb/net/if_ipheth.c
index c8a348a..d666835 100644
--- a/sys/dev/usb/net/if_ipheth.c
+++ b/sys/dev/usb/net/if_ipheth.c
@@ -148,7 +148,7 @@ static const struct usb_ether_methods ipheth_ue_methods = {
USB_IFACE_CLASS(c), USB_IFACE_SUBCLASS(sc), \
USB_IFACE_PROTOCOL(pt)
-static const struct usb_device_id ipheth_devs[] = {
+static const STRUCT_USB_HOST_ID ipheth_devs[] = {
{IPHETH_ID(USB_VENDOR_APPLE, USB_PRODUCT_APPLE_IPHONE,
IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS,
IPHETH_USBINTF_PROTO)},
diff --git a/sys/dev/usb/net/if_kue.c b/sys/dev/usb/net/if_kue.c
index 6c97d28..5480a5d 100644
--- a/sys/dev/usb/net/if_kue.c
+++ b/sys/dev/usb/net/if_kue.c
@@ -100,7 +100,7 @@ __FBSDID("$FreeBSD$");
/*
* Various supported device vendors/products.
*/
-static const struct usb_device_id kue_devs[] = {
+static const STRUCT_USB_HOST_ID kue_devs[] = {
#define KUE_DEV(v,p) { USB_VP(USB_VENDOR_##v, USB_PRODUCT_##v##_##p) }
KUE_DEV(3COM, 3C19250),
KUE_DEV(3COM, 3C460),
diff --git a/sys/dev/usb/net/if_mos.c b/sys/dev/usb/net/if_mos.c
index a0e453c..1e884f9 100644
--- a/sys/dev/usb/net/if_mos.c
+++ b/sys/dev/usb/net/if_mos.c
@@ -146,7 +146,7 @@ SYSCTL_INT(_hw_usb_mos, OID_AUTO, debug, CTLFLAG_RW, &mos_debug, 0,
/* Various supported device vendors/products. */
-static const struct usb_device_id mos_devs[] = {
+static const STRUCT_USB_HOST_ID mos_devs[] = {
{USB_VPI(USB_VENDOR_MOSCHIP, USB_PRODUCT_MOSCHIP_MCS7730, MCS7730)},
{USB_VPI(USB_VENDOR_MOSCHIP, USB_PRODUCT_MOSCHIP_MCS7830, MCS7830)},
{USB_VPI(USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_LN030, MCS7830)},
diff --git a/sys/dev/usb/net/if_rue.c b/sys/dev/usb/net/if_rue.c
index 1dadd57..afd2f4d 100644
--- a/sys/dev/usb/net/if_rue.c
+++ b/sys/dev/usb/net/if_rue.c
@@ -108,7 +108,7 @@ SYSCTL_INT(_hw_usb_rue, OID_AUTO, debug, CTLFLAG_RW,
* Various supported device vendors/products.
*/
-static const struct usb_device_id rue_devs[] = {
+static const STRUCT_USB_HOST_ID rue_devs[] = {
{USB_VPI(USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUAKTX, 0)},
{USB_VPI(USB_VENDOR_REALTEK, USB_PRODUCT_REALTEK_USBKR100, 0)},
{USB_VPI(USB_VENDOR_OQO, USB_PRODUCT_OQO_ETHER01, 0)},
diff --git a/sys/dev/usb/net/if_udav.c b/sys/dev/usb/net/if_udav.c
index a1a0a8d..d2cceaa 100644
--- a/sys/dev/usb/net/if_udav.c
+++ b/sys/dev/usb/net/if_udav.c
@@ -199,7 +199,7 @@ SYSCTL_INT(_hw_usb_udav, OID_AUTO, debug, CTLFLAG_RW, &udav_debug, 0,
#define UDAV_CLRBIT(sc, reg, x) \
udav_csr_write1(sc, reg, udav_csr_read1(sc, reg) & ~(x))
-static const struct usb_device_id udav_devs[] = {
+static const STRUCT_USB_HOST_ID udav_devs[] = {
/* ShanTou DM9601 USB NIC */
{USB_VPI(USB_VENDOR_SHANTOU, USB_PRODUCT_SHANTOU_DM9601, 0)},
/* ShanTou ST268 USB NIC */
@@ -210,6 +210,7 @@ static const struct usb_device_id udav_devs[] = {
{USB_VPI(USB_VENDOR_SHANTOU, USB_PRODUCT_SHANTOU_ADM8515, 0)},
/* Kontron AG USB Ethernet */
{USB_VPI(USB_VENDOR_KONTRON, USB_PRODUCT_KONTRON_DM9601, 0)},
+ {USB_VPI(USB_VENDOR_KONTRON, USB_PRODUCT_KONTRON_JP1082, 0)},
};
static void
diff --git a/sys/dev/usb/net/if_usie.c b/sys/dev/usb/net/if_usie.c
new file mode 100644
index 0000000..cda1d3d
--- /dev/null
+++ b/sys/dev/usb/net/if_usie.c
@@ -0,0 +1,1586 @@
+/*-
+ * Copyright (c) 2011 Anybots Inc
+ * written by Akinori Furukoshi <moonlightakkiy@yahoo.ca>
+ * - ucom part is based on u3g.c
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/queue.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/module.h>
+#include <sys/sockio.h>
+#include <sys/socket.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/condvar.h>
+#include <sys/sysctl.h>
+#include <sys/malloc.h>
+#include <sys/taskqueue.h>
+
+#include <machine/bus.h>
+
+#include <net/if.h>
+#include <net/if_types.h>
+#include <net/netisr.h>
+#include <net/bpf.h>
+#include <net/ethernet.h>
+
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <netinet/udp.h>
+
+#include <net80211/ieee80211_ioctl.h>
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+#include <dev/usb/usbdi_util.h>
+#include <dev/usb/usb_cdc.h>
+#include "usbdevs.h"
+
+#define USB_DEBUG_VAR usie_debug
+#include <dev/usb/usb_debug.h>
+#include <dev/usb/usb_process.h>
+#include <dev/usb/usb_msctest.h>
+
+#include <dev/usb/serial/usb_serial.h>
+
+#include <dev/usb/net/if_usievar.h>
+
+#ifdef USB_DEBUG
+static int usie_debug = 0;
+
+SYSCTL_NODE(_hw_usb, OID_AUTO, usie, CTLFLAG_RW, 0, "sierra USB modem");
+SYSCTL_INT(_hw_usb_usie, OID_AUTO, debug, CTLFLAG_RW, &usie_debug, 0,
+ "usie debug level");
+#endif
+
+/* Sierra Wireless Direct IP modems */
+static const STRUCT_USB_HOST_ID usie_devs[] = {
+#define USIE_DEV(v, d) { \
+ USB_VP(USB_VENDOR_##v, USB_PRODUCT_##v##_##d) }
+ USIE_DEV(SIERRA, MC8700),
+ USIE_DEV(SIERRA, TRUINSTALL),
+ USIE_DEV(AIRPRIME, USB308),
+#undef USIE_DEV
+};
+
+static device_probe_t usie_probe;
+static device_attach_t usie_attach;
+static device_detach_t usie_detach;
+
+static void usie_uc_update_line_state(struct ucom_softc *, uint8_t);
+static void usie_uc_cfg_get_status(struct ucom_softc *, uint8_t *, uint8_t *);
+static void usie_uc_cfg_set_dtr(struct ucom_softc *, uint8_t);
+static void usie_uc_cfg_set_rts(struct ucom_softc *, uint8_t);
+static void usie_uc_cfg_open(struct ucom_softc *);
+static void usie_uc_cfg_close(struct ucom_softc *);
+static void usie_uc_start_read(struct ucom_softc *);
+static void usie_uc_stop_read(struct ucom_softc *);
+static void usie_uc_start_write(struct ucom_softc *);
+static void usie_uc_stop_write(struct ucom_softc *);
+
+static usb_callback_t usie_uc_tx_callback;
+static usb_callback_t usie_uc_rx_callback;
+static usb_callback_t usie_uc_status_callback;
+static usb_callback_t usie_if_tx_callback;
+static usb_callback_t usie_if_rx_callback;
+static usb_callback_t usie_if_status_callback;
+
+static void usie_if_sync_to(void *);
+static void usie_if_sync_cb(void *, int);
+static void usie_if_status_cb(void *, int);
+
+static void usie_if_start(struct ifnet *);
+static int usie_if_output(struct ifnet *, struct mbuf *, struct sockaddr *, struct route *);
+static void usie_if_init(void *);
+static void usie_if_stop(struct usie_softc *);
+static int usie_if_ioctl(struct ifnet *, u_long, caddr_t);
+
+static int usie_do_request(struct usie_softc *, struct usb_device_request *, void *);
+static int usie_if_cmd(struct usie_softc *, uint8_t);
+static void usie_cns_req(struct usie_softc *, uint32_t, uint16_t);
+static void usie_cns_rsp(struct usie_softc *, struct usie_cns *);
+static void usie_hip_rsp(struct usie_softc *, uint8_t *, uint32_t);
+static int usie_driver_loaded(struct module *, int, void *);
+
+static const struct usb_config usie_uc_config[USIE_UC_N_XFER] = {
+ [USIE_UC_STATUS] = {
+ .type = UE_INTERRUPT,
+ .endpoint = UE_ADDR_ANY,
+ .direction = UE_DIR_IN,
+ .bufsize = 0, /* use wMaxPacketSize */
+ .flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
+ .callback = &usie_uc_status_callback,
+ },
+ [USIE_UC_RX] = {
+ .type = UE_BULK,
+ .endpoint = UE_ADDR_ANY,
+ .direction = UE_DIR_IN,
+ .bufsize = USIE_BUFSIZE,
+ .flags = {.pipe_bof = 1,.short_xfer_ok = 1,.proxy_buffer = 1,},
+ .callback = &usie_uc_rx_callback,
+ },
+ [USIE_UC_TX] = {
+ .type = UE_BULK,
+ .endpoint = UE_ADDR_ANY,
+ .direction = UE_DIR_OUT,
+ .bufsize = USIE_BUFSIZE,
+ .flags = {.pipe_bof = 1,.force_short_xfer = 1,},
+ .callback = &usie_uc_tx_callback,
+ }
+};
+
+static const struct usb_config usie_if_config[USIE_IF_N_XFER] = {
+ [USIE_IF_STATUS] = {
+ .type = UE_INTERRUPT,
+ .endpoint = UE_ADDR_ANY,
+ .direction = UE_DIR_IN,
+ .bufsize = 0, /* use wMaxPacketSize */
+ .flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
+ .callback = &usie_if_status_callback,
+ },
+ [USIE_IF_RX] = {
+ .type = UE_BULK,
+ .endpoint = UE_ADDR_ANY,
+ .direction = UE_DIR_IN,
+ .bufsize = USIE_BUFSIZE,
+ .flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
+ .callback = &usie_if_rx_callback,
+ },
+ [USIE_IF_TX] = {
+ .type = UE_BULK,
+ .endpoint = UE_ADDR_ANY,
+ .direction = UE_DIR_OUT,
+ .bufsize = MAX(USIE_BUFSIZE, MCLBYTES),
+ .flags = {.pipe_bof = 1,.force_short_xfer = 1,},
+ .callback = &usie_if_tx_callback,
+ }
+};
+
+static device_method_t usie_methods[] = {
+ DEVMETHOD(device_probe, usie_probe),
+ DEVMETHOD(device_attach, usie_attach),
+ DEVMETHOD(device_detach, usie_detach),
+ {0, 0}
+};
+
+static driver_t usie_driver = {
+ .name = "usie",
+ .methods = usie_methods,
+ .size = sizeof(struct usie_softc),
+};
+
+static devclass_t usie_devclass;
+static eventhandler_tag usie_etag;
+
+DRIVER_MODULE(usie, uhub, usie_driver, usie_devclass, usie_driver_loaded, 0);
+MODULE_DEPEND(usie, ucom, 1, 1, 1);
+MODULE_DEPEND(usie, usb, 1, 1, 1);
+MODULE_VERSION(usie, 1);
+
+static const struct ucom_callback usie_uc_callback = {
+ .ucom_cfg_get_status = &usie_uc_cfg_get_status,
+ .ucom_cfg_set_dtr = &usie_uc_cfg_set_dtr,
+ .ucom_cfg_set_rts = &usie_uc_cfg_set_rts,
+ .ucom_cfg_open = &usie_uc_cfg_open,
+ .ucom_cfg_close = &usie_uc_cfg_close,
+ .ucom_start_read = &usie_uc_start_read,
+ .ucom_stop_read = &usie_uc_stop_read,
+ .ucom_start_write = &usie_uc_start_write,
+ .ucom_stop_write = &usie_uc_stop_write,
+};
+
+static void
+usie_autoinst(void *arg, struct usb_device *udev,
+ struct usb_attach_arg *uaa)
+{
+ struct usb_interface *iface;
+ struct usb_interface_descriptor *id;
+ struct usb_device_request req;
+ int err;
+
+ if (uaa->dev_state != UAA_DEV_READY)
+ return;
+
+ iface = usbd_get_iface(udev, 0);
+ if (iface == NULL)
+ return;
+
+ id = iface->idesc;
+ if (id == NULL || id->bInterfaceClass != UICLASS_MASS)
+ return;
+
+ if (usbd_lookup_id_by_uaa(usie_devs, sizeof(usie_devs), uaa) != 0)
+ return; /* no device match */
+
+ if (bootverbose) {
+ DPRINTF("Ejecting %s %s\n",
+ usb_get_manufacturer(udev),
+ usb_get_product(udev));
+ }
+ req.bmRequestType = UT_VENDOR;
+ req.bRequest = UR_SET_INTERFACE;
+ USETW(req.wValue, UF_DEVICE_REMOTE_WAKEUP);
+ USETW(req.wIndex, UHF_PORT_CONNECTION);
+ USETW(req.wLength, 0);
+
+ /* at this moment there is no mutex */
+ err = usbd_do_request_flags(udev, NULL, &req,
+ NULL, 0, NULL, 250 /* ms */ );
+
+ /* success, mark the udev as disappearing */
+ if (err == 0)
+ uaa->dev_state = UAA_DEV_EJECTING;
+}
+
+static int
+usie_probe(device_t self)
+{
+ struct usb_attach_arg *uaa = device_get_ivars(self);
+
+ if (uaa->usb_mode != USB_MODE_HOST)
+ return (ENXIO);
+ if (uaa->info.bConfigIndex != USIE_CNFG_INDEX)
+ return (ENXIO);
+ if (uaa->info.bIfaceIndex != USIE_IFACE_INDEX)
+ return (ENXIO);
+ if (uaa->info.bInterfaceClass != UICLASS_VENDOR)
+ return (ENXIO);
+
+ return (usbd_lookup_id_by_uaa(usie_devs, sizeof(usie_devs), uaa));
+}
+
+static int
+usie_attach(device_t self)
+{
+ struct usie_softc *sc = device_get_softc(self);
+ struct usb_attach_arg *uaa = device_get_ivars(self);
+ struct ifnet *ifp;
+ struct usb_interface *iface;
+ struct usb_interface_descriptor *id;
+ struct usb_device_request req;
+ int err;
+ uint16_t fwattr;
+ uint8_t iface_index;
+ uint8_t ifidx;
+ uint8_t start;
+
+ device_set_usb_desc(self);
+ sc->sc_udev = uaa->device;
+ sc->sc_dev = self;
+
+ mtx_init(&sc->sc_mtx, "usie", MTX_NETWORK_LOCK, MTX_DEF);
+
+ TASK_INIT(&sc->sc_if_status_task, 0, usie_if_status_cb, sc);
+ TASK_INIT(&sc->sc_if_sync_task, 0, usie_if_sync_cb, sc);
+
+ usb_callout_init_mtx(&sc->sc_if_sync_ch, &sc->sc_mtx, 0);
+
+ mtx_lock(&sc->sc_mtx);
+
+ /* set power mode to D0 */
+ req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
+ req.bRequest = USIE_POWER;
+ USETW(req.wValue, 0);
+ USETW(req.wIndex, 0);
+ USETW(req.wLength, 0);
+ if (usie_do_request(sc, &req, NULL)) {
+ mtx_unlock(&sc->sc_mtx);
+ goto detach;
+ }
+ /* read fw attr */
+ fwattr = 0;
+ req.bmRequestType = UT_READ_VENDOR_DEVICE;
+ req.bRequest = USIE_FW_ATTR;
+ USETW(req.wValue, 0);
+ USETW(req.wIndex, 0);
+ USETW(req.wLength, sizeof(fwattr));
+ if (usie_do_request(sc, &req, &fwattr)) {
+ mtx_unlock(&sc->sc_mtx);
+ goto detach;
+ }
+ mtx_unlock(&sc->sc_mtx);
+
+ /* check DHCP supports */
+ DPRINTF("fwattr=%x\n", fwattr);
+ if (!(fwattr & USIE_FW_DHCP)) {
+ device_printf(self, "DHCP is not supported. A firmware upgrade might be needed.\n");
+ }
+
+ /* find available interfaces */
+ sc->sc_nucom = 0;
+ for (ifidx = 0; ifidx < USIE_IFACE_MAX; ifidx++) {
+ iface = usbd_get_iface(uaa->device, ifidx);
+ if (iface == NULL)
+ break;
+
+ id = usbd_get_interface_descriptor(iface);
+ if ((id == NULL) || (id->bInterfaceClass != UICLASS_VENDOR))
+ continue;
+
+ /* setup Direct IP transfer */
+ if (id->bInterfaceNumber >= 7 && id->bNumEndpoints == 3) {
+ sc->sc_if_ifnum = id->bInterfaceNumber;
+ iface_index = ifidx;
+
+ DPRINTF("ifnum=%d, ifidx=%d\n",
+ sc->sc_if_ifnum, ifidx);
+
+ err = usbd_transfer_setup(uaa->device,
+ &iface_index, sc->sc_if_xfer, usie_if_config,
+ USIE_IF_N_XFER, sc, &sc->sc_mtx);
+
+ if (err == 0)
+ continue;
+
+ device_printf(self,
+ "could not allocate USB transfers on "
+ "iface_index=%d, err=%s\n",
+ iface_index, usbd_errstr(err));
+ goto detach;
+ }
+
+ /* setup ucom */
+ if (sc->sc_nucom >= USIE_UCOM_MAX)
+ continue;
+
+ usbd_set_parent_iface(uaa->device, ifidx,
+ uaa->info.bIfaceIndex);
+
+ DPRINTF("NumEndpoints=%d bInterfaceNumber=%d\n",
+ id->bNumEndpoints, id->bInterfaceNumber);
+
+ if (id->bNumEndpoints == 2) {
+ sc->sc_uc_xfer[sc->sc_nucom][0] = NULL;
+ start = 1;
+ } else
+ start = 0;
+
+ err = usbd_transfer_setup(uaa->device, &ifidx,
+ sc->sc_uc_xfer[sc->sc_nucom] + start,
+ usie_uc_config + start, USIE_UC_N_XFER - start,
+ &sc->sc_ucom[sc->sc_nucom], &sc->sc_mtx);
+
+ if (err != 0) {
+ DPRINTF("usbd_transfer_setup error=%s\n", usbd_errstr(err));
+ continue;
+ }
+
+ mtx_lock(&sc->sc_mtx);
+ for (; start < USIE_UC_N_XFER; start++)
+ usbd_xfer_set_stall(sc->sc_uc_xfer[sc->sc_nucom][start]);
+ mtx_unlock(&sc->sc_mtx);
+
+ sc->sc_uc_ifnum[sc->sc_nucom] = id->bInterfaceNumber;
+
+ sc->sc_nucom++; /* found a port */
+ }
+
+ if (sc->sc_nucom == 0) {
+ device_printf(self, "no comports found\n");
+ goto detach;
+ }
+
+ err = ucom_attach(&sc->sc_super_ucom, sc->sc_ucom,
+ sc->sc_nucom, sc, &usie_uc_callback, &sc->sc_mtx);
+
+ if (err != 0) {
+ DPRINTF("ucom_attach failed\n");
+ goto detach;
+ }
+ DPRINTF("Found %d interfaces.\n", sc->sc_nucom);
+
+ /* setup ifnet (Direct IP) */
+ sc->sc_ifp = ifp = if_alloc(IFT_OTHER);
+
+ if (ifp == NULL) {
+ device_printf(self, "Could not allocate a network interface\n");
+ goto detach;
+ }
+ if_initname(ifp, "usie", device_get_unit(self));
+
+ ifp->if_softc = sc;
+ ifp->if_mtu = USIE_MTU_MAX;
+ ifp->if_flags |= IFF_NOARP;
+ ifp->if_init = usie_if_init;
+ ifp->if_ioctl = usie_if_ioctl;
+ ifp->if_start = usie_if_start;
+ ifp->if_output = usie_if_output;
+ IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
+ ifp->if_snd.ifq_drv_maxlen = ifqmaxlen;
+ IFQ_SET_READY(&ifp->if_snd);
+
+ if_attach(ifp);
+ bpfattach(ifp, DLT_RAW, 0);
+
+ if (fwattr & USIE_PM_AUTO) {
+ usbd_set_power_mode(uaa->device, USB_POWER_MODE_SAVE);
+ DPRINTF("enabling automatic suspend and resume\n");
+ } else {
+ usbd_set_power_mode(uaa->device, USB_POWER_MODE_ON);
+ DPRINTF("USB power is always ON\n");
+ }
+
+ DPRINTF("device attached\n");
+ return (0);
+
+detach:
+ usie_detach(self);
+ return (ENOMEM);
+}
+
+static int
+usie_detach(device_t self)
+{
+ struct usie_softc *sc = device_get_softc(self);
+ uint8_t x;
+
+ /* detach ifnet */
+ if (sc->sc_ifp != NULL) {
+ usie_if_stop(sc);
+ usbd_transfer_unsetup(sc->sc_if_xfer, USIE_IF_N_XFER);
+ bpfdetach(sc->sc_ifp);
+ if_detach(sc->sc_ifp);
+ if_free(sc->sc_ifp);
+ sc->sc_ifp = NULL;
+ }
+ /* detach ucom */
+ if (sc->sc_nucom > 0)
+ ucom_detach(&sc->sc_super_ucom, sc->sc_ucom);
+
+ /* stop all USB transfers */
+ usbd_transfer_unsetup(sc->sc_if_xfer, USIE_IF_N_XFER);
+
+ for (x = 0; x != USIE_UCOM_MAX; x++)
+ usbd_transfer_unsetup(sc->sc_uc_xfer[x], USIE_UC_N_XFER);
+
+ mtx_destroy(&sc->sc_mtx);
+
+ return (0);
+}
+
+static void
+usie_uc_update_line_state(struct ucom_softc *ucom, uint8_t ls)
+{
+ struct usie_softc *sc = ucom->sc_parent;
+ struct usb_device_request req;
+
+ if (sc->sc_uc_xfer[ucom->sc_subunit][USIE_UC_STATUS] == NULL)
+ return;
+
+ req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
+ req.bRequest = USIE_LINK_STATE;
+ USETW(req.wValue, ls);
+ USETW(req.wIndex, sc->sc_uc_ifnum[ucom->sc_subunit]);
+ USETW(req.wLength, 0);
+
+ DPRINTF("sc_uc_ifnum=%d\n", sc->sc_uc_ifnum[ucom->sc_subunit]);
+
+ usie_do_request(sc, &req, NULL);
+}
+
+static void
+usie_uc_cfg_get_status(struct ucom_softc *ucom, uint8_t *lsr, uint8_t *msr)
+{
+ struct usie_softc *sc = ucom->sc_parent;
+
+ *msr = sc->sc_msr;
+ *lsr = sc->sc_lsr;
+}
+
+static void
+usie_uc_cfg_set_dtr(struct ucom_softc *ucom, uint8_t flag)
+{
+ uint8_t dtr;
+
+ dtr = flag ? USIE_LS_DTR : 0;
+ usie_uc_update_line_state(ucom, dtr);
+}
+
+static void
+usie_uc_cfg_set_rts(struct ucom_softc *ucom, uint8_t flag)
+{
+ uint8_t rts;
+
+ rts = flag ? USIE_LS_RTS : 0;
+ usie_uc_update_line_state(ucom, rts);
+}
+
+static void
+usie_uc_cfg_open(struct ucom_softc *ucom)
+{
+ struct usie_softc *sc = ucom->sc_parent;
+
+ /* usbd_transfer_start() is NULL safe */
+
+ usbd_transfer_start(sc->sc_uc_xfer[ucom->sc_subunit][USIE_UC_STATUS]);
+}
+
+static void
+usie_uc_cfg_close(struct ucom_softc *ucom)
+{
+ struct usie_softc *sc = ucom->sc_parent;
+
+ usbd_transfer_stop(sc->sc_uc_xfer[ucom->sc_subunit][USIE_UC_STATUS]);
+}
+
+static void
+usie_uc_start_read(struct ucom_softc *ucom)
+{
+ struct usie_softc *sc = ucom->sc_parent;
+
+ usbd_transfer_start(sc->sc_uc_xfer[ucom->sc_subunit][USIE_UC_RX]);
+}
+
+static void
+usie_uc_stop_read(struct ucom_softc *ucom)
+{
+ struct usie_softc *sc = ucom->sc_parent;
+
+ usbd_transfer_stop(sc->sc_uc_xfer[ucom->sc_subunit][USIE_UC_RX]);
+}
+
+static void
+usie_uc_start_write(struct ucom_softc *ucom)
+{
+ struct usie_softc *sc = ucom->sc_parent;
+
+ usbd_transfer_start(sc->sc_uc_xfer[ucom->sc_subunit][USIE_UC_TX]);
+}
+
+static void
+usie_uc_stop_write(struct ucom_softc *ucom)
+{
+ struct usie_softc *sc = ucom->sc_parent;
+
+ usbd_transfer_stop(sc->sc_uc_xfer[ucom->sc_subunit][USIE_UC_TX]);
+}
+
+static void
+usie_uc_rx_callback(struct usb_xfer *xfer, usb_error_t error)
+{
+ struct ucom_softc *ucom = usbd_xfer_softc(xfer);
+ struct usie_softc *sc = ucom->sc_parent;
+ struct usb_page_cache *pc;
+ uint32_t actlen;
+
+ usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
+
+ switch (USB_GET_STATE(xfer)) {
+ case USB_ST_TRANSFERRED:
+ pc = usbd_xfer_get_frame(xfer, 0);
+
+ /* handle CnS response */
+ if (ucom == sc->sc_ucom && actlen >= USIE_HIPCNS_MIN) {
+
+ DPRINTF("transferred=%u\n", actlen);
+
+ /* check if it is really CnS reply */
+ usbd_copy_out(pc, 0, sc->sc_resp_temp, 1);
+
+ if (sc->sc_resp_temp[0] == USIE_HIP_FRM_CHR) {
+
+ /* verify actlen */
+ if (actlen > USIE_BUFSIZE)
+ actlen = USIE_BUFSIZE;
+
+ /* get complete message */
+ usbd_copy_out(pc, 0, sc->sc_resp_temp, actlen);
+ usie_hip_rsp(sc, sc->sc_resp_temp, actlen);
+
+ /* need to fall though */
+ goto tr_setup;
+ }
+ /* else call ucom_put_data() */
+ }
+ /* standard ucom transfer */
+ ucom_put_data(ucom, pc, 0, actlen);
+
+ /* fall though */
+ case USB_ST_SETUP:
+tr_setup:
+ usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
+ usbd_transfer_submit(xfer);
+ break;
+
+ default: /* Error */
+ if (error != USB_ERR_CANCELLED) {
+ usbd_xfer_set_stall(xfer);
+ goto tr_setup;
+ }
+ break;
+ }
+}
+
+static void
+usie_uc_tx_callback(struct usb_xfer *xfer, usb_error_t error)
+{
+ struct ucom_softc *ucom = usbd_xfer_softc(xfer);
+ struct usb_page_cache *pc;
+ uint32_t actlen;
+
+ switch (USB_GET_STATE(xfer)) {
+ case USB_ST_TRANSFERRED:
+ case USB_ST_SETUP:
+tr_setup:
+ pc = usbd_xfer_get_frame(xfer, 0);
+
+ /* handle CnS request */
+ struct mbuf *m = usbd_xfer_get_priv(xfer);
+
+ if (m != NULL) {
+ usbd_m_copy_in(pc, 0, m, 0, m->m_pkthdr.len);
+ usbd_xfer_set_frame_len(xfer, 0, m->m_pkthdr.len);
+ usbd_xfer_set_priv(xfer, NULL);
+ usbd_transfer_submit(xfer);
+ m_freem(m);
+ break;
+ }
+ /* standard ucom transfer */
+ if (ucom_get_data(ucom, pc, 0, USIE_BUFSIZE, &actlen)) {
+ usbd_xfer_set_frame_len(xfer, 0, actlen);
+ usbd_transfer_submit(xfer);
+ }
+ break;
+
+ default: /* Error */
+ if (error != USB_ERR_CANCELLED) {
+ usbd_xfer_set_stall(xfer);
+ goto tr_setup;
+ }
+ break;
+ }
+}
+
+static void
+usie_uc_status_callback(struct usb_xfer *xfer, usb_error_t error)
+{
+ struct usb_page_cache *pc;
+ struct {
+ struct usb_device_request req;
+ uint16_t param;
+ } st;
+ uint32_t actlen;
+ uint16_t param;
+
+ usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
+
+ switch (USB_GET_STATE(xfer)) {
+ case USB_ST_TRANSFERRED:
+ DPRINTFN(4, "info received, actlen=%u\n", actlen);
+
+ if (actlen < sizeof(st)) {
+ DPRINTF("data too short actlen=%u\n", actlen);
+ goto tr_setup;
+ }
+ pc = usbd_xfer_get_frame(xfer, 0);
+ usbd_copy_out(pc, 0, &st, sizeof(st));
+
+ if (st.req.bmRequestType == 0xa1 && st.req.bRequest == 0x20) {
+ struct ucom_softc *ucom = usbd_xfer_softc(xfer);
+ struct usie_softc *sc = ucom->sc_parent;
+
+ param = le16toh(st.param);
+ DPRINTF("param=%x\n", param);
+ sc->sc_msr = sc->sc_lsr = 0;
+ sc->sc_msr |= (param & USIE_DCD) ? SER_DCD : 0;
+ sc->sc_msr |= (param & USIE_DSR) ? SER_DSR : 0;
+ sc->sc_msr |= (param & USIE_RI) ? SER_RI : 0;
+ sc->sc_msr |= (param & USIE_CTS) ? 0 : SER_CTS;
+ sc->sc_msr |= (param & USIE_RTS) ? SER_RTS : 0;
+ sc->sc_msr |= (param & USIE_DTR) ? SER_DTR : 0;
+ }
+ /* fall though */
+ case USB_ST_SETUP:
+tr_setup:
+ usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
+ usbd_transfer_submit(xfer);
+ break;
+
+ default: /* Error */
+ DPRINTF("USB transfer error, %s\n",
+ usbd_errstr(error));
+
+ if (error != USB_ERR_CANCELLED) {
+ usbd_xfer_set_stall(xfer);
+ goto tr_setup;
+ }
+ break;
+ }
+}
+
+static void
+usie_if_rx_callback(struct usb_xfer *xfer, usb_error_t error)
+{
+ struct usie_softc *sc = usbd_xfer_softc(xfer);
+ struct ifnet *ifp = sc->sc_ifp;
+ struct mbuf *m0;
+ struct mbuf *m = NULL;
+ struct usie_desc *rxd;
+ uint32_t actlen;
+ uint16_t err;
+ uint16_t pkt;
+ uint16_t ipl;
+ uint16_t len;
+ uint16_t diff;
+ uint8_t pad;
+ uint8_t ipv;
+
+ usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
+
+ switch (USB_GET_STATE(xfer)) {
+ case USB_ST_TRANSFERRED:
+ DPRINTFN(15, "rx done, actlen=%u\n", actlen);
+
+ if (actlen < sizeof(struct usie_hip)) {
+ DPRINTF("data too short %u\n", actlen);
+ goto tr_setup;
+ }
+ m = sc->sc_rxm;
+ sc->sc_rxm = NULL;
+
+ /* fall though */
+ case USB_ST_SETUP:
+tr_setup:
+
+ if (sc->sc_rxm == NULL) {
+ sc->sc_rxm = m_getjcl(M_DONTWAIT, MT_DATA, M_PKTHDR,
+ MJUMPAGESIZE /* could be bigger than MCLBYTES */ );
+ }
+ if (sc->sc_rxm == NULL) {
+ DPRINTF("could not allocate Rx mbuf\n");
+ ifp->if_ierrors++;
+ usbd_xfer_set_stall(xfer);
+ usbd_xfer_set_frames(xfer, 0);
+ } else {
+ /*
+ * Directly loading a mbuf cluster into DMA to
+ * save some data copying. This works because
+ * there is only one cluster.
+ */
+ usbd_xfer_set_frame_data(xfer, 0,
+ mtod(sc->sc_rxm, caddr_t), MIN(MJUMPAGESIZE, USIE_RXSZ_MAX));
+ usbd_xfer_set_frames(xfer, 1);
+ }
+ usbd_transfer_submit(xfer);
+ break;
+
+ default: /* Error */
+ DPRINTF("USB transfer error, %s\n", usbd_errstr(error));
+
+ if (error != USB_ERR_CANCELLED) {
+ /* try to clear stall first */
+ usbd_xfer_set_stall(xfer);
+ ifp->if_ierrors++;
+ goto tr_setup;
+ }
+ if (sc->sc_rxm != NULL) {
+ m_freem(sc->sc_rxm);
+ sc->sc_rxm = NULL;
+ }
+ break;
+ }
+
+ if (m == NULL)
+ return;
+
+ mtx_unlock(&sc->sc_mtx);
+
+ m->m_pkthdr.len = m->m_len = actlen;
+
+ err = pkt = 0;
+
+ /* HW can aggregate multiple frames in a single USB xfer */
+ for (;;) {
+ rxd = mtod(m, struct usie_desc *);
+
+ len = be16toh(rxd->hip.len) & USIE_HIP_IP_LEN_MASK;
+ pad = (rxd->hip.id & USIE_HIP_PAD) ? 1 : 0;
+ ipl = (len - pad - ETHER_HDR_LEN);
+ if (ipl >= len) {
+ DPRINTF("Corrupt frame\n");
+ m_freem(m);
+ break;
+ }
+ diff = sizeof(struct usie_desc) + ipl + pad;
+
+ if (((rxd->hip.id & USIE_HIP_MASK) != USIE_HIP_IP) ||
+ (be16toh(rxd->desc_type) & USIE_TYPE_MASK) != USIE_IP_RX) {
+ DPRINTF("received wrong type of packet\n");
+ m->m_data += diff;
+ m->m_pkthdr.len = (m->m_len -= diff);
+ err++;
+ if (m->m_pkthdr.len > 0)
+ continue;
+ m_freem(m);
+ break;
+ }
+ switch (be16toh(rxd->ethhdr.ether_type)) {
+ case ETHERTYPE_IP:
+ ipv = NETISR_IP;
+ break;
+#ifdef INET6
+ case ETHERTYPE_IPV6:
+ ipv = NETISR_IPV6;
+ break;
+#endif
+ default:
+ DPRINTF("unsupported ether type\n");
+ err++;
+ break;
+ }
+
+ /* the last packet */
+ if (m->m_pkthdr.len <= diff) {
+ m->m_data += (sizeof(struct usie_desc) + pad);
+ m->m_pkthdr.len = m->m_len = ipl;
+ m->m_pkthdr.rcvif = ifp;
+ BPF_MTAP(sc->sc_ifp, m);
+ netisr_dispatch(ipv, m);
+ break;
+ }
+ /* copy aggregated frames to another mbuf */
+ m0 = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
+ if (__predict_false(m0 == NULL)) {
+ DPRINTF("could not allocate mbuf\n");
+ err++;
+ m_freem(m);
+ break;
+ }
+ m_copydata(m, sizeof(struct usie_desc) + pad, ipl, mtod(m0, caddr_t));
+ m0->m_pkthdr.rcvif = ifp;
+ m0->m_pkthdr.len = m0->m_len = ipl;
+
+ BPF_MTAP(sc->sc_ifp, m0);
+ netisr_dispatch(ipv, m0);
+
+ m->m_data += diff;
+ m->m_pkthdr.len = (m->m_len -= diff);
+ }
+
+ mtx_lock(&sc->sc_mtx);
+
+ ifp->if_ierrors += err;
+ ifp->if_ipackets += pkt;
+}
+
+static void
+usie_if_tx_callback(struct usb_xfer *xfer, usb_error_t error)
+{
+ struct usie_softc *sc = usbd_xfer_softc(xfer);
+ struct usb_page_cache *pc;
+ struct ifnet *ifp = sc->sc_ifp;
+ struct mbuf *m;
+ uint16_t size;
+
+ switch (USB_GET_STATE(xfer)) {
+ case USB_ST_TRANSFERRED:
+ DPRINTFN(11, "transfer complete\n");
+ ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+ ifp->if_opackets++;
+
+ /* fall though */
+ case USB_ST_SETUP:
+tr_setup:
+
+ if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
+ break;
+
+ IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
+ if (m == NULL)
+ break;
+
+ if (m->m_pkthdr.len > (MCLBYTES - ETHER_HDR_LEN +
+ ETHER_CRC_LEN - sizeof(sc->sc_txd))) {
+ DPRINTF("packet len is too big: %d\n",
+ m->m_pkthdr.len);
+ break;
+ }
+ pc = usbd_xfer_get_frame(xfer, 0);
+
+ sc->sc_txd.hip.len = htobe16(m->m_pkthdr.len +
+ ETHER_HDR_LEN + ETHER_CRC_LEN);
+ size = sizeof(sc->sc_txd);
+
+ usbd_copy_in(pc, 0, &sc->sc_txd, size);
+ usbd_m_copy_in(pc, size, m, 0, m->m_pkthdr.len);
+ usbd_xfer_set_frame_len(xfer, 0, m->m_pkthdr.len +
+ size + ETHER_CRC_LEN);
+
+ BPF_MTAP(ifp, m);
+
+ m_freem(m);
+
+ usbd_transfer_submit(xfer);
+ break;
+
+ default: /* Error */
+ DPRINTF("USB transfer error, %s\n",
+ usbd_errstr(error));
+ ifp->if_oerrors++;
+
+ if (error != USB_ERR_CANCELLED) {
+ usbd_xfer_set_stall(xfer);
+ ifp->if_ierrors++;
+ goto tr_setup;
+ }
+ break;
+ }
+}
+
+static void
+usie_if_status_callback(struct usb_xfer *xfer, usb_error_t error)
+{
+ struct usie_softc *sc = usbd_xfer_softc(xfer);
+ struct usb_page_cache *pc;
+ struct usb_cdc_notification cdc;
+ uint32_t actlen;
+
+ usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
+
+ switch (USB_GET_STATE(xfer)) {
+ case USB_ST_TRANSFERRED:
+ DPRINTFN(4, "info received, actlen=%d\n", actlen);
+
+ /* usb_cdc_notification - .data[16] */
+ if (actlen < (sizeof(cdc) - 16)) {
+ DPRINTF("data too short %d\n", actlen);
+ goto tr_setup;
+ }
+ pc = usbd_xfer_get_frame(xfer, 0);
+ usbd_copy_out(pc, 0, &cdc, (sizeof(cdc) - 16));
+
+ DPRINTFN(4, "bNotification=%x\n", cdc.bNotification);
+
+ if (cdc.bNotification & UCDC_N_RESPONSE_AVAILABLE) {
+ taskqueue_enqueue(taskqueue_thread,
+ &sc->sc_if_status_task);
+ }
+ /* fall though */
+ case USB_ST_SETUP:
+tr_setup:
+ usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
+ usbd_transfer_submit(xfer);
+ break;
+
+ default: /* Error */
+ DPRINTF("USB transfer error, %s\n",
+ usbd_errstr(error));
+
+ if (error != USB_ERR_CANCELLED) {
+ usbd_xfer_set_stall(xfer);
+ goto tr_setup;
+ }
+ break;
+ }
+}
+
+static void
+usie_if_sync_to(void *arg)
+{
+ struct usie_softc *sc = arg;
+
+ taskqueue_enqueue(taskqueue_thread, &sc->sc_if_sync_task);
+}
+
+static void
+usie_if_sync_cb(void *arg, int pending)
+{
+ struct usie_softc *sc = arg;
+
+ mtx_lock(&sc->sc_mtx);
+
+ /* call twice */
+ usie_if_cmd(sc, USIE_HIP_SYNC2M);
+ usie_if_cmd(sc, USIE_HIP_SYNC2M);
+
+ usb_callout_reset(&sc->sc_if_sync_ch, 2 * hz, usie_if_sync_to, sc);
+
+ mtx_unlock(&sc->sc_mtx);
+}
+
+static void
+usie_if_status_cb(void *arg, int pending)
+{
+ struct usie_softc *sc = arg;
+ struct ifnet *ifp = sc->sc_ifp;
+ struct usb_device_request req;
+ struct usie_hip *hip;
+ struct usie_lsi *lsi;
+ uint16_t actlen;
+ uint8_t ntries;
+ uint8_t pad;
+
+ mtx_lock(&sc->sc_mtx);
+
+ req.bmRequestType = UT_READ_CLASS_INTERFACE;
+ req.bRequest = UCDC_GET_ENCAPSULATED_RESPONSE;
+ USETW(req.wValue, 0);
+ USETW(req.wIndex, sc->sc_if_ifnum);
+ USETW(req.wLength, sizeof(sc->sc_status_temp));
+
+ for (ntries = 0; ntries != 10; ntries++) {
+ int err;
+
+ err = usbd_do_request_flags(sc->sc_udev,
+ &sc->sc_mtx, &req, sc->sc_status_temp, USB_SHORT_XFER_OK,
+ &actlen, USB_DEFAULT_TIMEOUT);
+
+ if (err == 0)
+ break;
+
+ DPRINTF("Control request failed: %s %d/10\n",
+ usbd_errstr(err), ntries);
+
+ usb_pause_mtx(&sc->sc_mtx, USB_MS_TO_TICKS(10));
+ }
+
+ if (ntries == 10) {
+ mtx_unlock(&sc->sc_mtx);
+ DPRINTF("Timeout\n");
+ return;
+ }
+
+ hip = (struct usie_hip *)sc->sc_status_temp;
+
+ pad = (hip->id & USIE_HIP_PAD) ? 1 : 0;
+
+ DPRINTF("hip.id=%x hip.len=%d actlen=%u pad=%d\n",
+ hip->id, be16toh(hip->len), actlen, pad);
+
+ switch (hip->id & USIE_HIP_MASK) {
+ case USIE_HIP_SYNC2H:
+ usie_if_cmd(sc, USIE_HIP_SYNC2M);
+ break;
+ case USIE_HIP_RESTR:
+ usb_callout_stop(&sc->sc_if_sync_ch);
+ break;
+ case USIE_HIP_UMTS:
+ lsi = (struct usie_lsi *)(
+ sc->sc_status_temp + sizeof(struct usie_hip) + pad);
+
+ DPRINTF("lsi.proto=%x lsi.len=%d\n", lsi->proto,
+ be16toh(lsi->len));
+
+ if (lsi->proto != USIE_LSI_UMTS)
+ break;
+
+ if (lsi->area == USIE_LSI_AREA_NO ||
+ lsi->area == USIE_LSI_AREA_NODATA) {
+ device_printf(sc->sc_dev, "no service available\n");
+ break;
+ }
+ if (lsi->state == USIE_LSI_STATE_IDLE) {
+ DPRINTF("lsi.state=%x\n", lsi->state);
+ break;
+ }
+ DPRINTF("ctx=%x\n", hip->param);
+ sc->sc_txd.hip.param = hip->param;
+
+ sc->sc_net.addr_len = lsi->pdp_addr_len;
+ memcpy(&sc->sc_net.dns1_addr, &lsi->dns1_addr, 16);
+ memcpy(&sc->sc_net.dns2_addr, &lsi->dns2_addr, 16);
+ memcpy(sc->sc_net.pdp_addr, lsi->pdp_addr, 16);
+ memcpy(sc->sc_net.gw_addr, lsi->gw_addr, 16);
+ ifp->if_flags |= IFF_UP;
+ ifp->if_drv_flags |= IFF_DRV_RUNNING;
+
+ device_printf(sc->sc_dev, "IP Addr=%d.%d.%d.%d\n",
+ *lsi->pdp_addr, *(lsi->pdp_addr + 1),
+ *(lsi->pdp_addr + 2), *(lsi->pdp_addr + 3));
+ device_printf(sc->sc_dev, "Gateway Addr=%d.%d.%d.%d\n",
+ *lsi->gw_addr, *(lsi->gw_addr + 1),
+ *(lsi->gw_addr + 2), *(lsi->gw_addr + 3));
+ device_printf(sc->sc_dev, "Prim NS Addr=%d.%d.%d.%d\n",
+ *lsi->dns1_addr, *(lsi->dns1_addr + 1),
+ *(lsi->dns1_addr + 2), *(lsi->dns1_addr + 3));
+ device_printf(sc->sc_dev, "Scnd NS Addr=%d.%d.%d.%d\n",
+ *lsi->dns2_addr, *(lsi->dns2_addr + 1),
+ *(lsi->dns2_addr + 2), *(lsi->dns2_addr + 3));
+
+ usie_cns_req(sc, USIE_CNS_ID_RSSI, USIE_CNS_OB_RSSI);
+ break;
+
+ case USIE_HIP_RCGI:
+ /* ignore, workaround for sloppy windows */
+ break;
+ default:
+ DPRINTF("undefined msgid: %x\n", hip->id);
+ break;
+ }
+
+ mtx_unlock(&sc->sc_mtx);
+}
+
+static void
+usie_if_start(struct ifnet *ifp)
+{
+ struct usie_softc *sc = ifp->if_softc;
+
+ if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
+ DPRINTF("Not running\n");
+ return;
+ }
+ mtx_lock(&sc->sc_mtx);
+ usbd_transfer_start(sc->sc_if_xfer[USIE_IF_TX]);
+ mtx_unlock(&sc->sc_mtx);
+
+ DPRINTFN(3, "interface started\n");
+}
+
+static int
+usie_if_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
+ struct route *ro)
+{
+ int err;
+
+ DPRINTF("proto=%x\n", dst->sa_family);
+
+ switch (dst->sa_family) {
+#ifdef INET6
+ case AF_INET6;
+ /* fall though */
+#endif
+ case AF_INET:
+ break;
+
+ /* silently drop dhclient packets */
+ case AF_UNSPEC:
+ m_freem(m);
+ return (0);
+
+ /* drop other packet types */
+ default:
+ m_freem(m);
+ return (EAFNOSUPPORT);
+ }
+
+ err = (ifp->if_transmit)(ifp, m);
+ if (err) {
+ ifp->if_oerrors++;
+ return (ENOBUFS);
+ }
+ ifp->if_opackets++;
+
+ return (0);
+}
+
+static void
+usie_if_init(void *arg)
+{
+ struct usie_softc *sc = arg;
+ struct ifnet *ifp = sc->sc_ifp;
+ uint8_t i;
+
+ mtx_lock(&sc->sc_mtx);
+
+ /* write tx descriptor */
+ sc->sc_txd.hip.id = USIE_HIP_CTX;
+ sc->sc_txd.hip.param = 0; /* init value */
+ sc->sc_txd.desc_type = htobe16(USIE_IP_TX);
+
+ for (i = 0; i != USIE_IF_N_XFER; i++)
+ usbd_xfer_set_stall(sc->sc_if_xfer[i]);
+
+ usbd_transfer_start(sc->sc_uc_xfer[USIE_HIP_IF][USIE_UC_RX]);
+ usbd_transfer_start(sc->sc_if_xfer[USIE_IF_STATUS]);
+ usbd_transfer_start(sc->sc_if_xfer[USIE_IF_RX]);
+
+ /* if not running, initiate the modem */
+ if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
+ usie_cns_req(sc, USIE_CNS_ID_INIT, USIE_CNS_OB_LINK_UPDATE);
+
+ mtx_unlock(&sc->sc_mtx);
+
+ DPRINTF("ifnet initialized\n");
+}
+
+static void
+usie_if_stop(struct usie_softc *sc)
+{
+ usb_callout_drain(&sc->sc_if_sync_ch);
+
+ mtx_lock(&sc->sc_mtx);
+
+ /* usie_cns_req() clears IFF_* flags */
+ usie_cns_req(sc, USIE_CNS_ID_STOP, USIE_CNS_OB_LINK_UPDATE);
+
+ usbd_transfer_stop(sc->sc_if_xfer[USIE_IF_TX]);
+ usbd_transfer_stop(sc->sc_if_xfer[USIE_IF_RX]);
+ usbd_transfer_stop(sc->sc_if_xfer[USIE_IF_STATUS]);
+
+ /* shutdown device */
+ usie_if_cmd(sc, USIE_HIP_DOWN);
+
+ mtx_unlock(&sc->sc_mtx);
+}
+
+static int
+usie_if_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
+{
+ struct usie_softc *sc = ifp->if_softc;
+ struct ieee80211req *ireq;
+ struct ieee80211req_sta_info si;
+ struct ifmediareq *ifmr;
+
+ switch (cmd) {
+ case SIOCSIFFLAGS:
+ if (ifp->if_flags & IFF_UP) {
+ if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
+ usie_if_init(sc);
+ } else {
+ if (ifp->if_drv_flags & IFF_DRV_RUNNING)
+ usie_if_stop(sc);
+ }
+ break;
+
+ case SIOCSIFCAP:
+ if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
+ device_printf(sc->sc_dev,
+ "Connect to the network first.\n");
+ break;
+ }
+ mtx_lock(&sc->sc_mtx);
+ usie_cns_req(sc, USIE_CNS_ID_RSSI, USIE_CNS_OB_RSSI);
+ mtx_unlock(&sc->sc_mtx);
+ break;
+
+ case SIOCG80211:
+ ireq = (struct ieee80211req *)data;
+
+ if (ireq->i_type != IEEE80211_IOC_STA_INFO)
+ break;
+
+ memset(&si, 0, sizeof(si));
+ si.isi_len = sizeof(si);
+ /*
+ * ifconfig expects RSSI in 0.5dBm units
+ * relative to the noise floor.
+ */
+ si.isi_rssi = 2 * sc->sc_rssi;
+ if (copyout(&si, (uint8_t *)ireq->i_data + 8,
+ sizeof(struct ieee80211req_sta_info)))
+ DPRINTF("copyout failed\n");
+ DPRINTF("80211\n");
+ break;
+
+ case SIOCGIFMEDIA: /* to fool ifconfig */
+ ifmr = (struct ifmediareq *)data;
+ ifmr->ifm_count = 1;
+ DPRINTF("media\n");
+ break;
+
+ case SIOCSIFADDR:
+ case SIOCSIFDSTADDR:
+ break;
+
+ default:
+ return (EINVAL);
+ }
+ return (0);
+}
+
+static int
+usie_do_request(struct usie_softc *sc, struct usb_device_request *req,
+ void *data)
+{
+ int err = 0;
+ int ntries;
+
+ mtx_assert(&sc->sc_mtx, MA_OWNED);
+
+ for (ntries = 0; ntries != 10; ntries++) {
+ err = usbd_do_request(sc->sc_udev,
+ &sc->sc_mtx, req, data);
+ if (err == 0)
+ break;
+
+ DPRINTF("Control request failed: %s %d/10\n",
+ usbd_errstr(err), ntries);
+
+ usb_pause_mtx(&sc->sc_mtx, USB_MS_TO_TICKS(10));
+ }
+ return (err);
+}
+
+static int
+usie_if_cmd(struct usie_softc *sc, uint8_t cmd)
+{
+ struct usb_device_request req;
+ struct usie_hip msg;
+
+ msg.len = 0;
+ msg.id = cmd;
+ msg.param = 0;
+
+ req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
+ req.bRequest = UCDC_SEND_ENCAPSULATED_COMMAND;
+ USETW(req.wValue, 0);
+ USETW(req.wIndex, sc->sc_if_ifnum);
+ USETW(req.wLength, sizeof(msg));
+
+ DPRINTF("cmd=%x\n", cmd);
+
+ return (usie_do_request(sc, &req, &msg));
+}
+
+static void
+usie_cns_req(struct usie_softc *sc, uint32_t id, uint16_t obj)
+{
+ struct ifnet *ifp = sc->sc_ifp;
+ struct mbuf *m;
+ struct usb_xfer *xfer;
+ struct usie_hip *hip;
+ struct usie_cns *cns;
+ uint8_t *param;
+ uint8_t *tmp;
+ uint8_t cns_len;
+
+ m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
+ if (__predict_false(m == NULL)) {
+ DPRINTF("could not allocate mbuf\n");
+ ifp->if_ierrors++;
+ return;
+ }
+ /* to align usie_hip{} on 32 bit */
+ m->m_data += 3;
+ param = mtod(m, uint8_t *);
+ *param++ = USIE_HIP_FRM_CHR;
+ hip = (struct usie_hip *)param;
+ cns = (struct usie_cns *)(hip + 1);
+
+ tmp = param + USIE_HIPCNS_MIN - 2;
+
+ switch (obj) {
+ case USIE_CNS_OB_LINK_UPDATE:
+ cns_len = 2;
+ cns->op = USIE_CNS_OP_SET;
+ *tmp++ = 1; /* profile ID, always use 1 for now */
+ *tmp++ = id == USIE_CNS_ID_INIT ? 1 : 0;
+ break;
+
+ case USIE_CNS_OB_PROF_WRITE:
+ cns_len = 245;
+ cns->op = USIE_CNS_OP_SET;
+ *tmp++ = 1; /* profile ID, always use 1 for now */
+ *tmp++ = 2;
+ memcpy(tmp, &sc->sc_net, 34);
+ memset(tmp + 35, 0, 245 - 36);
+ tmp += 243;
+ break;
+
+ case USIE_CNS_OB_RSSI:
+ cns_len = 0;
+ cns->op = USIE_CNS_OP_REQ;
+ break;
+
+ default:
+ DPRINTF("unsupported CnS object type\n");
+ return;
+ }
+ *tmp = USIE_HIP_FRM_CHR;
+
+ hip->len = htobe16(sizeof(struct usie_cns) + cns_len);
+ hip->id = USIE_HIP_CNS2M;
+ hip->param = 0; /* none for CnS */
+
+ cns->obj = htobe16(obj);
+ cns->id = htobe32(id);
+ cns->len = cns_len;
+ cns->rsv0 = cns->rsv1 = 0; /* always '0' */
+
+ param = (uint8_t *)(cns + 1);
+
+ DPRINTF("param: %16D\n", param, ":");
+
+ m->m_pkthdr.len = m->m_len = USIE_HIPCNS_MIN + cns_len + 2;
+
+ xfer = sc->sc_uc_xfer[USIE_HIP_IF][USIE_UC_TX];
+
+ if (usbd_xfer_get_priv(xfer) == NULL) {
+ usbd_xfer_set_priv(xfer, m);
+ usbd_transfer_start(xfer);
+ } else {
+ DPRINTF("Dropped CNS event\n");
+ m_freem(m);
+ }
+}
+
+static void
+usie_cns_rsp(struct usie_softc *sc, struct usie_cns *cns)
+{
+ struct ifnet *ifp = sc->sc_ifp;
+
+ DPRINTF("received CnS\n");
+
+ switch (be16toh(cns->obj)) {
+ case USIE_CNS_OB_LINK_UPDATE:
+ if (be32toh(cns->id) & USIE_CNS_ID_INIT)
+ usie_if_sync_to(sc);
+ else if (be32toh(cns->id) & USIE_CNS_ID_STOP) {
+ ifp->if_flags &= ~IFF_UP;
+ ifp->if_drv_flags &=
+ ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
+ } else
+ DPRINTF("undefined link update\n");
+ break;
+
+ case USIE_CNS_OB_RSSI:
+ sc->sc_rssi = be16toh(*(int16_t *)(cns + 1));
+ if (sc->sc_rssi <= 0)
+ device_printf(sc->sc_dev, "No signal\n");
+ else {
+ device_printf(sc->sc_dev, "RSSI=%ddBm\n",
+ sc->sc_rssi - 110);
+ }
+ break;
+
+ case USIE_CNS_OB_PROF_WRITE:
+ break;
+
+ case USIE_CNS_OB_PDP_READ:
+ break;
+
+ default:
+ DPRINTF("undefined CnS\n");
+ break;
+ }
+}
+
+static void
+usie_hip_rsp(struct usie_softc *sc, uint8_t *rsp, uint32_t len)
+{
+ struct usie_hip *hip;
+ struct usie_cns *cns;
+ uint32_t i;
+ uint32_t j;
+ uint32_t off;
+ uint8_t tmp[USIE_HIPCNS_MAX] __aligned(4);
+
+ for (off = 0; (off + USIE_HIPCNS_MIN) <= len; off++) {
+
+ uint8_t pad;
+
+ while ((off < len) && (rsp[off] == USIE_HIP_FRM_CHR))
+ off++;
+
+ /* Unstuff the bytes */
+ for (i = j = 0; ((i + off) < len) &&
+ (j < USIE_HIPCNS_MAX); i++) {
+
+ if (rsp[i + off] == USIE_HIP_FRM_CHR)
+ break;
+
+ if (rsp[i + off] == USIE_HIP_ESC_CHR) {
+ if ((i + off + 1) >= len)
+ break;
+ tmp[j++] = rsp[i++ + off + 1] ^ 0x20;
+ } else {
+ tmp[j++] = rsp[i + off];
+ }
+ }
+
+ off += i;
+
+ DPRINTF("frame len=%d\n", j);
+
+ if (j < sizeof(struct usie_hip)) {
+ DPRINTF("too little data\n");
+ break;
+ }
+ /*
+ * Make sure we are not reading the stack if something
+ * is wrong.
+ */
+ memset(tmp + j, 0, sizeof(tmp) - j);
+
+ hip = (struct usie_hip *)tmp;
+
+ DPRINTF("hip: len=%d msgID=%02x, param=%02x\n",
+ be16toh(hip->len), hip->id, hip->param);
+
+ pad = (hip->id & USIE_HIP_PAD) ? 1 : 0;
+
+ if ((hip->id & USIE_HIP_MASK) == USIE_HIP_CNS2H) {
+ cns = (struct usie_cns *)(((uint8_t *)(hip + 1)) + pad);
+
+ if (j < (sizeof(struct usie_cns) +
+ sizeof(struct usie_hip) + pad)) {
+ DPRINTF("too little data\n");
+ break;
+ }
+ DPRINTF("cns: obj=%04x, op=%02x, rsv0=%02x, "
+ "app=%08x, rsv1=%02x, len=%d\n",
+ be16toh(cns->obj), cns->op, cns->rsv0,
+ be32toh(cns->id), cns->rsv1, cns->len);
+
+ if (cns->op & USIE_CNS_OP_ERR)
+ DPRINTF("CnS error response\n");
+ else
+ usie_cns_rsp(sc, cns);
+
+ i = sizeof(struct usie_hip) + pad + sizeof(struct usie_cns);
+ j = cns->len;
+ } else {
+ i = sizeof(struct usie_hip) + pad;
+ j = be16toh(hip->len);
+ }
+#ifdef USB_DEBUG
+ if (usie_debug == 0)
+ continue;
+
+ while (i < USIE_HIPCNS_MAX && j > 0) {
+ DPRINTF("param[0x%02x] = 0x%02x\n", i, tmp[i]);
+ i++;
+ j--;
+ }
+#endif
+ }
+}
+
+static int
+usie_driver_loaded(struct module *mod, int what, void *arg)
+{
+ switch (what) {
+ case MOD_LOAD:
+ /* register autoinstall handler */
+ usie_etag = EVENTHANDLER_REGISTER(usb_dev_configured,
+ usie_autoinst, NULL, EVENTHANDLER_PRI_ANY);
+ break;
+ case MOD_UNLOAD:
+ EVENTHANDLER_DEREGISTER(usb_dev_configured, usie_etag);
+ break;
+ default:
+ return (EOPNOTSUPP);
+ }
+ return (0);
+}
+
diff --git a/sys/dev/usb/net/if_usievar.h b/sys/dev/usb/net/if_usievar.h
new file mode 100644
index 0000000..9ba0dc8
--- /dev/null
+++ b/sys/dev/usb/net/if_usievar.h
@@ -0,0 +1,256 @@
+/* $FreeBSD$ */
+
+/*-
+ * Copyright (c) 2011 Anybots Inc
+ * written by Akinori Furukoshi <moonlightakkiy@yahoo.ca>
+ * - ucom part is based on u3g.c
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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 _IF_USEVAR_H_
+#define _IF_USEVAR_H_
+
+#define USIE_DCD 0x0001
+#define USIE_DSR 0x0002
+#define USIE_DTR 0x0004
+#define USIE_RI 0x0008
+#define USIE_CTS 0x0100
+#define USIE_RTS 0x0200
+
+#define USIE_HIP_FRM_CHR 0x7e
+#define USIE_HIP_ESC_CHR 0x7d
+#define USIE_HIP_IF 0
+
+#define USIE_HIPCNS_MIN 16 /* HIP + CnS + 2 framing char */
+#define USIE_HIPCNS_MAX 261 /* HIP + max CnS 255 + 2 framing char */
+
+#define USIE_CNFG_INDEX 0
+#define USIE_IFACE_INDEX 0
+#define USIE_IFACE_MAX 12
+#define USIE_BUFSIZE 2048
+#define USIE_MTU_MAX 1500
+#define USIE_RXSZ_MAX 4096
+
+/* USB control pipe request */
+#define USIE_POWER 0x00
+#define USIE_FW_ATTR 0x06
+#define USIE_NMEA 0x07
+#define USIE_LINK_STATE 0x22
+
+/* firmware attr flags */
+#define USIE_PM_AUTO (1 << 1)
+#define USIE_FW_DHCP (1 << 3) /* DHCP capable */
+
+/* line state flags */
+#define USIE_LS_DTR (1 << 0)
+#define USIE_LS_RTS (1 << 1)
+
+/* Host Interface Porotocol Header */
+struct usie_hip {
+ uint16_t len;
+#define USIE_HIP_LEN_MASK 0x3fff
+#define USIE_HIP_IP_LEN_MASK 0x07ff
+
+ uint8_t id;
+#define USIE_HIP_PAD (1 << 7)
+#define USIE_HIP_MASK 0x7f
+#define USIE_HIP_SYNC2M 0x20 /* host -> modem */
+#define USIE_HIP_DOWN 0x26
+#define USIE_HIP_CNS2M 0x2b /* h -> m */
+#define USIE_HIP_CTX 0x3f
+#define USIE_HIP_SYNC2H 0x60 /* h <- m */
+#define USIE_HIP_RESTR 0x62
+#define USIE_HIP_RCGI 0x64
+#define USIE_HIP_CNS2H 0x6b /* h <- m */
+#define USIE_HIP_UMTS 0x78
+#define USIE_HIP_IP 0x7f
+
+ uint8_t param;
+} __packed __aligned(4);
+
+/* Control and Status Header */
+struct usie_cns {
+ uint16_t obj; /* object type */
+#define USIE_CNS_OB_RSSI 0x1001 /* read RSSI */
+#define USIE_CNS_OB_HW_DISABLE 0x1011 /* disable h/w */
+#define USIE_CNS_OB_PW_SW 0x1071 /* power on/off */
+#define USIE_CNS_OB_PROF_WRITE 0x7003 /* write profile */
+#define USIE_CNS_OB_LINK_UPDATE 0x7004 /* dis/connect */
+#define USIE_CNS_OB_PDP_READ 0x7006 /* read out IP addr */
+
+ uint8_t op; /* operation type */
+#define USIE_CNS_OP_ERR (1 << 7)/* | == error */
+#define USIE_CNS_OP_REQ 0x01 /* host -> modem */
+#define USIE_CNS_OP_RSP 0x02 /* h <- m */
+#define USIE_CNS_OP_SET 0x03 /* h -> m */
+#define USIE_CNS_OP_ACK 0x04 /* h <- m */
+#define USIE_CNS_OP_NOTIF_ON 0x05 /* h -> m */
+#define USIE_CNS_OP_RSP_ON 0x06 /* h <- m */
+#define USIE_CNS_OP_NOTIF 0x07 /* h <- m */
+#define USIE_CNS_OP_NOTIF_OFF 0x08 /* h -> m */
+#define USIE_CNS_OP_RSP_OFF 0x09 /* h <- m */
+#define USIE_CNS_OP_REQ_CHG 0x0a /* h -> m */
+#define USIE_CNS_OP_RSP_CHG 0x0b /* h <- m */
+
+ uint8_t rsv0; /* reserved, always '0' */
+ uint32_t id; /* caller ID */
+/*
+ * .id is to identify calling functions
+ * h/w responses with the same .id used in request. Only '0' is reserved
+ * for notification (asynchronous message generated by h/w without any
+ * request). All other values are user defineable.
+ */
+#define USIE_CNS_ID_NOTIF 0x00000000 /* reserved */
+#define USIE_CNS_ID_INIT 0x00000001
+#define USIE_CNS_ID_STOP 0x00000002
+#define USIE_CNS_ID_DNS 0x00000003
+#define USIE_CNS_ID_RSSI 0x00000004
+
+ uint8_t rsv1; /* reserved, always '0' */
+ uint8_t len; /* length of param */
+} __packed;
+
+/*
+ * CnS param attached to struct usie_cns
+ * usie_cns.len is total size of this param
+ * max 255
+ */
+#define USIE_CNS_PM_UP 0x01
+#define USIE_CNS_PM_DOWN 0x00
+
+/* Link Sense Indication data structure */
+struct usie_lsi {
+ uint8_t proto;
+#define USIE_LSI_UMTS 0x01
+
+ uint8_t pad0;
+ uint16_t len;
+ uint8_t area;
+#define USIE_LSI_AREA_NO 0x00
+#define USIE_LSI_AREA_NODATA 0x01
+
+ uint8_t pad1[41];
+ uint8_t state;
+#define USIE_LSI_STATE_IDLE 0x00
+
+ uint8_t pad2[33];
+ uint8_t type;
+#define USIE_LSI_IP4 0x00
+
+ uint8_t pdp_addr_len; /* PDP addr */
+ uint8_t pdp_addr[16];
+ uint8_t pad3[23];
+ uint8_t dns1_addr_len; /* DNS addr */
+ uint8_t dns1_addr[16];
+ uint8_t dns2_addr_len;
+ uint8_t dns2_addr[16];
+ uint8_t wins1_addr_len; /* Wins addr */
+ uint8_t wins1_addr[16];
+ uint8_t wins2_addr_len;
+ uint8_t wins2_addr[16];
+ uint8_t pad4[4];
+ uint8_t gw_addr_len; /* GW addr */
+ uint8_t gw_addr[16];
+ uint8_t rsv[8];
+} __packed;
+
+struct usie_net_info {
+ uint8_t addr_len;
+ uint8_t pdp_addr[16];
+ uint8_t dns1_addr[16];
+ uint8_t dns2_addr[16];
+ uint8_t gw_addr[16];
+} __packed;
+
+/* Tx/Rx IP packet descriptor */
+struct usie_desc {
+ struct usie_hip hip;
+ uint16_t desc_type;
+#define USIE_TYPE_MASK 0x03ff
+#define USIE_IP_TX 0x0002
+#define USIE_IP_RX 0x0202
+
+ struct ether_header ethhdr;
+} __packed;
+
+enum {
+ USIE_UC_STATUS,
+ USIE_UC_RX,
+ USIE_UC_TX,
+ USIE_UC_N_XFER
+};
+
+enum {
+ USIE_IF_STATUS,
+ USIE_IF_RX,
+ USIE_IF_TX,
+ USIE_IF_N_XFER
+};
+
+struct usie_softc {
+ struct ucom_super_softc sc_super_ucom;
+
+#define USIE_UCOM_MAX 6
+ struct ucom_softc sc_ucom[USIE_UCOM_MAX];
+ uint8_t sc_uc_ifnum[USIE_UCOM_MAX];
+
+ struct mtx sc_mtx;
+
+ struct task sc_if_status_task;
+ struct task sc_if_sync_task;
+ struct usb_callout sc_if_sync_ch;
+
+ struct usie_net_info sc_net;
+
+ struct usie_desc sc_txd;
+
+ struct usb_xfer *sc_uc_xfer[USIE_UCOM_MAX][USIE_UC_N_XFER];
+ struct usb_xfer *sc_if_xfer[USIE_IF_N_XFER];
+
+ struct ifnet *sc_ifp;
+ struct usb_device *sc_udev;
+ device_t sc_dev;
+
+ struct mbuf *sc_rxm;
+
+ uint16_t sc_if_ifnum;
+
+ int16_t sc_rssi;
+
+ uint8_t sc_msr;
+ uint8_t sc_lsr;
+ uint8_t sc_nucom;
+
+ uint8_t sc_resp_temp[USIE_BUFSIZE] __aligned(4);
+ uint8_t sc_status_temp[USIE_BUFSIZE] __aligned(4);
+};
+
+/* Some code assumptions */
+
+extern uint8_t usie_assert[((sizeof(struct usie_hip) +
+ sizeof(struct usie_lsi) + 1) <= USIE_BUFSIZE) ? 1 : -1];
+
+extern uint8_t ucdc_assert[(sizeof(struct usb_cdc_notification)
+ >= 16) ? 1 : -1];
+
+#endif /* _IF_USEVAR_H_ */
diff --git a/sys/dev/usb/net/uhso.c b/sys/dev/usb/net/uhso.c
index 06ac416..cbb0b08 100644
--- a/sys/dev/usb/net/uhso.c
+++ b/sys/dev/usb/net/uhso.c
@@ -247,7 +247,7 @@ static char *uhso_port_type_sysctl[] = {
/* ifnet device unit allocations */
static struct unrhdr *uhso_ifnet_unit = NULL;
-static const struct usb_device_id uhso_devs[] = {
+static const STRUCT_USB_HOST_ID uhso_devs[] = {
#define UHSO_DEV(v,p,i) { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, i) }
/* Option GlobeSurfer iCON 7.2 */
UHSO_DEV(OPTION, GSICON72, UHSO_STATIC_IFACE),
@@ -1754,6 +1754,7 @@ uhso_if_rxflush(void *arg)
/* Dispatch to IP layer */
BPF_MTAP(sc->sc_ifp, m);
+ M_SETFIB(m, ifp->if_fib);
netisr_dispatch(isr, m);
m = m0 != NULL ? m0 : NULL;
mtx_lock(&sc->sc_mtx);
diff --git a/sys/dev/usb/quirk/usb_quirk.c b/sys/dev/usb/quirk/usb_quirk.c
index 0c3d673..e54b908 100644
--- a/sys/dev/usb/quirk/usb_quirk.c
+++ b/sys/dev/usb/quirk/usb_quirk.c
@@ -472,6 +472,7 @@ static struct usb_quirk_entry usb_quirks[USB_DEV_QUIRKS_MAX] = {
USB_QUIRK(ROLAND, SD20, 0x0000, 0xffff, UQ_AU_VENDOR_CLASS),
USB_QUIRK(ROLAND, SD80, 0x0000, 0xffff, UQ_AU_VENDOR_CLASS),
USB_QUIRK(ROLAND, UA700, 0x0000, 0xffff, UQ_AU_VENDOR_CLASS),
+ USB_QUIRK(MEDELI, DD305, 0x0000, 0xffff, UQ_SINGLE_CMD_MIDI, UQ_MATCH_VENDOR_ONLY),
};
#undef USB_QUIRK_VP
#undef USB_QUIRK
@@ -538,6 +539,7 @@ static const char *usb_quirk_str[USB_QUIRK_MAX] = {
[UQ_MSC_EJECT_TCT] = "UQ_MSC_EJECT_TCT",
[UQ_BAD_MIDI] = "UQ_BAD_MIDI",
[UQ_AU_VENDOR_CLASS] = "UQ_AU_VENDOR_CLASS",
+ [UQ_SINGLE_CMD_MIDI] = "UQ_SINGLE_CMD_MIDI",
};
/*------------------------------------------------------------------------*
diff --git a/sys/dev/usb/quirk/usb_quirk.h b/sys/dev/usb/quirk/usb_quirk.h
index e86794e..e012842 100644
--- a/sys/dev/usb/quirk/usb_quirk.h
+++ b/sys/dev/usb/quirk/usb_quirk.h
@@ -102,6 +102,7 @@ enum {
UQ_BAD_MIDI, /* device claims MIDI class, but isn't */
UQ_AU_VENDOR_CLASS, /* audio device uses vendor and not audio class */
+ UQ_SINGLE_CMD_MIDI, /* at most one command per USB packet */
USB_QUIRK_MAX
};
diff --git a/sys/dev/usb/serial/u3g.c b/sys/dev/usb/serial/u3g.c
index c332bfb..31e8e11 100644
--- a/sys/dev/usb/serial/u3g.c
+++ b/sys/dev/usb/serial/u3g.c
@@ -182,7 +182,7 @@ MODULE_DEPEND(u3g, ucom, 1, 1, 1);
MODULE_DEPEND(u3g, usb, 1, 1, 1);
MODULE_VERSION(u3g, 1);
-static const struct usb_device_id u3g_devs[] = {
+static const STRUCT_USB_HOST_ID u3g_devs[] = {
#define U3G_DEV(v,p,i) { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, i) }
U3G_DEV(ACERP, H10, 0),
U3G_DEV(AIRPLUS, MCD650, 0),
diff --git a/sys/dev/usb/serial/uark.c b/sys/dev/usb/serial/uark.c
index 75100f2..2c3943d 100644
--- a/sys/dev/usb/serial/uark.c
+++ b/sys/dev/usb/serial/uark.c
@@ -170,7 +170,7 @@ MODULE_DEPEND(uark, ucom, 1, 1, 1);
MODULE_DEPEND(uark, usb, 1, 1, 1);
MODULE_VERSION(uark, 1);
-static const struct usb_device_id uark_devs[] = {
+static const STRUCT_USB_HOST_ID uark_devs[] = {
{USB_VPI(USB_VENDOR_ARKMICRO, USB_PRODUCT_ARKMICRO_ARK3116, 0)},
};
diff --git a/sys/dev/usb/serial/ubsa.c b/sys/dev/usb/serial/ubsa.c
index 1a5a75a..6afe05b 100644
--- a/sys/dev/usb/serial/ubsa.c
+++ b/sys/dev/usb/serial/ubsa.c
@@ -239,7 +239,7 @@ static const struct ucom_callback ubsa_callback = {
.ucom_poll = &ubsa_poll,
};
-static const struct usb_device_id ubsa_devs[] = {
+static const STRUCT_USB_HOST_ID ubsa_devs[] = {
/* AnyData ADU-500A */
{USB_VPI(USB_VENDOR_ANYDATA, USB_PRODUCT_ANYDATA_ADU_500A, 0)},
/* AnyData ADU-E100A/H */
diff --git a/sys/dev/usb/serial/uchcom.c b/sys/dev/usb/serial/uchcom.c
index 60fa9e0..3f69c4d 100644
--- a/sys/dev/usb/serial/uchcom.c
+++ b/sys/dev/usb/serial/uchcom.c
@@ -204,7 +204,7 @@ static const struct uchcom_divider_record dividers[] =
#define NUM_DIVIDERS (sizeof (dividers) / sizeof (dividers[0]))
-static const struct usb_device_id uchcom_devs[] = {
+static const STRUCT_USB_HOST_ID uchcom_devs[] = {
{USB_VPI(USB_VENDOR_WCH, USB_PRODUCT_WCH_CH341SER, 0)},
{USB_VPI(USB_VENDOR_WCH2, USB_PRODUCT_WCH2_CH341SER, 0)},
};
diff --git a/sys/dev/usb/serial/ucycom.c b/sys/dev/usb/serial/ucycom.c
index a58398a..8fef219 100644
--- a/sys/dev/usb/serial/ucycom.c
+++ b/sys/dev/usb/serial/ucycom.c
@@ -180,7 +180,7 @@ MODULE_VERSION(ucycom, 1);
/*
* Supported devices
*/
-static const struct usb_device_id ucycom_devs[] = {
+static const STRUCT_USB_HOST_ID ucycom_devs[] = {
{USB_VPI(USB_VENDOR_DELORME, USB_PRODUCT_DELORME_EARTHMATE, MODEL_CY7C64013)},
};
diff --git a/sys/dev/usb/serial/ufoma.c b/sys/dev/usb/serial/ufoma.c
index a32fd47..31be85c 100644
--- a/sys/dev/usb/serial/ufoma.c
+++ b/sys/dev/usb/serial/ufoma.c
@@ -327,6 +327,11 @@ MODULE_DEPEND(ufoma, ucom, 1, 1, 1);
MODULE_DEPEND(ufoma, usb, 1, 1, 1);
MODULE_VERSION(ufoma, 1);
+static const STRUCT_USB_HOST_ID ufoma_devs[] = {
+ {USB_IFACE_CLASS(UICLASS_CDC),
+ USB_IFACE_SUBCLASS(UISUBCLASS_MCPC),},
+};
+
static int
ufoma_probe(device_t dev)
{
@@ -334,30 +339,31 @@ ufoma_probe(device_t dev)
struct usb_interface_descriptor *id;
struct usb_config_descriptor *cd;
usb_mcpc_acm_descriptor *mad;
+ int error;
- if (uaa->usb_mode != USB_MODE_HOST) {
+ if (uaa->usb_mode != USB_MODE_HOST)
return (ENXIO);
- }
+
+ error = usbd_lookup_id_by_uaa(ufoma_devs, sizeof(ufoma_devs), uaa);
+ if (error)
+ return (error);
+
id = usbd_get_interface_descriptor(uaa->iface);
cd = usbd_get_config_descriptor(uaa->device);
- if ((id == NULL) ||
- (cd == NULL) ||
- (id->bInterfaceClass != UICLASS_CDC) ||
- (id->bInterfaceSubClass != UISUBCLASS_MCPC)) {
+ if (id == NULL || cd == NULL)
return (ENXIO);
- }
+
mad = ufoma_get_intconf(cd, id, UDESC_VS_INTERFACE, UDESCSUB_MCPC_ACM);
- if (mad == NULL) {
+ if (mad == NULL)
return (ENXIO);
- }
+
#ifndef UFOMA_HANDSFREE
if ((mad->bType == UMCPC_ACM_TYPE_AB5) ||
- (mad->bType == UMCPC_ACM_TYPE_AB6)) {
+ (mad->bType == UMCPC_ACM_TYPE_AB6))
return (ENXIO);
- }
#endif
- return (0);
+ return (BUS_PROBE_GENERIC);
}
static int
diff --git a/sys/dev/usb/serial/uftdi.c b/sys/dev/usb/serial/uftdi.c
index b196862..1c88063 100644
--- a/sys/dev/usb/serial/uftdi.c
+++ b/sys/dev/usb/serial/uftdi.c
@@ -206,7 +206,7 @@ MODULE_DEPEND(uftdi, ucom, 1, 1, 1);
MODULE_DEPEND(uftdi, usb, 1, 1, 1);
MODULE_VERSION(uftdi, 1);
-static struct usb_device_id uftdi_devs[] = {
+static STRUCT_USB_HOST_ID uftdi_devs[] = {
#define UFTDI_DEV(v,p,t) \
{ USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, UFTDI_TYPE_##t) }
UFTDI_DEV(ATMEL, STK541, 8U232AM),
diff --git a/sys/dev/usb/serial/ugensa.c b/sys/dev/usb/serial/ugensa.c
index 0c2f2c4..6b0955e 100644
--- a/sys/dev/usb/serial/ugensa.c
+++ b/sys/dev/usb/serial/ugensa.c
@@ -154,7 +154,7 @@ MODULE_DEPEND(ugensa, ucom, 1, 1, 1);
MODULE_DEPEND(ugensa, usb, 1, 1, 1);
MODULE_VERSION(ugensa, 1);
-static const struct usb_device_id ugensa_devs[] = {
+static const STRUCT_USB_HOST_ID ugensa_devs[] = {
{USB_VPI(USB_VENDOR_AIRPRIME, USB_PRODUCT_AIRPRIME_PC5220, 0)},
{USB_VPI(USB_VENDOR_CMOTECH, USB_PRODUCT_CMOTECH_CDMA_MODEM1, 0)},
{USB_VPI(USB_VENDOR_KYOCERA2, USB_PRODUCT_KYOCERA2_CDMA_MSM_K, 0)},
diff --git a/sys/dev/usb/serial/uipaq.c b/sys/dev/usb/serial/uipaq.c
index 6f96164..d038e17 100644
--- a/sys/dev/usb/serial/uipaq.c
+++ b/sys/dev/usb/serial/uipaq.c
@@ -153,7 +153,7 @@ static const struct ucom_callback uipaq_callback = {
* support the same hardware. Numeric values are used where no usbdevs
* entries exist.
*/
-static const struct usb_device_id uipaq_devs[] = {
+static const STRUCT_USB_HOST_ID uipaq_devs[] = {
/* Socket USB Sync */
{USB_VPI(0x0104, 0x00be, 0)},
/* USB Sync 0301 */
diff --git a/sys/dev/usb/serial/ulpt.c b/sys/dev/usb/serial/ulpt.c
index ec1aa24..def2ae5 100644
--- a/sys/dev/usb/serial/ulpt.c
+++ b/sys/dev/usb/serial/ulpt.c
@@ -483,24 +483,39 @@ ulpt_ioctl(struct usb_fifo *fifo, u_long cmd, void *data,
return (ENODEV);
}
+static const STRUCT_USB_HOST_ID ulpt_devs[] = {
+ /* Uni-directional USB printer */
+ {USB_IFACE_CLASS(UICLASS_PRINTER),
+ USB_IFACE_SUBCLASS(UISUBCLASS_PRINTER),
+ USB_IFACE_PROTOCOL(UIPROTO_PRINTER_UNI)},
+
+ /* Bi-directional USB printer */
+ {USB_IFACE_CLASS(UICLASS_PRINTER),
+ USB_IFACE_SUBCLASS(UISUBCLASS_PRINTER),
+ USB_IFACE_PROTOCOL(UIPROTO_PRINTER_BI)},
+
+ /* 1284 USB printer */
+ {USB_IFACE_CLASS(UICLASS_PRINTER),
+ USB_IFACE_SUBCLASS(UISUBCLASS_PRINTER),
+ USB_IFACE_PROTOCOL(UIPROTO_PRINTER_1284)},
+};
+
static int
ulpt_probe(device_t dev)
{
struct usb_attach_arg *uaa = device_get_ivars(dev);
+ int error;
DPRINTFN(11, "\n");
- if (uaa->usb_mode != USB_MODE_HOST) {
+ if (uaa->usb_mode != USB_MODE_HOST)
return (ENXIO);
- }
- if ((uaa->info.bInterfaceClass == UICLASS_PRINTER) &&
- (uaa->info.bInterfaceSubClass == UISUBCLASS_PRINTER) &&
- ((uaa->info.bInterfaceProtocol == UIPROTO_PRINTER_UNI) ||
- (uaa->info.bInterfaceProtocol == UIPROTO_PRINTER_BI) ||
- (uaa->info.bInterfaceProtocol == UIPROTO_PRINTER_1284))) {
- return (0);
- }
- return (ENXIO);
+
+ error = usbd_lookup_id_by_uaa(ulpt_devs, sizeof(ulpt_devs), uaa);
+ if (error)
+ return (error);
+
+ return (BUS_PROBE_GENERIC);
}
static int
diff --git a/sys/dev/usb/serial/umcs.c b/sys/dev/usb/serial/umcs.c
index c74044e..94ed4d9 100644
--- a/sys/dev/usb/serial/umcs.c
+++ b/sys/dev/usb/serial/umcs.c
@@ -253,7 +253,7 @@ static struct ucom_callback umcs7840_callback = {
.ucom_poll = &umcs7840_poll,
};
-static const struct usb_device_id umcs7840_devs[] = {
+static const STRUCT_USB_HOST_ID umcs7840_devs[] = {
{USB_VPI(USB_VENDOR_MOSCHIP, USB_PRODUCT_MOSCHIP_MCS7820, 0)},
{USB_VPI(USB_VENDOR_MOSCHIP, USB_PRODUCT_MOSCHIP_MCS7840, 0)},
};
diff --git a/sys/dev/usb/serial/umct.c b/sys/dev/usb/serial/umct.c
index 39dc9d7..16dd4a1 100644
--- a/sys/dev/usb/serial/umct.c
+++ b/sys/dev/usb/serial/umct.c
@@ -192,7 +192,7 @@ static const struct ucom_callback umct_callback = {
.ucom_poll = &umct_poll,
};
-static const struct usb_device_id umct_devs[] = {
+static const STRUCT_USB_HOST_ID umct_devs[] = {
{USB_VPI(USB_VENDOR_MCT, USB_PRODUCT_MCT_USB232, 0)},
{USB_VPI(USB_VENDOR_MCT, USB_PRODUCT_MCT_SITECOM_USB232, 0)},
{USB_VPI(USB_VENDOR_MCT, USB_PRODUCT_MCT_DU_H3SP_USB232, 0)},
diff --git a/sys/dev/usb/serial/umodem.c b/sys/dev/usb/serial/umodem.c
index c6d517b..ed5162f 100644
--- a/sys/dev/usb/serial/umodem.c
+++ b/sys/dev/usb/serial/umodem.c
@@ -123,7 +123,7 @@ SYSCTL_INT(_hw_usb_umodem, OID_AUTO, debug, CTLFLAG_RW,
&umodem_debug, 0, "Debug level");
#endif
-static const struct usb_device_id umodem_devs[] = {
+static const STRUCT_USB_HOST_ID umodem_devs[] = {
/* Generic Modem class match */
{USB_IFACE_CLASS(UICLASS_CDC),
USB_IFACE_SUBCLASS(UISUBCLASS_ABSTRACT_CONTROL_MODEL),
@@ -276,11 +276,14 @@ umodem_probe(device_t dev)
DPRINTFN(11, "\n");
- if (uaa->usb_mode != USB_MODE_HOST) {
+ if (uaa->usb_mode != USB_MODE_HOST)
return (ENXIO);
- }
+
error = usbd_lookup_id_by_uaa(umodem_devs, sizeof(umodem_devs), uaa);
- return (error);
+ if (error)
+ return (error);
+
+ return (BUS_PROBE_GENERIC);
}
static int
diff --git a/sys/dev/usb/serial/umoscom.c b/sys/dev/usb/serial/umoscom.c
index 4ab6cc0..c346ae6 100644
--- a/sys/dev/usb/serial/umoscom.c
+++ b/sys/dev/usb/serial/umoscom.c
@@ -280,7 +280,7 @@ MODULE_DEPEND(umoscom, ucom, 1, 1, 1);
MODULE_DEPEND(umoscom, usb, 1, 1, 1);
MODULE_VERSION(umoscom, 1);
-static const struct usb_device_id umoscom_devs[] = {
+static const STRUCT_USB_HOST_ID umoscom_devs[] = {
{USB_VPI(USB_VENDOR_MOSCHIP, USB_PRODUCT_MOSCHIP_MCS7703, 0)}
};
diff --git a/sys/dev/usb/serial/uplcom.c b/sys/dev/usb/serial/uplcom.c
index 108ee7b..4af0537 100644
--- a/sys/dev/usb/serial/uplcom.c
+++ b/sys/dev/usb/serial/uplcom.c
@@ -247,7 +247,7 @@ static struct ucom_callback uplcom_callback = {
#define UPLCOM_DEV(v,p) \
{ USB_VENDOR(USB_VENDOR_##v), USB_PRODUCT(USB_PRODUCT_##v##_##p) }
-static const struct usb_device_id uplcom_devs[] = {
+static const STRUCT_USB_HOST_ID uplcom_devs[] = {
UPLCOM_DEV(ACERP, S81), /* BenQ S81 phone */
UPLCOM_DEV(ADLINK, ND6530), /* ADLINK ND-6530 USB-Serial */
UPLCOM_DEV(ALCATEL, OT535), /* Alcatel One Touch 535/735 */
diff --git a/sys/dev/usb/serial/uslcom.c b/sys/dev/usb/serial/uslcom.c
index 1357c8d..6eaec83 100644
--- a/sys/dev/usb/serial/uslcom.c
+++ b/sys/dev/usb/serial/uslcom.c
@@ -173,7 +173,7 @@ static struct ucom_callback uslcom_callback = {
.ucom_poll = &uslcom_poll,
};
-static const struct usb_device_id uslcom_devs[] = {
+static const STRUCT_USB_HOST_ID uslcom_devs[] = {
#define USLCOM_DEV(v,p) { USB_VP(USB_VENDOR_##v, USB_PRODUCT_##v##_##p) }
USLCOM_DEV(BALTECH, CARDREADER),
USLCOM_DEV(CLIPSAL, 5500PCU),
diff --git a/sys/dev/usb/serial/uvisor.c b/sys/dev/usb/serial/uvisor.c
index 3efef5d..976ea19 100644
--- a/sys/dev/usb/serial/uvisor.c
+++ b/sys/dev/usb/serial/uvisor.c
@@ -253,7 +253,7 @@ MODULE_DEPEND(uvisor, ucom, 1, 1, 1);
MODULE_DEPEND(uvisor, usb, 1, 1, 1);
MODULE_VERSION(uvisor, 1);
-static const struct usb_device_id uvisor_devs[] = {
+static const STRUCT_USB_HOST_ID uvisor_devs[] = {
#define UVISOR_DEV(v,p,i) { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, i) }
UVISOR_DEV(ACEECA, MEZ1000, UVISOR_FLAG_PALM4),
UVISOR_DEV(ALPHASMART, DANA_SYNC, UVISOR_FLAG_PALM4),
diff --git a/sys/dev/usb/serial/uvscom.c b/sys/dev/usb/serial/uvscom.c
index d883190..52e02ad 100644
--- a/sys/dev/usb/serial/uvscom.c
+++ b/sys/dev/usb/serial/uvscom.c
@@ -233,7 +233,7 @@ static const struct ucom_callback uvscom_callback = {
.ucom_poll = &uvscom_poll,
};
-static const struct usb_device_id uvscom_devs[] = {
+static const STRUCT_USB_HOST_ID uvscom_devs[] = {
/* SUNTAC U-Cable type A4 */
{USB_VPI(USB_VENDOR_SUNTAC, USB_PRODUCT_SUNTAC_AS144L4, 0)},
/* SUNTAC U-Cable type D2 */
diff --git a/sys/dev/usb/storage/umass.c b/sys/dev/usb/storage/umass.c
index 158d843..9292c84 100644
--- a/sys/dev/usb/storage/umass.c
+++ b/sys/dev/usb/storage/umass.c
@@ -721,6 +721,11 @@ MODULE_VERSION(umass, 1);
* USB device probe/attach/detach
*/
+static const STRUCT_USB_HOST_ID __used umass_devs[] = {
+ /* generic mass storage class */
+ {USB_IFACE_CLASS(UICLASS_MASS),},
+};
+
static uint16_t
umass_get_proto(struct usb_interface *iface)
{
diff --git a/sys/dev/usb/storage/urio.c b/sys/dev/usb/storage/urio.c
index ee93439..6687173 100644
--- a/sys/dev/usb/storage/urio.c
+++ b/sys/dev/usb/storage/urio.c
@@ -198,22 +198,25 @@ DRIVER_MODULE(urio, uhub, urio_driver, urio_devclass, NULL, 0);
MODULE_DEPEND(urio, usb, 1, 1, 1);
MODULE_VERSION(urio, 1);
+static const STRUCT_USB_HOST_ID urio_devs[] = {
+ {USB_VPI(USB_VENDOR_DIAMOND, USB_PRODUCT_DIAMOND_RIO500USB, 0)},
+ {USB_VPI(USB_VENDOR_DIAMOND2, USB_PRODUCT_DIAMOND2_RIO600USB, 0)},
+ {USB_VPI(USB_VENDOR_DIAMOND2, USB_PRODUCT_DIAMOND2_RIO800USB, 0)},
+};
+
static int
urio_probe(device_t dev)
{
struct usb_attach_arg *uaa = device_get_ivars(dev);
- if (uaa->usb_mode != USB_MODE_HOST) {
+ if (uaa->usb_mode != USB_MODE_HOST)
return (ENXIO);
- }
- if ((((uaa->info.idVendor == USB_VENDOR_DIAMOND) &&
- (uaa->info.idProduct == USB_PRODUCT_DIAMOND_RIO500USB)) ||
- ((uaa->info.idVendor == USB_VENDOR_DIAMOND2) &&
- ((uaa->info.idProduct == USB_PRODUCT_DIAMOND2_RIO600USB) ||
- (uaa->info.idProduct == USB_PRODUCT_DIAMOND2_RIO800USB)))))
- return (0);
- else
+ if (uaa->info.bConfigIndex != 0)
return (ENXIO);
+ if (uaa->info.bIfaceIndex != 0)
+ return (ENXIO);
+
+ return (usbd_lookup_id_by_uaa(urio_devs, sizeof(urio_devs), uaa));
}
static int
diff --git a/sys/dev/usb/template/usb_template.c b/sys/dev/usb/template/usb_template.c
index 7bf17fe..cf97482 100644
--- a/sys/dev/usb/template/usb_template.c
+++ b/sys/dev/usb/template/usb_template.c
@@ -49,6 +49,7 @@
#include <sys/priv.h>
#include <dev/usb/usb.h>
+#include <dev/usb/usb_ioctl.h>
#include <dev/usb/usbdi.h>
#include <dev/usb/usbdi_util.h>
#include "usbdevs.h"
@@ -141,6 +142,31 @@ usb_make_raw_desc(struct usb_temp_setup *temp,
ud->bSlaveInterface[0] +=
temp->bInterfaceNumber;
}
+
+ /* check if we have got an interface association descriptor */
+
+ if ((raw[0] >= sizeof(struct usb_interface_assoc_descriptor)) &&
+ (raw[1] == UDESC_IFACE_ASSOC)) {
+ struct usb_interface_assoc_descriptor *iad = (void *)dst;
+
+ /* update the interface number */
+
+ iad->bFirstInterface +=
+ temp->bInterfaceNumber;
+ }
+
+ /* check if we have got a call management descriptor */
+
+ if ((raw[0] >= sizeof(struct usb_cdc_cm_descriptor)) &&
+ (raw[1] == UDESC_CS_INTERFACE) &&
+ (raw[2] == UDESCSUB_CDC_CM)) {
+ struct usb_cdc_cm_descriptor *ccd = (void *)dst;
+
+ /* update the interface number */
+
+ ccd->bDataInterface +=
+ temp->bInterfaceNumber;
+ }
}
temp->size += len;
}
@@ -476,6 +502,10 @@ usb_make_device_desc(struct usb_temp_setup *temp,
USETW(utd->udd.bcdUSB, 0x0250);
utd->udd.bMaxPacketSize = 255; /* 512 bytes */
break;
+ case USB_SPEED_SUPER:
+ USETW(utd->udd.bcdUSB, 0x0300);
+ utd->udd.bMaxPacketSize = 9; /* 2**9 = 512 bytes */
+ break;
default:
temp->err = USB_ERR_INVAL;
break;
@@ -1303,15 +1333,27 @@ usb_temp_setup_by_index(struct usb_device *udev, uint16_t index)
usb_error_t err;
switch (index) {
- case 0:
+ case USB_TEMP_MSC:
err = usb_temp_setup(udev, &usb_template_msc);
break;
- case 1:
+ case USB_TEMP_CDCE:
err = usb_temp_setup(udev, &usb_template_cdce);
break;
- case 2:
+ case USB_TEMP_MTP:
err = usb_temp_setup(udev, &usb_template_mtp);
break;
+ case USB_TEMP_MODEM:
+ err = usb_temp_setup(udev, &usb_template_modem);
+ break;
+ case USB_TEMP_AUDIO:
+ err = usb_temp_setup(udev, &usb_template_audio);
+ break;
+ case USB_TEMP_KBD:
+ err = usb_temp_setup(udev, &usb_template_kbd);
+ break;
+ case USB_TEMP_MOUSE:
+ err = usb_temp_setup(udev, &usb_template_mouse);
+ break;
default:
return (USB_ERR_INVAL);
}
diff --git a/sys/dev/usb/template/usb_template.h b/sys/dev/usb/template/usb_template.h
index 2473af3..b05272f 100644
--- a/sys/dev/usb/template/usb_template.h
+++ b/sys/dev/usb/template/usb_template.h
@@ -30,6 +30,10 @@
#ifndef _USB_TEMPLATE_H_
#define _USB_TEMPLATE_H_
+#ifndef USB_TEMPLATE_VENDOR
+#define USB_TEMPLATE_VENDOR 0x0001
+#endif
+
typedef const void *(usb_temp_get_string_desc_t)(uint16_t lang_id, uint8_t string_index);
typedef const void *(usb_temp_get_vendor_desc_t)(const struct usb_device_request *req, uint16_t *plen);
@@ -94,10 +98,14 @@ struct usb_temp_data {
/* prototypes */
+extern const struct usb_temp_device_desc usb_template_audio;
extern const struct usb_temp_device_desc usb_template_cdce;
-extern const struct usb_temp_device_desc usb_template_msc; /* Mass Storage Class */
-extern const struct usb_temp_device_desc usb_template_mtp; /* Message Transfer
- * Protocol */
+extern const struct usb_temp_device_desc usb_template_kbd;
+extern const struct usb_temp_device_desc usb_template_modem;
+extern const struct usb_temp_device_desc usb_template_mouse;
+extern const struct usb_temp_device_desc usb_template_msc;
+extern const struct usb_temp_device_desc usb_template_mtp;
+
usb_error_t usb_temp_setup(struct usb_device *,
const struct usb_temp_device_desc *);
void usb_temp_unsetup(struct usb_device *);
diff --git a/sys/dev/usb/template/usb_template_audio.c b/sys/dev/usb/template/usb_template_audio.c
new file mode 100644
index 0000000..8e9e7f0
--- /dev/null
+++ b/sys/dev/usb/template/usb_template_audio.c
@@ -0,0 +1,405 @@
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*-
+ * Copyright (c) 2010 Hans Petter Selasky. All rights reserved.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+/*
+ * This file contains the USB template for an USB Audio Device.
+ */
+
+#include <sys/stdint.h>
+#include <sys/stddef.h>
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/types.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/module.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/condvar.h>
+#include <sys/sysctl.h>
+#include <sys/sx.h>
+#include <sys/unistd.h>
+#include <sys/callout.h>
+#include <sys/malloc.h>
+#include <sys/priv.h>
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+#include <dev/usb/usb_cdc.h>
+
+#include <dev/usb/template/usb_template.h>
+
+enum {
+ INDEX_AUDIO_LANG,
+ INDEX_AUDIO_MIXER,
+ INDEX_AUDIO_RECORD,
+ INDEX_AUDIO_PLAYBACK,
+ INDEX_AUDIO_PRODUCT,
+ INDEX_AUDIO_MAX,
+};
+
+#define STRING_LANG \
+ 0x09, 0x04, /* American English */
+
+#define STRING_AUDIO_PRODUCT \
+ 'A', 0, 'u', 0, 'd', 0, 'i', 0, 'o', 0, ' ', 0, \
+ 'T', 0, 'e', 0, 's', 0, 't', 0, ' ', 0, \
+ 'D', 0, 'e', 0, 'v', 0, 'i', 0, 'c', 0, 'e', 0, ' ', 0,
+
+#define STRING_AUDIO_MIXER \
+ 'M', 0, 'i', 0, 'x', 0, 'e', 0, 'r', 0, ' ', 0, \
+ 'i', 0, 'n', 0, 't', 0, 'e', 0, 'r', 0, 'f', 0, 'a', 0, 'c', 0, 'e', 0,
+
+#define STRING_AUDIO_RECORD \
+ 'R', 0, 'e', 0, 'c', 0, 'o', 0, 'r', 0, 'd', 0, ' ', 0, \
+ 'i', 0, 'n', 0, 't', 0, 'e', 0, 'r', 0, 'f', 0, 'a', 0, 'c', 0, 'e', 0,
+
+#define STRING_AUDIO_PLAYBACK \
+ 'P', 0, 'l', 0, 'a', 0, 'y', 0, 'b', 0, 'a', 0, 'c', 0, 'k', 0, ' ', 0, \
+ 'i', 0, 'n', 0, 't', 0, 'e', 0, 'r', 0, 'f', 0, 'a', 0, 'c', 0, 'e', 0,
+
+
+/* make the real string descriptors */
+
+USB_MAKE_STRING_DESC(STRING_LANG, string_lang);
+USB_MAKE_STRING_DESC(STRING_AUDIO_MIXER, string_audio_mixer);
+USB_MAKE_STRING_DESC(STRING_AUDIO_RECORD, string_audio_record);
+USB_MAKE_STRING_DESC(STRING_AUDIO_PLAYBACK, string_audio_playback);
+USB_MAKE_STRING_DESC(STRING_AUDIO_PRODUCT, string_audio_product);
+
+/* prototypes */
+
+/*
+ * Audio Mixer description structures
+ *
+ * Some of the audio descriptors were dumped
+ * from a Creative Labs USB audio device.
+ */
+
+static const uint8_t audio_raw_desc_0[] = {
+ 0x0a, 0x24, 0x01, 0x00, 0x01, 0xa9, 0x00, 0x02,
+ 0x01, 0x02
+};
+
+static const uint8_t audio_raw_desc_1[] = {
+ 0x0c, 0x24, 0x02, 0x01, 0x01, 0x01, 0x00, 0x02,
+ 0x03, 0x00, 0x00, 0x00
+};
+
+static const uint8_t audio_raw_desc_2[] = {
+ 0x0c, 0x24, 0x02, 0x02, 0x01, 0x02, 0x00, 0x02,
+ 0x03, 0x00, 0x00, 0x00
+};
+
+static const uint8_t audio_raw_desc_3[] = {
+ 0x0c, 0x24, 0x02, 0x03, 0x03, 0x06, 0x00, 0x02,
+ 0x03, 0x00, 0x00, 0x00
+};
+
+static const uint8_t audio_raw_desc_4[] = {
+ 0x0c, 0x24, 0x02, 0x04, 0x05, 0x06, 0x00, 0x02,
+ 0x03, 0x00, 0x00, 0x00
+};
+
+static const uint8_t audio_raw_desc_5[] = {
+ 0x09, 0x24, 0x03, 0x05, 0x05, 0x06, 0x00, 0x01,
+ 0x00
+};
+
+static const uint8_t audio_raw_desc_6[] = {
+ 0x09, 0x24, 0x03, 0x06, 0x01, 0x03, 0x00, 0x09,
+ 0x00
+};
+
+static const uint8_t audio_raw_desc_7[] = {
+ 0x09, 0x24, 0x03, 0x07, 0x01, 0x01, 0x00, 0x08,
+ 0x00
+};
+
+static const uint8_t audio_raw_desc_8[] = {
+ 0x09, 0x24, 0x05, 0x08, 0x03, 0x0a, 0x0b, 0x0c,
+ 0x00
+};
+
+static const uint8_t audio_raw_desc_9[] = {
+ 0x0a, 0x24, 0x06, 0x09, 0x0f, 0x01, 0x01, 0x02,
+ 0x02, 0x00
+};
+
+static const uint8_t audio_raw_desc_10[] = {
+ 0x0a, 0x24, 0x06, 0x0a, 0x02, 0x01, 0x43, 0x00,
+ 0x00, 0x00
+};
+
+static const uint8_t audio_raw_desc_11[] = {
+ 0x0a, 0x24, 0x06, 0x0b, 0x03, 0x01, 0x01, 0x02,
+ 0x02, 0x00
+};
+
+static const uint8_t audio_raw_desc_12[] = {
+ 0x0a, 0x24, 0x06, 0x0c, 0x04, 0x01, 0x01, 0x00,
+ 0x00, 0x00
+};
+
+static const uint8_t audio_raw_desc_13[] = {
+ 0x0a, 0x24, 0x06, 0x0d, 0x02, 0x01, 0x03, 0x00,
+ 0x00, 0x00
+};
+
+static const uint8_t audio_raw_desc_14[] = {
+ 0x0a, 0x24, 0x06, 0x0e, 0x03, 0x01, 0x01, 0x02,
+ 0x02, 0x00
+};
+
+static const uint8_t audio_raw_desc_15[] = {
+ 0x0f, 0x24, 0x04, 0x0f, 0x03, 0x01, 0x0d, 0x0e,
+ 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static const void *audio_raw_iface_0_desc[] = {
+ audio_raw_desc_0,
+ audio_raw_desc_1,
+ audio_raw_desc_2,
+ audio_raw_desc_3,
+ audio_raw_desc_4,
+ audio_raw_desc_5,
+ audio_raw_desc_6,
+ audio_raw_desc_7,
+ audio_raw_desc_8,
+ audio_raw_desc_9,
+ audio_raw_desc_10,
+ audio_raw_desc_11,
+ audio_raw_desc_12,
+ audio_raw_desc_13,
+ audio_raw_desc_14,
+ audio_raw_desc_15,
+ NULL,
+};
+
+static const struct usb_temp_interface_desc audio_iface_0 = {
+ .ppEndpoints = NULL, /* no endpoints */
+ .ppRawDesc = audio_raw_iface_0_desc,
+ .bInterfaceClass = 1,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .iInterface = INDEX_AUDIO_MIXER,
+};
+
+static const uint8_t audio_raw_desc_20[] = {
+ 0x07, 0x24, 0x01, 0x01, 0x03, 0x01, 0x00
+
+};
+
+static const uint8_t audio_raw_desc_21[] = {
+ 0x0b, 0x24, 0x02, 0x01, 0x02, 0x02, 0x10, 0x01,
+ /* 48kHz */
+ 0x80, 0xbb, 0x00
+};
+
+static const uint8_t audio_raw_desc_22[] = {
+ 0x07, 0x25, 0x01, 0x00, 0x01, 0x04, 0x00
+};
+
+static const void *audio_raw_iface_1_desc[] = {
+ audio_raw_desc_20,
+ audio_raw_desc_21,
+ NULL,
+};
+
+static const void *audio_raw_ep_1_desc[] = {
+ audio_raw_desc_22,
+ NULL,
+};
+
+static const struct usb_temp_packet_size audio_isoc_mps = {
+ .mps[USB_SPEED_FULL] = 0xC8,
+ .mps[USB_SPEED_HIGH] = 0xC8,
+};
+
+static const struct usb_temp_interval audio_isoc_interval = {
+ .bInterval[USB_SPEED_FULL] = 1, /* 1:1 */
+ .bInterval[USB_SPEED_HIGH] = 4, /* 1:8 */
+};
+
+static const struct usb_temp_endpoint_desc audio_isoc_out_ep = {
+ .ppRawDesc = audio_raw_ep_1_desc,
+ .pPacketSize = &audio_isoc_mps,
+ .pIntervals = &audio_isoc_interval,
+ .bEndpointAddress = UE_DIR_OUT,
+ .bmAttributes = UE_ISOCHRONOUS | UE_ISO_ADAPT,
+};
+
+static const struct usb_temp_endpoint_desc *audio_iface_1_ep[] = {
+ &audio_isoc_out_ep,
+ NULL,
+};
+
+static const struct usb_temp_interface_desc audio_iface_1_alt_0 = {
+ .ppEndpoints = NULL, /* no endpoints */
+ .ppRawDesc = NULL, /* no raw descriptors */
+ .bInterfaceClass = 1,
+ .bInterfaceSubClass = 2,
+ .bInterfaceProtocol = 0,
+ .iInterface = INDEX_AUDIO_PLAYBACK,
+};
+
+static const struct usb_temp_interface_desc audio_iface_1_alt_1 = {
+ .ppEndpoints = audio_iface_1_ep,
+ .ppRawDesc = audio_raw_iface_1_desc,
+ .bInterfaceClass = 1,
+ .bInterfaceSubClass = 2,
+ .bInterfaceProtocol = 0,
+ .iInterface = INDEX_AUDIO_PLAYBACK,
+ .isAltInterface = 1, /* this is an alternate setting */
+};
+
+static const uint8_t audio_raw_desc_30[] = {
+ 0x07, 0x24, 0x01, 0x07, 0x01, 0x01, 0x00
+
+};
+
+static const uint8_t audio_raw_desc_31[] = {
+ 0x0b, 0x24, 0x02, 0x01, 0x02, 0x02, 0x10, 0x01,
+ /* 48kHz */
+ 0x80, 0xbb, 0x00
+};
+
+static const uint8_t audio_raw_desc_32[] = {
+ 0x07, 0x25, 0x01, 0x01, 0x00, 0x00, 0x00
+};
+
+static const void *audio_raw_iface_2_desc[] = {
+ audio_raw_desc_30,
+ audio_raw_desc_31,
+ NULL,
+};
+
+static const void *audio_raw_ep_2_desc[] = {
+ audio_raw_desc_32,
+ NULL,
+};
+
+static const struct usb_temp_endpoint_desc audio_isoc_in_ep = {
+ .ppRawDesc = audio_raw_ep_2_desc,
+ .pPacketSize = &audio_isoc_mps,
+ .pIntervals = &audio_isoc_interval,
+ .bEndpointAddress = UE_DIR_IN,
+ .bmAttributes = UE_ISOCHRONOUS | UE_ISO_ADAPT,
+};
+
+static const struct usb_temp_endpoint_desc *audio_iface_2_ep[] = {
+ &audio_isoc_in_ep,
+ NULL,
+};
+
+static const struct usb_temp_interface_desc audio_iface_2_alt_0 = {
+ .ppEndpoints = NULL, /* no endpoints */
+ .ppRawDesc = NULL, /* no raw descriptors */
+ .bInterfaceClass = 1,
+ .bInterfaceSubClass = 2,
+ .bInterfaceProtocol = 0,
+ .iInterface = INDEX_AUDIO_RECORD,
+};
+
+static const struct usb_temp_interface_desc audio_iface_2_alt_1 = {
+ .ppEndpoints = audio_iface_2_ep,
+ .ppRawDesc = audio_raw_iface_2_desc,
+ .bInterfaceClass = 1,
+ .bInterfaceSubClass = 2,
+ .bInterfaceProtocol = 0,
+ .iInterface = INDEX_AUDIO_RECORD,
+ .isAltInterface = 1, /* this is an alternate setting */
+};
+
+static const struct usb_temp_interface_desc *audio_interfaces[] = {
+ &audio_iface_0,
+ &audio_iface_1_alt_0,
+ &audio_iface_1_alt_1,
+ &audio_iface_2_alt_0,
+ &audio_iface_2_alt_1,
+ NULL,
+};
+
+static const struct usb_temp_config_desc audio_config_desc = {
+ .ppIfaceDesc = audio_interfaces,
+ .bmAttributes = UC_BUS_POWERED,
+ .bMaxPower = 25, /* 50 mA */
+ .iConfiguration = INDEX_AUDIO_PRODUCT,
+};
+
+static const struct usb_temp_config_desc *audio_configs[] = {
+ &audio_config_desc,
+ NULL,
+};
+
+static usb_temp_get_string_desc_t audio_get_string_desc;
+
+const struct usb_temp_device_desc usb_template_audio = {
+ .getStringDesc = &audio_get_string_desc,
+ .ppConfigDesc = audio_configs,
+ .idVendor = USB_TEMPLATE_VENDOR,
+ .idProduct = 0x000A,
+ .bcdDevice = 0x0100,
+ .bDeviceClass = UDCLASS_COMM,
+ .bDeviceSubClass = 0,
+ .bDeviceProtocol = 0,
+ .iManufacturer = 0,
+ .iProduct = INDEX_AUDIO_PRODUCT,
+ .iSerialNumber = 0,
+};
+
+/*------------------------------------------------------------------------*
+ * audio_get_string_desc
+ *
+ * Return values:
+ * NULL: Failure. No such string.
+ * Else: Success. Pointer to string descriptor is returned.
+ *------------------------------------------------------------------------*/
+static const void *
+audio_get_string_desc(uint16_t lang_id, uint8_t string_index)
+{
+ static const void *ptr[INDEX_AUDIO_MAX] = {
+ [INDEX_AUDIO_LANG] = &string_lang,
+ [INDEX_AUDIO_MIXER] = &string_audio_mixer,
+ [INDEX_AUDIO_RECORD] = &string_audio_record,
+ [INDEX_AUDIO_PLAYBACK] = &string_audio_playback,
+ [INDEX_AUDIO_PRODUCT] = &string_audio_product,
+ };
+
+ if (string_index == 0) {
+ return (&string_lang);
+ }
+ if (lang_id != 0x0409) {
+ return (NULL);
+ }
+ if (string_index < INDEX_AUDIO_MAX) {
+ return (ptr[string_index]);
+ }
+ return (NULL);
+}
diff --git a/sys/dev/usb/template/usb_template_cdce.c b/sys/dev/usb/template/usb_template_cdce.c
index c8b2c6c..481a69c 100644
--- a/sys/dev/usb/template/usb_template_cdce.c
+++ b/sys/dev/usb/template/usb_template_cdce.c
@@ -264,7 +264,7 @@ static const struct usb_temp_config_desc *eth_configs[] = {
const struct usb_temp_device_desc usb_template_cdce = {
.getStringDesc = &eth_get_string_desc,
.ppConfigDesc = eth_configs,
- .idVendor = 0x0001,
+ .idVendor = USB_TEMPLATE_VENDOR,
.idProduct = 0x0001,
.bcdDevice = 0x0100,
.bDeviceClass = UDCLASS_COMM,
diff --git a/sys/dev/usb/template/usb_template_kbd.c b/sys/dev/usb/template/usb_template_kbd.c
new file mode 100644
index 0000000..8928c06
--- /dev/null
+++ b/sys/dev/usb/template/usb_template_kbd.c
@@ -0,0 +1,224 @@
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*-
+ * Copyright (c) 2010 Hans Petter Selasky. All rights reserved.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+/*
+ * This file contains the USB template for an USB Keyboard Device.
+ */
+
+#include <sys/stdint.h>
+#include <sys/stddef.h>
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/types.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/module.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/condvar.h>
+#include <sys/sysctl.h>
+#include <sys/sx.h>
+#include <sys/unistd.h>
+#include <sys/callout.h>
+#include <sys/malloc.h>
+#include <sys/priv.h>
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+#include <dev/usb/usb_cdc.h>
+
+#include <dev/usb/template/usb_template.h>
+
+enum {
+ INDEX_LANG,
+ INDEX_KEYBOARD,
+ INDEX_PRODUCT,
+ INDEX_MAX,
+};
+
+#define STRING_LANG \
+ 0x09, 0x04, /* American English */
+
+#define STRING_PRODUCT \
+ 'K', 0, 'e', 0, 'y', 0, 'b', 0, 'o', 0, 'a', 0, 'r', 0, 'd', 0, ' ', 0, \
+ 'T', 0, 'e', 0, 's', 0, 't', 0, ' ', 0, \
+ 'D', 0, 'e', 0, 'v', 0, 'i', 0, 'c', 0, 'e', 0, ' ', 0,
+
+#define STRING_KEYBOARD \
+ 'K', 0, 'e', 0, 'y', 0, 'b', 0, 'o', 0, 'a', 0, 'r', 0, 'd', 0, ' ', 0, \
+ 'i', 0, 'n', 0, 't', 0, 'e', 0, 'r', 0, 'f', 0, 'a', 0, 'c', 0, 'e', 0,
+
+/* make the real string descriptors */
+
+USB_MAKE_STRING_DESC(STRING_LANG, string_lang);
+USB_MAKE_STRING_DESC(STRING_KEYBOARD, string_keyboard);
+USB_MAKE_STRING_DESC(STRING_PRODUCT, string_product);
+
+/* prototypes */
+
+static const struct usb_temp_packet_size keyboard_intr_mps = {
+ .mps[USB_SPEED_LOW] = 16,
+ .mps[USB_SPEED_FULL] = 16,
+ .mps[USB_SPEED_HIGH] = 16,
+};
+
+static const struct usb_temp_interval keyboard_intr_interval = {
+ .bInterval[USB_SPEED_LOW] = 2, /* ms */
+ .bInterval[USB_SPEED_FULL] = 2,
+ .bInterval[USB_SPEED_HIGH] = 2 * 8,
+};
+
+/* The following HID descriptor was dumped from a HP keyboard. */
+
+static uint8_t keyboard_hid_descriptor[] = {
+ 0x05, 0x01, 0x09, 0x06, 0xa1, 0x01, 0x05, 0x07,
+ 0x19, 0xe0, 0x29, 0xe7, 0x15, 0x00, 0x25, 0x01,
+ 0x75, 0x01, 0x95, 0x08, 0x81, 0x02, 0x95, 0x01,
+ 0x75, 0x08, 0x81, 0x01, 0x95, 0x03, 0x75, 0x01,
+ 0x05, 0x08, 0x19, 0x01, 0x29, 0x03, 0x91, 0x02,
+ 0x95, 0x05, 0x75, 0x01, 0x91, 0x01, 0x95, 0x06,
+ 0x75, 0x08, 0x15, 0x00, 0x26, 0xff, 0x00, 0x05,
+ 0x07, 0x19, 0x00, 0x2a, 0xff, 0x00, 0x81, 0x00,
+ 0xc0
+};
+
+static const struct usb_temp_endpoint_desc keyboard_ep_0 = {
+ .ppRawDesc = NULL, /* no raw descriptors */
+ .pPacketSize = &keyboard_intr_mps,
+ .pIntervals = &keyboard_intr_interval,
+ .bEndpointAddress = UE_DIR_IN,
+ .bmAttributes = UE_INTERRUPT,
+};
+
+static const struct usb_temp_endpoint_desc *keyboard_endpoints[] = {
+ &keyboard_ep_0,
+ NULL,
+};
+
+static const uint8_t keyboard_raw_desc[] = {
+ 0x09, 0x21, 0x10, 0x01, 0x00, 0x01, 0x22, sizeof(keyboard_hid_descriptor),
+ 0x00
+};
+
+static const void *keyboard_iface_0_desc[] = {
+ keyboard_raw_desc,
+ NULL,
+};
+
+static const struct usb_temp_interface_desc keyboard_iface_0 = {
+ .ppRawDesc = keyboard_iface_0_desc,
+ .ppEndpoints = keyboard_endpoints,
+ .bInterfaceClass = 3,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 1,
+ .iInterface = INDEX_KEYBOARD,
+};
+
+static const struct usb_temp_interface_desc *keyboard_interfaces[] = {
+ &keyboard_iface_0,
+ NULL,
+};
+
+static const struct usb_temp_config_desc keyboard_config_desc = {
+ .ppIfaceDesc = keyboard_interfaces,
+ .bmAttributes = UC_BUS_POWERED,
+ .bMaxPower = 25, /* 50 mA */
+ .iConfiguration = INDEX_PRODUCT,
+};
+
+static const struct usb_temp_config_desc *keyboard_configs[] = {
+ &keyboard_config_desc,
+ NULL,
+};
+
+static usb_temp_get_string_desc_t keyboard_get_string_desc;
+static usb_temp_get_vendor_desc_t keyboard_get_vendor_desc;
+
+const struct usb_temp_device_desc usb_template_kbd = {
+ .getStringDesc = &keyboard_get_string_desc,
+ .getVendorDesc = &keyboard_get_vendor_desc,
+ .ppConfigDesc = keyboard_configs,
+ .idVendor = USB_TEMPLATE_VENDOR,
+ .idProduct = 0x00CB,
+ .bcdDevice = 0x0100,
+ .bDeviceClass = UDCLASS_COMM,
+ .bDeviceSubClass = 0,
+ .bDeviceProtocol = 0,
+ .iManufacturer = 0,
+ .iProduct = INDEX_PRODUCT,
+ .iSerialNumber = 0,
+};
+
+/*------------------------------------------------------------------------*
+ * keyboard_get_vendor_desc
+ *
+ * Return values:
+ * NULL: Failure. No such vendor descriptor.
+ * Else: Success. Pointer to vendor descriptor is returned.
+ *------------------------------------------------------------------------*/
+static const void *
+keyboard_get_vendor_desc(const struct usb_device_request *req, uint16_t *plen)
+{
+ if ((req->bmRequestType == 0x81) && (req->bRequest == 0x06) &&
+ (req->wValue[0] == 0x00) && (req->wValue[1] == 0x22) &&
+ (req->wIndex[1] == 0) && (req->wIndex[0] == 0)) {
+
+ *plen = sizeof(keyboard_hid_descriptor);
+ return (keyboard_hid_descriptor);
+ }
+ return (NULL);
+}
+
+/*------------------------------------------------------------------------*
+ * keyboard_get_string_desc
+ *
+ * Return values:
+ * NULL: Failure. No such string.
+ * Else: Success. Pointer to string descriptor is returned.
+ *------------------------------------------------------------------------*/
+static const void *
+keyboard_get_string_desc(uint16_t lang_id, uint8_t string_index)
+{
+ static const void *ptr[INDEX_MAX] = {
+ [INDEX_LANG] = &string_lang,
+ [INDEX_KEYBOARD] = &string_keyboard,
+ [INDEX_PRODUCT] = &string_product,
+ };
+
+ if (string_index == 0) {
+ return (&string_lang);
+ }
+ if (lang_id != 0x0409) {
+ return (NULL);
+ }
+ if (string_index < INDEX_MAX) {
+ return (ptr[string_index]);
+ }
+ return (NULL);
+}
diff --git a/sys/dev/usb/template/usb_template_modem.c b/sys/dev/usb/template/usb_template_modem.c
new file mode 100644
index 0000000..6e0f940
--- /dev/null
+++ b/sys/dev/usb/template/usb_template_modem.c
@@ -0,0 +1,252 @@
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*-
+ * Copyright (c) 2010 Hans Petter Selasky. All rights reserved.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+/*
+ * This file contains the USB template for an USB Modem Device.
+ */
+
+#include <sys/stdint.h>
+#include <sys/stddef.h>
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/types.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/module.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/condvar.h>
+#include <sys/sysctl.h>
+#include <sys/sx.h>
+#include <sys/unistd.h>
+#include <sys/callout.h>
+#include <sys/malloc.h>
+#include <sys/priv.h>
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+#include <dev/usb/usb_cdc.h>
+
+#include <dev/usb/template/usb_template.h>
+
+enum {
+ INDEX_LANG,
+ INDEX_MODEM,
+ INDEX_PRODUCT,
+ INDEX_MAX,
+};
+
+#define STRING_LANG \
+ 0x09, 0x04, /* American English */
+
+#define STRING_PRODUCT \
+ 'M', 0, 'o', 0, 'd', 0, 'e', 0, 'm', 0, ' ', 0, \
+ 'T', 0, 'e', 0, 's', 0, 't', 0, ' ', 0, \
+ 'D', 0, 'e', 0, 'v', 0, 'i', 0, 'c', 0, 'e', 0, ' ', 0,
+
+#define STRING_MODEM \
+ 'M', 0, 'o', 0, 'd', 0, 'e', 0, 'm', 0, ' ', 0, \
+ 'i', 0, 'n', 0, 't', 0, 'e', 0, 'r', 0, 'f', 0, 'a', 0, 'c', 0, 'e', 0,
+
+/* make the real string descriptors */
+
+USB_MAKE_STRING_DESC(STRING_LANG, string_lang);
+USB_MAKE_STRING_DESC(STRING_MODEM, string_modem);
+USB_MAKE_STRING_DESC(STRING_PRODUCT, string_product);
+
+#define MODEM_IFACE_0 0
+#define MODEM_IFACE_1 1
+
+/* prototypes */
+
+static const struct usb_temp_packet_size modem_bulk_mps = {
+ .mps[USB_SPEED_LOW] = 8,
+ .mps[USB_SPEED_FULL] = 64,
+ .mps[USB_SPEED_HIGH] = 512,
+};
+
+static const struct usb_temp_packet_size modem_intr_mps = {
+ .mps[USB_SPEED_LOW] = 8,
+ .mps[USB_SPEED_FULL] = 8,
+ .mps[USB_SPEED_HIGH] = 8,
+};
+
+static const struct usb_temp_interval modem_intr_interval = {
+ .bInterval[USB_SPEED_LOW] = 10,
+ .bInterval[USB_SPEED_FULL] = 10,
+ .bInterval[USB_SPEED_HIGH] = 10 * 8,
+};
+
+static const struct usb_temp_endpoint_desc modem_ep_0 = {
+ .pPacketSize = &modem_intr_mps,
+ .pIntervals = &modem_intr_interval,
+ .bEndpointAddress = UE_DIR_IN,
+ .bmAttributes = UE_INTERRUPT,
+};
+
+static const struct usb_temp_endpoint_desc modem_ep_1 = {
+ .pPacketSize = &modem_bulk_mps,
+ .bEndpointAddress = UE_DIR_OUT,
+ .bmAttributes = UE_BULK,
+};
+
+static const struct usb_temp_endpoint_desc modem_ep_2 = {
+ .pPacketSize = &modem_bulk_mps,
+ .bEndpointAddress = UE_DIR_IN,
+ .bmAttributes = UE_BULK,
+};
+
+static const struct usb_temp_endpoint_desc *modem_iface_0_ep[] = {
+ &modem_ep_0,
+ NULL,
+};
+
+static const struct usb_temp_endpoint_desc *modem_iface_1_ep[] = {
+ &modem_ep_1,
+ &modem_ep_2,
+ NULL,
+};
+
+static const uint8_t modem_raw_desc_0[] = {
+ 0x05, 0x24, 0x00, 0x10, 0x01
+};
+
+static const uint8_t modem_raw_desc_1[] = {
+ 0x05, 0x24, 0x06, MODEM_IFACE_0, MODEM_IFACE_1
+};
+
+static const uint8_t modem_raw_desc_2[] = {
+ 0x05, 0x24, 0x01, 0x03, MODEM_IFACE_1
+};
+
+static const uint8_t modem_raw_desc_3[] = {
+ 0x04, 0x24, 0x02, 0x07
+};
+
+static const void *modem_iface_0_desc[] = {
+ &modem_raw_desc_0,
+ &modem_raw_desc_1,
+ &modem_raw_desc_2,
+ &modem_raw_desc_3,
+ NULL,
+};
+
+static const struct usb_temp_interface_desc modem_iface_0 = {
+ .ppRawDesc = modem_iface_0_desc,
+ .ppEndpoints = modem_iface_0_ep,
+ .bInterfaceClass = 2,
+ .bInterfaceSubClass = 2,
+ .bInterfaceProtocol = 1,
+ .iInterface = INDEX_MODEM,
+};
+
+static const struct usb_temp_interface_desc modem_iface_1 = {
+ .ppEndpoints = modem_iface_1_ep,
+ .bInterfaceClass = 10,
+ .bInterfaceSubClass = 0,
+ .bInterfaceProtocol = 0,
+ .iInterface = INDEX_MODEM,
+};
+
+static const struct usb_temp_interface_desc *modem_interfaces[] = {
+ &modem_iface_0,
+ &modem_iface_1,
+ NULL,
+};
+
+static const struct usb_temp_config_desc modem_config_desc = {
+ .ppIfaceDesc = modem_interfaces,
+ .bmAttributes = UC_BUS_POWERED,
+ .bMaxPower = 25, /* 50 mA */
+ .iConfiguration = INDEX_PRODUCT,
+};
+
+static const struct usb_temp_config_desc *modem_configs[] = {
+ &modem_config_desc,
+ NULL,
+};
+
+static usb_temp_get_string_desc_t modem_get_string_desc;
+static usb_temp_get_vendor_desc_t modem_get_vendor_desc;
+
+const struct usb_temp_device_desc usb_template_modem = {
+ .getStringDesc = &modem_get_string_desc,
+ .getVendorDesc = &modem_get_vendor_desc,
+ .ppConfigDesc = modem_configs,
+ .idVendor = USB_TEMPLATE_VENDOR,
+ .idProduct = 0x000E,
+ .bcdDevice = 0x0100,
+ .bDeviceClass = UDCLASS_COMM,
+ .bDeviceSubClass = 0,
+ .bDeviceProtocol = 0,
+ .iManufacturer = 0,
+ .iProduct = INDEX_PRODUCT,
+ .iSerialNumber = 0,
+};
+
+/*------------------------------------------------------------------------*
+ * modem_get_vendor_desc
+ *
+ * Return values:
+ * NULL: Failure. No such vendor descriptor.
+ * Else: Success. Pointer to vendor descriptor is returned.
+ *------------------------------------------------------------------------*/
+static const void *
+modem_get_vendor_desc(const struct usb_device_request *req, uint16_t *plen)
+{
+ return (NULL);
+}
+
+/*------------------------------------------------------------------------*
+ * modem_get_string_desc
+ *
+ * Return values:
+ * NULL: Failure. No such string.
+ * Else: Success. Pointer to string descriptor is returned.
+ *------------------------------------------------------------------------*/
+static const void *
+modem_get_string_desc(uint16_t lang_id, uint8_t string_index)
+{
+ static const void *ptr[INDEX_MAX] = {
+ [INDEX_LANG] = &string_lang,
+ [INDEX_MODEM] = &string_modem,
+ [INDEX_PRODUCT] = &string_product,
+ };
+
+ if (string_index == 0) {
+ return (&string_lang);
+ }
+ if (lang_id != 0x0409) {
+ return (NULL);
+ }
+ if (string_index < INDEX_MAX) {
+ return (ptr[string_index]);
+ }
+ return (NULL);
+}
diff --git a/sys/dev/usb/template/usb_template_mouse.c b/sys/dev/usb/template/usb_template_mouse.c
new file mode 100644
index 0000000..3ff0fb0
--- /dev/null
+++ b/sys/dev/usb/template/usb_template_mouse.c
@@ -0,0 +1,222 @@
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*-
+ * Copyright (c) 2010 Hans Petter Selasky. All rights reserved.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+/*
+ * This file contains the USB template for an USB Mouse Device.
+ */
+
+#include <sys/stdint.h>
+#include <sys/stddef.h>
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/types.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/module.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/condvar.h>
+#include <sys/sysctl.h>
+#include <sys/sx.h>
+#include <sys/unistd.h>
+#include <sys/callout.h>
+#include <sys/malloc.h>
+#include <sys/priv.h>
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+#include <dev/usb/usb_cdc.h>
+
+#include <dev/usb/template/usb_template.h>
+
+enum {
+ INDEX_LANG,
+ INDEX_MOUSE,
+ INDEX_PRODUCT,
+ INDEX_MAX,
+};
+
+#define STRING_LANG \
+ 0x09, 0x04, /* American English */
+
+#define STRING_PRODUCT \
+ 'M', 0, 'o', 0, 'u', 0, 's', 0, 'e', 0, ' ', 0, \
+ 'T', 0, 'e', 0, 's', 0, 't', 0, ' ', 0, \
+ 'D', 0, 'e', 0, 'v', 0, 'i', 0, 'c', 0, 'e', 0,
+
+#define STRING_MOUSE \
+ 'M', 0, 'o', 0, 'u', 0, 's', 0, 'e', 0, ' ', 0, \
+ 'i', 0, 'n', 0, 't', 0, 'e', 0, 'r', 0, 'f', 0, 'a', 0, 'c', 0, 'e', 0,
+
+/* make the real string descriptors */
+
+USB_MAKE_STRING_DESC(STRING_LANG, string_lang);
+USB_MAKE_STRING_DESC(STRING_MOUSE, string_mouse);
+USB_MAKE_STRING_DESC(STRING_PRODUCT, string_product);
+
+/* prototypes */
+
+/* The following HID descriptor was dumped from a HP mouse. */
+
+static uint8_t mouse_hid_descriptor[] = {
+ 0x05, 0x01, 0x09, 0x02, 0xa1, 0x01, 0x09, 0x01,
+ 0xa1, 0x00, 0x05, 0x09, 0x19, 0x01, 0x29, 0x03,
+ 0x15, 0x00, 0x25, 0x01, 0x95, 0x03, 0x75, 0x01,
+ 0x81, 0x02, 0x95, 0x05, 0x81, 0x03, 0x05, 0x01,
+ 0x09, 0x30, 0x09, 0x31, 0x09, 0x38, 0x15, 0x81,
+ 0x25, 0x7f, 0x75, 0x08, 0x95, 0x03, 0x81, 0x06,
+ 0xc0, 0xc0
+};
+
+static const struct usb_temp_packet_size mouse_intr_mps = {
+ .mps[USB_SPEED_LOW] = 8,
+ .mps[USB_SPEED_FULL] = 8,
+ .mps[USB_SPEED_HIGH] = 8,
+};
+
+static const struct usb_temp_interval mouse_intr_interval = {
+ .bInterval[USB_SPEED_LOW] = 2,
+ .bInterval[USB_SPEED_FULL] = 2,
+ .bInterval[USB_SPEED_HIGH] = 2 * 8,
+};
+
+static const struct usb_temp_endpoint_desc mouse_ep_0 = {
+ .ppRawDesc = NULL, /* no raw descriptors */
+ .pPacketSize = &mouse_intr_mps,
+ .pIntervals = &mouse_intr_interval,
+ .bEndpointAddress = UE_DIR_IN,
+ .bmAttributes = UE_INTERRUPT,
+};
+
+static const struct usb_temp_endpoint_desc *mouse_endpoints[] = {
+ &mouse_ep_0,
+ NULL,
+};
+
+static const uint8_t mouse_raw_desc[] = {
+ 0x09, 0x21, 0x10, 0x01, 0x00, 0x01, 0x22, sizeof(mouse_hid_descriptor),
+ 0x00
+};
+
+static const void *mouse_iface_0_desc[] = {
+ mouse_raw_desc,
+ NULL,
+};
+
+static const struct usb_temp_interface_desc mouse_iface_0 = {
+ .ppRawDesc = mouse_iface_0_desc,
+ .ppEndpoints = mouse_endpoints,
+ .bInterfaceClass = 3,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 2,
+ .iInterface = INDEX_MOUSE,
+};
+
+static const struct usb_temp_interface_desc *mouse_interfaces[] = {
+ &mouse_iface_0,
+ NULL,
+};
+
+static const struct usb_temp_config_desc mouse_config_desc = {
+ .ppIfaceDesc = mouse_interfaces,
+ .bmAttributes = UC_BUS_POWERED,
+ .bMaxPower = 25, /* 50 mA */
+ .iConfiguration = INDEX_PRODUCT,
+};
+
+static const struct usb_temp_config_desc *mouse_configs[] = {
+ &mouse_config_desc,
+ NULL,
+};
+
+static usb_temp_get_string_desc_t mouse_get_string_desc;
+static usb_temp_get_vendor_desc_t mouse_get_vendor_desc;
+
+const struct usb_temp_device_desc usb_template_mouse = {
+ .getStringDesc = &mouse_get_string_desc,
+ .getVendorDesc = &mouse_get_vendor_desc,
+ .ppConfigDesc = mouse_configs,
+ .idVendor = USB_TEMPLATE_VENDOR,
+ .idProduct = 0x00AE,
+ .bcdDevice = 0x0100,
+ .bDeviceClass = UDCLASS_COMM,
+ .bDeviceSubClass = 0,
+ .bDeviceProtocol = 0,
+ .iManufacturer = 0,
+ .iProduct = INDEX_PRODUCT,
+ .iSerialNumber = 0,
+};
+
+/*------------------------------------------------------------------------*
+ * mouse_get_vendor_desc
+ *
+ * Return values:
+ * NULL: Failure. No such vendor descriptor.
+ * Else: Success. Pointer to vendor descriptor is returned.
+ *------------------------------------------------------------------------*/
+static const void *
+mouse_get_vendor_desc(const struct usb_device_request *req, uint16_t *plen)
+{
+ if ((req->bmRequestType == 0x81) && (req->bRequest == 0x06) &&
+ (req->wValue[0] == 0x00) && (req->wValue[1] == 0x22) &&
+ (req->wIndex[1] == 0) && (req->wIndex[0] == 0)) {
+
+ *plen = sizeof(mouse_hid_descriptor);
+ return (mouse_hid_descriptor);
+ }
+ return (NULL);
+}
+
+/*------------------------------------------------------------------------*
+ * mouse_get_string_desc
+ *
+ * Return values:
+ * NULL: Failure. No such string.
+ * Else: Success. Pointer to string descriptor is returned.
+ *------------------------------------------------------------------------*/
+static const void *
+mouse_get_string_desc(uint16_t lang_id, uint8_t string_index)
+{
+ static const void *ptr[INDEX_MAX] = {
+ [INDEX_LANG] = &string_lang,
+ [INDEX_MOUSE] = &string_mouse,
+ [INDEX_PRODUCT] = &string_product,
+ };
+
+ if (string_index == 0) {
+ return (&string_lang);
+ }
+ if (lang_id != 0x0409) {
+ return (NULL);
+ }
+ if (string_index < INDEX_MAX) {
+ return (ptr[string_index]);
+ }
+ return (NULL);
+}
diff --git a/sys/dev/usb/template/usb_template_msc.c b/sys/dev/usb/template/usb_template_msc.c
index 598c9fd..5c05ffe 100644
--- a/sys/dev/usb/template/usb_template_msc.c
+++ b/sys/dev/usb/template/usb_template_msc.c
@@ -173,8 +173,8 @@ static const struct usb_temp_config_desc *msc_configs[] = {
const struct usb_temp_device_desc usb_template_msc = {
.getStringDesc = &msc_get_string_desc,
.ppConfigDesc = msc_configs,
- .idVendor = 0x0001,
- .idProduct = 0x0001,
+ .idVendor = USB_TEMPLATE_VENDOR,
+ .idProduct = 0x0012,
.bcdDevice = 0x0100,
.bDeviceClass = UDCLASS_COMM,
.bDeviceSubClass = 0,
diff --git a/sys/dev/usb/template/usb_template_mtp.c b/sys/dev/usb/template/usb_template_mtp.c
index ad09b58..f48fbf4 100644
--- a/sys/dev/usb/template/usb_template_mtp.c
+++ b/sys/dev/usb/template/usb_template_mtp.c
@@ -191,8 +191,8 @@ const struct usb_temp_device_desc usb_template_mtp = {
.getStringDesc = &mtp_get_string_desc,
.getVendorDesc = &mtp_get_vendor_desc,
.ppConfigDesc = mtp_configs,
- .idVendor = 0x0001,
- .idProduct = 0x0001,
+ .idVendor = USB_TEMPLATE_VENDOR,
+ .idProduct = 0x0011,
.bcdDevice = 0x0100,
.bDeviceClass = 0,
.bDeviceSubClass = 0,
diff --git a/sys/dev/usb/usb_device.c b/sys/dev/usb/usb_device.c
index 893e79d..932c022 100644
--- a/sys/dev/usb/usb_device.c
+++ b/sys/dev/usb/usb_device.c
@@ -1297,6 +1297,21 @@ usb_probe_and_attach(struct usb_device *udev, uint8_t iface_index)
usb_init_attach_arg(udev, &uaa);
+ /*
+ * If the whole USB device is targeted, invoke the USB event
+ * handler(s):
+ */
+ if (iface_index == USB_IFACE_INDEX_ANY) {
+
+ EVENTHANDLER_INVOKE(usb_dev_configured, udev, &uaa);
+
+ if (uaa.dev_state != UAA_DEV_READY) {
+ /* leave device unconfigured */
+ usb_unconfigure(udev, 0);
+ goto done;
+ }
+ }
+
/* Check if only one interface should be probed: */
if (iface_index != USB_IFACE_INDEX_ANY) {
i = iface_index;
@@ -1343,17 +1358,18 @@ usb_probe_and_attach(struct usb_device *udev, uint8_t iface_index)
uaa.info.bIfaceIndex,
uaa.info.bIfaceNum);
- if (usb_probe_and_attach_sub(udev, &uaa)) {
- /* ignore */
- }
- }
-
- if (uaa.temp_dev) {
- /* remove the last created child; it is unused */
+ usb_probe_and_attach_sub(udev, &uaa);
- if (device_delete_child(udev->parent_dev, uaa.temp_dev)) {
+ /*
+ * Remove the leftover child, if any, to enforce that
+ * a new nomatch devd event is generated for the next
+ * interface if no driver is found:
+ */
+ if (uaa.temp_dev == NULL)
+ continue;
+ if (device_delete_child(udev->parent_dev, uaa.temp_dev))
DPRINTFN(0, "device delete child failed\n");
- }
+ uaa.temp_dev = NULL;
}
done:
if (do_unlock)
@@ -1526,7 +1542,7 @@ usb_alloc_device(device_t parent_dev, struct usb_bus *bus,
/* initialise our SX-lock */
sx_init_flags(&udev->enum_sx, "USB config SX lock", SX_DUPOK);
- sx_init_flags(&udev->sr_sx, "USB suspend and resume SX lock", SX_DUPOK);
+ sx_init_flags(&udev->sr_sx, "USB suspend and resume SX lock", SX_NOWITNESS);
cv_init(&udev->ctrlreq_cv, "WCTRL");
cv_init(&udev->ref_cv, "UGONE");
@@ -1834,11 +1850,6 @@ repeat_set_config:
}
}
}
- EVENTHANDLER_INVOKE(usb_dev_configured, udev, &uaa);
- if (uaa.dev_state != UAA_DEV_READY) {
- /* leave device unconfigured */
- usb_unconfigure(udev, 0);
- }
config_done:
DPRINTF("new dev (addr %d), udev=%p, parent_hub=%p\n",
diff --git a/sys/dev/usb/usb_hid.c b/sys/dev/usb/usb_hid.c
index 21c4c50c..6bd51cd 100644
--- a/sys/dev/usb/usb_hid.c
+++ b/sys/dev/usb/usb_hid.c
@@ -702,6 +702,43 @@ hid_get_data_unsigned(const uint8_t *buf, usb_size_t len, struct hid_location *l
}
/*------------------------------------------------------------------------*
+ * hid_put_data
+ *------------------------------------------------------------------------*/
+void
+hid_put_data_unsigned(uint8_t *buf, usb_size_t len,
+ struct hid_location *loc, unsigned int value)
+{
+ uint32_t hpos = loc->pos;
+ uint32_t hsize = loc->size;
+ uint64_t data;
+ uint64_t mask;
+ uint32_t rpos;
+ uint8_t n;
+
+ DPRINTFN(11, "hid_put_data: loc %d/%d = %u\n", hpos, hsize, value);
+
+ /* Range check and limit */
+ if (hsize == 0)
+ return;
+ if (hsize > 32)
+ hsize = 32;
+
+ /* Put data in a safe way */
+ rpos = (hpos / 8);
+ n = (hsize + 7) / 8;
+ data = ((uint64_t)value) << (hpos % 8);
+ mask = ((1ULL << hsize) - 1ULL) << (hpos % 8);
+ rpos += n;
+ while (n--) {
+ rpos--;
+ if (rpos < len) {
+ buf[rpos] &= ~(mask >> (8 * n));
+ buf[rpos] |= (data >> (8 * n));
+ }
+ }
+}
+
+/*------------------------------------------------------------------------*
* hid_is_collection
*------------------------------------------------------------------------*/
int
diff --git a/sys/dev/usb/usb_hub.c b/sys/dev/usb/usb_hub.c
index 351b134..12898ec 100644
--- a/sys/dev/usb/usb_hub.c
+++ b/sys/dev/usb/usb_hub.c
@@ -1334,15 +1334,19 @@ uhub_child_pnpinfo_string(device_t parent, device_t child,
"devclass=0x%02x devsubclass=0x%02x "
"sernum=\"%s\" "
"release=0x%04x "
- "intclass=0x%02x intsubclass=0x%02x" "%s%s",
+ "mode=%s "
+ "intclass=0x%02x intsubclass=0x%02x "
+ "intprotocol=0x%02x " "%s%s",
UGETW(res.udev->ddesc.idVendor),
UGETW(res.udev->ddesc.idProduct),
res.udev->ddesc.bDeviceClass,
res.udev->ddesc.bDeviceSubClass,
usb_get_serial(res.udev),
UGETW(res.udev->ddesc.bcdDevice),
+ (res.udev->flags.usb_mode == USB_MODE_HOST) ? "host" : "device",
iface->idesc->bInterfaceClass,
iface->idesc->bInterfaceSubClass,
+ iface->idesc->bInterfaceProtocol,
iface->pnpinfo ? " " : "",
iface->pnpinfo ? iface->pnpinfo : "");
} else {
diff --git a/sys/dev/usb/usb_ioctl.h b/sys/dev/usb/usb_ioctl.h
index 452de94..d35fa10 100644
--- a/sys/dev/usb/usb_ioctl.h
+++ b/sys/dev/usb/usb_ioctl.h
@@ -39,6 +39,20 @@
#define USB_DEVICE_NAME "usbctl"
#define USB_DEVICE_DIR "usb"
#define USB_GENERIC_NAME "ugen"
+#define USB_TEMPLATE_SYSCTL "hw.usb.template" /* integer type */
+
+/* Definition of valid template sysctl values */
+
+enum {
+ USB_TEMP_MSC, /* USB Mass Storage */
+ USB_TEMP_CDCE, /* USB CDC Ethernet */
+ USB_TEMP_MTP, /* Message Transfer Protocol */
+ USB_TEMP_MODEM, /* USB CDC Modem */
+ USB_TEMP_AUDIO, /* USB Audio */
+ USB_TEMP_KBD, /* USB Keyboard */
+ USB_TEMP_MOUSE, /* USB Mouse */
+ USB_TEMP_MAX,
+};
struct usb_read_dir {
#ifdef COMPAT_32BIT
diff --git a/sys/dev/usb/usb_lookup.c b/sys/dev/usb/usb_lookup.c
index ced925e..e03f9b6 100644
--- a/sys/dev/usb/usb_lookup.c
+++ b/sys/dev/usb/usb_lookup.c
@@ -42,6 +42,8 @@
#include <sys/callout.h>
#include <sys/malloc.h>
#include <sys/priv.h>
+#include <sys/limits.h>
+#include <sys/endian.h>
#include <dev/usb/usb.h>
#include <dev/usb/usbdi.h>
@@ -105,13 +107,6 @@ usbd_lookup_id_by_info(const struct usb_device_id *id, usb_size_t sizeof_id,
(id->bDeviceProtocol != info->bDeviceProtocol)) {
continue;
}
- if ((info->bDeviceClass == 0xFF) &&
- (!(id->match_flag_vendor)) &&
- ((id->match_flag_int_class) ||
- (id->match_flag_int_subclass) ||
- (id->match_flag_int_protocol))) {
- continue;
- }
if ((id->match_flag_int_class) &&
(id->bInterfaceClass != info->bInterfaceClass)) {
continue;
@@ -151,3 +146,108 @@ usbd_lookup_id_by_uaa(const struct usb_device_id *id, usb_size_t sizeof_id,
}
return (ENXIO);
}
+
+/*------------------------------------------------------------------------*
+ * Export the USB device ID format we use to userspace tools.
+ *------------------------------------------------------------------------*/
+#if BYTE_ORDER == BIG_ENDIAN
+#define U16_XOR "8"
+#define U32_XOR "12"
+#define U64_XOR "56"
+#define U8_BITFIELD_XOR "7"
+#define U16_BITFIELD_XOR "15"
+#define U32_BITFIELD_XOR "31"
+#define U64_BITFIELD_XOR "63"
+#else
+#define U16_XOR "0"
+#define U32_XOR "0"
+#define U64_XOR "0"
+#define U8_BITFIELD_XOR "0"
+#define U16_BITFIELD_XOR "0"
+#define U32_BITFIELD_XOR "0"
+#define U64_BITFIELD_XOR "0"
+#endif
+
+#if USB_HAVE_COMPAT_LINUX
+#define MFL_SIZE "1"
+#else
+#define MFL_SIZE "0"
+#endif
+
+#ifdef KLD_MODULE
+static const char __section("bus_autoconf_format") __used usb_id_format[] = {
+
+ /* Declare that three different sections use the same format */
+
+ "usb_host_id{256,:}"
+ "usb_device_id{256,:}"
+ "usb_dual_id{256,:}"
+
+ /* List size of fields in the usb_device_id structure */
+
+#if ULONG_MAX >= 0xFFFFFFFFUL
+ "unused{0,8}"
+ "unused{0,8}"
+ "unused{0,8}"
+ "unused{0,8}"
+#if ULONG_MAX >= 0xFFFFFFFFFFFFFFFFULL
+ "unused{0,8}"
+ "unused{0,8}"
+ "unused{0,8}"
+ "unused{0,8}"
+#endif
+#else
+#error "Please update code."
+#endif
+
+ "idVendor[0]{" U16_XOR ",8}"
+ "idVendor[1]{" U16_XOR ",8}"
+ "idProduct[0]{" U16_XOR ",8}"
+ "idProduct[1]{" U16_XOR ",8}"
+ "bcdDevice_lo[0]{" U16_XOR ",8}"
+ "bcdDevice_lo[1]{" U16_XOR ",8}"
+ "bcdDevice_hi[0]{" U16_XOR ",8}"
+ "bcdDevice_hi[1]{" U16_XOR ",8}"
+
+ "bDeviceClass{0,8}"
+ "bDeviceSubClass{0,8}"
+ "bDeviceProtocol{0,8}"
+ "bInterfaceClass{0,8}"
+ "bInterfaceSubClass{0,8}"
+ "bInterfaceProtocol{0,8}"
+
+ "mf_vendor{" U8_BITFIELD_XOR ",1}"
+ "mf_product{" U8_BITFIELD_XOR ",1}"
+ "mf_dev_lo{" U8_BITFIELD_XOR ",1}"
+ "mf_dev_hi{" U8_BITFIELD_XOR ",1}"
+
+ "mf_dev_class{" U8_BITFIELD_XOR ",1}"
+ "mf_dev_subclass{" U8_BITFIELD_XOR ",1}"
+ "mf_dev_protocol{" U8_BITFIELD_XOR ",1}"
+ "mf_int_class{" U8_BITFIELD_XOR ",1}"
+
+ "mf_int_subclass{" U8_BITFIELD_XOR ",1}"
+ "mf_int_protocol{" U8_BITFIELD_XOR ",1}"
+ "unused{" U8_BITFIELD_XOR ",6}"
+
+ "mfl_vendor{" U16_XOR "," MFL_SIZE "}"
+ "mfl_product{" U16_XOR "," MFL_SIZE "}"
+ "mfl_dev_lo{" U16_XOR "," MFL_SIZE "}"
+ "mfl_dev_hi{" U16_XOR "," MFL_SIZE "}"
+
+ "mfl_dev_class{" U16_XOR "," MFL_SIZE "}"
+ "mfl_dev_subclass{" U16_XOR "," MFL_SIZE "}"
+ "mfl_dev_protocol{" U16_XOR "," MFL_SIZE "}"
+ "mfl_int_class{" U16_XOR "," MFL_SIZE "}"
+
+ "mfl_int_subclass{" U16_XOR "," MFL_SIZE "}"
+ "mfl_int_protocol{" U16_XOR "," MFL_SIZE "}"
+ "unused{" U16_XOR "," MFL_SIZE "}"
+ "unused{" U16_XOR "," MFL_SIZE "}"
+
+ "unused{" U16_XOR "," MFL_SIZE "}"
+ "unused{" U16_XOR "," MFL_SIZE "}"
+ "unused{" U16_XOR "," MFL_SIZE "}"
+ "unused{" U16_XOR "," MFL_SIZE "}"
+};
+#endif
diff --git a/sys/dev/usb/usb_msctest.c b/sys/dev/usb/usb_msctest.c
index 909615e..0b6024b 100644
--- a/sys/dev/usb/usb_msctest.c
+++ b/sys/dev/usb/usb_msctest.c
@@ -62,7 +62,6 @@
#include <dev/usb/usb_transfer.h>
#include <dev/usb/usb_msctest.h>
#include <dev/usb/usb_debug.h>
-#include <dev/usb/usb_busdma.h>
#include <dev/usb/usb_device.h>
#include <dev/usb/usb_request.h>
#include <dev/usb/usb_util.h>
@@ -489,6 +488,24 @@ bbb_attach(struct usb_device *udev, uint8_t iface_index)
struct usb_interface_descriptor *id;
struct bbb_transfer *sc;
usb_error_t err;
+ uint8_t do_unlock;
+
+ /* automatic locking */
+ if (usbd_enum_is_locked(udev)) {
+ do_unlock = 0;
+ } else {
+ do_unlock = 1;
+ usbd_enum_lock(udev);
+ }
+
+ /*
+ * Make sure any driver which is hooked up to this interface,
+ * like umass is gone:
+ */
+ usb_detach_device(udev, iface_index, 0);
+
+ if (do_unlock)
+ usbd_enum_unlock(udev);
iface = usbd_get_iface(udev, iface_index);
if (iface == NULL)
diff --git a/sys/dev/usb/usb_request.c b/sys/dev/usb/usb_request.c
index 4358ef4..bb5e0da 100644
--- a/sys/dev/usb/usb_request.c
+++ b/sys/dev/usb/usb_request.c
@@ -779,10 +779,17 @@ usbd_req_reset_port(struct usb_device *udev, struct mtx *mtx, uint8_t port)
uint16_t pr_recovery_delay;
#endif
- err = usbd_req_set_port_feature(udev, mtx, port, UHF_PORT_RESET);
- if (err) {
+ /* clear any leftover port reset changes first */
+ usbd_req_clear_port_feature(
+ udev, mtx, port, UHF_C_PORT_RESET);
+
+ /* assert port reset on the given port */
+ err = usbd_req_set_port_feature(
+ udev, mtx, port, UHF_PORT_RESET);
+
+ /* check for errors */
+ if (err)
goto done;
- }
#ifdef USB_DEBUG
/* range check input parameters */
pr_poll_delay = usb_pr_poll_delay;
@@ -798,6 +805,9 @@ usbd_req_reset_port(struct usb_device *udev, struct mtx *mtx, uint8_t port)
#endif
n = 0;
while (1) {
+ uint16_t status;
+ uint16_t change;
+
#ifdef USB_DEBUG
/* wait for the device to recover from reset */
usb_pause_mtx(mtx, USB_MS_TO_TICKS(pr_poll_delay));
@@ -811,14 +821,25 @@ usbd_req_reset_port(struct usb_device *udev, struct mtx *mtx, uint8_t port)
if (err) {
goto done;
}
+ status = UGETW(ps.wPortStatus);
+ change = UGETW(ps.wPortChange);
+
/* if the device disappeared, just give up */
- if (!(UGETW(ps.wPortStatus) & UPS_CURRENT_CONNECT_STATUS)) {
+ if (!(status & UPS_CURRENT_CONNECT_STATUS))
goto done;
- }
+
/* check if reset is complete */
- if (UGETW(ps.wPortChange) & UPS_C_PORT_RESET) {
+ if (change & UPS_C_PORT_RESET)
break;
- }
+
+ /*
+ * Some Virtual Machines like VirtualBox 4.x fail to
+ * generate a port reset change event. Check if reset
+ * is no longer asserted.
+ */
+ if (!(status & UPS_RESET))
+ break;
+
/* check for timeout */
if (n > 1000) {
n = 0;
diff --git a/sys/dev/usb/usbdevs b/sys/dev/usb/usbdevs
index a970206..386e546 100644
--- a/sys/dev/usb/usbdevs
+++ b/sys/dev/usb/usbdevs
@@ -484,6 +484,7 @@ vendor SHANTOU 0x0a46 ShanTou
vendor MEDIAGEAR 0x0a48 MediaGear
vendor BROADCOM 0x0a5c Broadcom
vendor GREENHOUSE 0x0a6b GREENHOUSE
+vendor MEDELI 0x0a67 Medeli
vendor GEOCAST 0x0a79 Geocast Network Systems
vendor IDQUANTIQUE 0x0aba id Quantique
vendor ZYDAS 0x0ace Zydas Technology Corporation
@@ -899,6 +900,7 @@ product AIRPLUS MCD650 0x3198 MCD650 modem
/* AirPrime products */
product AIRPRIME PC5220 0x0112 CDMA Wireless PC Card
+product AIRPRIME USB308 0x68A3 USB308 HSPA+ USB Modem
/* AirTies products */
product AIRTIES RT3070 0x2310 RT3070
@@ -1043,6 +1045,7 @@ product ASIX AX88172 0x1720 10/100 Ethernet
product ASIX AX88178 0x1780 AX88178
product ASIX AX88772 0x7720 AX88772
product ASIX AX88772A 0x772a AX88772A USB 2.0 10/100 Ethernet
+product ASIX AX88772B 0x772b AX88772B USB 2.0 10/100 Ethernet
/* ASUS products */
product ASUS2 USBN11 0x0b05 USB-N11
@@ -2014,6 +2017,7 @@ product KODAK DC280 0x0130 Digital Science DC280
/* Kontron AG products */
product KONTRON DM9601 0x8101 USB Ethernet
+product KONTRON JP1082 0x9700 USB Ethernet
/* Konica Corp. Products */
product KONICA CAMERA 0x0720 Digital Color Camera
@@ -2129,6 +2133,9 @@ product MCT DU_H3SP_USB232 0x0200 D-Link DU-H3SP USB BAY Hub
product MCT USB232 0x0210 USB-232 Interface
product MCT SITECOM_USB232 0x0230 Sitecom USB-232 Products
+/* Medeli */
+product MEDELI DD305 0x5011 DD305 Digital Drum Set
+
/* MediaTek, Inc. */
product MEDIATEK MTK3329 0x3329 MTK II GPS Receiver
diff --git a/sys/dev/usb/usbdi.h b/sys/dev/usb/usbdi.h
index 91cd3fa..d832c32 100644
--- a/sys/dev/usb/usbdi.h
+++ b/sys/dev/usb/usbdi.h
@@ -228,6 +228,18 @@ struct usb_config {
};
/*
+ * Use these macro when defining USB device ID arrays if you want to
+ * have your driver module automatically loaded in host, device or
+ * both modes respectivly:
+ */
+#define STRUCT_USB_HOST_ID \
+ struct usb_device_id __section("usb_host_id")
+#define STRUCT_USB_DEVICE_ID \
+ struct usb_device_id __section("usb_device_id")
+#define STRUCT_USB_DUAL_ID \
+ struct usb_device_id __section("usb_dual_id")
+
+/*
* The following structure is used when looking up an USB driver for
* an USB device. It is inspired by the Linux structure called
* "usb_device_id".
@@ -258,12 +270,15 @@ struct usb_device_id {
uint8_t match_flag_product:1;
uint8_t match_flag_dev_lo:1;
uint8_t match_flag_dev_hi:1;
+
uint8_t match_flag_dev_class:1;
uint8_t match_flag_dev_subclass:1;
uint8_t match_flag_dev_protocol:1;
uint8_t match_flag_int_class:1;
+
uint8_t match_flag_int_subclass:1;
uint8_t match_flag_int_protocol:1;
+ uint8_t match_flag_unused:6;
#if USB_HAVE_COMPAT_LINUX
/* which fields to match against */
@@ -279,7 +294,10 @@ struct usb_device_id {
#define USB_DEVICE_ID_MATCH_INT_SUBCLASS 0x0100
#define USB_DEVICE_ID_MATCH_INT_PROTOCOL 0x0200
#endif
-};
+} __aligned(32);
+
+/* check that the size of the structure above is correct */
+extern char usb_device_id_assert[(sizeof(struct usb_device_id) == 32) ? 1 : -1];
#define USB_VENDOR(vend) \
.match_flag_vendor = 1, .idVendor = (vend)
diff --git a/sys/dev/usb/usbhid.h b/sys/dev/usb/usbhid.h
index c07454f..4816e87 100644
--- a/sys/dev/usb/usbhid.h
+++ b/sys/dev/usb/usbhid.h
@@ -233,6 +233,8 @@ int32_t hid_get_data(const uint8_t *buf, usb_size_t len,
struct hid_location *loc);
uint32_t hid_get_data_unsigned(const uint8_t *buf, usb_size_t len,
struct hid_location *loc);
+void hid_put_data_unsigned(uint8_t *buf, usb_size_t len,
+ struct hid_location *loc, unsigned int value);
int hid_is_collection(const void *desc, usb_size_t size, uint32_t usage);
struct usb_hid_descriptor *hid_get_descriptor_from_usb(
struct usb_config_descriptor *cd,
diff --git a/sys/dev/usb/wlan/if_rum.c b/sys/dev/usb/wlan/if_rum.c
index 63b314d..5a69792 100644
--- a/sys/dev/usb/wlan/if_rum.c
+++ b/sys/dev/usb/wlan/if_rum.c
@@ -85,7 +85,7 @@ SYSCTL_INT(_hw_usb_rum, OID_AUTO, debug, CTLFLAG_RW, &rum_debug, 0,
"Debug level");
#endif
-static const struct usb_device_id rum_devs[] = {
+static const STRUCT_USB_HOST_ID rum_devs[] = {
#define RUM_DEV(v,p) { USB_VP(USB_VENDOR_##v, USB_PRODUCT_##v##_##p) }
RUM_DEV(ABOCOM, HWU54DM),
RUM_DEV(ABOCOM, RT2573_2),
diff --git a/sys/dev/usb/wlan/if_run.c b/sys/dev/usb/wlan/if_run.c
index 2cd147c..47823b9 100644
--- a/sys/dev/usb/wlan/if_run.c
+++ b/sys/dev/usb/wlan/if_run.c
@@ -96,7 +96,7 @@ SYSCTL_INT(_hw_usb_run, OID_AUTO, debug, CTLFLAG_RW, &run_debug, 0,
*/
#define RUN_CMDQ_GET(c) (atomic_fetchadd_32((c), 1) & RUN_CMDQ_MASQ)
-static const struct usb_device_id run_devs[] = {
+static const STRUCT_USB_HOST_ID run_devs[] = {
#define RUN_DEV(v,p) { USB_VP(USB_VENDOR_##v, USB_PRODUCT_##v##_##p) }
RUN_DEV(ABOCOM, RT2770),
RUN_DEV(ABOCOM, RT2870),
diff --git a/sys/dev/usb/wlan/if_uath.c b/sys/dev/usb/wlan/if_uath.c
index 35202a9..328dc4f 100644
--- a/sys/dev/usb/wlan/if_uath.c
+++ b/sys/dev/usb/wlan/if_uath.c
@@ -167,9 +167,8 @@ enum {
(((u_int8_t *)(p))[2] << 16) | (((u_int8_t *)(p))[3] << 24)))
/* recognized device vendors/products */
-static const struct usb_device_id uath_devs[] = {
+static const STRUCT_USB_HOST_ID uath_devs[] = {
#define UATH_DEV(v,p) { USB_VP(USB_VENDOR_##v, USB_PRODUCT_##v##_##p) }
- UATH_DEV(ACCTON, SMCWUSBG),
UATH_DEV(ACCTON, SMCWUSBTG2),
UATH_DEV(ATHEROS, AR5523),
UATH_DEV(ATHEROS2, AR5523_1),
diff --git a/sys/dev/usb/wlan/if_upgt.c b/sys/dev/usb/wlan/if_upgt.c
index d704cec..b9381a2 100644
--- a/sys/dev/usb/wlan/if_upgt.c
+++ b/sys/dev/usb/wlan/if_upgt.c
@@ -170,7 +170,7 @@ static int upgt_tx_start(struct upgt_softc *, struct mbuf *,
static const char *upgt_fwname = "upgt-gw3887";
-static const struct usb_device_id upgt_devs_2[] = {
+static const STRUCT_USB_HOST_ID upgt_devs[] = {
#define UPGT_DEV(v,p) { USB_VP(USB_VENDOR_##v, USB_PRODUCT_##v##_##p) }
/* version 2 devices */
UPGT_DEV(ACCTON, PRISM_GT),
@@ -236,7 +236,7 @@ upgt_match(device_t dev)
if (uaa->info.bIfaceIndex != UPGT_IFACE_INDEX)
return (ENXIO);
- return (usbd_lookup_id_by_uaa(upgt_devs_2, sizeof(upgt_devs_2), uaa));
+ return (usbd_lookup_id_by_uaa(upgt_devs, sizeof(upgt_devs), uaa));
}
static int
diff --git a/sys/dev/usb/wlan/if_ural.c b/sys/dev/usb/wlan/if_ural.c
index 65d974a..048392d 100644
--- a/sys/dev/usb/wlan/if_ural.c
+++ b/sys/dev/usb/wlan/if_ural.c
@@ -91,7 +91,7 @@ SYSCTL_INT(_hw_usb_ural, OID_AUTO, debug, CTLFLAG_RW, &ural_debug, 0,
((rssi) - (RAL_NOISE_FLOOR + RAL_RSSI_CORR)) : 0)
/* various supported device vendors/products */
-static const struct usb_device_id ural_devs[] = {
+static const STRUCT_USB_HOST_ID ural_devs[] = {
#define URAL_DEV(v,p) { USB_VP(USB_VENDOR_##v, USB_PRODUCT_##v##_##p) }
URAL_DEV(ASUS, WL167G),
URAL_DEV(ASUS, RT2570),
diff --git a/sys/dev/usb/wlan/if_urtw.c b/sys/dev/usb/wlan/if_urtw.c
index 3de2273..6ae7e16 100644
--- a/sys/dev/usb/wlan/if_urtw.c
+++ b/sys/dev/usb/wlan/if_urtw.c
@@ -102,7 +102,7 @@ TUNABLE_INT("hw.usb.urtw.preamble_mode", &urtw_preamble_mode);
{ USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, URTW_REV_RTL8187L) }
#define URTW_REV_RTL8187B 0
#define URTW_REV_RTL8187L 1
-static const struct usb_device_id urtw_devs[] = {
+static const STRUCT_USB_HOST_ID urtw_devs[] = {
URTW_DEV_B(NETGEAR, WG111V3),
URTW_DEV_B(REALTEK, RTL8187B_0),
URTW_DEV_B(REALTEK, RTL8187B_1),
@@ -115,7 +115,7 @@ static const struct usb_device_id urtw_devs[] = {
URTW_DEV_L(REALTEK, RTL8187),
URTW_DEV_L(SITECOMEU, WL168V1),
URTW_DEV_L(SURECOM, EP9001G2A),
- { USB_VPI(0x1b75, 0x8187, URTW_REV_RTL8187L) },
+ { USB_VPI(USB_VENDOR_OVISLINK, 0x8187, URTW_REV_RTL8187L) },
{ USB_VPI(USB_VENDOR_DICKSMITH, 0x9401, URTW_REV_RTL8187L) },
{ USB_VPI(USB_VENDOR_HP, 0xca02, URTW_REV_RTL8187L) },
{ USB_VPI(USB_VENDOR_LOGITEC, 0x010c, URTW_REV_RTL8187L) },
diff --git a/sys/dev/usb/wlan/if_zyd.c b/sys/dev/usb/wlan/if_zyd.c
index 43ec6ca..f8d905e 100644
--- a/sys/dev/usb/wlan/if_zyd.c
+++ b/sys/dev/usb/wlan/if_zyd.c
@@ -200,7 +200,7 @@ static const struct zyd_phy_pair zyd_def_phyB[] = ZYD_DEF_PHYB;
{ USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, ZYD_ZD1211) }
#define ZYD_ZD1211B_DEV(v,p) \
{ USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, ZYD_ZD1211B) }
-static const struct usb_device_id zyd_devs[] = {
+static const STRUCT_USB_HOST_ID zyd_devs[] = {
/* ZYD_ZD1211 */
ZYD_ZD1211_DEV(3COM2, 3CRUSB10075),
ZYD_ZD1211_DEV(ABOCOM, WL54),
OpenPOWER on IntegriCloud