root/sound/usb/6fire/firmware.c

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

DEFINITIONS

This source file includes following definitions.
  1. usb6fire_fw_ihex_hex
  2. usb6fire_fw_ihex_next_record
  3. usb6fire_fw_ihex_init
  4. usb6fire_fw_ezusb_write
  5. usb6fire_fw_ezusb_read
  6. usb6fire_fw_fpga_write
  7. usb6fire_fw_ezusb_upload
  8. usb6fire_fw_fpga_upload
  9. usb6fire_fw_check
  10. usb6fire_fw_init

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * Linux driver for TerraTec DMX 6Fire USB
   4  *
   5  * Firmware loader
   6  *
   7  * Author:      Torsten Schenk <torsten.schenk@zoho.com>
   8  * Created:     Jan 01, 2011
   9  * Copyright:   (C) Torsten Schenk
  10  */
  11 
  12 #include <linux/firmware.h>
  13 #include <linux/module.h>
  14 #include <linux/bitrev.h>
  15 #include <linux/kernel.h>
  16 
  17 #include "firmware.h"
  18 #include "chip.h"
  19 
  20 MODULE_FIRMWARE("6fire/dmx6firel2.ihx");
  21 MODULE_FIRMWARE("6fire/dmx6fireap.ihx");
  22 MODULE_FIRMWARE("6fire/dmx6firecf.bin");
  23 
  24 enum {
  25         FPGA_BUFSIZE = 512, FPGA_EP = 2
  26 };
  27 
  28 /*
  29  * wMaxPacketSize of pcm endpoints.
  30  * keep synced with rates_in_packet_size and rates_out_packet_size in pcm.c
  31  * fpp: frames per isopacket
  32  *
  33  * CAUTION: keep sizeof <= buffer[] in usb6fire_fw_init
  34  */
  35 static const u8 ep_w_max_packet_size[] = {
  36         0xe4, 0x00, 0xe4, 0x00, /* alt 1: 228 EP2 and EP6 (7 fpp) */
  37         0xa4, 0x01, 0xa4, 0x01, /* alt 2: 420 EP2 and EP6 (13 fpp)*/
  38         0x94, 0x01, 0x5c, 0x02  /* alt 3: 404 EP2 and 604 EP6 (25 fpp) */
  39 };
  40 
  41 static const u8 known_fw_versions[][2] = {
  42         { 0x03, 0x01 }
  43 };
  44 
  45 struct ihex_record {
  46         u16 address;
  47         u8 len;
  48         u8 data[256];
  49         char error; /* true if an error occurred parsing this record */
  50 
  51         u8 max_len; /* maximum record length in whole ihex */
  52 
  53         /* private */
  54         const char *txt_data;
  55         unsigned int txt_length;
  56         unsigned int txt_offset; /* current position in txt_data */
  57 };
  58 
  59 static u8 usb6fire_fw_ihex_hex(const u8 *data, u8 *crc)
  60 {
  61         u8 val = 0;
  62         int hval;
  63 
  64         hval = hex_to_bin(data[0]);
  65         if (hval >= 0)
  66                 val |= (hval << 4);
  67 
  68         hval = hex_to_bin(data[1]);
  69         if (hval >= 0)
  70                 val |= hval;
  71 
  72         *crc += val;
  73         return val;
  74 }
  75 
  76 /*
  77  * returns true if record is available, false otherwise.
  78  * iff an error occurred, false will be returned and record->error will be true.
  79  */
  80 static bool usb6fire_fw_ihex_next_record(struct ihex_record *record)
  81 {
  82         u8 crc = 0;
  83         u8 type;
  84         int i;
  85 
  86         record->error = false;
  87 
  88         /* find begin of record (marked by a colon) */
  89         while (record->txt_offset < record->txt_length
  90                         && record->txt_data[record->txt_offset] != ':')
  91                 record->txt_offset++;
  92         if (record->txt_offset == record->txt_length)
  93                 return false;
  94 
  95         /* number of characters needed for len, addr and type entries */
  96         record->txt_offset++;
  97         if (record->txt_offset + 8 > record->txt_length) {
  98                 record->error = true;
  99                 return false;
 100         }
 101 
 102         record->len = usb6fire_fw_ihex_hex(record->txt_data +
 103                         record->txt_offset, &crc);
 104         record->txt_offset += 2;
 105         record->address = usb6fire_fw_ihex_hex(record->txt_data +
 106                         record->txt_offset, &crc) << 8;
 107         record->txt_offset += 2;
 108         record->address |= usb6fire_fw_ihex_hex(record->txt_data +
 109                         record->txt_offset, &crc);
 110         record->txt_offset += 2;
 111         type = usb6fire_fw_ihex_hex(record->txt_data +
 112                         record->txt_offset, &crc);
 113         record->txt_offset += 2;
 114 
 115         /* number of characters needed for data and crc entries */
 116         if (record->txt_offset + 2 * (record->len + 1) > record->txt_length) {
 117                 record->error = true;
 118                 return false;
 119         }
 120         for (i = 0; i < record->len; i++) {
 121                 record->data[i] = usb6fire_fw_ihex_hex(record->txt_data
 122                                 + record->txt_offset, &crc);
 123                 record->txt_offset += 2;
 124         }
 125         usb6fire_fw_ihex_hex(record->txt_data + record->txt_offset, &crc);
 126         if (crc) {
 127                 record->error = true;
 128                 return false;
 129         }
 130 
 131         if (type == 1 || !record->len) /* eof */
 132                 return false;
 133         else if (type == 0)
 134                 return true;
 135         else {
 136                 record->error = true;
 137                 return false;
 138         }
 139 }
 140 
 141 static int usb6fire_fw_ihex_init(const struct firmware *fw,
 142                 struct ihex_record *record)
 143 {
 144         record->txt_data = fw->data;
 145         record->txt_length = fw->size;
 146         record->txt_offset = 0;
 147         record->max_len = 0;
 148         /* read all records, if loop ends, record->error indicates,
 149          * whether ihex is valid. */
 150         while (usb6fire_fw_ihex_next_record(record))
 151                 record->max_len = max(record->len, record->max_len);
 152         if (record->error)
 153                 return -EINVAL;
 154         record->txt_offset = 0;
 155         return 0;
 156 }
 157 
 158 static int usb6fire_fw_ezusb_write(struct usb_device *device,
 159                 int type, int value, char *data, int len)
 160 {
 161         int ret;
 162 
 163         ret = usb_control_msg(device, usb_sndctrlpipe(device, 0), type,
 164                         USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 165                         value, 0, data, len, HZ);
 166         if (ret < 0)
 167                 return ret;
 168         else if (ret != len)
 169                 return -EIO;
 170         return 0;
 171 }
 172 
 173 static int usb6fire_fw_ezusb_read(struct usb_device *device,
 174                 int type, int value, char *data, int len)
 175 {
 176         int ret = usb_control_msg(device, usb_rcvctrlpipe(device, 0), type,
 177                         USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, value,
 178                         0, data, len, HZ);
 179         if (ret < 0)
 180                 return ret;
 181         else if (ret != len)
 182                 return -EIO;
 183         return 0;
 184 }
 185 
 186 static int usb6fire_fw_fpga_write(struct usb_device *device,
 187                 char *data, int len)
 188 {
 189         int actual_len;
 190         int ret;
 191 
 192         ret = usb_bulk_msg(device, usb_sndbulkpipe(device, FPGA_EP), data, len,
 193                         &actual_len, HZ);
 194         if (ret < 0)
 195                 return ret;
 196         else if (actual_len != len)
 197                 return -EIO;
 198         return 0;
 199 }
 200 
 201 static int usb6fire_fw_ezusb_upload(
 202                 struct usb_interface *intf, const char *fwname,
 203                 unsigned int postaddr, u8 *postdata, unsigned int postlen)
 204 {
 205         int ret;
 206         u8 data;
 207         struct usb_device *device = interface_to_usbdev(intf);
 208         const struct firmware *fw = NULL;
 209         struct ihex_record *rec = kmalloc(sizeof(struct ihex_record),
 210                         GFP_KERNEL);
 211 
 212         if (!rec)
 213                 return -ENOMEM;
 214 
 215         ret = request_firmware(&fw, fwname, &device->dev);
 216         if (ret < 0) {
 217                 kfree(rec);
 218                 dev_err(&intf->dev,
 219                         "error requesting ezusb firmware %s.\n", fwname);
 220                 return ret;
 221         }
 222         ret = usb6fire_fw_ihex_init(fw, rec);
 223         if (ret < 0) {
 224                 kfree(rec);
 225                 release_firmware(fw);
 226                 dev_err(&intf->dev,
 227                         "error validating ezusb firmware %s.\n", fwname);
 228                 return ret;
 229         }
 230         /* upload firmware image */
 231         data = 0x01; /* stop ezusb cpu */
 232         ret = usb6fire_fw_ezusb_write(device, 0xa0, 0xe600, &data, 1);
 233         if (ret < 0) {
 234                 kfree(rec);
 235                 release_firmware(fw);
 236                 dev_err(&intf->dev,
 237                         "unable to upload ezusb firmware %s: begin message.\n",
 238                         fwname);
 239                 return ret;
 240         }
 241 
 242         while (usb6fire_fw_ihex_next_record(rec)) { /* write firmware */
 243                 ret = usb6fire_fw_ezusb_write(device, 0xa0, rec->address,
 244                                 rec->data, rec->len);
 245                 if (ret < 0) {
 246                         kfree(rec);
 247                         release_firmware(fw);
 248                         dev_err(&intf->dev,
 249                                 "unable to upload ezusb firmware %s: data urb.\n",
 250                                 fwname);
 251                         return ret;
 252                 }
 253         }
 254 
 255         release_firmware(fw);
 256         kfree(rec);
 257         if (postdata) { /* write data after firmware has been uploaded */
 258                 ret = usb6fire_fw_ezusb_write(device, 0xa0, postaddr,
 259                                 postdata, postlen);
 260                 if (ret < 0) {
 261                         dev_err(&intf->dev,
 262                                 "unable to upload ezusb firmware %s: post urb.\n",
 263                                 fwname);
 264                         return ret;
 265                 }
 266         }
 267 
 268         data = 0x00; /* resume ezusb cpu */
 269         ret = usb6fire_fw_ezusb_write(device, 0xa0, 0xe600, &data, 1);
 270         if (ret < 0) {
 271                 dev_err(&intf->dev,
 272                         "unable to upload ezusb firmware %s: end message.\n",
 273                         fwname);
 274                 return ret;
 275         }
 276         return 0;
 277 }
 278 
 279 static int usb6fire_fw_fpga_upload(
 280                 struct usb_interface *intf, const char *fwname)
 281 {
 282         int ret;
 283         int i;
 284         struct usb_device *device = interface_to_usbdev(intf);
 285         u8 *buffer = kmalloc(FPGA_BUFSIZE, GFP_KERNEL);
 286         const char *c;
 287         const char *end;
 288         const struct firmware *fw;
 289 
 290         if (!buffer)
 291                 return -ENOMEM;
 292 
 293         ret = request_firmware(&fw, fwname, &device->dev);
 294         if (ret < 0) {
 295                 dev_err(&intf->dev, "unable to get fpga firmware %s.\n",
 296                                 fwname);
 297                 kfree(buffer);
 298                 return -EIO;
 299         }
 300 
 301         c = fw->data;
 302         end = fw->data + fw->size;
 303 
 304         ret = usb6fire_fw_ezusb_write(device, 8, 0, NULL, 0);
 305         if (ret < 0) {
 306                 kfree(buffer);
 307                 release_firmware(fw);
 308                 dev_err(&intf->dev,
 309                         "unable to upload fpga firmware: begin urb.\n");
 310                 return ret;
 311         }
 312 
 313         while (c != end) {
 314                 for (i = 0; c != end && i < FPGA_BUFSIZE; i++, c++)
 315                         buffer[i] = bitrev8((u8)*c);
 316 
 317                 ret = usb6fire_fw_fpga_write(device, buffer, i);
 318                 if (ret < 0) {
 319                         release_firmware(fw);
 320                         kfree(buffer);
 321                         dev_err(&intf->dev,
 322                                 "unable to upload fpga firmware: fw urb.\n");
 323                         return ret;
 324                 }
 325         }
 326         release_firmware(fw);
 327         kfree(buffer);
 328 
 329         ret = usb6fire_fw_ezusb_write(device, 9, 0, NULL, 0);
 330         if (ret < 0) {
 331                 dev_err(&intf->dev,
 332                         "unable to upload fpga firmware: end urb.\n");
 333                 return ret;
 334         }
 335         return 0;
 336 }
 337 
 338 /* check, if the firmware version the devices has currently loaded
 339  * is known by this driver. 'version' needs to have 4 bytes version
 340  * info data. */
 341 static int usb6fire_fw_check(struct usb_interface *intf, const u8 *version)
 342 {
 343         int i;
 344 
 345         for (i = 0; i < ARRAY_SIZE(known_fw_versions); i++)
 346                 if (!memcmp(version, known_fw_versions + i, 2))
 347                         return 0;
 348 
 349         dev_err(&intf->dev, "invalid firmware version in device: %4ph. "
 350                         "please reconnect to power. if this failure "
 351                         "still happens, check your firmware installation.",
 352                         version);
 353         return -EINVAL;
 354 }
 355 
 356 int usb6fire_fw_init(struct usb_interface *intf)
 357 {
 358         int i;
 359         int ret;
 360         struct usb_device *device = interface_to_usbdev(intf);
 361         /* buffer: 8 receiving bytes from device and
 362          * sizeof(EP_W_MAX_PACKET_SIZE) bytes for non-const copy */
 363         u8 buffer[12];
 364 
 365         ret = usb6fire_fw_ezusb_read(device, 1, 0, buffer, 8);
 366         if (ret < 0) {
 367                 dev_err(&intf->dev,
 368                         "unable to receive device firmware state.\n");
 369                 return ret;
 370         }
 371         if (buffer[0] != 0xeb || buffer[1] != 0xaa || buffer[2] != 0x55) {
 372                 dev_err(&intf->dev,
 373                         "unknown device firmware state received from device:");
 374                 for (i = 0; i < 8; i++)
 375                         printk(KERN_CONT "%02x ", buffer[i]);
 376                 printk(KERN_CONT "\n");
 377                 return -EIO;
 378         }
 379         /* do we need fpga loader ezusb firmware? */
 380         if (buffer[3] == 0x01) {
 381                 ret = usb6fire_fw_ezusb_upload(intf,
 382                                 "6fire/dmx6firel2.ihx", 0, NULL, 0);
 383                 if (ret < 0)
 384                         return ret;
 385                 return FW_NOT_READY;
 386         }
 387         /* do we need fpga firmware and application ezusb firmware? */
 388         else if (buffer[3] == 0x02) {
 389                 ret = usb6fire_fw_check(intf, buffer + 4);
 390                 if (ret < 0)
 391                         return ret;
 392                 ret = usb6fire_fw_fpga_upload(intf, "6fire/dmx6firecf.bin");
 393                 if (ret < 0)
 394                         return ret;
 395                 memcpy(buffer, ep_w_max_packet_size,
 396                                 sizeof(ep_w_max_packet_size));
 397                 ret = usb6fire_fw_ezusb_upload(intf, "6fire/dmx6fireap.ihx",
 398                                 0x0003, buffer, sizeof(ep_w_max_packet_size));
 399                 if (ret < 0)
 400                         return ret;
 401                 return FW_NOT_READY;
 402         }
 403         /* all fw loaded? */
 404         else if (buffer[3] == 0x03)
 405                 return usb6fire_fw_check(intf, buffer + 4);
 406         /* unknown data? */
 407         else {
 408                 dev_err(&intf->dev,
 409                         "unknown device firmware state received from device: ");
 410                 for (i = 0; i < 8; i++)
 411                         printk(KERN_CONT "%02x ", buffer[i]);
 412                 printk(KERN_CONT "\n");
 413                 return -EIO;
 414         }
 415         return 0;
 416 }
 417 

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