|
@@ -112,6 +112,7 @@
|
|
*/
|
|
*/
|
|
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/module.h>
|
|
|
|
+#include <linux/firmware.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/tty.h>
|
|
#include <linux/tty.h>
|
|
#include <linux/tty_flip.h>
|
|
#include <linux/tty_flip.h>
|
|
@@ -120,7 +121,6 @@
|
|
#include <linux/sched.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/serial.h>
|
|
#include <linux/serial.h>
|
|
#include <linux/mm.h>
|
|
#include <linux/mm.h>
|
|
-#include <linux/miscdevice.h>
|
|
|
|
#include <linux/interrupt.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/timer.h>
|
|
#include <linux/timer.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/delay.h>
|
|
@@ -175,8 +175,6 @@ static struct tty_driver *isicom_normal;
|
|
static struct timer_list tx;
|
|
static struct timer_list tx;
|
|
static char re_schedule = 1;
|
|
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_tx(unsigned long _data);
|
|
static void isicom_start(struct tty_struct *tty);
|
|
static void isicom_start(struct tty_struct *tty);
|
|
|
|
|
|
@@ -384,233 +382,6 @@ static inline void kill_queue(struct isi_port *port, short queue)
|
|
unlock_card(card);
|
|
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(unsigned long 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, base;
|
|
|
|
- u16 word_count;
|
|
|
|
- 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%lx ",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%lx).\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%lx).\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%lx).\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 ...
|
|
* ISICOM Driver specific routines ...
|
|
*
|
|
*
|
|
@@ -1927,6 +1698,175 @@ end:
|
|
return retval;
|
|
return retval;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static inline int WaitTillCardIsFree(u16 base)
|
|
|
|
+{
|
|
|
|
+ unsigned long count = 0;
|
|
|
|
+
|
|
|
|
+ while (!(inw(base + 0xe) & 0x1) && count++ < 100)
|
|
|
|
+ msleep(5);
|
|
|
|
+
|
|
|
|
+ return !(inw(base + 0xe) & 0x1);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int __devinit load_firmware(struct pci_dev *pdev,
|
|
|
|
+ const unsigned int index, const unsigned int signature)
|
|
|
|
+{
|
|
|
|
+ struct isi_board *board = pci_get_drvdata(pdev);
|
|
|
|
+ const struct firmware *fw;
|
|
|
|
+ unsigned long base = board->base;
|
|
|
|
+ unsigned int a;
|
|
|
|
+ u16 word_count, status;
|
|
|
|
+ int retval = -EIO;
|
|
|
|
+ char *name;
|
|
|
|
+ u8 *data;
|
|
|
|
+
|
|
|
|
+ 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:
|
|
|
|
+ dev_err(&pdev->dev, "Unknown signature.\n");
|
|
|
|
+ goto end;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ retval = request_firmware(&fw, name, &pdev->dev);
|
|
|
|
+ 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) {
|
|
|
|
+ dev_warn(&pdev->dev, "Card%d rejected load header:\n"
|
|
|
|
+ "Address:0x%x\nCount:0x%x\nStatus: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) {
|
|
|
|
+ dev_err(&pdev->dev, "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) {
|
|
|
|
+ dev_warn(&pdev->dev, "Card%d rejected verify header:\n"
|
|
|
|
+ "Address: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);
|
|
|
|
+ dev_err(&pdev->dev, "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) {
|
|
|
|
+ dev_err(&pdev->dev, "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
|
|
* Insmod can set static symbols so keep these static
|
|
*/
|
|
*/
|
|
@@ -1976,6 +1916,10 @@ static int __devinit isicom_probe(struct pci_dev *pdev,
|
|
if (retval < 0)
|
|
if (retval < 0)
|
|
goto errunri;
|
|
goto errunri;
|
|
|
|
|
|
|
|
+ retval = load_firmware(pdev, index, signature);
|
|
|
|
+ if (retval < 0)
|
|
|
|
+ goto errunri;
|
|
|
|
+
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
errunri:
|
|
errunri:
|
|
@@ -2048,10 +1992,6 @@ static int __devinit isicom_setup(void)
|
|
goto errtty;
|
|
goto errtty;
|
|
}
|
|
}
|
|
|
|
|
|
- retval = misc_register(&isiloader_device);
|
|
|
|
- if (retval < 0)
|
|
|
|
- goto errpci;
|
|
|
|
-
|
|
|
|
init_timer(&tx);
|
|
init_timer(&tx);
|
|
tx.expires = jiffies + 1;
|
|
tx.expires = jiffies + 1;
|
|
tx.data = 0;
|
|
tx.data = 0;
|
|
@@ -2060,8 +2000,6 @@ static int __devinit isicom_setup(void)
|
|
add_timer(&tx);
|
|
add_timer(&tx);
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
-errpci:
|
|
|
|
- pci_unregister_driver(&isicom_driver);
|
|
|
|
errtty:
|
|
errtty:
|
|
isicom_unregister_tty_driver();
|
|
isicom_unregister_tty_driver();
|
|
error:
|
|
error:
|