Changeset View
Changeset View
Standalone View
Standalone View
head/sys/netgraph/bluetooth/drivers/ubt/ng_ubt.c
Show First 20 Lines • Show All 246 Lines • ▼ Show 20 Lines | |||||
/**************************************************************************** | /**************************************************************************** | ||||
**************************************************************************** | **************************************************************************** | ||||
** USB specific | ** USB specific | ||||
**************************************************************************** | **************************************************************************** | ||||
****************************************************************************/ | ****************************************************************************/ | ||||
/* USB methods */ | /* USB methods */ | ||||
static usb_callback_t ubt_probe_intr_callback; | |||||
static usb_callback_t ubt_ctrl_write_callback; | static usb_callback_t ubt_ctrl_write_callback; | ||||
static usb_callback_t ubt_intr_read_callback; | static usb_callback_t ubt_intr_read_callback; | ||||
static usb_callback_t ubt_bulk_read_callback; | static usb_callback_t ubt_bulk_read_callback; | ||||
static usb_callback_t ubt_bulk_write_callback; | static usb_callback_t ubt_bulk_write_callback; | ||||
static usb_callback_t ubt_isoc_read_callback; | static usb_callback_t ubt_isoc_read_callback; | ||||
static usb_callback_t ubt_isoc_write_callback; | static usb_callback_t ubt_isoc_write_callback; | ||||
static int ubt_fwd_mbuf_up(ubt_softc_p, struct mbuf **); | static int ubt_fwd_mbuf_up(ubt_softc_p, struct mbuf **); | ||||
▲ Show 20 Lines • Show All 153 Lines • ▼ Show 20 Lines | static const STRUCT_USB_HOST_ID ubt_ignore_devs[] = | ||||
{ USB_VPI(0x0489, 0xe056, 0), USB_DEV_BCD_LTEQ(1) }, | { USB_VPI(0x0489, 0xe056, 0), USB_DEV_BCD_LTEQ(1) }, | ||||
/* Atheros AR5BBU12 with sflash firmware */ | /* Atheros AR5BBU12 with sflash firmware */ | ||||
{ USB_VPI(0x0489, 0xe02c, 0), USB_DEV_BCD_LTEQ(1) }, | { USB_VPI(0x0489, 0xe02c, 0), USB_DEV_BCD_LTEQ(1) }, | ||||
/* Atheros AR5BBU12 with sflash firmware */ | /* Atheros AR5BBU12 with sflash firmware */ | ||||
{ USB_VPI(0x0489, 0xe03c, 0), USB_DEV_BCD_LTEQ(1) }, | { USB_VPI(0x0489, 0xe03c, 0), USB_DEV_BCD_LTEQ(1) }, | ||||
{ USB_VPI(0x0489, 0xe036, 0), USB_DEV_BCD_LTEQ(1) }, | { USB_VPI(0x0489, 0xe036, 0), USB_DEV_BCD_LTEQ(1) }, | ||||
/* Intel Wireless 8260 and successors are handled in ng_ubt_intel.c */ | |||||
{ USB_VPI(USB_VENDOR_INTEL2, 0x0a2b, 0) }, | |||||
{ USB_VPI(USB_VENDOR_INTEL2, 0x0aaa, 0) }, | |||||
{ USB_VPI(USB_VENDOR_INTEL2, 0x0025, 0) }, | |||||
{ USB_VPI(USB_VENDOR_INTEL2, 0x0026, 0) }, | |||||
{ USB_VPI(USB_VENDOR_INTEL2, 0x0029, 0) }, | |||||
}; | }; | ||||
/* List of supported bluetooth devices */ | /* List of supported bluetooth devices */ | ||||
static const STRUCT_USB_HOST_ID ubt_devs[] = | static const STRUCT_USB_HOST_ID ubt_devs[] = | ||||
{ | { | ||||
/* Generic Bluetooth class devices */ | /* Generic Bluetooth class devices */ | ||||
{ USB_IFACE_CLASS(UDCLASS_WIRELESS), | { USB_IFACE_CLASS(UDCLASS_WIRELESS), | ||||
USB_IFACE_SUBCLASS(UDSUBCLASS_RF), | USB_IFACE_SUBCLASS(UDSUBCLASS_RF), | ||||
▲ Show 20 Lines • Show All 66 Lines • ▼ Show 20 Lines | static const STRUCT_USB_HOST_ID ubt_devs[] = | ||||
{ USB_VPI(USB_VENDOR_ASUS, 0x17b5, 0) }, | { USB_VPI(USB_VENDOR_ASUS, 0x17b5, 0) }, | ||||
{ USB_VPI(USB_VENDOR_ASUS, 0x17cb, 0) }, | { USB_VPI(USB_VENDOR_ASUS, 0x17cb, 0) }, | ||||
{ USB_VPI(USB_VENDOR_LITEON, 0x2003, 0) }, | { USB_VPI(USB_VENDOR_LITEON, 0x2003, 0) }, | ||||
{ USB_VPI(USB_VENDOR_FOXCONN, 0xe042, 0) }, | { USB_VPI(USB_VENDOR_FOXCONN, 0xe042, 0) }, | ||||
{ USB_VPI(USB_VENDOR_DELL, 0x8197, 0) }, | { USB_VPI(USB_VENDOR_DELL, 0x8197, 0) }, | ||||
}; | }; | ||||
/* | /* | ||||
* Does a synchronous (waits for completion event) execution of HCI command. | |||||
* Size of both command and response buffers are passed in length field of | |||||
* corresponding structures in "Parameter Total Length" format i.e. | |||||
* not including HCI packet headers. | |||||
* | |||||
* Must not be used after USB transfers have been configured in attach routine. | |||||
*/ | |||||
usb_error_t | |||||
ubt_do_hci_request(struct usb_device *udev, struct ubt_hci_cmd *cmd, | |||||
void *evt, usb_timeout_t timeout) | |||||
{ | |||||
static const struct usb_config ubt_probe_config = { | |||||
.type = UE_INTERRUPT, | |||||
.endpoint = UE_ADDR_ANY, | |||||
.direction = UE_DIR_IN, | |||||
.flags = { .pipe_bof = 1, .short_xfer_ok = 1 }, | |||||
.bufsize = UBT_INTR_BUFFER_SIZE, | |||||
.callback = &ubt_probe_intr_callback, | |||||
}; | |||||
struct usb_device_request req; | |||||
struct usb_xfer *xfer[1]; | |||||
struct mtx mtx; | |||||
usb_error_t error = USB_ERR_NORMAL_COMPLETION; | |||||
uint8_t iface_index = 0; | |||||
/* Initialize a USB control request and then do it */ | |||||
bzero(&req, sizeof(req)); | |||||
req.bmRequestType = UBT_HCI_REQUEST; | |||||
req.wIndex[0] = iface_index; | |||||
USETW(req.wLength, UBT_HCI_CMD_SIZE(cmd)); | |||||
error = usbd_do_request(udev, NULL, &req, cmd); | |||||
if (error != USB_ERR_NORMAL_COMPLETION) { | |||||
printf("ng_ubt: usbd_do_request error=%s\n", | |||||
usbd_errstr(error)); | |||||
return (error); | |||||
} | |||||
if (evt == NULL) | |||||
return (USB_ERR_NORMAL_COMPLETION); | |||||
/* Initialize INTR endpoint xfer and wait for response */ | |||||
mtx_init(&mtx, "ubt pb", NULL, MTX_DEF); | |||||
error = usbd_transfer_setup(udev, &iface_index, xfer, | |||||
&ubt_probe_config, 1, evt, &mtx); | |||||
if (error == USB_ERR_NORMAL_COMPLETION) { | |||||
mtx_lock(&mtx); | |||||
usbd_transfer_start(*xfer); | |||||
if (msleep_sbt(evt, &mtx, 0, "ubt pb", SBT_1MS * timeout, | |||||
0, C_HARDCLOCK) == EWOULDBLOCK) { | |||||
printf("ng_ubt: HCI command 0x%04x timed out\n", | |||||
le16toh(cmd->opcode)); | |||||
error = USB_ERR_TIMEOUT; | |||||
} | |||||
usbd_transfer_stop(*xfer); | |||||
mtx_unlock(&mtx); | |||||
usbd_transfer_unsetup(xfer, 1); | |||||
} else | |||||
printf("ng_ubt: usbd_transfer_setup error=%s\n", | |||||
usbd_errstr(error)); | |||||
mtx_destroy(&mtx); | |||||
return (error); | |||||
} | |||||
/* | |||||
* Probe for a USB Bluetooth device. | * Probe for a USB Bluetooth device. | ||||
* USB context. | * USB context. | ||||
*/ | */ | ||||
static int | static int | ||||
ubt_probe(device_t dev) | ubt_probe(device_t dev) | ||||
{ | { | ||||
struct usb_attach_arg *uaa = device_get_ivars(dev); | struct usb_attach_arg *uaa = device_get_ivars(dev); | ||||
▲ Show 20 Lines • Show All 198 Lines • ▼ Show 20 Lines | ubt_detach(device_t dev) | ||||
UBT_NG_UNLOCK(sc); | UBT_NG_UNLOCK(sc); | ||||
mtx_destroy(&sc->sc_if_mtx); | mtx_destroy(&sc->sc_if_mtx); | ||||
mtx_destroy(&sc->sc_ng_mtx); | mtx_destroy(&sc->sc_ng_mtx); | ||||
return (0); | return (0); | ||||
} /* ubt_detach */ | } /* ubt_detach */ | ||||
/* | /* | ||||
* Called when incoming interrupt transfer (HCI event) has completed, i.e. | |||||
* HCI event was received from the device during device probe stage. | |||||
* USB context. | |||||
*/ | |||||
static void | |||||
ubt_probe_intr_callback(struct usb_xfer *xfer, usb_error_t error) | |||||
{ | |||||
struct ubt_hci_event *evt = usbd_xfer_softc(xfer); | |||||
struct usb_page_cache *pc; | |||||
int actlen; | |||||
usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); | |||||
switch (USB_GET_STATE(xfer)) { | |||||
case USB_ST_TRANSFERRED: | |||||
if (actlen > UBT_HCI_EVENT_SIZE(evt)) | |||||
actlen = UBT_HCI_EVENT_SIZE(evt); | |||||
pc = usbd_xfer_get_frame(xfer, 0); | |||||
usbd_copy_out(pc, 0, evt, actlen); | |||||
/* OneShot mode */ | |||||
wakeup(evt); | |||||
break; | |||||
case USB_ST_SETUP: | |||||
submit_next: | |||||
/* Try clear stall first */ | |||||
usbd_xfer_set_stall(xfer); | |||||
usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); | |||||
usbd_transfer_submit(xfer); | |||||
break; | |||||
default: | |||||
if (error != USB_ERR_CANCELLED) { | |||||
printf("ng_ubt: interrupt transfer failed: %s\n", | |||||
usbd_errstr(error)); | |||||
goto submit_next; | |||||
} | |||||
break; | |||||
} | |||||
} /* ubt_probe_intr_callback */ | |||||
/* | |||||
* Called when outgoing control request (HCI command) has completed, i.e. | * Called when outgoing control request (HCI command) has completed, i.e. | ||||
* HCI command was sent to the device. | * HCI command was sent to the device. | ||||
* USB context. | * USB context. | ||||
*/ | */ | ||||
static void | static void | ||||
ubt_ctrl_write_callback(struct usb_xfer *xfer, usb_error_t error) | ubt_ctrl_write_callback(struct usb_xfer *xfer, usb_error_t error) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 1,118 Lines • ▼ Show 20 Lines | ubt_modevent(module_t mod, int event, void *data) | ||||
default: | default: | ||||
error = EOPNOTSUPP; | error = EOPNOTSUPP; | ||||
break; | break; | ||||
} | } | ||||
return (error); | return (error); | ||||
} /* ubt_modevent */ | } /* ubt_modevent */ | ||||
static devclass_t ubt_devclass; | devclass_t ubt_devclass; | ||||
static device_method_t ubt_methods[] = | static device_method_t ubt_methods[] = | ||||
{ | { | ||||
DEVMETHOD(device_probe, ubt_probe), | DEVMETHOD(device_probe, ubt_probe), | ||||
DEVMETHOD(device_attach, ubt_attach), | DEVMETHOD(device_attach, ubt_attach), | ||||
DEVMETHOD(device_detach, ubt_detach), | DEVMETHOD(device_detach, ubt_detach), | ||||
DEVMETHOD_END | DEVMETHOD_END | ||||
}; | }; | ||||
static driver_t ubt_driver = | driver_t ubt_driver = | ||||
{ | { | ||||
.name = "ubt", | .name = "ubt", | ||||
.methods = ubt_methods, | .methods = ubt_methods, | ||||
.size = sizeof(struct ubt_softc), | .size = sizeof(struct ubt_softc), | ||||
}; | }; | ||||
DRIVER_MODULE(ng_ubt, uhub, ubt_driver, ubt_devclass, ubt_modevent, 0); | DRIVER_MODULE(ng_ubt, uhub, ubt_driver, ubt_devclass, ubt_modevent, 0); | ||||
MODULE_VERSION(ng_ubt, NG_BLUETOOTH_VERSION); | MODULE_VERSION(ng_ubt, NG_BLUETOOTH_VERSION); | ||||
MODULE_DEPEND(ng_ubt, netgraph, NG_ABI_VERSION, NG_ABI_VERSION, NG_ABI_VERSION); | MODULE_DEPEND(ng_ubt, netgraph, NG_ABI_VERSION, NG_ABI_VERSION, NG_ABI_VERSION); | ||||
MODULE_DEPEND(ng_ubt, ng_hci, NG_BLUETOOTH_VERSION, NG_BLUETOOTH_VERSION, NG_BLUETOOTH_VERSION); | MODULE_DEPEND(ng_ubt, ng_hci, NG_BLUETOOTH_VERSION, NG_BLUETOOTH_VERSION, NG_BLUETOOTH_VERSION); | ||||
MODULE_DEPEND(ng_ubt, usb, 1, 1, 1); | MODULE_DEPEND(ng_ubt, usb, 1, 1, 1); | ||||
USB_PNP_HOST_INFO(ubt_devs); | USB_PNP_HOST_INFO(ubt_devs); |