162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Emagic EMI 2|6 usb audio interface firmware loader. 462306a36Sopenharmony_ci * Copyright (C) 2002 562306a36Sopenharmony_ci * Tapio Laxström (tapio.laxstrom@iptime.fi) 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci#include <linux/kernel.h> 862306a36Sopenharmony_ci#include <linux/errno.h> 962306a36Sopenharmony_ci#include <linux/slab.h> 1062306a36Sopenharmony_ci#include <linux/module.h> 1162306a36Sopenharmony_ci#include <linux/usb.h> 1262306a36Sopenharmony_ci#include <linux/delay.h> 1362306a36Sopenharmony_ci#include <linux/firmware.h> 1462306a36Sopenharmony_ci#include <linux/ihex.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci/* include firmware (variables)*/ 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci/* FIXME: This is quick and dirty solution! */ 1962306a36Sopenharmony_ci#define SPDIF /* if you want SPDIF comment next line */ 2062306a36Sopenharmony_ci//#undef SPDIF /* if you want MIDI uncomment this line */ 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#ifdef SPDIF 2362306a36Sopenharmony_ci#define FIRMWARE_FW "emi62/spdif.fw" 2462306a36Sopenharmony_ci#else 2562306a36Sopenharmony_ci#define FIRMWARE_FW "emi62/midi.fw" 2662306a36Sopenharmony_ci#endif 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#define EMI62_VENDOR_ID 0x086a /* Emagic Soft-und Hardware GmBH */ 2962306a36Sopenharmony_ci#define EMI62_PRODUCT_ID 0x0110 /* EMI 6|2m without firmware */ 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#define ANCHOR_LOAD_INTERNAL 0xA0 /* Vendor specific request code for Anchor Upload/Download (This one is implemented in the core) */ 3262306a36Sopenharmony_ci#define ANCHOR_LOAD_EXTERNAL 0xA3 /* This command is not implemented in the core. Requires firmware */ 3362306a36Sopenharmony_ci#define ANCHOR_LOAD_FPGA 0xA5 /* This command is not implemented in the core. Requires firmware. Emagic extension */ 3462306a36Sopenharmony_ci#define MAX_INTERNAL_ADDRESS 0x1B3F /* This is the highest internal RAM address for the AN2131Q */ 3562306a36Sopenharmony_ci#define CPUCS_REG 0x7F92 /* EZ-USB Control and Status Register. Bit 0 controls 8051 reset */ 3662306a36Sopenharmony_ci#define INTERNAL_RAM(address) (address <= MAX_INTERNAL_ADDRESS) 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_cistatic int emi62_writememory(struct usb_device *dev, int address, 3962306a36Sopenharmony_ci const unsigned char *data, int length, 4062306a36Sopenharmony_ci __u8 bRequest); 4162306a36Sopenharmony_cistatic int emi62_set_reset(struct usb_device *dev, unsigned char reset_bit); 4262306a36Sopenharmony_cistatic int emi62_load_firmware (struct usb_device *dev); 4362306a36Sopenharmony_cistatic int emi62_probe(struct usb_interface *intf, const struct usb_device_id *id); 4462306a36Sopenharmony_cistatic void emi62_disconnect(struct usb_interface *intf); 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci/* thanks to drivers/usb/serial/keyspan_pda.c code */ 4762306a36Sopenharmony_cistatic int emi62_writememory(struct usb_device *dev, int address, 4862306a36Sopenharmony_ci const unsigned char *data, int length, 4962306a36Sopenharmony_ci __u8 request) 5062306a36Sopenharmony_ci{ 5162306a36Sopenharmony_ci int result; 5262306a36Sopenharmony_ci unsigned char *buffer = kmemdup(data, length, GFP_KERNEL); 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci if (!buffer) { 5562306a36Sopenharmony_ci dev_err(&dev->dev, "kmalloc(%d) failed.\n", length); 5662306a36Sopenharmony_ci return -ENOMEM; 5762306a36Sopenharmony_ci } 5862306a36Sopenharmony_ci /* Note: usb_control_msg returns negative value on error or length of the 5962306a36Sopenharmony_ci * data that was written! */ 6062306a36Sopenharmony_ci result = usb_control_msg (dev, usb_sndctrlpipe(dev, 0), request, 0x40, address, 0, buffer, length, 300); 6162306a36Sopenharmony_ci kfree (buffer); 6262306a36Sopenharmony_ci return result; 6362306a36Sopenharmony_ci} 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci/* thanks to drivers/usb/serial/keyspan_pda.c code */ 6662306a36Sopenharmony_cistatic int emi62_set_reset (struct usb_device *dev, unsigned char reset_bit) 6762306a36Sopenharmony_ci{ 6862306a36Sopenharmony_ci int response; 6962306a36Sopenharmony_ci dev_info(&dev->dev, "%s - %d\n", __func__, reset_bit); 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci response = emi62_writememory (dev, CPUCS_REG, &reset_bit, 1, 0xa0); 7262306a36Sopenharmony_ci if (response < 0) 7362306a36Sopenharmony_ci dev_err(&dev->dev, "set_reset (%d) failed\n", reset_bit); 7462306a36Sopenharmony_ci return response; 7562306a36Sopenharmony_ci} 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci#define FW_LOAD_SIZE 1023 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_cistatic int emi62_load_firmware (struct usb_device *dev) 8062306a36Sopenharmony_ci{ 8162306a36Sopenharmony_ci const struct firmware *loader_fw = NULL; 8262306a36Sopenharmony_ci const struct firmware *bitstream_fw = NULL; 8362306a36Sopenharmony_ci const struct firmware *firmware_fw = NULL; 8462306a36Sopenharmony_ci const struct ihex_binrec *rec; 8562306a36Sopenharmony_ci int err = -ENOMEM; 8662306a36Sopenharmony_ci int i; 8762306a36Sopenharmony_ci __u32 addr; /* Address to write */ 8862306a36Sopenharmony_ci __u8 *buf; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci dev_dbg(&dev->dev, "load_firmware\n"); 9162306a36Sopenharmony_ci buf = kmalloc(FW_LOAD_SIZE, GFP_KERNEL); 9262306a36Sopenharmony_ci if (!buf) 9362306a36Sopenharmony_ci goto wraperr; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci err = request_ihex_firmware(&loader_fw, "emi62/loader.fw", &dev->dev); 9662306a36Sopenharmony_ci if (err) 9762306a36Sopenharmony_ci goto nofw; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci err = request_ihex_firmware(&bitstream_fw, "emi62/bitstream.fw", 10062306a36Sopenharmony_ci &dev->dev); 10162306a36Sopenharmony_ci if (err) 10262306a36Sopenharmony_ci goto nofw; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci err = request_ihex_firmware(&firmware_fw, FIRMWARE_FW, &dev->dev); 10562306a36Sopenharmony_ci if (err) { 10662306a36Sopenharmony_ci nofw: 10762306a36Sopenharmony_ci goto wraperr; 10862306a36Sopenharmony_ci } 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci /* Assert reset (stop the CPU in the EMI) */ 11162306a36Sopenharmony_ci err = emi62_set_reset(dev,1); 11262306a36Sopenharmony_ci if (err < 0) 11362306a36Sopenharmony_ci goto wraperr; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci rec = (const struct ihex_binrec *)loader_fw->data; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci /* 1. We need to put the loader for the FPGA into the EZ-USB */ 11862306a36Sopenharmony_ci while (rec) { 11962306a36Sopenharmony_ci err = emi62_writememory(dev, be32_to_cpu(rec->addr), 12062306a36Sopenharmony_ci rec->data, be16_to_cpu(rec->len), 12162306a36Sopenharmony_ci ANCHOR_LOAD_INTERNAL); 12262306a36Sopenharmony_ci if (err < 0) 12362306a36Sopenharmony_ci goto wraperr; 12462306a36Sopenharmony_ci rec = ihex_next_binrec(rec); 12562306a36Sopenharmony_ci } 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci /* De-assert reset (let the CPU run) */ 12862306a36Sopenharmony_ci err = emi62_set_reset(dev,0); 12962306a36Sopenharmony_ci if (err < 0) 13062306a36Sopenharmony_ci goto wraperr; 13162306a36Sopenharmony_ci msleep(250); /* let device settle */ 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci /* 2. We upload the FPGA firmware into the EMI 13462306a36Sopenharmony_ci * Note: collect up to 1023 (yes!) bytes and send them with 13562306a36Sopenharmony_ci * a single request. This is _much_ faster! */ 13662306a36Sopenharmony_ci rec = (const struct ihex_binrec *)bitstream_fw->data; 13762306a36Sopenharmony_ci do { 13862306a36Sopenharmony_ci i = 0; 13962306a36Sopenharmony_ci addr = be32_to_cpu(rec->addr); 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci /* intel hex records are terminated with type 0 element */ 14262306a36Sopenharmony_ci while (rec && (i + be16_to_cpu(rec->len) < FW_LOAD_SIZE)) { 14362306a36Sopenharmony_ci memcpy(buf + i, rec->data, be16_to_cpu(rec->len)); 14462306a36Sopenharmony_ci i += be16_to_cpu(rec->len); 14562306a36Sopenharmony_ci rec = ihex_next_binrec(rec); 14662306a36Sopenharmony_ci } 14762306a36Sopenharmony_ci err = emi62_writememory(dev, addr, buf, i, ANCHOR_LOAD_FPGA); 14862306a36Sopenharmony_ci if (err < 0) 14962306a36Sopenharmony_ci goto wraperr; 15062306a36Sopenharmony_ci } while (rec); 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci /* Assert reset (stop the CPU in the EMI) */ 15362306a36Sopenharmony_ci err = emi62_set_reset(dev,1); 15462306a36Sopenharmony_ci if (err < 0) 15562306a36Sopenharmony_ci goto wraperr; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci /* 3. We need to put the loader for the firmware into the EZ-USB (again...) */ 15862306a36Sopenharmony_ci for (rec = (const struct ihex_binrec *)loader_fw->data; 15962306a36Sopenharmony_ci rec; rec = ihex_next_binrec(rec)) { 16062306a36Sopenharmony_ci err = emi62_writememory(dev, be32_to_cpu(rec->addr), 16162306a36Sopenharmony_ci rec->data, be16_to_cpu(rec->len), 16262306a36Sopenharmony_ci ANCHOR_LOAD_INTERNAL); 16362306a36Sopenharmony_ci if (err < 0) 16462306a36Sopenharmony_ci goto wraperr; 16562306a36Sopenharmony_ci } 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci /* De-assert reset (let the CPU run) */ 16862306a36Sopenharmony_ci err = emi62_set_reset(dev,0); 16962306a36Sopenharmony_ci if (err < 0) 17062306a36Sopenharmony_ci goto wraperr; 17162306a36Sopenharmony_ci msleep(250); /* let device settle */ 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci /* 4. We put the part of the firmware that lies in the external RAM into the EZ-USB */ 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci for (rec = (const struct ihex_binrec *)firmware_fw->data; 17662306a36Sopenharmony_ci rec; rec = ihex_next_binrec(rec)) { 17762306a36Sopenharmony_ci if (!INTERNAL_RAM(be32_to_cpu(rec->addr))) { 17862306a36Sopenharmony_ci err = emi62_writememory(dev, be32_to_cpu(rec->addr), 17962306a36Sopenharmony_ci rec->data, be16_to_cpu(rec->len), 18062306a36Sopenharmony_ci ANCHOR_LOAD_EXTERNAL); 18162306a36Sopenharmony_ci if (err < 0) 18262306a36Sopenharmony_ci goto wraperr; 18362306a36Sopenharmony_ci } 18462306a36Sopenharmony_ci } 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci /* Assert reset (stop the CPU in the EMI) */ 18762306a36Sopenharmony_ci err = emi62_set_reset(dev,1); 18862306a36Sopenharmony_ci if (err < 0) 18962306a36Sopenharmony_ci goto wraperr; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci for (rec = (const struct ihex_binrec *)firmware_fw->data; 19262306a36Sopenharmony_ci rec; rec = ihex_next_binrec(rec)) { 19362306a36Sopenharmony_ci if (INTERNAL_RAM(be32_to_cpu(rec->addr))) { 19462306a36Sopenharmony_ci err = emi62_writememory(dev, be32_to_cpu(rec->addr), 19562306a36Sopenharmony_ci rec->data, be16_to_cpu(rec->len), 19662306a36Sopenharmony_ci ANCHOR_LOAD_EXTERNAL); 19762306a36Sopenharmony_ci if (err < 0) 19862306a36Sopenharmony_ci goto wraperr; 19962306a36Sopenharmony_ci } 20062306a36Sopenharmony_ci } 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci /* De-assert reset (let the CPU run) */ 20362306a36Sopenharmony_ci err = emi62_set_reset(dev,0); 20462306a36Sopenharmony_ci if (err < 0) 20562306a36Sopenharmony_ci goto wraperr; 20662306a36Sopenharmony_ci msleep(250); /* let device settle */ 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci release_firmware(loader_fw); 20962306a36Sopenharmony_ci release_firmware(bitstream_fw); 21062306a36Sopenharmony_ci release_firmware(firmware_fw); 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci kfree(buf); 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci /* return 1 to fail the driver inialization 21562306a36Sopenharmony_ci * and give real driver change to load */ 21662306a36Sopenharmony_ci return 1; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ciwraperr: 21962306a36Sopenharmony_ci if (err < 0) 22062306a36Sopenharmony_ci dev_err(&dev->dev,"%s - error loading firmware: error = %d\n", 22162306a36Sopenharmony_ci __func__, err); 22262306a36Sopenharmony_ci release_firmware(loader_fw); 22362306a36Sopenharmony_ci release_firmware(bitstream_fw); 22462306a36Sopenharmony_ci release_firmware(firmware_fw); 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci kfree(buf); 22762306a36Sopenharmony_ci dev_err(&dev->dev, "Error\n"); 22862306a36Sopenharmony_ci return err; 22962306a36Sopenharmony_ci} 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_cistatic const struct usb_device_id id_table[] = { 23262306a36Sopenharmony_ci { USB_DEVICE(EMI62_VENDOR_ID, EMI62_PRODUCT_ID) }, 23362306a36Sopenharmony_ci { } /* Terminating entry */ 23462306a36Sopenharmony_ci}; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ciMODULE_DEVICE_TABLE (usb, id_table); 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_cistatic int emi62_probe(struct usb_interface *intf, const struct usb_device_id *id) 23962306a36Sopenharmony_ci{ 24062306a36Sopenharmony_ci struct usb_device *dev = interface_to_usbdev(intf); 24162306a36Sopenharmony_ci dev_dbg(&intf->dev, "emi62_probe\n"); 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci dev_info(&intf->dev, "%s start\n", __func__); 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci emi62_load_firmware(dev); 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci /* do not return the driver context, let real audio driver do that */ 24862306a36Sopenharmony_ci return -EIO; 24962306a36Sopenharmony_ci} 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_cistatic void emi62_disconnect(struct usb_interface *intf) 25262306a36Sopenharmony_ci{ 25362306a36Sopenharmony_ci} 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_cistatic struct usb_driver emi62_driver = { 25662306a36Sopenharmony_ci .name = "emi62 - firmware loader", 25762306a36Sopenharmony_ci .probe = emi62_probe, 25862306a36Sopenharmony_ci .disconnect = emi62_disconnect, 25962306a36Sopenharmony_ci .id_table = id_table, 26062306a36Sopenharmony_ci}; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_cimodule_usb_driver(emi62_driver); 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ciMODULE_AUTHOR("Tapio Laxström"); 26562306a36Sopenharmony_ciMODULE_DESCRIPTION("Emagic EMI 6|2m firmware loader."); 26662306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ciMODULE_FIRMWARE("emi62/loader.fw"); 26962306a36Sopenharmony_ciMODULE_FIRMWARE("emi62/bitstream.fw"); 27062306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_FW); 27162306a36Sopenharmony_ci/* vi:ai:syntax=c:sw=8:ts=8:tw=80 27262306a36Sopenharmony_ci */ 273