1 /* 2 * EZ-USB specific functions used by some of the USB to Serial drivers. 3 * 4 * Copyright (C) 1999 - 2002 Greg Kroah-Hartman (greg@kroah.com) 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License version 8 * 2 as published by the Free Software Foundation. 9 */ 10 11 #include <linux/kernel.h> 12 #include <linux/init.h> 13 #include <linux/slab.h> 14 #include <linux/module.h> 15 #include <linux/usb.h> 16 #include <linux/firmware.h> 17 #include <linux/ihex.h> 18 #include <linux/usb/ezusb.h> 19 20 struct ezusb_fx_type { 21 /* EZ-USB Control and Status Register. Bit 0 controls 8051 reset */ 22 unsigned short cpucs_reg; 23 unsigned short max_internal_adress; 24 }; 25 26 static struct ezusb_fx_type ezusb_fx1 = { 27 .cpucs_reg = 0x7F92, 28 .max_internal_adress = 0x1B3F, 29 }; 30 31 /* Commands for writing to memory */ 32 #define WRITE_INT_RAM 0xA0 33 #define WRITE_EXT_RAM 0xA3 34 35 static int ezusb_writememory(struct usb_device *dev, int address, 36 unsigned char *data, int length, __u8 request) 37 { 38 int result; 39 unsigned char *transfer_buffer; 40 41 if (!dev) 42 return -ENODEV; 43 44 transfer_buffer = kmemdup(data, length, GFP_KERNEL); 45 if (!transfer_buffer) { 46 dev_err(&dev->dev, "%s - kmalloc(%d) failed.\n", 47 __func__, length); 48 return -ENOMEM; 49 } 50 result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), request, 51 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 52 address, 0, transfer_buffer, length, 3000); 53 54 kfree(transfer_buffer); 55 return result; 56 } 57 58 static int ezusb_set_reset(struct usb_device *dev, unsigned short cpucs_reg, 59 unsigned char reset_bit) 60 { 61 int response = ezusb_writememory(dev, cpucs_reg, &reset_bit, 1, WRITE_INT_RAM); 62 if (response < 0) 63 dev_err(&dev->dev, "%s-%d failed: %d\n", 64 __func__, reset_bit, response); 65 return response; 66 } 67 68 int ezusb_fx1_set_reset(struct usb_device *dev, unsigned char reset_bit) 69 { 70 return ezusb_set_reset(dev, ezusb_fx1.cpucs_reg, reset_bit); 71 } 72 EXPORT_SYMBOL_GPL(ezusb_fx1_set_reset); 73 74 static int ezusb_ihex_firmware_download(struct usb_device *dev, 75 struct ezusb_fx_type fx, 76 const char *firmware_path) 77 { 78 int ret = -ENOENT; 79 const struct firmware *firmware = NULL; 80 const struct ihex_binrec *record; 81 82 if (request_ihex_firmware(&firmware, firmware_path, 83 &dev->dev)) { 84 dev_err(&dev->dev, 85 "%s - request \"%s\" failed\n", 86 __func__, firmware_path); 87 goto out; 88 } 89 90 ret = ezusb_set_reset(dev, fx.cpucs_reg, 0); 91 if (ret < 0) 92 goto out; 93 94 record = (const struct ihex_binrec *)firmware->data; 95 for (; record; record = ihex_next_binrec(record)) { 96 if (be32_to_cpu(record->addr) > fx.max_internal_adress) { 97 ret = ezusb_writememory(dev, be32_to_cpu(record->addr), 98 (unsigned char *)record->data, 99 be16_to_cpu(record->len), WRITE_EXT_RAM); 100 if (ret < 0) { 101 dev_err(&dev->dev, "%s - ezusb_writememory " 102 "failed writing internal memory " 103 "(%d %04X %p %d)\n", __func__, ret, 104 be32_to_cpu(record->addr), record->data, 105 be16_to_cpu(record->len)); 106 goto out; 107 } 108 } 109 } 110 111 ret = ezusb_set_reset(dev, fx.cpucs_reg, 1); 112 if (ret < 0) 113 goto out; 114 record = (const struct ihex_binrec *)firmware->data; 115 for (; record; record = ihex_next_binrec(record)) { 116 if (be32_to_cpu(record->addr) <= fx.max_internal_adress) { 117 ret = ezusb_writememory(dev, be32_to_cpu(record->addr), 118 (unsigned char *)record->data, 119 be16_to_cpu(record->len), WRITE_INT_RAM); 120 if (ret < 0) { 121 dev_err(&dev->dev, "%s - ezusb_writememory " 122 "failed writing external memory " 123 "(%d %04X %p %d)\n", __func__, ret, 124 be32_to_cpu(record->addr), record->data, 125 be16_to_cpu(record->len)); 126 goto out; 127 } 128 } 129 } 130 ret = ezusb_set_reset(dev, fx.cpucs_reg, 0); 131 out: 132 release_firmware(firmware); 133 return ret; 134 } 135 136 int ezusb_fx1_ihex_firmware_download(struct usb_device *dev, 137 const char *firmware_path) 138 { 139 return ezusb_ihex_firmware_download(dev, ezusb_fx1, firmware_path); 140 } 141 EXPORT_SYMBOL_GPL(ezusb_fx1_ihex_firmware_download); 142 143 #if 0 144 /* 145 * Once someone one needs these fx2 functions, uncomment them 146 * and add them to ezusb.h and all should be good. 147 */ 148 static struct ezusb_fx_type ezusb_fx2 = { 149 .cpucs_reg = 0xE600, 150 .max_internal_adress = 0x3FFF, 151 }; 152 153 int ezusb_fx2_set_reset(struct usb_device *dev, unsigned char reset_bit) 154 { 155 return ezusb_set_reset(dev, ezusb_fx2.cpucs_reg, reset_bit); 156 } 157 EXPORT_SYMBOL_GPL(ezusb_fx2_set_reset); 158 159 int ezusb_fx2_ihex_firmware_download(struct usb_device *dev, 160 const char *firmware_path) 161 { 162 return ezusb_ihex_firmware_download(dev, ezusb_fx2, firmware_path); 163 } 164 EXPORT_SYMBOL_GPL(ezusb_fx2_ihex_firmware_download); 165 #endif 166 167 MODULE_LICENSE("GPL"); 168