ubtbcmfw.c revision 188746
1184610Salfred/* 2184610Salfred * ubtbcmfw.c 3184610Salfred */ 4184610Salfred 5184610Salfred/*- 6187866Semax * Copyright (c) 2003-2009 Maksim Yevmenkin <m_evmenkin@yahoo.com> 7184610Salfred * All rights reserved. 8184610Salfred * 9184610Salfred * Redistribution and use in source and binary forms, with or without 10184610Salfred * modification, are permitted provided that the following conditions 11184610Salfred * are met: 12184610Salfred * 1. Redistributions of source code must retain the above copyright 13184610Salfred * notice, this list of conditions and the following disclaimer. 14184610Salfred * 2. Redistributions in binary form must reproduce the above copyright 15184610Salfred * notice, this list of conditions and the following disclaimer in the 16184610Salfred * documentation and/or other materials provided with the distribution. 17184610Salfred * 18184610Salfred * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21184610Salfred * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22184610Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23184610Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24184610Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25184610Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26184610Salfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27184610Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28184610Salfred * SUCH DAMAGE. 29184610Salfred * 30184610Salfred * $Id: ubtbcmfw.c,v 1.3 2003/10/10 19:15:08 max Exp $ 31184610Salfred * $FreeBSD: head/sys/dev/usb2/bluetooth/ubtbcmfw2.c 188746 2009-02-18 06:33:10Z thompsa $ 32184610Salfred */ 33184610Salfred 34188746Sthompsa#include "usbdevs.h" 35184610Salfred#include <dev/usb2/include/usb2_standard.h> 36184610Salfred#include <dev/usb2/include/usb2_mfunc.h> 37184610Salfred#include <dev/usb2/include/usb2_error.h> 38184610Salfred#include <dev/usb2/include/usb2_ioctl.h> 39184610Salfred 40184610Salfred#define USB_DEBUG_VAR usb2_debug 41184610Salfred 42184610Salfred#include <dev/usb2/core/usb2_core.h> 43184610Salfred#include <dev/usb2/core/usb2_debug.h> 44184610Salfred#include <dev/usb2/core/usb2_parse.h> 45184610Salfred#include <dev/usb2/core/usb2_lookup.h> 46184610Salfred#include <dev/usb2/core/usb2_util.h> 47184610Salfred#include <dev/usb2/core/usb2_busdma.h> 48184610Salfred#include <dev/usb2/core/usb2_mbuf.h> 49184610Salfred#include <dev/usb2/core/usb2_dev.h> 50184610Salfred 51184610Salfred/* 52184610Salfred * Download firmware to BCM2033. 53184610Salfred */ 54184610Salfred 55184610Salfred#define UBTBCMFW_CONFIG_NO 1 /* Config number */ 56184610Salfred#define UBTBCMFW_IFACE_IDX 0 /* Control interface */ 57184610Salfred 58187866Semax#define UBTBCMFW_BSIZE 1024 59187866Semax#define UBTBCMFW_IFQ_MAXLEN 2 60187866Semax 61187259Sthompsaenum { 62187866Semax UBTBCMFW_BULK_DT_WR = 0, 63187866Semax UBTBCMFW_INTR_DT_RD, 64187866Semax UBTBCMFW_N_TRANSFER, 65187259Sthompsa}; 66187259Sthompsa 67184610Salfredstruct ubtbcmfw_softc { 68187866Semax struct usb2_device *sc_udev; 69187866Semax struct mtx sc_mtx; 70187866Semax struct usb2_xfer *sc_xfer[UBTBCMFW_N_TRANSFER]; 71187866Semax struct usb2_fifo_sc sc_fifo; 72184610Salfred}; 73184610Salfred 74187866Semax/* 75187866Semax * Prototypes 76187866Semax */ 77184610Salfred 78187866Semaxstatic device_probe_t ubtbcmfw_probe; 79187866Semaxstatic device_attach_t ubtbcmfw_attach; 80187866Semaxstatic device_detach_t ubtbcmfw_detach; 81184610Salfred 82187866Semaxstatic usb2_callback_t ubtbcmfw_write_callback; 83187866Semaxstatic usb2_callback_t ubtbcmfw_read_callback; 84184610Salfred 85187866Semaxstatic usb2_fifo_close_t ubtbcmfw_close; 86187866Semaxstatic usb2_fifo_cmd_t ubtbcmfw_start_read; 87187866Semaxstatic usb2_fifo_cmd_t ubtbcmfw_start_write; 88187866Semaxstatic usb2_fifo_cmd_t ubtbcmfw_stop_read; 89187866Semaxstatic usb2_fifo_cmd_t ubtbcmfw_stop_write; 90187866Semaxstatic usb2_fifo_ioctl_t ubtbcmfw_ioctl; 91187866Semaxstatic usb2_fifo_open_t ubtbcmfw_open; 92184610Salfred 93187866Semaxstatic struct usb2_fifo_methods ubtbcmfw_fifo_methods = 94187866Semax{ 95187866Semax .f_close = &ubtbcmfw_close, 96187866Semax .f_ioctl = &ubtbcmfw_ioctl, 97187866Semax .f_open = &ubtbcmfw_open, 98187866Semax .f_start_read = &ubtbcmfw_start_read, 99187866Semax .f_start_write = &ubtbcmfw_start_write, 100187866Semax .f_stop_read = &ubtbcmfw_stop_read, 101187866Semax .f_stop_write = &ubtbcmfw_stop_write, 102187866Semax .basename[0] = "ubtbcmfw", 103187866Semax .basename[1] = "ubtbcmfw", 104187866Semax .basename[2] = "ubtbcmfw", 105187866Semax .postfix[0] = "", 106187866Semax .postfix[1] = ".1", 107187866Semax .postfix[2] = ".2", 108184610Salfred}; 109184610Salfred 110187866Semax/* 111187866Semax * Device's config structure 112187866Semax */ 113184610Salfred 114187866Semaxstatic const struct usb2_config ubtbcmfw_config[UBTBCMFW_N_TRANSFER] = 115187866Semax{ 116187259Sthompsa [UBTBCMFW_BULK_DT_WR] = { 117187866Semax .type = UE_BULK, 118187866Semax .endpoint = 0x02, /* fixed */ 119187866Semax .direction = UE_DIR_OUT, 120187866Semax .if_index = UBTBCMFW_IFACE_IDX, 121187866Semax .mh.bufsize = UBTBCMFW_BSIZE, 122187866Semax .mh.flags = { .pipe_bof = 1, .force_short_xfer = 1, 123187866Semax .proxy_buffer = 1, }, 124187866Semax .mh.callback = &ubtbcmfw_write_callback, 125184610Salfred }, 126184610Salfred 127187866Semax [UBTBCMFW_INTR_DT_RD] = { 128187866Semax .type = UE_INTERRUPT, 129187866Semax .endpoint = 0x01, /* fixed */ 130187866Semax .direction = UE_DIR_IN, 131187866Semax .if_index = UBTBCMFW_IFACE_IDX, 132187866Semax .mh.bufsize = UBTBCMFW_BSIZE, 133187866Semax .mh.flags = { .pipe_bof = 1, .short_xfer_ok = 1, 134187866Semax .proxy_buffer = 1, }, 135187866Semax .mh.callback = &ubtbcmfw_read_callback, 136184610Salfred }, 137184610Salfred}; 138184610Salfred 139184610Salfred/* 140184610Salfred * Module 141184610Salfred */ 142184610Salfred 143187866Semaxstatic devclass_t ubtbcmfw_devclass; 144184610Salfred 145187866Semaxstatic device_method_t ubtbcmfw_methods[] = 146187866Semax{ 147184610Salfred DEVMETHOD(device_probe, ubtbcmfw_probe), 148184610Salfred DEVMETHOD(device_attach, ubtbcmfw_attach), 149184610Salfred DEVMETHOD(device_detach, ubtbcmfw_detach), 150184610Salfred {0, 0} 151184610Salfred}; 152184610Salfred 153187866Semaxstatic driver_t ubtbcmfw_driver = 154187866Semax{ 155187866Semax .name = "ubtbcmfw", 156187866Semax .methods = ubtbcmfw_methods, 157187866Semax .size = sizeof(struct ubtbcmfw_softc), 158184610Salfred}; 159184610Salfred 160184610SalfredDRIVER_MODULE(ubtbcmfw, ushub, ubtbcmfw_driver, ubtbcmfw_devclass, NULL, 0); 161184610SalfredMODULE_DEPEND(ubtbcmfw, usb2_bluetooth, 1, 1, 1); 162184610SalfredMODULE_DEPEND(ubtbcmfw, usb2_core, 1, 1, 1); 163184610Salfred 164184610Salfred/* 165184610Salfred * Probe for a USB Bluetooth device 166184610Salfred */ 167184610Salfred 168184610Salfredstatic int 169184610Salfredubtbcmfw_probe(device_t dev) 170184610Salfred{ 171187866Semax const struct usb2_device_id devs[] = { 172187866Semax /* Broadcom BCM2033 devices only */ 173187866Semax { USB_VPI(USB_VENDOR_BROADCOM, USB_PRODUCT_BROADCOM_BCM2033, 0) }, 174187866Semax }; 175184610Salfred 176187866Semax struct usb2_attach_arg *uaa = device_get_ivars(dev); 177187866Semax 178187866Semax if (uaa->usb2_mode != USB_MODE_HOST) 179184610Salfred return (ENXIO); 180187866Semax 181184610Salfred if (uaa->info.bIfaceIndex != 0) 182184610Salfred return (ENXIO); 183184610Salfred 184187866Semax return (usb2_lookup_id_by_uaa(devs, sizeof(devs), uaa)); 185187866Semax} /* ubtbcmfw_probe */ 186184610Salfred 187184610Salfred/* 188184610Salfred * Attach the device 189184610Salfred */ 190184610Salfred 191184610Salfredstatic int 192184610Salfredubtbcmfw_attach(device_t dev) 193184610Salfred{ 194187866Semax struct usb2_attach_arg *uaa = device_get_ivars(dev); 195187866Semax struct ubtbcmfw_softc *sc = device_get_softc(dev); 196187866Semax uint8_t iface_index; 197187866Semax int error; 198184610Salfred 199184610Salfred sc->sc_udev = uaa->device; 200184610Salfred 201184610Salfred device_set_usb2_desc(dev); 202184610Salfred 203184610Salfred mtx_init(&sc->sc_mtx, "ubtbcmfw lock", NULL, MTX_DEF | MTX_RECURSE); 204184610Salfred 205184610Salfred iface_index = UBTBCMFW_IFACE_IDX; 206187866Semax error = usb2_transfer_setup(uaa->device, &iface_index, sc->sc_xfer, 207187866Semax ubtbcmfw_config, UBTBCMFW_N_TRANSFER, 208187866Semax sc, &sc->sc_mtx); 209187866Semax if (error != 0) { 210187866Semax device_printf(dev, "allocating USB transfers failed. %s\n", 211187866Semax usb2_errstr(error)); 212184610Salfred goto detach; 213184610Salfred } 214187866Semax 215187866Semax /* Set interface permissions */ 216184610Salfred usb2_set_iface_perm(uaa->device, uaa->info.bIfaceIndex, 217187866Semax UID_ROOT, GID_OPERATOR, 0644); 218184610Salfred 219187866Semax error = usb2_fifo_attach(uaa->device, sc, &sc->sc_mtx, 220187866Semax &ubtbcmfw_fifo_methods, &sc->sc_fifo, 221187866Semax device_get_unit(dev), 0 - 1, uaa->info.bIfaceIndex); 222187866Semax if (error != 0) { 223187866Semax device_printf(dev, "could not attach fifo. %s\n", 224187866Semax usb2_errstr(error)); 225184610Salfred goto detach; 226184610Salfred } 227184610Salfred 228187866Semax return (0); /* success */ 229187866Semax 230184610Salfreddetach: 231184610Salfred ubtbcmfw_detach(dev); 232184610Salfred 233187866Semax return (ENXIO); /* failure */ 234187866Semax} /* ubtbcmfw_attach */ 235187866Semax 236184610Salfred/* 237184610Salfred * Detach the device 238184610Salfred */ 239184610Salfred 240184610Salfredstatic int 241184610Salfredubtbcmfw_detach(device_t dev) 242184610Salfred{ 243187866Semax struct ubtbcmfw_softc *sc = device_get_softc(dev); 244184610Salfred 245184610Salfred usb2_fifo_detach(&sc->sc_fifo); 246184610Salfred 247187866Semax usb2_transfer_unsetup(sc->sc_xfer, UBTBCMFW_N_TRANSFER); 248184610Salfred 249184610Salfred mtx_destroy(&sc->sc_mtx); 250184610Salfred 251184610Salfred return (0); 252187866Semax} /* ubtbcmfw_detach */ 253184610Salfred 254187866Semax/* 255187866Semax * USB write callback 256187866Semax */ 257187866Semax 258184610Salfredstatic void 259184610Salfredubtbcmfw_write_callback(struct usb2_xfer *xfer) 260184610Salfred{ 261187866Semax struct ubtbcmfw_softc *sc = xfer->priv_sc; 262187866Semax struct usb2_fifo *f = sc->sc_fifo.fp[USB_FIFO_TX]; 263187866Semax uint32_t actlen; 264184610Salfred 265184610Salfred switch (USB_GET_STATE(xfer)) { 266187866Semax case USB_ST_SETUP: 267184610Salfred case USB_ST_TRANSFERRED: 268187866Semaxsetup_next: 269184610Salfred if (usb2_fifo_get_data(f, xfer->frbuffers, 0, 270187866Semax xfer->max_data_length, &actlen, 0)) { 271184610Salfred xfer->frlengths[0] = actlen; 272184610Salfred usb2_start_hardware(xfer); 273184610Salfred } 274187866Semax break; 275184610Salfred 276187866Semax default: /* Error */ 277184610Salfred if (xfer->error != USB_ERR_CANCELLED) { 278184610Salfred /* try to clear stall first */ 279187866Semax xfer->flags.stall_pipe = 1; 280187866Semax goto setup_next; 281184610Salfred } 282187866Semax break; 283184610Salfred } 284187866Semax} /* ubtbcmfw_write_callback */ 285184610Salfred 286187866Semax/* 287187866Semax * USB read callback 288187866Semax */ 289184610Salfred 290184610Salfredstatic void 291184610Salfredubtbcmfw_read_callback(struct usb2_xfer *xfer) 292184610Salfred{ 293187866Semax struct ubtbcmfw_softc *sc = xfer->priv_sc; 294187866Semax struct usb2_fifo *fifo = sc->sc_fifo.fp[USB_FIFO_RX]; 295184610Salfred 296184610Salfred switch (USB_GET_STATE(xfer)) { 297184610Salfred case USB_ST_TRANSFERRED: 298187866Semax usb2_fifo_put_data(fifo, xfer->frbuffers, 0, xfer->actlen, 1); 299187866Semax /* FALLTHROUGH */ 300184610Salfred 301184610Salfred case USB_ST_SETUP: 302187866Semaxsetup_next: 303187866Semax if (usb2_fifo_put_bytes_max(fifo) > 0) { 304184610Salfred xfer->frlengths[0] = xfer->max_data_length; 305184610Salfred usb2_start_hardware(xfer); 306184610Salfred } 307187866Semax break; 308184610Salfred 309187866Semax default: /* Error */ 310184610Salfred if (xfer->error != USB_ERR_CANCELLED) { 311184610Salfred /* try to clear stall first */ 312187866Semax xfer->flags.stall_pipe = 1; 313187866Semax goto setup_next; 314184610Salfred } 315187866Semax break; 316184610Salfred } 317187866Semax} /* ubtbcmfw_read_callback */ 318184610Salfred 319187866Semax/* 320187866Semax * Called when we about to start read()ing from the device 321187866Semax */ 322184610Salfred 323184610Salfredstatic void 324184610Salfredubtbcmfw_start_read(struct usb2_fifo *fifo) 325184610Salfred{ 326187866Semax struct ubtbcmfw_softc *sc = fifo->priv_sc0; 327184610Salfred 328187866Semax usb2_transfer_start(sc->sc_xfer[UBTBCMFW_INTR_DT_RD]); 329187866Semax} /* ubtbcmfw_start_read */ 330184610Salfred 331187866Semax/* 332187866Semax * Called when we about to stop reading (i.e. closing fifo) 333187866Semax */ 334187866Semax 335184610Salfredstatic void 336184610Salfredubtbcmfw_stop_read(struct usb2_fifo *fifo) 337184610Salfred{ 338187866Semax struct ubtbcmfw_softc *sc = fifo->priv_sc0; 339184610Salfred 340187866Semax usb2_transfer_stop(sc->sc_xfer[UBTBCMFW_INTR_DT_RD]); 341187866Semax} /* ubtbcmfw_stop_read */ 342184610Salfred 343187866Semax/* 344187866Semax * Called when we about to start write()ing to the device, poll()ing 345187866Semax * for write or flushing fifo 346187866Semax */ 347187866Semax 348184610Salfredstatic void 349184610Salfredubtbcmfw_start_write(struct usb2_fifo *fifo) 350184610Salfred{ 351187866Semax struct ubtbcmfw_softc *sc = fifo->priv_sc0; 352184610Salfred 353187259Sthompsa usb2_transfer_start(sc->sc_xfer[UBTBCMFW_BULK_DT_WR]); 354187866Semax} /* ubtbcmfw_start_write */ 355184610Salfred 356187866Semax/* 357187866Semax * Called when we about to stop writing (i.e. closing fifo) 358187866Semax */ 359187866Semax 360184610Salfredstatic void 361184610Salfredubtbcmfw_stop_write(struct usb2_fifo *fifo) 362184610Salfred{ 363187866Semax struct ubtbcmfw_softc *sc = fifo->priv_sc0; 364184610Salfred 365187259Sthompsa usb2_transfer_stop(sc->sc_xfer[UBTBCMFW_BULK_DT_WR]); 366187866Semax} /* ubtbcmfw_stop_write */ 367184610Salfred 368187866Semax/* 369187866Semax * Called when fifo is open 370187866Semax */ 371187866Semax 372184610Salfredstatic int 373184610Salfredubtbcmfw_open(struct usb2_fifo *fifo, int fflags, struct thread *td) 374184610Salfred{ 375187866Semax struct ubtbcmfw_softc *sc = fifo->priv_sc0; 376187866Semax struct usb2_xfer *xfer; 377184610Salfred 378187866Semax /* 379187866Semax * f_open fifo method can only be called with either FREAD 380187866Semax * or FWRITE flag set at one time. 381187866Semax */ 382187866Semax 383187866Semax if (fflags & FREAD) 384187866Semax xfer = sc->sc_xfer[UBTBCMFW_INTR_DT_RD]; 385187866Semax else if (fflags & FWRITE) 386187866Semax xfer = sc->sc_xfer[UBTBCMFW_BULK_DT_WR]; 387187866Semax else 388187994Salfred return (EINVAL); /* should not happen */ 389187994Salfred 390187866Semax if (usb2_fifo_alloc_buffer(fifo, xfer->max_data_length, 391187866Semax UBTBCMFW_IFQ_MAXLEN) != 0) 392187866Semax return (ENOMEM); 393187866Semax 394184610Salfred return (0); 395187866Semax} /* ubtbcmfw_open */ 396184610Salfred 397187866Semax/* 398187866Semax * Called when fifo is closed 399187866Semax */ 400187866Semax 401184610Salfredstatic void 402184610Salfredubtbcmfw_close(struct usb2_fifo *fifo, int fflags, struct thread *td) 403184610Salfred{ 404187866Semax if (fflags & (FREAD | FWRITE)) 405184610Salfred usb2_fifo_free_buffer(fifo); 406187866Semax} /* ubtbcmfw_close */ 407184610Salfred 408187866Semax/* 409187866Semax * Process ioctl() on USB device 410187866Semax */ 411187866Semax 412184610Salfredstatic int 413184610Salfredubtbcmfw_ioctl(struct usb2_fifo *fifo, u_long cmd, void *data, 414184610Salfred int fflags, struct thread *td) 415184610Salfred{ 416187866Semax struct ubtbcmfw_softc *sc = fifo->priv_sc0; 417187866Semax int error = 0; 418184610Salfred 419184610Salfred switch (cmd) { 420184610Salfred case USB_GET_DEVICE_DESC: 421187866Semax memcpy(data, usb2_get_device_descriptor(sc->sc_udev), 422187866Semax sizeof(struct usb2_device_descriptor)); 423184610Salfred break; 424184610Salfred 425184610Salfred default: 426184610Salfred error = EINVAL; 427184610Salfred break; 428184610Salfred } 429187866Semax 430184610Salfred return (error); 431187866Semax} /* ubtbcmfw_ioctl */ 432