lkml.org 
[lkml]   [2005]   [Oct]   [9]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Date
    Subject[PATCH2 5/6] isicom: Firmware loading
    Firmware loading

    Firmware loading via hotplug added.
    Cleanup firmware old-method fields in header file.

    Generated in 2.6.14-rc2-mm2 kernel version

    Signed-off-by: Jiri Slaby <xslaby@fi.muni.cz>

    ---
    drivers/char/isicom.c | 409 ++++++++++++++++++++----------------------------
    include/linux/isicom.h | 35 ----
    2 files changed, 171 insertions(+), 273 deletions(-)

    diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c
    --- a/drivers/char/isicom.c
    +++ b/drivers/char/isicom.c
    @@ -112,6 +112,7 @@
    */

    #include <linux/module.h>
    +#include <linux/firmware.h>
    #include <linux/kernel.h>
    #include <linux/tty.h>
    #include <linux/tty_flip.h>
    @@ -120,7 +121,6 @@
    #include <linux/sched.h>
    #include <linux/serial.h>
    #include <linux/mm.h>
    -#include <linux/miscdevice.h>
    #include <linux/interrupt.h>
    #include <linux/timer.h>
    #include <linux/delay.h>
    @@ -175,8 +175,6 @@ static struct tty_driver *isicom_normal;
    static struct timer_list tx;
    static char re_schedule = 1;

    -static int ISILoad_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg);
    -
    static void isicom_tx(unsigned long _data);
    static void isicom_start(struct tty_struct *tty);

    @@ -385,233 +383,6 @@ static inline void kill_queue(struct isi
    unlock_card(card);
    }

    -
    -/*
    - * Firmware loader driver specific routines. This needs to mostly die
    - * and be replaced with request_firmware.
    - */
    -
    -static struct file_operations ISILoad_fops = {
    - .owner = THIS_MODULE,
    - .ioctl = ISILoad_ioctl,
    -};
    -
    -static struct miscdevice isiloader_device = {
    - ISILOAD_MISC_MINOR, "isictl", &ISILoad_fops
    -};
    -
    -
    -static inline int WaitTillCardIsFree(u16 base)
    -{
    - unsigned long count=0;
    - while( (!(inw(base+0xe) & 0x1)) && (count++ < 6000000));
    - if (inw(base+0xe)&0x1)
    - return 0;
    - else
    - return 1;
    -}
    -
    -static int ISILoad_ioctl(struct inode *inode, struct file *filp,
    - unsigned int cmd, unsigned long arg)
    -{
    - unsigned int card, i, j, signature, status, portcount = 0;
    - unsigned long t;
    - u16 word_count, base;
    - bin_frame frame;
    - void __user *argp = (void __user *)arg;
    - /* exec_record exec_rec; */
    -
    - if (get_user(card, (int __user *)argp))
    - return -EFAULT;
    -
    - if (card < 0 || card >= BOARD_COUNT)
    - return -ENXIO;
    -
    - base=isi_card[card].base;
    -
    - if (base==0)
    - return -ENXIO; /* disabled or not used */
    -
    - switch(cmd) {
    - case MIOCTL_RESET_CARD:
    - if (!capable(CAP_SYS_ADMIN))
    - return -EPERM;
    - printk(KERN_DEBUG "ISILoad:Resetting Card%d at 0x%x ",card+1,base);
    -
    - inw(base+0x8);
    -
    - for (t=jiffies+HZ/100;time_before(jiffies, t););
    -
    - outw(0,base+0x8); /* Reset */
    -
    - for (j=1;j<=3;j++) {
    - for (t=jiffies+HZ;time_before(jiffies, t););
    - printk(".");
    - }
    - signature=(inw(base+0x4)) & 0xff;
    - if (isi_card[card].isa) {
    -
    - if (!(inw(base+0xe) & 0x1) || (inw(base+0x2))) {
    -#ifdef ISICOM_DEBUG
    - printk("\nbase+0x2=0x%x , base+0xe=0x%x",inw(base+0x2),inw(base+0xe));
    -#endif
    - printk("\nISILoad:ISA Card%d reset failure (Possible bad I/O Port Address 0x%x).\n",card+1,base);
    - return -EIO;
    - }
    - }
    - else {
    - portcount = inw(base+0x2);
    - if (!(inw(base+0xe) & 0x1) || ((portcount!=0) && (portcount!=4) && (portcount!=8))) {
    -#ifdef ISICOM_DEBUG
    - printk("\nbase+0x2=0x%x , base+0xe=0x%x",inw(base+0x2),inw(base+0xe));
    -#endif
    - printk("\nISILoad:PCI Card%d reset failure (Possible bad I/O Port Address 0x%x).\n",card+1,base);
    - return -EIO;
    - }
    - }
    - switch(signature) {
    - case 0xa5:
    - case 0xbb:
    - case 0xdd:
    - if (isi_card[card].isa)
    - isi_card[card].port_count = 8;
    - else {
    - if (portcount == 4)
    - isi_card[card].port_count = 4;
    - else
    - isi_card[card].port_count = 8;
    - }
    - isi_card[card].shift_count = 12;
    - break;
    -
    - case 0xcc: isi_card[card].port_count = 16;
    - isi_card[card].shift_count = 11;
    - break;
    -
    - default: printk("ISILoad:Card%d reset failure (Possible bad I/O Port Address 0x%x).\n",card+1,base);
    -#ifdef ISICOM_DEBUG
    - printk("Sig=0x%x\n",signature);
    -#endif
    - return -EIO;
    - }
    - printk("-Done\n");
    - return put_user(signature,(unsigned __user *)argp);
    -
    - case MIOCTL_LOAD_FIRMWARE:
    - if (!capable(CAP_SYS_ADMIN))
    - return -EPERM;
    -
    - if (copy_from_user(&frame, argp, sizeof(bin_frame)))
    - return -EFAULT;
    -
    - if (WaitTillCardIsFree(base))
    - return -EIO;
    -
    - outw(0xf0,base); /* start upload sequence */
    - outw(0x00,base);
    - outw((frame.addr), base); /* lsb of adderess */
    -
    - word_count=(frame.count >> 1) + frame.count % 2;
    - outw(word_count, base);
    - InterruptTheCard(base);
    -
    - for (i=0;i<=0x2f;i++); /* a wee bit of delay */
    -
    - if (WaitTillCardIsFree(base))
    - return -EIO;
    -
    - if ((status=inw(base+0x4))!=0) {
    - printk(KERN_WARNING "ISILoad:Card%d rejected load header:\nAddress:0x%x \nCount:0x%x \nStatus:0x%x \n",
    - card+1, frame.addr, frame.count, status);
    - return -EIO;
    - }
    - outsw(base, (void *) frame.bin_data, word_count);
    -
    - InterruptTheCard(base);
    -
    - for (i=0;i<=0x0f;i++); /* another wee bit of delay */
    -
    - if (WaitTillCardIsFree(base))
    - return -EIO;
    -
    - if ((status=inw(base+0x4))!=0) {
    - printk(KERN_ERR "ISILoad:Card%d got out of sync.Card Status:0x%x\n",card+1, status);
    - return -EIO;
    - }
    - return 0;
    -
    - case MIOCTL_READ_FIRMWARE:
    - if (!capable(CAP_SYS_ADMIN))
    - return -EPERM;
    -
    - if (copy_from_user(&frame, argp, sizeof(bin_header)))
    - return -EFAULT;
    -
    - if (WaitTillCardIsFree(base))
    - return -EIO;
    -
    - outw(0xf1,base); /* start download sequence */
    - outw(0x00,base);
    - outw((frame.addr), base); /* lsb of adderess */
    -
    - word_count=(frame.count >> 1) + frame.count % 2;
    - outw(word_count+1, base);
    - InterruptTheCard(base);
    -
    - for (i=0;i<=0xf;i++); /* a wee bit of delay */
    -
    - if (WaitTillCardIsFree(base))
    - return -EIO;
    -
    - if ((status=inw(base+0x4))!=0) {
    - printk(KERN_WARNING "ISILoad:Card%d rejected verify header:\nAddress:0x%x \nCount:0x%x \nStatus:0x%x \n",
    - card+1, frame.addr, frame.count, status);
    - return -EIO;
    - }
    -
    - inw(base);
    - insw(base, frame.bin_data, word_count);
    - InterruptTheCard(base);
    -
    - for (i=0;i<=0x0f;i++); /* another wee bit of delay */
    -
    - if (WaitTillCardIsFree(base))
    - return -EIO;
    -
    - if ((status=inw(base+0x4))!=0) {
    - printk(KERN_ERR "ISILoad:Card%d verify got out of sync.Card Status:0x%x\n",card+1, status);
    - return -EIO;
    - }
    -
    - if (copy_to_user(argp, &frame, sizeof(bin_frame)))
    - return -EFAULT;
    - return 0;
    -
    - case MIOCTL_XFER_CTRL:
    - if (!capable(CAP_SYS_ADMIN))
    - return -EPERM;
    - if (WaitTillCardIsFree(base))
    - return -EIO;
    -
    - outw(0xf2, base);
    - outw(0x800, base);
    - outw(0x0, base);
    - outw(0x0, base);
    - InterruptTheCard(base);
    - outw(0x0, base+0x4); /* for ISI4608 cards */
    -
    - isi_card[card].status |= FIRMWARE_LOADED;
    - return 0;
    -
    - default:
    -#ifdef ISICOM_DEBUG
    - printk(KERN_DEBUG "ISILoad: Received Ioctl cmd 0x%x.\n", cmd);
    -#endif
    - return -ENOIOCTLCMD;
    - }
    -}
    -
    -
    /*
    * ISICOM Driver specific routines ...
    *
    @@ -1944,6 +1715,174 @@ end:
    return retval;
    }

    +static inline int WaitTillCardIsFree(u16 base)
    +{
    + unsigned long count=0;
    + while( (!(inw(base+0xe) & 0x1)) && (count++ < 6000000));
    + if (inw(base+0xe)&0x1)
    + return 0;
    + else
    + return 1;
    +}
    +
    +static int __devinit load_firmware(struct isi_board *board,
    + const unsigned int index, const unsigned int signature)
    +{
    + int retval = -EIO;
    + unsigned int a;
    + char *name;
    + u8 *data;
    + u16 word_count, status, base = board->base;
    + const struct firmware *fw;
    + struct stframe {
    + u16 addr;
    + u16 count;
    + u8 data[0];
    + } *frame;
    +
    + switch (signature) {
    + case 0xa5:
    + name = "isi608.bin";
    + break;
    + case 0xbb:
    + name = "isi608em.bin";
    + break;
    + case 0xcc:
    + name = "isi616em.bin";
    + break;
    + case 0xdd:
    + name = "isi4608.bin";
    + break;
    + case 0xee:
    + name = "isi4616.bin";
    + break;
    + default:
    + printk(KERN_ERR "Unknown signature.\n");
    + goto end;
    + }
    +
    + retval = request_firmware(&fw, name, &board->device);
    + if (retval)
    + goto end;
    +
    + for (frame = (struct stframe*)fw->data;
    + frame < (struct stframe*)(fw->data + fw->size);
    + frame++) {
    + if (WaitTillCardIsFree(base))
    + goto errrelfw;
    +
    + outw(0xf0, base); /* start upload sequence */
    + outw(0x00, base);
    + outw(frame->addr, base); /* lsb of address */
    +
    + word_count = frame->count / 2 + frame->count % 2;
    + outw(word_count, base);
    + InterruptTheCard(base);
    +
    + udelay(100); /* 0x2f */
    +
    + if (WaitTillCardIsFree(base))
    + goto errrelfw;
    +
    + if ((status = inw(base + 0x4)) != 0) {
    + printk(KERN_WARNING "ISILoad:Card%d rejected load "
    + "header:\nAddress:0x%x \nCount:0x%x \n"
    + "Status:0x%x \n", index + 1, frame->addr,
    + frame->count, status);
    + goto errrelfw;
    + }
    + outsw(base, frame->data, word_count);
    +
    + InterruptTheCard(base);
    +
    + udelay(50); /* 0x0f */
    +
    + if (WaitTillCardIsFree(base))
    + goto errrelfw;
    +
    + if ((status = inw(base + 0x4)) != 0) {
    + printk(KERN_ERR "ISILoad:Card%d got out of sync.Card "
    + "Status:0x%x\n", index + 1, status);
    + goto errrelfw;
    + }
    + }
    +
    + retval = -EIO;
    +
    + if (WaitTillCardIsFree(base))
    + goto errrelfw;
    +
    + outw(0xf2, base);
    + outw(0x800, base);
    + outw(0x0, base);
    + outw(0x0, base);
    + InterruptTheCard(base);
    + outw(0x0, base + 0x4); /* for ISI4608 cards */
    +
    +/* XXX: should we test it by reading it back and comparing with original like
    + * in load firmware package? */
    + for (frame = (struct stframe*)fw->data;
    + frame < (struct stframe*)(fw->data + fw->size);
    + frame++) {
    + if (WaitTillCardIsFree(base))
    + goto errrelfw;
    +
    + outw(0xf1, base); /* start download sequence */
    + outw(0x00, base);
    + outw(frame->addr, base); /* lsb of address */
    +
    + word_count = (frame->count >> 1) + frame->count % 2;
    + outw(word_count + 1, base);
    + InterruptTheCard(base);
    +
    + udelay(50); /* 0xf */
    +
    + if (WaitTillCardIsFree(base))
    + goto errrelfw;
    +
    + if ((status = inw(base + 0x4)) != 0) {
    + printk(KERN_WARNING "ISILoad:Card%d rejected verify "
    + "header:\nAddress:0x%x \nCount:0x%x\nStatus: "
    + "0x%x \n", index + 1, frame->addr, frame->count,
    + status);
    + goto errrelfw;
    + }
    +
    + data = kmalloc(word_count * 2, GFP_KERNEL);
    + inw(base);
    + insw(base, data, word_count);
    + InterruptTheCard(base);
    +
    + for (a = 0; a < frame->count; a++)
    + if (data[a] != frame->data[a]) {
    + kfree(data);
    + printk(KERN_ERR "ISILoad:Card%d, firmware "
    + "upload failed\n", index + 1);
    + goto errrelfw;
    + }
    + kfree(data);
    +
    + udelay(50); /* 0xf */
    +
    + if (WaitTillCardIsFree(base))
    + goto errrelfw;
    +
    + if ((status = inw(base + 0x4)) != 0) {
    + printk(KERN_ERR "ISILoad:Card%d verify got out of "
    + "sync. Card Status:0x%x\n", index + 1, status);
    + goto errrelfw;
    + }
    + }
    +
    + board->status |= FIRMWARE_LOADED;
    + retval = 0;
    +
    +errrelfw:
    + release_firmware(fw);
    +end:
    + return retval;
    +}
    +
    /*
    * Insmod can set static symbols so keep these static
    */
    @@ -1992,9 +1931,9 @@ static int __devinit isicom_probe(struct
    if (retval < 0)
    goto errunri;

    -/* retval = load_firmware(board, index, signature);
    + retval = load_firmware(board, index, signature);
    if (retval < 0)
    - goto errunri; */
    + goto errunri;

    return 0;

    @@ -2081,10 +2020,6 @@ static int __devinit isicom_setup(void)
    goto errtty;
    }

    - retval = misc_register(&isiloader_device);
    - if (retval < 0)
    - goto errpci;
    -
    init_timer(&tx);
    tx.expires = jiffies + 1;
    tx.data = 0;
    @@ -2093,8 +2028,6 @@ static int __devinit isicom_setup(void)
    add_timer(&tx);

    return 0;
    -errpci:
    - pci_unregister_driver(&isicom_driver);
    errtty:
    isicom_unregister_tty_driver();
    error:
    diff --git a/include/linux/isicom.h b/include/linux/isicom.h
    --- a/include/linux/isicom.h
    +++ b/include/linux/isicom.h
    @@ -4,46 +4,11 @@
    /*#define ISICOM_DEBUG*/
    /*#define ISICOM_DEBUG_DTR_RTS*/

    -
    -/*
    - * Firmware Loader definitions ...
    - */
    -
    -#define __MultiTech ('M'<<8)
    -#define MIOCTL_LOAD_FIRMWARE (__MultiTech | 0x01)
    -#define MIOCTL_READ_FIRMWARE (__MultiTech | 0x02)
    -#define MIOCTL_XFER_CTRL (__MultiTech | 0x03)
    -#define MIOCTL_RESET_CARD (__MultiTech | 0x04)
    -
    -#define DATA_SIZE 16
    -
    -typedef struct {
    - unsigned short exec_segment;
    - unsigned short exec_addr;
    -} exec_record;
    -
    -typedef struct {
    - int board; /* Board to load */
    - unsigned short addr;
    - unsigned short count;
    -} bin_header;
    -
    -typedef struct {
    - int board; /* Board to load */
    - unsigned short addr;
    - unsigned short count;
    - unsigned short segment;
    - unsigned char bin_data[DATA_SIZE];
    -} bin_frame;
    -
    #ifdef __KERNEL__

    #define YES 1
    #define NO 0

    -#define ISILOAD_MISC_MINOR 155 /* /dev/isctl */
    -#define ISILOAD_NAME "ISILoad"
    -
    /*
    * ISICOM Driver definitions ...
    *
    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/
    \
     
     \ /
      Last update: 2005-10-09 21:49    [W:0.046 / U:63.524 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site