linux/drivers/bluetooth/bcm203x.c
<<
>>
Prefs
   1/*
   2 *
   3 *  Broadcom Blutonium firmware driver
   4 *
   5 *  Copyright (C) 2003  Maxim Krasnyansky <maxk@qualcomm.com>
   6 *  Copyright (C) 2003  Marcel Holtmann <marcel@holtmann.org>
   7 *
   8 *
   9 *  This program is free software; you can redistribute it and/or modify
  10 *  it under the terms of the GNU General Public License as published by
  11 *  the Free Software Foundation; either version 2 of the License, or
  12 *  (at your option) any later version.
  13 *
  14 *  This program is distributed in the hope that it will be useful,
  15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17 *  GNU General Public License for more details.
  18 *
  19 *  You should have received a copy of the GNU General Public License
  20 *  along with this program; if not, write to the Free Software
  21 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  22 *
  23 */
  24
  25#include <linux/module.h>
  26
  27#include <linux/kernel.h>
  28#include <linux/init.h>
  29#include <linux/slab.h>
  30#include <linux/types.h>
  31#include <linux/errno.h>
  32
  33#include <linux/device.h>
  34#include <linux/firmware.h>
  35
  36#include <linux/usb.h>
  37
  38#include <net/bluetooth/bluetooth.h>
  39
  40#define VERSION "1.2"
  41
  42static struct usb_device_id bcm203x_table[] = {
  43        /* Broadcom Blutonium (BCM2033) */
  44        { USB_DEVICE(0x0a5c, 0x2033) },
  45
  46        { }     /* Terminating entry */
  47};
  48
  49MODULE_DEVICE_TABLE(usb, bcm203x_table);
  50
  51#define BCM203X_ERROR           0
  52#define BCM203X_RESET           1
  53#define BCM203X_LOAD_MINIDRV    2
  54#define BCM203X_SELECT_MEMORY   3
  55#define BCM203X_CHECK_MEMORY    4
  56#define BCM203X_LOAD_FIRMWARE   5
  57#define BCM203X_CHECK_FIRMWARE  6
  58
  59#define BCM203X_IN_EP           0x81
  60#define BCM203X_OUT_EP          0x02
  61
  62struct bcm203x_data {
  63        struct usb_device       *udev;
  64
  65        unsigned long           state;
  66
  67        struct work_struct      work;
  68
  69        struct urb              *urb;
  70        unsigned char           *buffer;
  71
  72        unsigned char           *fw_data;
  73        unsigned int            fw_size;
  74        unsigned int            fw_sent;
  75};
  76
  77static void bcm203x_complete(struct urb *urb)
  78{
  79        struct bcm203x_data *data = urb->context;
  80        struct usb_device *udev = urb->dev;
  81        int len;
  82
  83        BT_DBG("udev %p urb %p", udev, urb);
  84
  85        if (urb->status) {
  86                BT_ERR("URB failed with status %d", urb->status);
  87                data->state = BCM203X_ERROR;
  88                return;
  89        }
  90
  91        switch (data->state) {
  92        case BCM203X_LOAD_MINIDRV:
  93                memcpy(data->buffer, "#", 1);
  94
  95                usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(udev, BCM203X_OUT_EP),
  96                                data->buffer, 1, bcm203x_complete, data);
  97
  98                data->state = BCM203X_SELECT_MEMORY;
  99
 100                schedule_work(&data->work);
 101                break;
 102
 103        case BCM203X_SELECT_MEMORY:
 104                usb_fill_int_urb(urb, udev, usb_rcvintpipe(udev, BCM203X_IN_EP),
 105                                data->buffer, 32, bcm203x_complete, data, 1);
 106
 107                data->state = BCM203X_CHECK_MEMORY;
 108
 109                if (usb_submit_urb(data->urb, GFP_ATOMIC) < 0)
 110                        BT_ERR("Can't submit URB");
 111                break;
 112
 113        case BCM203X_CHECK_MEMORY:
 114                if (data->buffer[0] != '#') {
 115                        BT_ERR("Memory select failed");
 116                        data->state = BCM203X_ERROR;
 117                        break;
 118                }
 119
 120                data->state = BCM203X_LOAD_FIRMWARE;
 121
 122        case BCM203X_LOAD_FIRMWARE:
 123                if (data->fw_sent == data->fw_size) {
 124                        usb_fill_int_urb(urb, udev, usb_rcvintpipe(udev, BCM203X_IN_EP),
 125                                data->buffer, 32, bcm203x_complete, data, 1);
 126
 127                        data->state = BCM203X_CHECK_FIRMWARE;
 128                } else {
 129                        len = min_t(uint, data->fw_size - data->fw_sent, 4096);
 130
 131                        usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(udev, BCM203X_OUT_EP),
 132                                data->fw_data + data->fw_sent, len, bcm203x_complete, data);
 133
 134                        data->fw_sent += len;
 135                }
 136
 137                if (usb_submit_urb(data->urb, GFP_ATOMIC) < 0)
 138                        BT_ERR("Can't submit URB");
 139                break;
 140
 141        case BCM203X_CHECK_FIRMWARE:
 142                if (data->buffer[0] != '.') {
 143                        BT_ERR("Firmware loading failed");
 144                        data->state = BCM203X_ERROR;
 145                        break;
 146                }
 147
 148                data->state = BCM203X_RESET;
 149                break;
 150        }
 151}
 152
 153static void bcm203x_work(struct work_struct *work)
 154{
 155        struct bcm203x_data *data =
 156                container_of(work, struct bcm203x_data, work);
 157
 158        if (usb_submit_urb(data->urb, GFP_ATOMIC) < 0)
 159                BT_ERR("Can't submit URB");
 160}
 161
 162static int bcm203x_probe(struct usb_interface *intf, const struct usb_device_id *id)
 163{
 164        const struct firmware *firmware;
 165        struct usb_device *udev = interface_to_usbdev(intf);
 166        struct bcm203x_data *data;
 167        int size;
 168
 169        BT_DBG("intf %p id %p", intf, id);
 170
 171        if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
 172                return -ENODEV;
 173
 174        data = kzalloc(sizeof(*data), GFP_KERNEL);
 175        if (!data) {
 176                BT_ERR("Can't allocate memory for data structure");
 177                return -ENOMEM;
 178        }
 179
 180        data->udev  = udev;
 181        data->state = BCM203X_LOAD_MINIDRV;
 182
 183        data->urb = usb_alloc_urb(0, GFP_KERNEL);
 184        if (!data->urb) {
 185                BT_ERR("Can't allocate URB");
 186                kfree(data);
 187                return -ENOMEM;
 188        }
 189
 190        if (request_firmware(&firmware, "BCM2033-MD.hex", &udev->dev) < 0) {
 191                BT_ERR("Mini driver request failed");
 192                usb_free_urb(data->urb);
 193                kfree(data);
 194                return -EIO;
 195        }
 196
 197        BT_DBG("minidrv data %p size %zu", firmware->data, firmware->size);
 198
 199        size = max_t(uint, firmware->size, 4096);
 200
 201        data->buffer = kmalloc(size, GFP_KERNEL);
 202        if (!data->buffer) {
 203                BT_ERR("Can't allocate memory for mini driver");
 204                release_firmware(firmware);
 205                usb_free_urb(data->urb);
 206                kfree(data);
 207                return -ENOMEM;
 208        }
 209
 210        memcpy(data->buffer, firmware->data, firmware->size);
 211
 212        usb_fill_bulk_urb(data->urb, udev, usb_sndbulkpipe(udev, BCM203X_OUT_EP),
 213                        data->buffer, firmware->size, bcm203x_complete, data);
 214
 215        release_firmware(firmware);
 216
 217        if (request_firmware(&firmware, "BCM2033-FW.bin", &udev->dev) < 0) {
 218                BT_ERR("Firmware request failed");
 219                usb_free_urb(data->urb);
 220                kfree(data->buffer);
 221                kfree(data);
 222                return -EIO;
 223        }
 224
 225        BT_DBG("firmware data %p size %zu", firmware->data, firmware->size);
 226
 227        data->fw_data = kmalloc(firmware->size, GFP_KERNEL);
 228        if (!data->fw_data) {
 229                BT_ERR("Can't allocate memory for firmware image");
 230                release_firmware(firmware);
 231                usb_free_urb(data->urb);
 232                kfree(data->buffer);
 233                kfree(data);
 234                return -ENOMEM;
 235        }
 236
 237        memcpy(data->fw_data, firmware->data, firmware->size);
 238        data->fw_size = firmware->size;
 239        data->fw_sent = 0;
 240
 241        release_firmware(firmware);
 242
 243        INIT_WORK(&data->work, bcm203x_work);
 244
 245        usb_set_intfdata(intf, data);
 246
 247        schedule_work(&data->work);
 248
 249        return 0;
 250}
 251
 252static void bcm203x_disconnect(struct usb_interface *intf)
 253{
 254        struct bcm203x_data *data = usb_get_intfdata(intf);
 255
 256        BT_DBG("intf %p", intf);
 257
 258        usb_kill_urb(data->urb);
 259
 260        usb_set_intfdata(intf, NULL);
 261
 262        usb_free_urb(data->urb);
 263        kfree(data->fw_data);
 264        kfree(data->buffer);
 265        kfree(data);
 266}
 267
 268static struct usb_driver bcm203x_driver = {
 269        .name           = "bcm203x",
 270        .probe          = bcm203x_probe,
 271        .disconnect     = bcm203x_disconnect,
 272        .id_table       = bcm203x_table,
 273};
 274
 275static int __init bcm203x_init(void)
 276{
 277        int err;
 278
 279        BT_INFO("Broadcom Blutonium firmware driver ver %s", VERSION);
 280
 281        err = usb_register(&bcm203x_driver);
 282        if (err < 0)
 283                BT_ERR("Failed to register USB driver");
 284
 285        return err;
 286}
 287
 288static void __exit bcm203x_exit(void)
 289{
 290        usb_deregister(&bcm203x_driver);
 291}
 292
 293module_init(bcm203x_init);
 294module_exit(bcm203x_exit);
 295
 296MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
 297MODULE_DESCRIPTION("Broadcom Blutonium firmware driver ver " VERSION);
 298MODULE_VERSION(VERSION);
 299MODULE_LICENSE("GPL");
 300MODULE_FIRMWARE("BCM2033-MD.hex");
 301MODULE_FIRMWARE("BCM2033-FW.bin");
 302