ALSA: bebob: Send a cue to load firmware for M-Audio Firewire series
authorTakashi Sakamoto <o-takashi@sakamocchi.jp>
Fri, 25 Apr 2014 13:45:29 +0000 (22:45 +0900)
committerTakashi Iwai <tiwai@suse.de>
Mon, 26 May 2014 12:32:58 +0000 (14:32 +0200)
Just powering on, these devices below wait to download firmware.
 - Firewire Audiophile
 - Firewire 410
 - Firewire 1814
 - ProjectMix I/O

But firmware version 5058 or later, flash memory in the device stores the
firmware. So this driver can enable these devices by sending a certain cue to
load the firmware.

Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/firewire/bebob/bebob.c
sound/firewire/bebob/bebob.h
sound/firewire/bebob/bebob_maudio.c

index ffb042b..e1dd421 100644 (file)
@@ -177,18 +177,21 @@ bebob_probe(struct fw_unit *unit,
        }
 
        if ((entry->vendor_id == VEN_FOCUSRITE) &&
-           (entry->model_id == MODEL_FOCUSRITE_SAFFIRE_BOTH)) {
+           (entry->model_id == MODEL_FOCUSRITE_SAFFIRE_BOTH))
                spec = get_saffire_spec(unit);
-       } else if ((entry->vendor_id == VEN_MAUDIO1) &&
-                  (entry->model_id == MODEL_MAUDIO_AUDIOPHILE_BOTH) &&
-                  !check_audiophile_booted(unit)) {
-                       err = 0;
-                       goto end;
-       } else {
+       else if ((entry->vendor_id == VEN_MAUDIO1) &&
+                (entry->model_id == MODEL_MAUDIO_AUDIOPHILE_BOTH) &&
+                !check_audiophile_booted(unit))
+               spec = NULL;
+       else
                spec = (const struct snd_bebob_spec *)entry->driver_data;
-       }
+
        if (spec == NULL) {
-               err = -ENOSYS;
+               if ((entry->vendor_id == VEN_MAUDIO1) ||
+                   (entry->vendor_id == VEN_MAUDIO2))
+                       err = snd_bebob_maudio_load_firmware(unit);
+               else
+                       err = -ENOSYS;
                goto end;
        }
 
@@ -374,6 +377,7 @@ static const struct ieee1394_device_id bebob_id_table[] = {
        SND_BEBOB_DEV_ENTRY(VEN_FOCUSRITE, MODEL_FOCUSRITE_SAFFIRE_BOTH,
                            &saffire_spec),
        /* M-Audio, Firewire 410 */
+       SND_BEBOB_DEV_ENTRY(VEN_MAUDIO2, 0x00010058, NULL),     /* bootloader */
        SND_BEBOB_DEV_ENTRY(VEN_MAUDIO2, 0x00010046, &maudio_fw410_spec),
        /* M-Audio, Firewire Audiophile */
        SND_BEBOB_DEV_ENTRY(VEN_MAUDIO1, MODEL_MAUDIO_AUDIOPHILE_BOTH,
@@ -387,6 +391,7 @@ static const struct ieee1394_device_id bebob_id_table[] = {
        /* M-Audio, ProFireLightbridge */
        SND_BEBOB_DEV_ENTRY(VEN_MAUDIO1, 0x000100a1, &spec_normal),
        /* Firewire 1814 */
+       SND_BEBOB_DEV_ENTRY(VEN_MAUDIO1, 0x00010070, NULL),     /* bootloader */
        SND_BEBOB_DEV_ENTRY(VEN_MAUDIO1, MODEL_MAUDIO_FW1814,
                            &maudio_special_spec),
        /* M-Audio ProjectMix */
index eba0129..4a54e74 100644 (file)
@@ -242,6 +242,7 @@ extern struct snd_bebob_spec maudio_ozonic_spec;
 extern struct snd_bebob_spec maudio_nrv10_spec;
 extern struct snd_bebob_spec maudio_special_spec;
 int snd_bebob_maudio_special_discover(struct snd_bebob *bebob, bool is1814);
+int snd_bebob_maudio_load_firmware(struct fw_unit *unit);
 
 #define SND_BEBOB_DEV_ENTRY(vendor, model, data) \
 { \
index 544094b..52b1a40 100644 (file)
  * settings when completing uploading. Then these devices generate bus reset
  * and are recognized as new devices with the firmware.
  *
+ * But with firmware version 5058 or later, the firmware is stored to flash
+ * memory in the device and drivers can tell bootloader to load the firmware
+ * by sending a cue. This cue must be sent one time.
+ *
  * For streaming, both of output and input streams are needed for Firewire 410
  * and Ozonic. The single stream is OK for the other devices even if the clock
  * source is not SYT-Match (I note no devices use SYT-Match).
  * functionality is between 0xffc700700000 to 0xffc70070009c.
  */
 
+/* Offset from information register */
+#define INFO_OFFSET_SW_DATE    0x20
+
+/* Bootloader Protocol Version 1 */
+#define MAUDIO_BOOTLOADER_CUE1 0x00000001
+/*
+ * Initializing configuration to factory settings (= 0x1101), (swapped in line),
+ * Command code is zero (= 0x00),
+ * the number of operands is zero (= 0x00)(at least significant byte)
+ */
+#define MAUDIO_BOOTLOADER_CUE2 0x01110000
+/* padding */
+#define MAUDIO_BOOTLOADER_CUE3 0x00000000
+
 #define MAUDIO_SPECIFIC_ADDRESS        0xffc700000000
 
 #define METER_OFFSET           0x00600000
@@ -67,6 +85,52 @@ struct special_params {
        struct snd_ctl_elem_id *ctl_id_sync;
 };
 
+/*
+ * For some M-Audio devices, this module just send cue to load firmware. After
+ * loading, the device generates bus reset and newly detected.
+ *
+ * If we make any transactions to load firmware, the operation may failed.
+ */
+int snd_bebob_maudio_load_firmware(struct fw_unit *unit)
+{
+       struct fw_device *device = fw_parent_device(unit);
+       int err, rcode;
+       u64 date;
+       __be32 cues[3] = {
+               MAUDIO_BOOTLOADER_CUE1,
+               MAUDIO_BOOTLOADER_CUE2,
+               MAUDIO_BOOTLOADER_CUE3
+       };
+
+       /* check date of software used to build */
+       err = snd_bebob_read_block(unit, INFO_OFFSET_SW_DATE,
+                                  &date, sizeof(u64));
+       if (err < 0)
+               goto end;
+       /*
+        * firmware version 5058 or later has date later than "20070401", but
+        * 'date' is not null-terminated.
+        */
+       if (date < 0x3230303730343031) {
+               dev_err(&unit->device,
+                       "Use firmware version 5058 or later\n");
+               err = -ENOSYS;
+               goto end;
+       }
+
+       rcode = fw_run_transaction(device->card, TCODE_WRITE_BLOCK_REQUEST,
+                                  device->node_id, device->generation,
+                                  device->max_speed, BEBOB_ADDR_REG_REQ,
+                                  cues, sizeof(cues));
+       if (rcode != RCODE_COMPLETE) {
+               dev_err(&unit->device,
+                       "Failed to send a cue to load firmware\n");
+               err = -EIO;
+       }
+end:
+       return err;
+}
+
 static inline int
 get_meter(struct snd_bebob *bebob, void *buf, unsigned int size)
 {