aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/isicom.c
diff options
context:
space:
mode:
authorJiri Slaby <xslaby@fi.muni.cz>2006-01-09 23:54:25 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-01-10 11:02:01 -0500
commite65c1db19fe8177fa2da53e3e0bddffe585b2d47 (patch)
tree4d1c54f559812b71c9fde79383d00db908c1fd4f /drivers/char/isicom.c
parent9ac0948b20f76d9659add91f868c57383ea1e4e5 (diff)
[PATCH] char/isicom: Firmware loading
Firmware loading via hotplug added. Cleanup firmware old-way fields in header file. Signed-off-by: Jiri Slaby <xslaby@fi.muni.cz> Cc: Greg KH <greg@kroah.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/char/isicom.c')
-rw-r--r--drivers/char/isicom.c410
1 files changed, 174 insertions, 236 deletions
diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c
index 9ef8ab301768..55a47b33ff34 100644
--- a/drivers/char/isicom.c
+++ b/drivers/char/isicom.c
@@ -112,6 +112,7 @@
112 */ 112 */
113 113
114#include <linux/module.h> 114#include <linux/module.h>
115#include <linux/firmware.h>
115#include <linux/kernel.h> 116#include <linux/kernel.h>
116#include <linux/tty.h> 117#include <linux/tty.h>
117#include <linux/tty_flip.h> 118#include <linux/tty_flip.h>
@@ -120,7 +121,6 @@
120#include <linux/sched.h> 121#include <linux/sched.h>
121#include <linux/serial.h> 122#include <linux/serial.h>
122#include <linux/mm.h> 123#include <linux/mm.h>
123#include <linux/miscdevice.h>
124#include <linux/interrupt.h> 124#include <linux/interrupt.h>
125#include <linux/timer.h> 125#include <linux/timer.h>
126#include <linux/delay.h> 126#include <linux/delay.h>
@@ -175,8 +175,6 @@ static struct tty_driver *isicom_normal;
175static struct timer_list tx; 175static struct timer_list tx;
176static char re_schedule = 1; 176static char re_schedule = 1;
177 177
178static int ISILoad_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg);
179
180static void isicom_tx(unsigned long _data); 178static void isicom_tx(unsigned long _data);
181static void isicom_start(struct tty_struct *tty); 179static void isicom_start(struct tty_struct *tty);
182 180
@@ -384,233 +382,6 @@ static inline void kill_queue(struct isi_port *port, short queue)
384 unlock_card(card); 382 unlock_card(card);
385} 383}
386 384
387
388/*
389 * Firmware loader driver specific routines. This needs to mostly die
390 * and be replaced with request_firmware.
391 */
392
393static struct file_operations ISILoad_fops = {
394 .owner = THIS_MODULE,
395 .ioctl = ISILoad_ioctl,
396};
397
398static struct miscdevice isiloader_device = {
399 ISILOAD_MISC_MINOR, "isictl", &ISILoad_fops
400};
401
402
403static inline int WaitTillCardIsFree(unsigned long base)
404{
405 unsigned long count=0;
406 while( (!(inw(base+0xe) & 0x1)) && (count++ < 6000000));
407 if (inw(base+0xe)&0x1)
408 return 0;
409 else
410 return 1;
411}
412
413static int ISILoad_ioctl(struct inode *inode, struct file *filp,
414 unsigned int cmd, unsigned long arg)
415{
416 unsigned int card, i, j, signature, status, portcount = 0;
417 unsigned long t, base;
418 u16 word_count;
419 bin_frame frame;
420 void __user *argp = (void __user *)arg;
421 /* exec_record exec_rec; */
422
423 if (get_user(card, (int __user *)argp))
424 return -EFAULT;
425
426 if (card < 0 || card >= BOARD_COUNT)
427 return -ENXIO;
428
429 base=isi_card[card].base;
430
431 if (base==0)
432 return -ENXIO; /* disabled or not used */
433
434 switch(cmd) {
435 case MIOCTL_RESET_CARD:
436 if (!capable(CAP_SYS_ADMIN))
437 return -EPERM;
438 printk(KERN_DEBUG "ISILoad:Resetting Card%d at 0x%lx ",card+1,base);
439
440 inw(base+0x8);
441
442 for (t=jiffies+HZ/100;time_before(jiffies, t););
443
444 outw(0,base+0x8); /* Reset */
445
446 for (j=1;j<=3;j++) {
447 for (t=jiffies+HZ;time_before(jiffies, t););
448 printk(".");
449 }
450 signature=(inw(base+0x4)) & 0xff;
451 if (isi_card[card].isa) {
452
453 if (!(inw(base+0xe) & 0x1) || (inw(base+0x2))) {
454#ifdef ISICOM_DEBUG
455 printk("\nbase+0x2=0x%x , base+0xe=0x%x",inw(base+0x2),inw(base+0xe));
456#endif
457 printk("\nISILoad:ISA Card%d reset failure (Possible bad I/O Port Address 0x%lx).\n",card+1,base);
458 return -EIO;
459 }
460 }
461 else {
462 portcount = inw(base+0x2);
463 if (!(inw(base+0xe) & 0x1) || ((portcount!=0) && (portcount!=4) && (portcount!=8))) {
464#ifdef ISICOM_DEBUG
465 printk("\nbase+0x2=0x%x , base+0xe=0x%x",inw(base+0x2),inw(base+0xe));
466#endif
467 printk("\nISILoad:PCI Card%d reset failure (Possible bad I/O Port Address 0x%lx).\n",card+1,base);
468 return -EIO;
469 }
470 }
471 switch(signature) {
472 case 0xa5:
473 case 0xbb:
474 case 0xdd:
475 if (isi_card[card].isa)
476 isi_card[card].port_count = 8;
477 else {
478 if (portcount == 4)
479 isi_card[card].port_count = 4;
480 else
481 isi_card[card].port_count = 8;
482 }
483 isi_card[card].shift_count = 12;
484 break;
485
486 case 0xcc: isi_card[card].port_count = 16;
487 isi_card[card].shift_count = 11;
488 break;
489
490 default: printk("ISILoad:Card%d reset failure (Possible bad I/O Port Address 0x%lx).\n",card+1,base);
491#ifdef ISICOM_DEBUG
492 printk("Sig=0x%x\n",signature);
493#endif
494 return -EIO;
495 }
496 printk("-Done\n");
497 return put_user(signature,(unsigned __user *)argp);
498
499 case MIOCTL_LOAD_FIRMWARE:
500 if (!capable(CAP_SYS_ADMIN))
501 return -EPERM;
502
503 if (copy_from_user(&frame, argp, sizeof(bin_frame)))
504 return -EFAULT;
505
506 if (WaitTillCardIsFree(base))
507 return -EIO;
508
509 outw(0xf0,base); /* start upload sequence */
510 outw(0x00,base);
511 outw((frame.addr), base); /* lsb of adderess */
512
513 word_count=(frame.count >> 1) + frame.count % 2;
514 outw(word_count, base);
515 InterruptTheCard(base);
516
517 for (i=0;i<=0x2f;i++); /* a wee bit of delay */
518
519 if (WaitTillCardIsFree(base))
520 return -EIO;
521
522 if ((status=inw(base+0x4))!=0) {
523 printk(KERN_WARNING "ISILoad:Card%d rejected load header:\nAddress:0x%x \nCount:0x%x \nStatus:0x%x \n",
524 card+1, frame.addr, frame.count, status);
525 return -EIO;
526 }
527 outsw(base, (void *) frame.bin_data, word_count);
528
529 InterruptTheCard(base);
530
531 for (i=0;i<=0x0f;i++); /* another wee bit of delay */
532
533 if (WaitTillCardIsFree(base))
534 return -EIO;
535
536 if ((status=inw(base+0x4))!=0) {
537 printk(KERN_ERR "ISILoad:Card%d got out of sync.Card Status:0x%x\n",card+1, status);
538 return -EIO;
539 }
540 return 0;
541
542 case MIOCTL_READ_FIRMWARE:
543 if (!capable(CAP_SYS_ADMIN))
544 return -EPERM;
545
546 if (copy_from_user(&frame, argp, sizeof(bin_header)))
547 return -EFAULT;
548
549 if (WaitTillCardIsFree(base))
550 return -EIO;
551
552 outw(0xf1,base); /* start download sequence */
553 outw(0x00,base);
554 outw((frame.addr), base); /* lsb of adderess */
555
556 word_count=(frame.count >> 1) + frame.count % 2;
557 outw(word_count+1, base);
558 InterruptTheCard(base);
559
560 for (i=0;i<=0xf;i++); /* a wee bit of delay */
561
562 if (WaitTillCardIsFree(base))
563 return -EIO;
564
565 if ((status=inw(base+0x4))!=0) {
566 printk(KERN_WARNING "ISILoad:Card%d rejected verify header:\nAddress:0x%x \nCount:0x%x \nStatus:0x%x \n",
567 card+1, frame.addr, frame.count, status);
568 return -EIO;
569 }
570
571 inw(base);
572 insw(base, frame.bin_data, word_count);
573 InterruptTheCard(base);
574
575 for (i=0;i<=0x0f;i++); /* another wee bit of delay */
576
577 if (WaitTillCardIsFree(base))
578 return -EIO;
579
580 if ((status=inw(base+0x4))!=0) {
581 printk(KERN_ERR "ISILoad:Card%d verify got out of sync.Card Status:0x%x\n",card+1, status);
582 return -EIO;
583 }
584
585 if (copy_to_user(argp, &frame, sizeof(bin_frame)))
586 return -EFAULT;
587 return 0;
588
589 case MIOCTL_XFER_CTRL:
590 if (!capable(CAP_SYS_ADMIN))
591 return -EPERM;
592 if (WaitTillCardIsFree(base))
593 return -EIO;
594
595 outw(0xf2, base);
596 outw(0x800, base);
597 outw(0x0, base);
598 outw(0x0, base);
599 InterruptTheCard(base);
600 outw(0x0, base+0x4); /* for ISI4608 cards */
601
602 isi_card[card].status |= FIRMWARE_LOADED;
603 return 0;
604
605 default:
606#ifdef ISICOM_DEBUG
607 printk(KERN_DEBUG "ISILoad: Received Ioctl cmd 0x%x.\n", cmd);
608#endif
609 return -ENOIOCTLCMD;
610 }
611}
612
613
614/* 385/*
615 * ISICOM Driver specific routines ... 386 * ISICOM Driver specific routines ...
616 * 387 *
@@ -1927,6 +1698,175 @@ end:
1927 return retval; 1698 return retval;
1928} 1699}
1929 1700
1701static inline int WaitTillCardIsFree(u16 base)
1702{
1703 unsigned long count = 0;
1704
1705 while (!(inw(base + 0xe) & 0x1) && count++ < 100)
1706 msleep(5);
1707
1708 return !(inw(base + 0xe) & 0x1);
1709}
1710
1711static int __devinit load_firmware(struct pci_dev *pdev,
1712 const unsigned int index, const unsigned int signature)
1713{
1714 struct isi_board *board = pci_get_drvdata(pdev);
1715 const struct firmware *fw;
1716 unsigned long base = board->base;
1717 unsigned int a;
1718 u16 word_count, status;
1719 int retval = -EIO;
1720 char *name;
1721 u8 *data;
1722
1723 struct stframe {
1724 u16 addr;
1725 u16 count;
1726 u8 data[0];
1727 } *frame;
1728
1729 switch (signature) {
1730 case 0xa5:
1731 name = "isi608.bin";
1732 break;
1733 case 0xbb:
1734 name = "isi608em.bin";
1735 break;
1736 case 0xcc:
1737 name = "isi616em.bin";
1738 break;
1739 case 0xdd:
1740 name = "isi4608.bin";
1741 break;
1742 case 0xee:
1743 name = "isi4616.bin";
1744 break;
1745 default:
1746 dev_err(&pdev->dev, "Unknown signature.\n");
1747 goto end;
1748 }
1749
1750 retval = request_firmware(&fw, name, &pdev->dev);
1751 if (retval)
1752 goto end;
1753
1754 for (frame = (struct stframe *)fw->data;
1755 frame < (struct stframe *)(fw->data + fw->size);
1756 frame++) {
1757 if (WaitTillCardIsFree(base))
1758 goto errrelfw;
1759
1760 outw(0xf0, base); /* start upload sequence */
1761 outw(0x00, base);
1762 outw(frame->addr, base); /* lsb of address */
1763
1764 word_count = frame->count / 2 + frame->count % 2;
1765 outw(word_count, base);
1766 InterruptTheCard(base);
1767
1768 udelay(100); /* 0x2f */
1769
1770 if (WaitTillCardIsFree(base))
1771 goto errrelfw;
1772
1773 if ((status = inw(base + 0x4)) != 0) {
1774 dev_warn(&pdev->dev, "Card%d rejected load header:\n"
1775 "Address:0x%x\nCount:0x%x\nStatus:0x%x\n",
1776 index + 1, frame->addr, frame->count, status);
1777 goto errrelfw;
1778 }
1779 outsw(base, frame->data, word_count);
1780
1781 InterruptTheCard(base);
1782
1783 udelay(50); /* 0x0f */
1784
1785 if (WaitTillCardIsFree(base))
1786 goto errrelfw;
1787
1788 if ((status = inw(base + 0x4)) != 0) {
1789 dev_err(&pdev->dev, "Card%d got out of sync.Card "
1790 "Status:0x%x\n", index + 1, status);
1791 goto errrelfw;
1792 }
1793 }
1794
1795 retval = -EIO;
1796
1797 if (WaitTillCardIsFree(base))
1798 goto errrelfw;
1799
1800 outw(0xf2, base);
1801 outw(0x800, base);
1802 outw(0x0, base);
1803 outw(0x0, base);
1804 InterruptTheCard(base);
1805 outw(0x0, base + 0x4); /* for ISI4608 cards */
1806
1807/* XXX: should we test it by reading it back and comparing with original like
1808 * in load firmware package? */
1809 for (frame = (struct stframe*)fw->data;
1810 frame < (struct stframe*)(fw->data + fw->size);
1811 frame++) {
1812 if (WaitTillCardIsFree(base))
1813 goto errrelfw;
1814
1815 outw(0xf1, base); /* start download sequence */
1816 outw(0x00, base);
1817 outw(frame->addr, base); /* lsb of address */
1818
1819 word_count = (frame->count >> 1) + frame->count % 2;
1820 outw(word_count + 1, base);
1821 InterruptTheCard(base);
1822
1823 udelay(50); /* 0xf */
1824
1825 if (WaitTillCardIsFree(base))
1826 goto errrelfw;
1827
1828 if ((status = inw(base + 0x4)) != 0) {
1829 dev_warn(&pdev->dev, "Card%d rejected verify header:\n"
1830 "Address:0x%x\nCount:0x%x\nStatus: 0x%x\n",
1831 index + 1, frame->addr, frame->count, status);
1832 goto errrelfw;
1833 }
1834
1835 data = kmalloc(word_count * 2, GFP_KERNEL);
1836 inw(base);
1837 insw(base, data, word_count);
1838 InterruptTheCard(base);
1839
1840 for (a = 0; a < frame->count; a++)
1841 if (data[a] != frame->data[a]) {
1842 kfree(data);
1843 dev_err(&pdev->dev, "Card%d, firmware upload "
1844 "failed\n", index + 1);
1845 goto errrelfw;
1846 }
1847 kfree(data);
1848
1849 udelay(50); /* 0xf */
1850
1851 if (WaitTillCardIsFree(base))
1852 goto errrelfw;
1853
1854 if ((status = inw(base + 0x4)) != 0) {
1855 dev_err(&pdev->dev, "Card%d verify got out of sync. "
1856 "Card Status:0x%x\n", index + 1, status);
1857 goto errrelfw;
1858 }
1859 }
1860
1861 board->status |= FIRMWARE_LOADED;
1862 retval = 0;
1863
1864errrelfw:
1865 release_firmware(fw);
1866end:
1867 return retval;
1868}
1869
1930/* 1870/*
1931 * Insmod can set static symbols so keep these static 1871 * Insmod can set static symbols so keep these static
1932 */ 1872 */
@@ -1976,6 +1916,10 @@ static int __devinit isicom_probe(struct pci_dev *pdev,
1976 if (retval < 0) 1916 if (retval < 0)
1977 goto errunri; 1917 goto errunri;
1978 1918
1919 retval = load_firmware(pdev, index, signature);
1920 if (retval < 0)
1921 goto errunri;
1922
1979 return 0; 1923 return 0;
1980 1924
1981errunri: 1925errunri:
@@ -2048,10 +1992,6 @@ static int __devinit isicom_setup(void)
2048 goto errtty; 1992 goto errtty;
2049 } 1993 }
2050 1994
2051 retval = misc_register(&isiloader_device);
2052 if (retval < 0)
2053 goto errpci;
2054
2055 init_timer(&tx); 1995 init_timer(&tx);
2056 tx.expires = jiffies + 1; 1996 tx.expires = jiffies + 1;
2057 tx.data = 0; 1997 tx.data = 0;
@@ -2060,8 +2000,6 @@ static int __devinit isicom_setup(void)
2060 add_timer(&tx); 2000 add_timer(&tx);
2061 2001
2062 return 0; 2002 return 0;
2063errpci:
2064 pci_unregister_driver(&isicom_driver);
2065errtty: 2003errtty:
2066 isicom_unregister_tty_driver(); 2004 isicom_unregister_tty_driver();
2067error: 2005error: