linux/drivers/usb/misc/ezusb.c
<<
>>
Prefs
   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
  20struct 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
  26static 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
  35static 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
  58static 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
  68int 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}
  72EXPORT_SYMBOL_GPL(ezusb_fx1_set_reset);
  73
  74static 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);
 131out:
 132        release_firmware(firmware);
 133        return ret;
 134}
 135
 136int 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}
 141EXPORT_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 */
 148static struct ezusb_fx_type ezusb_fx2 = {
 149        .cpucs_reg = 0xE600,
 150        .max_internal_adress = 0x3FFF,
 151};
 152
 153int 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}
 157EXPORT_SYMBOL_GPL(ezusb_fx2_set_reset);
 158
 159int 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}
 164EXPORT_SYMBOL_GPL(ezusb_fx2_ihex_firmware_download);
 165#endif
 166
 167MODULE_LICENSE("GPL");
 168