root/drivers/bluetooth/bcm203x.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. bcm203x_complete
  2. bcm203x_work
  3. bcm203x_probe
  4. bcm203x_disconnect

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

/* [<][>][^][v][top][bottom][index][help] */