ubtbcmfw.c revision 190734
1169689Skan/* 2169689Skan * ubtbcmfw.c 3169689Skan */ 4169689Skan 5169689Skan/*- 6169689Skan * Copyright (c) 2003-2009 Maksim Yevmenkin <m_evmenkin@yahoo.com> 7169689Skan * All rights reserved. 8169689Skan * 9169689Skan * Redistribution and use in source and binary forms, with or without 10169689Skan * modification, are permitted provided that the following conditions 11169689Skan * are met: 12169689Skan * 1. Redistributions of source code must retain the above copyright 13169689Skan * notice, this list of conditions and the following disclaimer. 14169689Skan * 2. Redistributions in binary form must reproduce the above copyright 15169689Skan * notice, this list of conditions and the following disclaimer in the 16169689Skan * documentation and/or other materials provided with the distribution. 17169689Skan * 18169689Skan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19169689Skan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20169689Skan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21169689Skan * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22169689Skan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23169689Skan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24169689Skan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25169689Skan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26169689Skan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27169689Skan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28169689Skan * SUCH DAMAGE. 29169689Skan * 30169689Skan * $Id: ubtbcmfw.c,v 1.3 2003/10/10 19:15:08 max Exp $ 31169689Skan * $FreeBSD: head/sys/dev/usb/bluetooth/ubtbcmfw.c 190734 2009-04-05 18:20:38Z thompsa $ 32169689Skan */ 33169689Skan 34169689Skan#include "usbdevs.h" 35169689Skan#include <dev/usb/usb.h> 36169689Skan#include <dev/usb/usb_mfunc.h> 37169689Skan#include <dev/usb/usb_error.h> 38169689Skan#include <dev/usb/usb_ioctl.h> 39169689Skan 40169689Skan#define USB_DEBUG_VAR usb2_debug 41169689Skan 42169689Skan#include <dev/usb/usb_core.h> 43169689Skan#include <dev/usb/usb_debug.h> 44169689Skan#include <dev/usb/usb_parse.h> 45169689Skan#include <dev/usb/usb_lookup.h> 46169689Skan#include <dev/usb/usb_util.h> 47169689Skan#include <dev/usb/usb_busdma.h> 48169689Skan#include <dev/usb/usb_mbuf.h> 49169689Skan#include <dev/usb/usb_dev.h> 50169689Skan 51169689Skan/* 52169689Skan * Download firmware to BCM2033. 53169689Skan */ 54169689Skan 55169689Skan#define UBTBCMFW_CONFIG_NO 1 /* Config number */ 56169689Skan#define UBTBCMFW_IFACE_IDX 0 /* Control interface */ 57169689Skan 58169689Skan#define UBTBCMFW_BSIZE 1024 59169689Skan#define UBTBCMFW_IFQ_MAXLEN 2 60169689Skan 61169689Skanenum { 62169689Skan UBTBCMFW_BULK_DT_WR = 0, 63169689Skan UBTBCMFW_INTR_DT_RD, 64169689Skan UBTBCMFW_N_TRANSFER, 65169689Skan}; 66169689Skan 67169689Skanstruct ubtbcmfw_softc { 68169689Skan struct usb2_device *sc_udev; 69169689Skan struct mtx sc_mtx; 70169689Skan struct usb2_xfer *sc_xfer[UBTBCMFW_N_TRANSFER]; 71169689Skan struct usb2_fifo_sc sc_fifo; 72169689Skan}; 73169689Skan 74169689Skan/* 75169689Skan * Prototypes 76169689Skan */ 77169689Skan 78169689Skanstatic device_probe_t ubtbcmfw_probe; 79169689Skanstatic device_attach_t ubtbcmfw_attach; 80169689Skanstatic device_detach_t ubtbcmfw_detach; 81169689Skan 82169689Skanstatic usb2_callback_t ubtbcmfw_write_callback; 83169689Skanstatic usb2_callback_t ubtbcmfw_read_callback; 84169689Skan 85169689Skanstatic usb2_fifo_close_t ubtbcmfw_close; 86169689Skanstatic usb2_fifo_cmd_t ubtbcmfw_start_read; 87169689Skanstatic usb2_fifo_cmd_t ubtbcmfw_start_write; 88169689Skanstatic usb2_fifo_cmd_t ubtbcmfw_stop_read; 89169689Skanstatic usb2_fifo_cmd_t ubtbcmfw_stop_write; 90169689Skanstatic usb2_fifo_ioctl_t ubtbcmfw_ioctl; 91169689Skanstatic usb2_fifo_open_t ubtbcmfw_open; 92169689Skan 93169689Skanstatic struct usb2_fifo_methods ubtbcmfw_fifo_methods = 94169689Skan{ 95169689Skan .f_close = &ubtbcmfw_close, 96169689Skan .f_ioctl = &ubtbcmfw_ioctl, 97169689Skan .f_open = &ubtbcmfw_open, 98169689Skan .f_start_read = &ubtbcmfw_start_read, 99169689Skan .f_start_write = &ubtbcmfw_start_write, 100169689Skan .f_stop_read = &ubtbcmfw_stop_read, 101169689Skan .f_stop_write = &ubtbcmfw_stop_write, 102169689Skan .basename[0] = "ubtbcmfw", 103169689Skan .basename[1] = "ubtbcmfw", 104169689Skan .basename[2] = "ubtbcmfw", 105169689Skan .postfix[0] = "", 106169689Skan .postfix[1] = ".1", 107169689Skan .postfix[2] = ".2", 108169689Skan}; 109169689Skan 110169689Skan/* 111169689Skan * Device's config structure 112169689Skan */ 113169689Skan 114169689Skanstatic const struct usb2_config ubtbcmfw_config[UBTBCMFW_N_TRANSFER] = 115169689Skan{ 116169689Skan [UBTBCMFW_BULK_DT_WR] = { 117169689Skan .type = UE_BULK, 118169689Skan .endpoint = 0x02, /* fixed */ 119169689Skan .direction = UE_DIR_OUT, 120169689Skan .if_index = UBTBCMFW_IFACE_IDX, 121169689Skan .bufsize = UBTBCMFW_BSIZE, 122169689Skan .flags = { .pipe_bof = 1, .force_short_xfer = 1, 123169689Skan .proxy_buffer = 1, }, 124169689Skan .callback = &ubtbcmfw_write_callback, 125169689Skan }, 126169689Skan 127169689Skan [UBTBCMFW_INTR_DT_RD] = { 128169689Skan .type = UE_INTERRUPT, 129169689Skan .endpoint = 0x01, /* fixed */ 130169689Skan .direction = UE_DIR_IN, 131169689Skan .if_index = UBTBCMFW_IFACE_IDX, 132169689Skan .bufsize = UBTBCMFW_BSIZE, 133169689Skan .flags = { .pipe_bof = 1, .short_xfer_ok = 1, 134169689Skan .proxy_buffer = 1, }, 135169689Skan .callback = &ubtbcmfw_read_callback, 136169689Skan }, 137169689Skan}; 138169689Skan 139169689Skan/* 140169689Skan * Module 141169689Skan */ 142169689Skan 143169689Skanstatic devclass_t ubtbcmfw_devclass; 144169689Skan 145169689Skanstatic device_method_t ubtbcmfw_methods[] = 146169689Skan{ 147169689Skan DEVMETHOD(device_probe, ubtbcmfw_probe), 148169689Skan DEVMETHOD(device_attach, ubtbcmfw_attach), 149169689Skan DEVMETHOD(device_detach, ubtbcmfw_detach), 150169689Skan {0, 0} 151169689Skan}; 152169689Skan 153169689Skanstatic driver_t ubtbcmfw_driver = 154169689Skan{ 155169689Skan .name = "ubtbcmfw", 156169689Skan .methods = ubtbcmfw_methods, 157169689Skan .size = sizeof(struct ubtbcmfw_softc), 158169689Skan}; 159169689Skan 160169689SkanDRIVER_MODULE(ubtbcmfw, uhub, ubtbcmfw_driver, ubtbcmfw_devclass, NULL, 0); 161169689SkanMODULE_DEPEND(ubtbcmfw, usb, 1, 1, 1); 162169689Skan 163169689Skan/* 164169689Skan * Probe for a USB Bluetooth device 165169689Skan */ 166169689Skan 167169689Skanstatic int 168169689Skanubtbcmfw_probe(device_t dev) 169169689Skan{ 170169689Skan const struct usb2_device_id devs[] = { 171169689Skan /* Broadcom BCM2033 devices only */ 172169689Skan { USB_VPI(USB_VENDOR_BROADCOM, USB_PRODUCT_BROADCOM_BCM2033, 0) }, 173169689Skan }; 174169689Skan 175169689Skan struct usb2_attach_arg *uaa = device_get_ivars(dev); 176169689Skan 177169689Skan if (uaa->usb2_mode != USB_MODE_HOST) 178169689Skan return (ENXIO); 179169689Skan 180169689Skan if (uaa->info.bIfaceIndex != 0) 181169689Skan return (ENXIO); 182169689Skan 183169689Skan return (usb2_lookup_id_by_uaa(devs, sizeof(devs), uaa)); 184169689Skan} /* ubtbcmfw_probe */ 185169689Skan 186169689Skan/* 187169689Skan * Attach the device 188169689Skan */ 189169689Skan 190169689Skanstatic int 191169689Skanubtbcmfw_attach(device_t dev) 192169689Skan{ 193169689Skan struct usb2_attach_arg *uaa = device_get_ivars(dev); 194169689Skan struct ubtbcmfw_softc *sc = device_get_softc(dev); 195169689Skan uint8_t iface_index; 196169689Skan int error; 197169689Skan 198169689Skan sc->sc_udev = uaa->device; 199169689Skan 200169689Skan device_set_usb2_desc(dev); 201169689Skan 202169689Skan mtx_init(&sc->sc_mtx, "ubtbcmfw lock", NULL, MTX_DEF | MTX_RECURSE); 203169689Skan 204169689Skan iface_index = UBTBCMFW_IFACE_IDX; 205169689Skan error = usb2_transfer_setup(uaa->device, &iface_index, sc->sc_xfer, 206169689Skan ubtbcmfw_config, UBTBCMFW_N_TRANSFER, 207169689Skan sc, &sc->sc_mtx); 208169689Skan if (error != 0) { 209169689Skan device_printf(dev, "allocating USB transfers failed. %s\n", 210169689Skan usb2_errstr(error)); 211169689Skan goto detach; 212169689Skan } 213169689Skan 214169689Skan error = usb2_fifo_attach(uaa->device, sc, &sc->sc_mtx, 215169689Skan &ubtbcmfw_fifo_methods, &sc->sc_fifo, 216169689Skan device_get_unit(dev), 0 - 1, uaa->info.bIfaceIndex, 217169689Skan UID_ROOT, GID_OPERATOR, 0644); 218169689Skan if (error != 0) { 219169689Skan device_printf(dev, "could not attach fifo. %s\n", 220169689Skan usb2_errstr(error)); 221169689Skan goto detach; 222169689Skan } 223169689Skan 224169689Skan return (0); /* success */ 225169689Skan 226169689Skandetach: 227169689Skan ubtbcmfw_detach(dev); 228169689Skan 229169689Skan return (ENXIO); /* failure */ 230169689Skan} /* ubtbcmfw_attach */ 231169689Skan 232169689Skan/* 233169689Skan * Detach the device 234169689Skan */ 235169689Skan 236169689Skanstatic int 237169689Skanubtbcmfw_detach(device_t dev) 238169689Skan{ 239169689Skan struct ubtbcmfw_softc *sc = device_get_softc(dev); 240169689Skan 241169689Skan usb2_fifo_detach(&sc->sc_fifo); 242169689Skan 243169689Skan usb2_transfer_unsetup(sc->sc_xfer, UBTBCMFW_N_TRANSFER); 244169689Skan 245169689Skan mtx_destroy(&sc->sc_mtx); 246169689Skan 247169689Skan return (0); 248169689Skan} /* ubtbcmfw_detach */ 249169689Skan 250169689Skan/* 251169689Skan * USB write callback 252169689Skan */ 253169689Skan 254169689Skanstatic void 255169689Skanubtbcmfw_write_callback(struct usb2_xfer *xfer) 256169689Skan{ 257169689Skan struct ubtbcmfw_softc *sc = xfer->priv_sc; 258169689Skan struct usb2_fifo *f = sc->sc_fifo.fp[USB_FIFO_TX]; 259169689Skan uint32_t actlen; 260169689Skan 261169689Skan switch (USB_GET_STATE(xfer)) { 262169689Skan case USB_ST_SETUP: 263169689Skan case USB_ST_TRANSFERRED: 264169689Skansetup_next: 265169689Skan if (usb2_fifo_get_data(f, xfer->frbuffers, 0, 266169689Skan xfer->max_data_length, &actlen, 0)) { 267169689Skan xfer->frlengths[0] = actlen; 268169689Skan usb2_start_hardware(xfer); 269169689Skan } 270169689Skan break; 271169689Skan 272169689Skan default: /* Error */ 273169689Skan if (xfer->error != USB_ERR_CANCELLED) { 274169689Skan /* try to clear stall first */ 275169689Skan xfer->flags.stall_pipe = 1; 276169689Skan goto setup_next; 277169689Skan } 278169689Skan break; 279169689Skan } 280169689Skan} /* ubtbcmfw_write_callback */ 281169689Skan 282169689Skan/* 283169689Skan * USB read callback 284169689Skan */ 285169689Skan 286169689Skanstatic void 287169689Skanubtbcmfw_read_callback(struct usb2_xfer *xfer) 288169689Skan{ 289169689Skan struct ubtbcmfw_softc *sc = xfer->priv_sc; 290169689Skan struct usb2_fifo *fifo = sc->sc_fifo.fp[USB_FIFO_RX]; 291169689Skan 292169689Skan switch (USB_GET_STATE(xfer)) { 293169689Skan case USB_ST_TRANSFERRED: 294169689Skan usb2_fifo_put_data(fifo, xfer->frbuffers, 0, xfer->actlen, 1); 295169689Skan /* FALLTHROUGH */ 296169689Skan 297169689Skan case USB_ST_SETUP: 298169689Skansetup_next: 299169689Skan if (usb2_fifo_put_bytes_max(fifo) > 0) { 300169689Skan xfer->frlengths[0] = xfer->max_data_length; 301169689Skan usb2_start_hardware(xfer); 302169689Skan } 303169689Skan break; 304169689Skan 305169689Skan default: /* Error */ 306169689Skan if (xfer->error != USB_ERR_CANCELLED) { 307169689Skan /* try to clear stall first */ 308169689Skan xfer->flags.stall_pipe = 1; 309169689Skan goto setup_next; 310169689Skan } 311169689Skan break; 312169689Skan } 313169689Skan} /* ubtbcmfw_read_callback */ 314169689Skan 315169689Skan/* 316169689Skan * Called when we about to start read()ing from the device 317169689Skan */ 318169689Skan 319169689Skanstatic void 320169689Skanubtbcmfw_start_read(struct usb2_fifo *fifo) 321169689Skan{ 322169689Skan struct ubtbcmfw_softc *sc = fifo->priv_sc0; 323169689Skan 324169689Skan usb2_transfer_start(sc->sc_xfer[UBTBCMFW_INTR_DT_RD]); 325169689Skan} /* ubtbcmfw_start_read */ 326169689Skan 327169689Skan/* 328169689Skan * Called when we about to stop reading (i.e. closing fifo) 329169689Skan */ 330169689Skan 331169689Skanstatic void 332169689Skanubtbcmfw_stop_read(struct usb2_fifo *fifo) 333169689Skan{ 334169689Skan struct ubtbcmfw_softc *sc = fifo->priv_sc0; 335169689Skan 336169689Skan usb2_transfer_stop(sc->sc_xfer[UBTBCMFW_INTR_DT_RD]); 337169689Skan} /* ubtbcmfw_stop_read */ 338169689Skan 339169689Skan/* 340169689Skan * Called when we about to start write()ing to the device, poll()ing 341169689Skan * for write or flushing fifo 342169689Skan */ 343169689Skan 344169689Skanstatic void 345169689Skanubtbcmfw_start_write(struct usb2_fifo *fifo) 346169689Skan{ 347169689Skan struct ubtbcmfw_softc *sc = fifo->priv_sc0; 348169689Skan 349169689Skan usb2_transfer_start(sc->sc_xfer[UBTBCMFW_BULK_DT_WR]); 350169689Skan} /* ubtbcmfw_start_write */ 351169689Skan 352169689Skan/* 353169689Skan * Called when we about to stop writing (i.e. closing fifo) 354169689Skan */ 355169689Skan 356169689Skanstatic void 357169689Skanubtbcmfw_stop_write(struct usb2_fifo *fifo) 358169689Skan{ 359169689Skan struct ubtbcmfw_softc *sc = fifo->priv_sc0; 360169689Skan 361169689Skan usb2_transfer_stop(sc->sc_xfer[UBTBCMFW_BULK_DT_WR]); 362169689Skan} /* ubtbcmfw_stop_write */ 363169689Skan 364169689Skan/* 365169689Skan * Called when fifo is open 366169689Skan */ 367169689Skan 368169689Skanstatic int 369169689Skanubtbcmfw_open(struct usb2_fifo *fifo, int fflags) 370169689Skan{ 371169689Skan struct ubtbcmfw_softc *sc = fifo->priv_sc0; 372169689Skan struct usb2_xfer *xfer; 373169689Skan 374169689Skan /* 375169689Skan * f_open fifo method can only be called with either FREAD 376169689Skan * or FWRITE flag set at one time. 377169689Skan */ 378169689Skan 379169689Skan if (fflags & FREAD) 380169689Skan xfer = sc->sc_xfer[UBTBCMFW_INTR_DT_RD]; 381169689Skan else if (fflags & FWRITE) 382169689Skan xfer = sc->sc_xfer[UBTBCMFW_BULK_DT_WR]; 383169689Skan else 384169689Skan return (EINVAL); /* should not happen */ 385169689Skan 386169689Skan if (usb2_fifo_alloc_buffer(fifo, xfer->max_data_length, 387169689Skan UBTBCMFW_IFQ_MAXLEN) != 0) 388169689Skan return (ENOMEM); 389169689Skan 390169689Skan return (0); 391169689Skan} /* ubtbcmfw_open */ 392169689Skan 393169689Skan/* 394169689Skan * Called when fifo is closed 395169689Skan */ 396169689Skan 397169689Skanstatic void 398169689Skanubtbcmfw_close(struct usb2_fifo *fifo, int fflags) 399169689Skan{ 400169689Skan if (fflags & (FREAD | FWRITE)) 401169689Skan usb2_fifo_free_buffer(fifo); 402169689Skan} /* ubtbcmfw_close */ 403169689Skan 404169689Skan/* 405169689Skan * Process ioctl() on USB device 406169689Skan */ 407169689Skan 408169689Skanstatic int 409169689Skanubtbcmfw_ioctl(struct usb2_fifo *fifo, u_long cmd, void *data, 410169689Skan int fflags) 411169689Skan{ 412169689Skan struct ubtbcmfw_softc *sc = fifo->priv_sc0; 413169689Skan int error = 0; 414169689Skan 415169689Skan switch (cmd) { 416169689Skan case USB_GET_DEVICE_DESC: 417169689Skan memcpy(data, usb2_get_device_descriptor(sc->sc_udev), 418169689Skan sizeof(struct usb2_device_descriptor)); 419169689Skan break; 420169689Skan 421169689Skan default: 422169689Skan error = EINVAL; 423169689Skan break; 424169689Skan } 425169689Skan 426169689Skan return (error); 427169689Skan} /* ubtbcmfw_ioctl */ 428169689Skan