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/atomic.h>
  28#include <linux/kernel.h>
  29#include <linux/init.h>
  30#include <linux/slab.h>
  31#include <linux/types.h>
  32#include <linux/errno.h>
  33
  34#include <linux/device.h>
  35#include <linux/firmware.h>
  36
  37#include <linux/usb.h>
  38
  39#include <net/bluetooth/bluetooth.h>
  40
  41#define VERSION "1.2"
  42
  43static const struct usb_device_id bcm203x_table[] = {
  44        /* Broadcom Blutonium (BCM2033) */
  45        { USB_DEVICE(0x0a5c, 0x2033) },
  46
  47        { }     /* Terminating entry */
  48};
  49
  50MODULE_DEVICE_TABLE(usb, bcm203x_table);
  51
  52#define BCM203X_ERROR           0
  53#define BCM203X_RESET           1
  54#define BCM203X_LOAD_MINIDRV    2
  55#define BCM203X_SELECT_MEMORY   3
  56#define BCM203X_CHECK_MEMORY    4
  57#define BCM203X_LOAD_FIRMWARE   5
  58#define BCM203X_CHECK_FIRMWARE  6
  59
  60#define BCM203X_IN_EP           0x81
  61#define BCM203X_OUT_EP          0x02
  62
  63struct bcm203x_data {
  64        struct usb_device       *udev;
  65
  66        unsigned long           state;
  67
  68        struct work_struct      work;
  69        atomic_t                shutdown;
  70
  71        struct urb              *urb;
  72        unsigned char           *buffer;
  73
  74        unsigned char           *fw_data;
  75        unsigned int            fw_size;
  76        unsigned int            fw_sent;
  77};
  78
  79static void bcm203x_complete(struct urb *urb)
  80{
  81        struct bcm203x_data *data = urb->context;
  82        struct usb_device *udev = urb->dev;
  83        int len;
  84
  85        BT_DBG("udev %p urb %p", udev, urb);
  86
  87        if (urb->status) {
  88                BT_ERR("URB failed with status %d", urb->status);
  89                data->state = BCM203X_ERROR;
  90                return;
  91        }
  92
  93        switch (data->state) {
  94        case BCM203X_LOAD_MINIDRV:
  95                memcpy(data->buffer, "#", 1);
  96
  97                usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(udev, BCM203X_OUT_EP),
  98                                data->buffer, 1, bcm203x_complete, data);
  99
 100                data->state = BCM203X_SELECT_MEMORY;
 101
 102                /* use workqueue to have a small delay */
 103                schedule_work(&data->work);
 104                break;
 105
 106        case BCM203X_SELECT_MEMORY:
 107                usb_fill_int_urb(urb, udev, usb_rcvintpipe(udev, BCM203X_IN_EP),
 108                                data->buffer, 32, bcm203x_complete, data, 1);
 109
 110                data->state = BCM203X_CHECK_MEMORY;
 111
 112                if (usb_submit_urb(data->urb, GFP_ATOMIC) < 0)
 113                        BT_ERR("Can't submit URB");
 114                break;
 115
 116        case BCM203X_CHECK_MEMORY:
 117                if (data->buffer[0] != '#') {
 118                        BT_ERR("Memory select failed");
 119                        data->state = BCM203X_ERROR;
 120                        break;
 121                }
 122
 123                data->state = BCM203X_LOAD_FIRMWARE;
 124
 125        case BCM203X_LOAD_FIRMWARE:
 126                if (data->fw_sent == data->fw_size) {
 127                        usb_fill_int_urb(urb, udev, usb_rcvintpipe(udev, BCM203X_IN_EP),
 128                                data->buffer, 32, bcm203x_complete, data, 1);
 129
 130                        data->state = BCM203X_CHECK_FIRMWARE;
 131                } else {
 132                        len = min_t(uint, data->fw_size - data->fw_sent, 4096);
 133
 134                        usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(udev, BCM203X_OUT_EP),
 135                                data->fw_data + data->fw_sent, len, bcm203x_complete, data);
 136
 137                        data->fw_sent += len;
 138                }
 139
 140                if (usb_submit_urb(data->urb, GFP_ATOMIC) < 0)
 141                        BT_ERR("Can't submit URB");
 142                break;
 143
 144        case BCM203X_CHECK_FIRMWARE:
 145                if (data->buffer[0] != '.') {
 146                        BT_ERR("Firmware loading failed");
 147                        data->state = BCM203X_ERROR;
 148                        break;
 149                }
 150
 151                data->state = BCM203X_RESET;
 152                break;
 153        }
 154}
 155
 156static void bcm203x_work(struct work_struct *work)
 157{
 158        struct bcm203x_data *data =
 159                container_of(work, struct bcm203x_data, work);
 160
 161        if (atomic_read(&data->shutdown))
 162                return;
 163
 164        if (usb_submit_urb(data->urb, GFP_KERNEL) < 0)
 165                BT_ERR("Can't submit URB");
 166}
 167
 168static int bcm203x_probe(struct usb_interface *intf, const struct usb_device_id *id)
 169{
 170        const struct firmware *firmware;
 171        struct usb_device *udev = interface_to_usbdev(intf);
 172        struct bcm203x_data *data;
 173        int size;
 174
 175        BT_DBG("intf %p id %p", intf, id);
 176
 177        if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
 178                return -ENODEV;
 179
 180        data = devm_kzalloc(&intf->dev, sizeof(*data), GFP_KERNEL);
 181        if (!data) {
 182                BT_ERR("Can't allocate memory for data structure");
 183                return -ENOMEM;
 184        }
 185
 186        data->udev  = udev;
 187        data->state = BCM203X_LOAD_MINIDRV;
 188
 189        data->urb = usb_alloc_urb(0, GFP_KERNEL);
 190        if (!data->urb) {
 191                BT_ERR("Can't allocate URB");
 192                return -ENOMEM;
 193        }
 194
 195        if (request_firmware(&firmware, "BCM2033-MD.hex", &udev->dev) < 0) {
 196                BT_ERR("Mini driver request failed");
 197                usb_free_urb(data->urb);
 198                return -EIO;
 199        }
 200
 201        BT_DBG("minidrv data %p size %zu", firmware->data, firmware->size);
 202
 203        size = max_t(uint, firmware->size, 4096);
 204
 205        data->buffer = kmalloc(size, GFP_KERNEL);
 206        if (!data->buffer) {
 207                BT_ERR("Can't allocate memory for mini driver");
 208                release_firmware(firmware);
 209                usb_free_urb(data->urb);
 210                return -ENOMEM;
 211        }
 212
 213        memcpy(data->buffer, firmware->data, firmware->size);
 214
 215        usb_fill_bulk_urb(data->urb, udev, usb_sndbulkpipe(udev, BCM203X_OUT_EP),
 216                        data->buffer, firmware->size, bcm203x_complete, data);
 217
 218        release_firmware(firmware);
 219
 220        if (request_firmware(&firmware, "BCM2033-FW.bin", &udev->dev) < 0) {
 221                BT_ERR("Firmware request failed");
 222                usb_free_urb(data->urb);
 223                kfree(data->buffer);
 224                return -EIO;
 225        }
 226
 227        BT_DBG("firmware data %p size %zu", firmware->data, firmware->size);
 228
 229        data->fw_data = kmemdup(firmware->data, firmware->size, GFP_KERNEL);
 230        if (!data->fw_data) {
 231                BT_ERR("Can't allocate memory for firmware image");
 232                release_firmware(firmware);
 233                usb_free_urb(data->urb);
 234                kfree(data->buffer);
 235                return -ENOMEM;
 236        }
 237
 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        /* use workqueue to have a small delay */
 248        schedule_work(&data->work);
 249
 250        return 0;
 251}
 252
 253static void bcm203x_disconnect(struct usb_interface *intf)
 254{
 255        struct bcm203x_data *data = usb_get_intfdata(intf);
 256
 257        BT_DBG("intf %p", intf);
 258
 259        atomic_inc(&data->shutdown);
 260        cancel_work_sync(&data->work);
 261
 262        usb_kill_urb(data->urb);
 263
 264        usb_set_intfdata(intf, NULL);
 265
 266        usb_free_urb(data->urb);
 267        kfree(data->fw_data);
 268        kfree(data->buffer);
 269}
 270
 271static struct usb_driver bcm203x_driver = {
 272        .name           = "bcm203x",
 273        .probe          = bcm203x_probe,
 274        .disconnect     = bcm203x_disconnect,
 275        .id_table       = bcm203x_table,
 276        .disable_hub_initiated_lpm = 1,
 277};
 278
 279module_usb_driver(bcm203x_driver);
 280
 281MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
 282MODULE_DESCRIPTION("Broadcom Blutonium firmware driver ver " VERSION);
 283MODULE_VERSION(VERSION);
 284MODULE_LICENSE("GPL");
 285MODULE_FIRMWARE("BCM2033-MD.hex");
 286MODULE_FIRMWARE("BCM2033-FW.bin");
 287
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.