1/* 2 * ubtbcmfw.c 3 */ 4 5/*- 6 * Copyright (c) 2003-2009 Maksim Yevmenkin <m_evmenkin@yahoo.com> 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 * 30 * $Id: ubtbcmfw.c,v 1.3 2003/10/10 19:15:08 max Exp $
|
31 * $FreeBSD: head/sys/netgraph/bluetooth/drivers/ubtbcmfw/ubtbcmfw.c 193045 2009-05-29 18:46:57Z thompsa $
|
31 * $FreeBSD: head/sys/netgraph/bluetooth/drivers/ubtbcmfw/ubtbcmfw.c 194228 2009-06-15 01:02:43Z thompsa $ |
32 */ 33 34#include "usbdevs.h" 35#include <dev/usb/usb.h> 36#include <dev/usb/usb_mfunc.h> 37#include <dev/usb/usb_error.h> 38#include <dev/usb/usb_ioctl.h> 39
|
40#define USB_DEBUG_VAR usb2_debug
|
40#define USB_DEBUG_VAR usb_debug |
41 42#include <dev/usb/usb_core.h> 43#include <dev/usb/usb_debug.h> 44#include <dev/usb/usb_parse.h> 45#include <dev/usb/usb_lookup.h> 46#include <dev/usb/usb_util.h> 47#include <dev/usb/usb_busdma.h> 48#include <dev/usb/usb_mbuf.h> 49#include <dev/usb/usb_dev.h> 50 51/* 52 * Download firmware to BCM2033. 53 */ 54 55#define UBTBCMFW_CONFIG_NO 1 /* Config number */ 56#define UBTBCMFW_IFACE_IDX 0 /* Control interface */ 57 58#define UBTBCMFW_BSIZE 1024 59#define UBTBCMFW_IFQ_MAXLEN 2 60 61enum { 62 UBTBCMFW_BULK_DT_WR = 0, 63 UBTBCMFW_INTR_DT_RD, 64 UBTBCMFW_N_TRANSFER, 65}; 66 67struct ubtbcmfw_softc { 68 struct usb_device *sc_udev; 69 struct mtx sc_mtx; 70 struct usb_xfer *sc_xfer[UBTBCMFW_N_TRANSFER]; 71 struct usb_fifo_sc sc_fifo; 72}; 73 74/* 75 * Prototypes 76 */ 77 78static device_probe_t ubtbcmfw_probe; 79static device_attach_t ubtbcmfw_attach; 80static device_detach_t ubtbcmfw_detach; 81 82static usb_callback_t ubtbcmfw_write_callback; 83static usb_callback_t ubtbcmfw_read_callback; 84 85static usb_fifo_close_t ubtbcmfw_close; 86static usb_fifo_cmd_t ubtbcmfw_start_read; 87static usb_fifo_cmd_t ubtbcmfw_start_write; 88static usb_fifo_cmd_t ubtbcmfw_stop_read; 89static usb_fifo_cmd_t ubtbcmfw_stop_write; 90static usb_fifo_ioctl_t ubtbcmfw_ioctl; 91static usb_fifo_open_t ubtbcmfw_open; 92 93static struct usb_fifo_methods ubtbcmfw_fifo_methods = 94{ 95 .f_close = &ubtbcmfw_close, 96 .f_ioctl = &ubtbcmfw_ioctl, 97 .f_open = &ubtbcmfw_open, 98 .f_start_read = &ubtbcmfw_start_read, 99 .f_start_write = &ubtbcmfw_start_write, 100 .f_stop_read = &ubtbcmfw_stop_read, 101 .f_stop_write = &ubtbcmfw_stop_write, 102 .basename[0] = "ubtbcmfw", 103 .basename[1] = "ubtbcmfw", 104 .basename[2] = "ubtbcmfw", 105 .postfix[0] = "", 106 .postfix[1] = ".1", 107 .postfix[2] = ".2", 108}; 109 110/* 111 * Device's config structure 112 */ 113 114static const struct usb_config ubtbcmfw_config[UBTBCMFW_N_TRANSFER] = 115{ 116 [UBTBCMFW_BULK_DT_WR] = { 117 .type = UE_BULK, 118 .endpoint = 0x02, /* fixed */ 119 .direction = UE_DIR_OUT, 120 .if_index = UBTBCMFW_IFACE_IDX, 121 .bufsize = UBTBCMFW_BSIZE, 122 .flags = { .pipe_bof = 1, .force_short_xfer = 1, 123 .proxy_buffer = 1, }, 124 .callback = &ubtbcmfw_write_callback, 125 }, 126 127 [UBTBCMFW_INTR_DT_RD] = { 128 .type = UE_INTERRUPT, 129 .endpoint = 0x01, /* fixed */ 130 .direction = UE_DIR_IN, 131 .if_index = UBTBCMFW_IFACE_IDX, 132 .bufsize = UBTBCMFW_BSIZE, 133 .flags = { .pipe_bof = 1, .short_xfer_ok = 1, 134 .proxy_buffer = 1, }, 135 .callback = &ubtbcmfw_read_callback, 136 }, 137}; 138 139/* 140 * Module 141 */ 142 143static devclass_t ubtbcmfw_devclass; 144 145static device_method_t ubtbcmfw_methods[] = 146{ 147 DEVMETHOD(device_probe, ubtbcmfw_probe), 148 DEVMETHOD(device_attach, ubtbcmfw_attach), 149 DEVMETHOD(device_detach, ubtbcmfw_detach), 150 {0, 0} 151}; 152 153static driver_t ubtbcmfw_driver = 154{ 155 .name = "ubtbcmfw", 156 .methods = ubtbcmfw_methods, 157 .size = sizeof(struct ubtbcmfw_softc), 158}; 159 160DRIVER_MODULE(ubtbcmfw, uhub, ubtbcmfw_driver, ubtbcmfw_devclass, NULL, 0); 161MODULE_DEPEND(ubtbcmfw, usb, 1, 1, 1); 162 163/* 164 * Probe for a USB Bluetooth device 165 */ 166 167static int 168ubtbcmfw_probe(device_t dev) 169{ 170 const struct usb_device_id devs[] = { 171 /* Broadcom BCM2033 devices only */ 172 { USB_VPI(USB_VENDOR_BROADCOM, USB_PRODUCT_BROADCOM_BCM2033, 0) }, 173 }; 174 175 struct usb_attach_arg *uaa = device_get_ivars(dev); 176 177 if (uaa->usb_mode != USB_MODE_HOST) 178 return (ENXIO); 179 180 if (uaa->info.bIfaceIndex != 0) 181 return (ENXIO); 182
|
183 return (usb2_lookup_id_by_uaa(devs, sizeof(devs), uaa));
|
183 return (usbd_lookup_id_by_uaa(devs, sizeof(devs), uaa)); |
184} /* ubtbcmfw_probe */ 185 186/* 187 * Attach the device 188 */ 189 190static int 191ubtbcmfw_attach(device_t dev) 192{ 193 struct usb_attach_arg *uaa = device_get_ivars(dev); 194 struct ubtbcmfw_softc *sc = device_get_softc(dev); 195 uint8_t iface_index; 196 int error; 197 198 sc->sc_udev = uaa->device; 199
|
200 device_set_usb2_desc(dev);
|
200 device_set_usb_desc(dev); |
201 202 mtx_init(&sc->sc_mtx, "ubtbcmfw lock", NULL, MTX_DEF | MTX_RECURSE); 203 204 iface_index = UBTBCMFW_IFACE_IDX;
|
205 error = usb2_transfer_setup(uaa->device, &iface_index, sc->sc_xfer,
|
205 error = usbd_transfer_setup(uaa->device, &iface_index, sc->sc_xfer, |
206 ubtbcmfw_config, UBTBCMFW_N_TRANSFER, 207 sc, &sc->sc_mtx); 208 if (error != 0) { 209 device_printf(dev, "allocating USB transfers failed. %s\n",
|
210 usb2_errstr(error));
|
210 usbd_errstr(error)); |
211 goto detach; 212 } 213
|
214 error = usb2_fifo_attach(uaa->device, sc, &sc->sc_mtx,
|
214 error = usb_fifo_attach(uaa->device, sc, &sc->sc_mtx, |
215 &ubtbcmfw_fifo_methods, &sc->sc_fifo, 216 device_get_unit(dev), 0 - 1, uaa->info.bIfaceIndex, 217 UID_ROOT, GID_OPERATOR, 0644); 218 if (error != 0) { 219 device_printf(dev, "could not attach fifo. %s\n",
|
220 usb2_errstr(error));
|
220 usbd_errstr(error)); |
221 goto detach; 222 } 223 224 return (0); /* success */ 225 226detach: 227 ubtbcmfw_detach(dev); 228 229 return (ENXIO); /* failure */ 230} /* ubtbcmfw_attach */ 231 232/* 233 * Detach the device 234 */ 235 236static int 237ubtbcmfw_detach(device_t dev) 238{ 239 struct ubtbcmfw_softc *sc = device_get_softc(dev); 240
|
241 usb2_fifo_detach(&sc->sc_fifo);
|
241 usb_fifo_detach(&sc->sc_fifo); |
242
|
243 usb2_transfer_unsetup(sc->sc_xfer, UBTBCMFW_N_TRANSFER);
|
243 usbd_transfer_unsetup(sc->sc_xfer, UBTBCMFW_N_TRANSFER); |
244 245 mtx_destroy(&sc->sc_mtx); 246 247 return (0); 248} /* ubtbcmfw_detach */ 249 250/* 251 * USB write callback 252 */ 253 254static void 255ubtbcmfw_write_callback(struct usb_xfer *xfer) 256{ 257 struct ubtbcmfw_softc *sc = xfer->priv_sc; 258 struct usb_fifo *f = sc->sc_fifo.fp[USB_FIFO_TX]; 259 uint32_t actlen; 260 261 switch (USB_GET_STATE(xfer)) { 262 case USB_ST_SETUP: 263 case USB_ST_TRANSFERRED: 264setup_next:
|
265 if (usb2_fifo_get_data(f, xfer->frbuffers, 0,
|
265 if (usb_fifo_get_data(f, xfer->frbuffers, 0, |
266 xfer->max_data_length, &actlen, 0)) { 267 xfer->frlengths[0] = actlen;
|
268 usb2_start_hardware(xfer);
|
268 usbd_transfer_submit(xfer); |
269 } 270 break; 271 272 default: /* Error */ 273 if (xfer->error != USB_ERR_CANCELLED) { 274 /* try to clear stall first */ 275 xfer->flags.stall_pipe = 1; 276 goto setup_next; 277 } 278 break; 279 } 280} /* ubtbcmfw_write_callback */ 281 282/* 283 * USB read callback 284 */ 285 286static void 287ubtbcmfw_read_callback(struct usb_xfer *xfer) 288{ 289 struct ubtbcmfw_softc *sc = xfer->priv_sc; 290 struct usb_fifo *fifo = sc->sc_fifo.fp[USB_FIFO_RX]; 291 292 switch (USB_GET_STATE(xfer)) { 293 case USB_ST_TRANSFERRED:
|
294 usb2_fifo_put_data(fifo, xfer->frbuffers, 0, xfer->actlen, 1);
|
294 usb_fifo_put_data(fifo, xfer->frbuffers, 0, xfer->actlen, 1); |
295 /* FALLTHROUGH */ 296 297 case USB_ST_SETUP: 298setup_next:
|
299 if (usb2_fifo_put_bytes_max(fifo) > 0) {
|
299 if (usb_fifo_put_bytes_max(fifo) > 0) { |
300 xfer->frlengths[0] = xfer->max_data_length;
|
301 usb2_start_hardware(xfer);
|
301 usbd_transfer_submit(xfer); |
302 } 303 break; 304 305 default: /* Error */ 306 if (xfer->error != USB_ERR_CANCELLED) { 307 /* try to clear stall first */ 308 xfer->flags.stall_pipe = 1; 309 goto setup_next; 310 } 311 break; 312 } 313} /* ubtbcmfw_read_callback */ 314 315/* 316 * Called when we about to start read()ing from the device 317 */ 318 319static void 320ubtbcmfw_start_read(struct usb_fifo *fifo) 321{ 322 struct ubtbcmfw_softc *sc = fifo->priv_sc0; 323
|
324 usb2_transfer_start(sc->sc_xfer[UBTBCMFW_INTR_DT_RD]);
|
324 usbd_transfer_start(sc->sc_xfer[UBTBCMFW_INTR_DT_RD]); |
325} /* ubtbcmfw_start_read */ 326 327/* 328 * Called when we about to stop reading (i.e. closing fifo) 329 */ 330 331static void 332ubtbcmfw_stop_read(struct usb_fifo *fifo) 333{ 334 struct ubtbcmfw_softc *sc = fifo->priv_sc0; 335
|
336 usb2_transfer_stop(sc->sc_xfer[UBTBCMFW_INTR_DT_RD]);
|
336 usbd_transfer_stop(sc->sc_xfer[UBTBCMFW_INTR_DT_RD]); |
337} /* ubtbcmfw_stop_read */ 338 339/* 340 * Called when we about to start write()ing to the device, poll()ing 341 * for write or flushing fifo 342 */ 343 344static void 345ubtbcmfw_start_write(struct usb_fifo *fifo) 346{ 347 struct ubtbcmfw_softc *sc = fifo->priv_sc0; 348
|
349 usb2_transfer_start(sc->sc_xfer[UBTBCMFW_BULK_DT_WR]);
|
349 usbd_transfer_start(sc->sc_xfer[UBTBCMFW_BULK_DT_WR]); |
350} /* ubtbcmfw_start_write */ 351 352/* 353 * Called when we about to stop writing (i.e. closing fifo) 354 */ 355 356static void 357ubtbcmfw_stop_write(struct usb_fifo *fifo) 358{ 359 struct ubtbcmfw_softc *sc = fifo->priv_sc0; 360
|
361 usb2_transfer_stop(sc->sc_xfer[UBTBCMFW_BULK_DT_WR]);
|
361 usbd_transfer_stop(sc->sc_xfer[UBTBCMFW_BULK_DT_WR]); |
362} /* ubtbcmfw_stop_write */ 363 364/* 365 * Called when fifo is open 366 */ 367 368static int 369ubtbcmfw_open(struct usb_fifo *fifo, int fflags) 370{ 371 struct ubtbcmfw_softc *sc = fifo->priv_sc0; 372 struct usb_xfer *xfer; 373 374 /* 375 * f_open fifo method can only be called with either FREAD 376 * or FWRITE flag set at one time. 377 */ 378 379 if (fflags & FREAD) 380 xfer = sc->sc_xfer[UBTBCMFW_INTR_DT_RD]; 381 else if (fflags & FWRITE) 382 xfer = sc->sc_xfer[UBTBCMFW_BULK_DT_WR]; 383 else 384 return (EINVAL); /* should not happen */ 385
|
386 if (usb2_fifo_alloc_buffer(fifo, xfer->max_data_length,
|
386 if (usb_fifo_alloc_buffer(fifo, xfer->max_data_length, |
387 UBTBCMFW_IFQ_MAXLEN) != 0) 388 return (ENOMEM); 389 390 return (0); 391} /* ubtbcmfw_open */ 392 393/* 394 * Called when fifo is closed 395 */ 396 397static void 398ubtbcmfw_close(struct usb_fifo *fifo, int fflags) 399{ 400 if (fflags & (FREAD | FWRITE))
|
401 usb2_fifo_free_buffer(fifo);
|
401 usb_fifo_free_buffer(fifo); |
402} /* ubtbcmfw_close */ 403 404/* 405 * Process ioctl() on USB device 406 */ 407 408static int 409ubtbcmfw_ioctl(struct usb_fifo *fifo, u_long cmd, void *data, 410 int fflags) 411{ 412 struct ubtbcmfw_softc *sc = fifo->priv_sc0; 413 int error = 0; 414 415 switch (cmd) { 416 case USB_GET_DEVICE_DESC:
|
417 memcpy(data, usb2_get_device_descriptor(sc->sc_udev),
|
417 memcpy(data, usbd_get_device_descriptor(sc->sc_udev), |
418 sizeof(struct usb_device_descriptor)); 419 break; 420 421 default: 422 error = EINVAL; 423 break; 424 } 425 426 return (error); 427} /* ubtbcmfw_ioctl */
|