1 /* 2 * ubtbcmfw.c 3 * 4 * Copyright (c) 2003 Maksim Yevmenkin <m_evmenkin@yahoo.com> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 * $Id: ubtbcmfw.c,v 1.3 2003/10/10 19:15:08 max Exp $ 29 * $FreeBSD$ 30 */ 31 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #include <sys/bus.h> 35 #include <sys/conf.h> 36 #include <sys/filio.h> 37 #include <sys/fcntl.h> 38 #include <sys/kernel.h> 39 #include <sys/module.h> 40 #include <sys/poll.h> 41 #include <sys/proc.h> 42 #include <sys/sysctl.h> 43 #include <sys/uio.h> 44 45 #include <dev/usb/usb.h> 46 #include <dev/usb/usbdi.h> 47 #include <dev/usb/usbdi_util.h> 48 49 #include "usbdevs.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 #define UBTBCMFW_INTR_IN_EP 0x81 /* Fixed endpoint */ 58 #define UBTBCMFW_BULK_OUT_EP 0x02 /* Fixed endpoint */ 59 #define UBTBCMFW_INTR_IN UE_GET_ADDR(UBTBCMFW_INTR_IN_EP) 60 #define UBTBCMFW_BULK_OUT UE_GET_ADDR(UBTBCMFW_BULK_OUT_EP) 61 62 struct ubtbcmfw_softc { 63 USBBASEDEVICE sc_dev; /* base device */ 64 usbd_device_handle sc_udev; /* USB device handle */ 65 struct cdev *sc_ctrl_dev; /* control device */ 66 struct cdev *sc_intr_in_dev; /* interrupt device */ 67 struct cdev *sc_bulk_out_dev; /* bulk device */ 68 usbd_pipe_handle sc_intr_in_pipe; /* interrupt pipe */ 69 usbd_pipe_handle sc_bulk_out_pipe; /* bulk out pipe */ 70 int sc_flags; 71 #define UBTBCMFW_CTRL_DEV (1 << 0) 72 #define UBTBCMFW_INTR_IN_DEV (1 << 1) 73 #define UBTBCMFW_BULK_OUT_DEV (1 << 2) 74 int sc_refcnt; 75 int sc_dying; 76 }; 77 78 typedef struct ubtbcmfw_softc *ubtbcmfw_softc_p; 79 80 /* 81 * Device methods 82 */ 83 84 #define UBTBCMFW_UNIT(n) ((minor(n) >> 4) & 0xf) 85 #define UBTBCMFW_ENDPOINT(n) (minor(n) & 0xf) 86 #define UBTBCMFW_MINOR(u, e) (((u) << 4) | (e)) 87 #define UBTBCMFW_BSIZE 1024 88 89 Static d_open_t ubtbcmfw_open; 90 Static d_close_t ubtbcmfw_close; 91 Static d_read_t ubtbcmfw_read; 92 Static d_write_t ubtbcmfw_write; 93 Static d_ioctl_t ubtbcmfw_ioctl; 94 Static d_poll_t ubtbcmfw_poll; 95 96 Static struct cdevsw ubtbcmfw_cdevsw = { 97 .d_version = D_VERSION, 98 .d_flags = D_NEEDGIANT, 99 .d_open = ubtbcmfw_open, 100 .d_close = ubtbcmfw_close, 101 .d_read = ubtbcmfw_read, 102 .d_write = ubtbcmfw_write, 103 .d_ioctl = ubtbcmfw_ioctl, 104 .d_poll = ubtbcmfw_poll, 105 .d_name = "ubtbcmfw", 106 }; 107 108 /* 109 * Module 110 */ 111 112 USB_DECLARE_DRIVER(ubtbcmfw); 113 DRIVER_MODULE(ubtbcmfw, uhub, ubtbcmfw_driver, ubtbcmfw_devclass, 114 usbd_driver_load, 0); 115 116 /* 117 * Probe for a USB Bluetooth device 118 */ 119 120 USB_MATCH(ubtbcmfw) 121 { 122 #define USB_PRODUCT_BROADCOM_BCM2033NF 0x2033 123 124 USB_MATCH_START(ubtbcmfw, uaa); 125 126 if (uaa->iface != NULL) 127 return (UMATCH_NONE); 128 129 /* Match the boot device. */ 130 if (uaa->vendor == USB_VENDOR_BROADCOM && 131 uaa->product == USB_PRODUCT_BROADCOM_BCM2033NF) 132 return (UMATCH_VENDOR_PRODUCT); 133 134 return (UMATCH_NONE); 135 } 136 137 /* 138 * Attach the device 139 */ 140 141 USB_ATTACH(ubtbcmfw) 142 { 143 USB_ATTACH_START(ubtbcmfw, sc, uaa); 144 usbd_interface_handle iface; 145 usbd_status err; 146 char devinfo[1024]; 147 148 sc->sc_udev = uaa->device; 149 usbd_devinfo(sc->sc_udev, 0, devinfo); 150 USB_ATTACH_SETUP; 151 printf("%s: %s\n", USBDEVNAME(sc->sc_dev), devinfo); 152 153 sc->sc_ctrl_dev = sc->sc_intr_in_dev = sc->sc_bulk_out_dev = NULL; 154 sc->sc_intr_in_pipe = sc->sc_bulk_out_pipe = NULL; 155 sc->sc_flags = sc->sc_refcnt = sc->sc_dying = 0; 156 157 err = usbd_set_config_no(sc->sc_udev, UBTBCMFW_CONFIG_NO, 1); 158 if (err) { 159 printf("%s: setting config no failed. %s\n", 160 USBDEVNAME(sc->sc_dev), usbd_errstr(err)); 161 goto bad; 162 } 163 164 err = usbd_device2interface_handle(sc->sc_udev, UBTBCMFW_IFACE_IDX, 165 &iface); 166 if (err) { 167 printf("%s: getting interface handle failed. %s\n", 168 USBDEVNAME(sc->sc_dev), usbd_errstr(err)); 169 goto bad; 170 } 171 172 /* Will be used as a bulk pipe */ 173 err = usbd_open_pipe(iface, UBTBCMFW_INTR_IN_EP, 0, 174 &sc->sc_intr_in_pipe); 175 if (err) { 176 printf("%s: open intr in failed. %s\n", 177 USBDEVNAME(sc->sc_dev), usbd_errstr(err)); 178 goto bad; 179 } 180 181 err = usbd_open_pipe(iface, UBTBCMFW_BULK_OUT_EP, 0, 182 &sc->sc_bulk_out_pipe); 183 if (err) { 184 printf("%s: open bulk out failed. %s\n", 185 USBDEVNAME(sc->sc_dev), usbd_errstr(err)); 186 goto bad; 187 } 188 189 /* Create device nodes */ 190 sc->sc_ctrl_dev = make_dev(&ubtbcmfw_cdevsw, 191 UBTBCMFW_MINOR(USBDEVUNIT(sc->sc_dev), 0), 192 UID_ROOT, GID_OPERATOR, 0644, 193 "%s", USBDEVNAME(sc->sc_dev)); 194 195 sc->sc_intr_in_dev = make_dev(&ubtbcmfw_cdevsw, 196 UBTBCMFW_MINOR(USBDEVUNIT(sc->sc_dev), UBTBCMFW_INTR_IN), 197 UID_ROOT, GID_OPERATOR, 0644, 198 "%s.%d", USBDEVNAME(sc->sc_dev), UBTBCMFW_INTR_IN); 199 200 sc->sc_bulk_out_dev = make_dev(&ubtbcmfw_cdevsw, 201 UBTBCMFW_MINOR(USBDEVUNIT(sc->sc_dev), UBTBCMFW_BULK_OUT), 202 UID_ROOT, GID_OPERATOR, 0644, 203 "%s.%d", USBDEVNAME(sc->sc_dev), UBTBCMFW_BULK_OUT); 204 205 USB_ATTACH_SUCCESS_RETURN; 206 bad: 207 ubtbcmfw_detach(self); 208 209 USB_ATTACH_ERROR_RETURN; 210 } 211 212 /* 213 * Detach the device 214 */ 215 216 USB_DETACH(ubtbcmfw) 217 { 218 USB_DETACH_START(ubtbcmfw, sc); 219 220 sc->sc_dying = 1; 221 222 if (-- sc->sc_refcnt >= 0) { 223 if (sc->sc_intr_in_pipe != NULL) 224 usbd_abort_pipe(sc->sc_intr_in_pipe); 225 226 if (sc->sc_bulk_out_pipe != NULL) 227 usbd_abort_pipe(sc->sc_bulk_out_pipe); 228 229 usb_detach_wait(USBDEV(sc->sc_dev)); 230 } 231 232 /* Destroy device nodes */ 233 if (sc->sc_bulk_out_dev != NULL) { 234 destroy_dev(sc->sc_bulk_out_dev); 235 sc->sc_bulk_out_dev = NULL; 236 } 237 238 if (sc->sc_intr_in_dev != NULL) { 239 destroy_dev(sc->sc_intr_in_dev); 240 sc->sc_intr_in_dev = NULL; 241 } 242 243 if (sc->sc_ctrl_dev != NULL) { 244 destroy_dev(sc->sc_ctrl_dev); 245 sc->sc_ctrl_dev = NULL; 246 } 247 248 /* Close pipes */ 249 if (sc->sc_intr_in_pipe != NULL) { 250 usbd_close_pipe(sc->sc_intr_in_pipe); 251 sc->sc_intr_in_pipe = NULL; 252 } 253 254 if (sc->sc_bulk_out_pipe != NULL) { 255 usbd_close_pipe(sc->sc_bulk_out_pipe); 256 sc->sc_intr_in_pipe = NULL; 257 } 258 259 return (0); 260 } 261 262 /* 263 * Open endpoint device 264 * XXX FIXME softc locking 265 */ 266 267 Static int 268 ubtbcmfw_open(struct cdev *dev, int flag, int mode, usb_proc_ptr p) 269 { 270 ubtbcmfw_softc_p sc = NULL; 271 int error = 0; 272 273 /* checks for sc != NULL */ 274 USB_GET_SC_OPEN(ubtbcmfw, UBTBCMFW_UNIT(dev), sc); 275 if (sc->sc_dying) 276 return (ENXIO); 277 278 switch (UBTBCMFW_ENDPOINT(dev)) { 279 case USB_CONTROL_ENDPOINT: 280 if (!(sc->sc_flags & UBTBCMFW_CTRL_DEV)) 281 sc->sc_flags |= UBTBCMFW_CTRL_DEV; 282 else 283 error = EBUSY; 284 break; 285 286 case UBTBCMFW_INTR_IN: 287 if (!(sc->sc_flags & UBTBCMFW_INTR_IN_DEV)) { 288 if (sc->sc_intr_in_pipe != NULL) 289 sc->sc_flags |= UBTBCMFW_INTR_IN_DEV; 290 else 291 error = ENXIO; 292 } else 293 error = EBUSY; 294 break; 295 296 case UBTBCMFW_BULK_OUT: 297 if (!(sc->sc_flags & UBTBCMFW_BULK_OUT_DEV)) { 298 if (sc->sc_bulk_out_pipe != NULL) 299 sc->sc_flags |= UBTBCMFW_BULK_OUT_DEV; 300 else 301 error = ENXIO; 302 } else 303 error = EBUSY; 304 break; 305 306 default: 307 error = ENXIO; 308 break; 309 } 310 311 return (error); 312 } 313 314 /* 315 * Close endpoint device 316 * XXX FIXME softc locking 317 */ 318 319 Static int 320 ubtbcmfw_close(struct cdev *dev, int flag, int mode, usb_proc_ptr p) 321 { 322 ubtbcmfw_softc_p sc = NULL; 323 324 USB_GET_SC(ubtbcmfw, UBTBCMFW_UNIT(dev), sc); 325 if (sc == NULL) 326 return (ENXIO); 327 328 switch (UBTBCMFW_ENDPOINT(dev)) { 329 case USB_CONTROL_ENDPOINT: 330 sc->sc_flags &= ~UBTBCMFW_CTRL_DEV; 331 break; 332 333 case UBTBCMFW_INTR_IN: 334 if (sc->sc_intr_in_pipe != NULL) 335 usbd_abort_pipe(sc->sc_intr_in_pipe); 336 337 sc->sc_flags &= ~UBTBCMFW_INTR_IN_DEV; 338 break; 339 340 case UBTBCMFW_BULK_OUT: 341 if (sc->sc_bulk_out_pipe != NULL) 342 usbd_abort_pipe(sc->sc_bulk_out_pipe); 343 344 sc->sc_flags &= ~UBTBCMFW_BULK_OUT_DEV; 345 break; 346 } 347 348 return (0); 349 } 350 351 /* 352 * Read from the endpoint device 353 * XXX FIXME softc locking 354 */ 355 356 Static int 357 ubtbcmfw_read(struct cdev *dev, struct uio *uio, int flag) 358 { 359 ubtbcmfw_softc_p sc = NULL; 360 u_int8_t buf[UBTBCMFW_BSIZE]; 361 usbd_xfer_handle xfer; 362 usbd_status err; 363 int n, tn, error = 0; 364 365 USB_GET_SC(ubtbcmfw, UBTBCMFW_UNIT(dev), sc); 366 if (sc == NULL || sc->sc_dying) 367 return (ENXIO); 368 369 if (UBTBCMFW_ENDPOINT(dev) != UBTBCMFW_INTR_IN) 370 return (EOPNOTSUPP); 371 if (sc->sc_intr_in_pipe == NULL) 372 return (ENXIO); 373 374 xfer = usbd_alloc_xfer(sc->sc_udev); 375 if (xfer == NULL) 376 return (ENOMEM); 377 378 sc->sc_refcnt ++; 379 380 while ((n = min(sizeof(buf), uio->uio_resid)) != 0) { 381 tn = n; 382 err = usbd_bulk_transfer(xfer, sc->sc_intr_in_pipe, 383 USBD_SHORT_XFER_OK, USBD_DEFAULT_TIMEOUT, 384 buf, &tn, "bcmrd"); 385 switch (err) { 386 case USBD_NORMAL_COMPLETION: 387 error = uiomove(buf, tn, uio); 388 break; 389 390 case USBD_INTERRUPTED: 391 error = EINTR; 392 break; 393 394 case USBD_TIMEOUT: 395 error = ETIMEDOUT; 396 break; 397 398 default: 399 error = EIO; 400 break; 401 } 402 403 if (error != 0 || tn < n) 404 break; 405 } 406 407 usbd_free_xfer(xfer); 408 409 if (-- sc->sc_refcnt < 0) 410 usb_detach_wakeup(USBDEV(sc->sc_dev)); 411 412 return (error); 413 } 414 415 /* 416 * Write into the endpoint device 417 * XXX FIXME softc locking 418 */ 419 420 Static int 421 ubtbcmfw_write(struct cdev *dev, struct uio *uio, int flag) 422 { 423 ubtbcmfw_softc_p sc = NULL; 424 u_int8_t buf[UBTBCMFW_BSIZE]; 425 usbd_xfer_handle xfer; 426 usbd_status err; 427 int n, error = 0; 428 429 USB_GET_SC(ubtbcmfw, UBTBCMFW_UNIT(dev), sc); 430 if (sc == NULL || sc->sc_dying) 431 return (ENXIO); 432 433 if (UBTBCMFW_ENDPOINT(dev) != UBTBCMFW_BULK_OUT) 434 return (EOPNOTSUPP); 435 if (sc->sc_bulk_out_pipe == NULL) 436 return (ENXIO); 437 438 xfer = usbd_alloc_xfer(sc->sc_udev); 439 if (xfer == NULL) 440 return (ENOMEM); 441 442 sc->sc_refcnt ++; 443 444 while ((n = min(sizeof(buf), uio->uio_resid)) != 0) { 445 error = uiomove(buf, n, uio); 446 if (error != 0) 447 break; 448 449 err = usbd_bulk_transfer(xfer, sc->sc_bulk_out_pipe, 450 0, USBD_DEFAULT_TIMEOUT, buf, &n, "bcmwr"); 451 switch (err) { 452 case USBD_NORMAL_COMPLETION: 453 break; 454 455 case USBD_INTERRUPTED: 456 error = EINTR; 457 break; 458 459 case USBD_TIMEOUT: 460 error = ETIMEDOUT; 461 break; 462 463 default: 464 error = EIO; 465 break; 466 } 467 468 if (error != 0) 469 break; 470 } 471 472 usbd_free_xfer(xfer); 473 474 if (-- sc->sc_refcnt < 0) 475 usb_detach_wakeup(USBDEV(sc->sc_dev)); 476 477 return (error); 478 } 479 480 /* 481 * Process ioctl on the endpoint device 482 * XXX FIXME softc locking 483 */ 484 485 Static int 486 ubtbcmfw_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, usb_proc_ptr p) 487 { 488 ubtbcmfw_softc_p sc = NULL; 489 int error = 0; 490 491 USB_GET_SC(ubtbcmfw, UBTBCMFW_UNIT(dev), sc); 492 if (sc == NULL || sc->sc_dying) 493 return (ENXIO); 494 495 if (UBTBCMFW_ENDPOINT(dev) != USB_CONTROL_ENDPOINT) 496 return (EOPNOTSUPP); 497 498 sc->sc_refcnt ++; 499 500 switch (cmd) { 501 case USB_GET_DEVICE_DESC: 502 *(usb_device_descriptor_t *) data = 503 *usbd_get_device_descriptor(sc->sc_udev); 504 break; 505 506 default: 507 error = EINVAL; 508 break; 509 } 510 511 if (-- sc->sc_refcnt < 0) 512 usb_detach_wakeup(USBDEV(sc->sc_dev)); 513 514 return (error); 515 } 516 517 /* 518 * Poll the endpoint device 519 * XXX FIXME softc locking 520 */ 521 522 Static int 523 ubtbcmfw_poll(struct cdev *dev, int events, usb_proc_ptr p) 524 { 525 ubtbcmfw_softc_p sc = NULL; 526 int revents = 0; 527 528 USB_GET_SC(ubtbcmfw, UBTBCMFW_UNIT(dev), sc); 529 if (sc == NULL) 530 return (ENXIO); 531 532 switch (UBTBCMFW_ENDPOINT(dev)) { 533 case UBTBCMFW_INTR_IN: 534 if (sc->sc_intr_in_pipe != NULL) 535 revents |= events & (POLLIN | POLLRDNORM); 536 else 537 revents = ENXIO; 538 break; 539 540 case UBTBCMFW_BULK_OUT: 541 if (sc->sc_bulk_out_pipe != NULL) 542 revents |= events & (POLLOUT | POLLWRNORM); 543 else 544 revents = ENXIO; 545 break; 546 547 default: 548 revents = EOPNOTSUPP; 549 break; 550 } 551 552 return (revents); 553 } 554 555