11da177e4SLinus Torvalds /* Derived from Applicom driver ac.c for SCO Unix */ 21da177e4SLinus Torvalds /* Ported by David Woodhouse, Axiom (Cambridge) Ltd. */ 31da177e4SLinus Torvalds /* dwmw2@infradead.org 30/8/98 */ 41da177e4SLinus Torvalds /* $Id: ac.c,v 1.30 2000/03/22 16:03:57 dwmw2 Exp $ */ 51da177e4SLinus Torvalds /* This module is for Linux 2.1 and 2.2 series kernels. */ 61da177e4SLinus Torvalds /*****************************************************************************/ 71da177e4SLinus Torvalds /* J PAGET 18/02/94 passage V2.4.2 ioctl avec code 2 reset to les interrupt */ 81da177e4SLinus Torvalds /* ceci pour reseter correctement apres une sortie sauvage */ 91da177e4SLinus Torvalds /* J PAGET 02/05/94 passage V2.4.3 dans le traitement de d'interruption, */ 101da177e4SLinus Torvalds /* LoopCount n'etait pas initialise a 0. */ 111da177e4SLinus Torvalds /* F LAFORSE 04/07/95 version V2.6.0 lecture bidon apres acces a une carte */ 121da177e4SLinus Torvalds /* pour liberer le bus */ 131da177e4SLinus Torvalds /* J.PAGET 19/11/95 version V2.6.1 Nombre, addresse,irq n'est plus configure */ 141da177e4SLinus Torvalds /* et passe en argument a acinit, mais est scrute sur le bus pour s'adapter */ 151da177e4SLinus Torvalds /* au nombre de cartes presentes sur le bus. IOCL code 6 affichait V2.4.3 */ 161da177e4SLinus Torvalds /* F.LAFORSE 28/11/95 creation de fichiers acXX.o avec les differentes */ 171da177e4SLinus Torvalds /* adresses de base des cartes, IOCTL 6 plus complet */ 181da177e4SLinus Torvalds /* J.PAGET le 19/08/96 copie de la version V2.6 en V2.8.0 sans modification */ 191da177e4SLinus Torvalds /* de code autre que le texte V2.6.1 en V2.8.0 */ 201da177e4SLinus Torvalds /*****************************************************************************/ 211da177e4SLinus Torvalds 221da177e4SLinus Torvalds 231da177e4SLinus Torvalds #include <linux/kernel.h> 241da177e4SLinus Torvalds #include <linux/module.h> 251da177e4SLinus Torvalds #include <linux/interrupt.h> 261da177e4SLinus Torvalds #include <linux/slab.h> 271da177e4SLinus Torvalds #include <linux/errno.h> 281da177e4SLinus Torvalds #include <linux/miscdevice.h> 291da177e4SLinus Torvalds #include <linux/pci.h> 301da177e4SLinus Torvalds #include <linux/wait.h> 311da177e4SLinus Torvalds #include <linux/init.h> 321da177e4SLinus Torvalds #include <linux/fs.h> 331da177e4SLinus Torvalds 341da177e4SLinus Torvalds #include <asm/io.h> 351da177e4SLinus Torvalds #include <asm/uaccess.h> 361da177e4SLinus Torvalds 371da177e4SLinus Torvalds #include "applicom.h" 381da177e4SLinus Torvalds 391da177e4SLinus Torvalds 401da177e4SLinus Torvalds /* NOTE: We use for loops with {write,read}b() instead of 411da177e4SLinus Torvalds memcpy_{from,to}io throughout this driver. This is because 421da177e4SLinus Torvalds the board doesn't correctly handle word accesses - only 431da177e4SLinus Torvalds bytes. 441da177e4SLinus Torvalds */ 451da177e4SLinus Torvalds 461da177e4SLinus Torvalds 471da177e4SLinus Torvalds #undef DEBUG 481da177e4SLinus Torvalds 491da177e4SLinus Torvalds #define MAX_BOARD 8 /* maximum of pc board possible */ 501da177e4SLinus Torvalds #define MAX_ISA_BOARD 4 511da177e4SLinus Torvalds #define LEN_RAM_IO 0x800 521da177e4SLinus Torvalds #define AC_MINOR 157 531da177e4SLinus Torvalds 541da177e4SLinus Torvalds #ifndef PCI_VENDOR_ID_APPLICOM 551da177e4SLinus Torvalds #define PCI_VENDOR_ID_APPLICOM 0x1389 561da177e4SLinus Torvalds #define PCI_DEVICE_ID_APPLICOM_PCIGENERIC 0x0001 571da177e4SLinus Torvalds #define PCI_DEVICE_ID_APPLICOM_PCI2000IBS_CAN 0x0002 581da177e4SLinus Torvalds #define PCI_DEVICE_ID_APPLICOM_PCI2000PFB 0x0003 591da177e4SLinus Torvalds #endif 601da177e4SLinus Torvalds 611da177e4SLinus Torvalds static char *applicom_pci_devnames[] = { 621da177e4SLinus Torvalds "PCI board", 631da177e4SLinus Torvalds "PCI2000IBS / PCI2000CAN", 641da177e4SLinus Torvalds "PCI2000PFB" 651da177e4SLinus Torvalds }; 661da177e4SLinus Torvalds 671da177e4SLinus Torvalds static struct pci_device_id applicom_pci_tbl[] = { 6853a7a1bbSJiri Slaby { PCI_VDEVICE(APPLICOM, PCI_DEVICE_ID_APPLICOM_PCIGENERIC) }, 6953a7a1bbSJiri Slaby { PCI_VDEVICE(APPLICOM, PCI_DEVICE_ID_APPLICOM_PCI2000IBS_CAN) }, 7053a7a1bbSJiri Slaby { PCI_VDEVICE(APPLICOM, PCI_DEVICE_ID_APPLICOM_PCI2000PFB) }, 711da177e4SLinus Torvalds { 0 } 721da177e4SLinus Torvalds }; 731da177e4SLinus Torvalds MODULE_DEVICE_TABLE(pci, applicom_pci_tbl); 741da177e4SLinus Torvalds 751da177e4SLinus Torvalds MODULE_AUTHOR("David Woodhouse & Applicom International"); 761da177e4SLinus Torvalds MODULE_DESCRIPTION("Driver for Applicom Profibus card"); 771da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 7814f8d3ffSScott James Remnant MODULE_ALIAS_MISCDEV(AC_MINOR); 791da177e4SLinus Torvalds 801da177e4SLinus Torvalds MODULE_SUPPORTED_DEVICE("ac"); 811da177e4SLinus Torvalds 821da177e4SLinus Torvalds 831da177e4SLinus Torvalds static struct applicom_board { 841da177e4SLinus Torvalds unsigned long PhysIO; 851da177e4SLinus Torvalds void __iomem *RamIO; 861da177e4SLinus Torvalds wait_queue_head_t FlagSleepSend; 871da177e4SLinus Torvalds long irq; 881da177e4SLinus Torvalds spinlock_t mutex; 891da177e4SLinus Torvalds } apbs[MAX_BOARD]; 901da177e4SLinus Torvalds 911da177e4SLinus Torvalds static unsigned int irq = 0; /* interrupt number IRQ */ 921da177e4SLinus Torvalds static unsigned long mem = 0; /* physical segment of board */ 931da177e4SLinus Torvalds 941da177e4SLinus Torvalds module_param(irq, uint, 0); 951da177e4SLinus Torvalds MODULE_PARM_DESC(irq, "IRQ of the Applicom board"); 961da177e4SLinus Torvalds module_param(mem, ulong, 0); 971da177e4SLinus Torvalds MODULE_PARM_DESC(mem, "Shared Memory Address of Applicom board"); 981da177e4SLinus Torvalds 991da177e4SLinus Torvalds static unsigned int numboards; /* number of installed boards */ 1001da177e4SLinus Torvalds static volatile unsigned char Dummy; 1011da177e4SLinus Torvalds static DECLARE_WAIT_QUEUE_HEAD(FlagSleepRec); 1021da177e4SLinus Torvalds static unsigned int WriteErrorCount; /* number of write error */ 1031da177e4SLinus Torvalds static unsigned int ReadErrorCount; /* number of read error */ 1041da177e4SLinus Torvalds static unsigned int DeviceErrorCount; /* number of device error */ 1051da177e4SLinus Torvalds 1061da177e4SLinus Torvalds static ssize_t ac_read (struct file *, char __user *, size_t, loff_t *); 1071da177e4SLinus Torvalds static ssize_t ac_write (struct file *, const char __user *, size_t, loff_t *); 1081da177e4SLinus Torvalds static int ac_ioctl(struct inode *, struct file *, unsigned int, 1091da177e4SLinus Torvalds unsigned long); 1107d12e780SDavid Howells static irqreturn_t ac_interrupt(int, void *); 1111da177e4SLinus Torvalds 11262322d25SArjan van de Ven static const struct file_operations ac_fops = { 1131da177e4SLinus Torvalds .owner = THIS_MODULE, 1141da177e4SLinus Torvalds .llseek = no_llseek, 1151da177e4SLinus Torvalds .read = ac_read, 1161da177e4SLinus Torvalds .write = ac_write, 1171da177e4SLinus Torvalds .ioctl = ac_ioctl, 1181da177e4SLinus Torvalds }; 1191da177e4SLinus Torvalds 1201da177e4SLinus Torvalds static struct miscdevice ac_miscdev = { 1211da177e4SLinus Torvalds AC_MINOR, 1221da177e4SLinus Torvalds "ac", 1231da177e4SLinus Torvalds &ac_fops 1241da177e4SLinus Torvalds }; 1251da177e4SLinus Torvalds 1261da177e4SLinus Torvalds static int dummy; /* dev_id for request_irq() */ 1271da177e4SLinus Torvalds 1281da177e4SLinus Torvalds static int ac_register_board(unsigned long physloc, void __iomem *loc, 1291da177e4SLinus Torvalds unsigned char boardno) 1301da177e4SLinus Torvalds { 1311da177e4SLinus Torvalds volatile unsigned char byte_reset_it; 1321da177e4SLinus Torvalds 1331da177e4SLinus Torvalds if((readb(loc + CONF_END_TEST) != 0x00) || 1341da177e4SLinus Torvalds (readb(loc + CONF_END_TEST + 1) != 0x55) || 1351da177e4SLinus Torvalds (readb(loc + CONF_END_TEST + 2) != 0xAA) || 1361da177e4SLinus Torvalds (readb(loc + CONF_END_TEST + 3) != 0xFF)) 1371da177e4SLinus Torvalds return 0; 1381da177e4SLinus Torvalds 1391da177e4SLinus Torvalds if (!boardno) 1401da177e4SLinus Torvalds boardno = readb(loc + NUMCARD_OWNER_TO_PC); 1411da177e4SLinus Torvalds 142e60b6e2fSEric Sesterhenn if (!boardno || boardno > MAX_BOARD) { 1431da177e4SLinus Torvalds printk(KERN_WARNING "Board #%d (at 0x%lx) is out of range (1 <= x <= %d).\n", 1441da177e4SLinus Torvalds boardno, physloc, MAX_BOARD); 1451da177e4SLinus Torvalds return 0; 1461da177e4SLinus Torvalds } 1471da177e4SLinus Torvalds 1481da177e4SLinus Torvalds if (apbs[boardno - 1].RamIO) { 1491da177e4SLinus Torvalds printk(KERN_WARNING "Board #%d (at 0x%lx) conflicts with previous board #%d (at 0x%lx)\n", 1501da177e4SLinus Torvalds boardno, physloc, boardno, apbs[boardno-1].PhysIO); 1511da177e4SLinus Torvalds return 0; 1521da177e4SLinus Torvalds } 1531da177e4SLinus Torvalds 1541da177e4SLinus Torvalds boardno--; 1551da177e4SLinus Torvalds 1561da177e4SLinus Torvalds apbs[boardno].PhysIO = physloc; 1571da177e4SLinus Torvalds apbs[boardno].RamIO = loc; 1581da177e4SLinus Torvalds init_waitqueue_head(&apbs[boardno].FlagSleepSend); 1591da177e4SLinus Torvalds spin_lock_init(&apbs[boardno].mutex); 1601da177e4SLinus Torvalds byte_reset_it = readb(loc + RAM_IT_TO_PC); 1611da177e4SLinus Torvalds 1621da177e4SLinus Torvalds numboards++; 1631da177e4SLinus Torvalds return boardno + 1; 1641da177e4SLinus Torvalds } 1651da177e4SLinus Torvalds 1662e611390SAdrian Bunk static void __exit applicom_exit(void) 1671da177e4SLinus Torvalds { 168819a3ebaSChristophe Lucas unsigned int i; 1691da177e4SLinus Torvalds 1701da177e4SLinus Torvalds misc_deregister(&ac_miscdev); 1711da177e4SLinus Torvalds 1721da177e4SLinus Torvalds for (i = 0; i < MAX_BOARD; i++) { 1731da177e4SLinus Torvalds 1741da177e4SLinus Torvalds if (!apbs[i].RamIO) 1751da177e4SLinus Torvalds continue; 1761da177e4SLinus Torvalds 1771da177e4SLinus Torvalds if (apbs[i].irq) 1781da177e4SLinus Torvalds free_irq(apbs[i].irq, &dummy); 1791da177e4SLinus Torvalds 1801da177e4SLinus Torvalds iounmap(apbs[i].RamIO); 1811da177e4SLinus Torvalds } 1821da177e4SLinus Torvalds } 1831da177e4SLinus Torvalds 1842e611390SAdrian Bunk static int __init applicom_init(void) 1851da177e4SLinus Torvalds { 1861da177e4SLinus Torvalds int i, numisa = 0; 1871da177e4SLinus Torvalds struct pci_dev *dev = NULL; 1881da177e4SLinus Torvalds void __iomem *RamIO; 189819a3ebaSChristophe Lucas int boardno, ret; 1901da177e4SLinus Torvalds 1911da177e4SLinus Torvalds printk(KERN_INFO "Applicom driver: $Id: ac.c,v 1.30 2000/03/22 16:03:57 dwmw2 Exp $\n"); 1921da177e4SLinus Torvalds 1931da177e4SLinus Torvalds /* No mem and irq given - check for a PCI card */ 1941da177e4SLinus Torvalds 1951da177e4SLinus Torvalds while ( (dev = pci_get_class(PCI_CLASS_OTHERS << 16, dev))) { 1961da177e4SLinus Torvalds 19753a7a1bbSJiri Slaby if (!pci_match_id(applicom_pci_tbl, dev)) 1981da177e4SLinus Torvalds continue; 1991da177e4SLinus Torvalds 2001da177e4SLinus Torvalds if (pci_enable_device(dev)) 2011da177e4SLinus Torvalds return -EIO; 2021da177e4SLinus Torvalds 20324cb2335SAlan Cox RamIO = ioremap_nocache(pci_resource_start(dev, 0), LEN_RAM_IO); 2041da177e4SLinus Torvalds 2051da177e4SLinus Torvalds if (!RamIO) { 206e29419ffSGreg Kroah-Hartman printk(KERN_INFO "ac.o: Failed to ioremap PCI memory " 207e29419ffSGreg Kroah-Hartman "space at 0x%llx\n", 20855b29a72SJiri Slaby (unsigned long long)pci_resource_start(dev, 0)); 2091da177e4SLinus Torvalds pci_disable_device(dev); 2101da177e4SLinus Torvalds return -EIO; 2111da177e4SLinus Torvalds } 2121da177e4SLinus Torvalds 213e29419ffSGreg Kroah-Hartman printk(KERN_INFO "Applicom %s found at mem 0x%llx, irq %d\n", 214e29419ffSGreg Kroah-Hartman applicom_pci_devnames[dev->device-1], 21555b29a72SJiri Slaby (unsigned long long)pci_resource_start(dev, 0), 2161da177e4SLinus Torvalds dev->irq); 2171da177e4SLinus Torvalds 21855b29a72SJiri Slaby boardno = ac_register_board(pci_resource_start(dev, 0), 21955b29a72SJiri Slaby RamIO, 0); 2201da177e4SLinus Torvalds if (!boardno) { 2211da177e4SLinus Torvalds printk(KERN_INFO "ac.o: PCI Applicom device doesn't have correct signature.\n"); 2221da177e4SLinus Torvalds iounmap(RamIO); 2231da177e4SLinus Torvalds pci_disable_device(dev); 2241da177e4SLinus Torvalds continue; 2251da177e4SLinus Torvalds } 2261da177e4SLinus Torvalds 2270f2ed4c6SThomas Gleixner if (request_irq(dev->irq, &ac_interrupt, IRQF_SHARED, "Applicom PCI", &dummy)) { 2281da177e4SLinus Torvalds printk(KERN_INFO "Could not allocate IRQ %d for PCI Applicom device.\n", dev->irq); 2291da177e4SLinus Torvalds iounmap(RamIO); 2301da177e4SLinus Torvalds pci_disable_device(dev); 2311da177e4SLinus Torvalds apbs[boardno - 1].RamIO = NULL; 2321da177e4SLinus Torvalds continue; 2331da177e4SLinus Torvalds } 2341da177e4SLinus Torvalds 2351da177e4SLinus Torvalds /* Enable interrupts. */ 2361da177e4SLinus Torvalds 2371da177e4SLinus Torvalds writeb(0x40, apbs[boardno - 1].RamIO + RAM_IT_FROM_PC); 2381da177e4SLinus Torvalds 2391da177e4SLinus Torvalds apbs[boardno - 1].irq = dev->irq; 2401da177e4SLinus Torvalds } 2411da177e4SLinus Torvalds 2421da177e4SLinus Torvalds /* Finished with PCI cards. If none registered, 2431da177e4SLinus Torvalds * and there was no mem/irq specified, exit */ 2441da177e4SLinus Torvalds 2451da177e4SLinus Torvalds if (!mem || !irq) { 2461da177e4SLinus Torvalds if (numboards) 2471da177e4SLinus Torvalds goto fin; 2481da177e4SLinus Torvalds else { 2491da177e4SLinus Torvalds printk(KERN_INFO "ac.o: No PCI boards found.\n"); 2501da177e4SLinus Torvalds printk(KERN_INFO "ac.o: For an ISA board you must supply memory and irq parameters.\n"); 2511da177e4SLinus Torvalds return -ENXIO; 2521da177e4SLinus Torvalds } 2531da177e4SLinus Torvalds } 2541da177e4SLinus Torvalds 2551da177e4SLinus Torvalds /* Now try the specified ISA cards */ 2561da177e4SLinus Torvalds 2571da177e4SLinus Torvalds for (i = 0; i < MAX_ISA_BOARD; i++) { 25824cb2335SAlan Cox RamIO = ioremap_nocache(mem + (LEN_RAM_IO * i), LEN_RAM_IO); 2591da177e4SLinus Torvalds 2601da177e4SLinus Torvalds if (!RamIO) { 2611da177e4SLinus Torvalds printk(KERN_INFO "ac.o: Failed to ioremap the ISA card's memory space (slot #%d)\n", i + 1); 2621da177e4SLinus Torvalds continue; 2631da177e4SLinus Torvalds } 2641da177e4SLinus Torvalds 2651da177e4SLinus Torvalds if (!(boardno = ac_register_board((unsigned long)mem+ (LEN_RAM_IO*i), 2661da177e4SLinus Torvalds RamIO,i+1))) { 2671da177e4SLinus Torvalds iounmap(RamIO); 2681da177e4SLinus Torvalds continue; 2691da177e4SLinus Torvalds } 2701da177e4SLinus Torvalds 2711da177e4SLinus Torvalds printk(KERN_NOTICE "Applicom ISA card found at mem 0x%lx, irq %d\n", mem + (LEN_RAM_IO*i), irq); 2721da177e4SLinus Torvalds 2731da177e4SLinus Torvalds if (!numisa) { 2740f2ed4c6SThomas Gleixner if (request_irq(irq, &ac_interrupt, IRQF_SHARED, "Applicom ISA", &dummy)) { 2751da177e4SLinus Torvalds printk(KERN_WARNING "Could not allocate IRQ %d for ISA Applicom device.\n", irq); 2761da177e4SLinus Torvalds iounmap(RamIO); 2771da177e4SLinus Torvalds apbs[boardno - 1].RamIO = NULL; 2781da177e4SLinus Torvalds } 2791da177e4SLinus Torvalds else 2801da177e4SLinus Torvalds apbs[boardno - 1].irq = irq; 2811da177e4SLinus Torvalds } 2821da177e4SLinus Torvalds else 2831da177e4SLinus Torvalds apbs[boardno - 1].irq = 0; 2841da177e4SLinus Torvalds 2851da177e4SLinus Torvalds numisa++; 2861da177e4SLinus Torvalds } 2871da177e4SLinus Torvalds 2881da177e4SLinus Torvalds if (!numisa) 289819a3ebaSChristophe Lucas printk(KERN_WARNING "ac.o: No valid ISA Applicom boards found " 290819a3ebaSChristophe Lucas "at mem 0x%lx\n", mem); 2911da177e4SLinus Torvalds 2921da177e4SLinus Torvalds fin: 2931da177e4SLinus Torvalds init_waitqueue_head(&FlagSleepRec); 2941da177e4SLinus Torvalds 2951da177e4SLinus Torvalds WriteErrorCount = 0; 2961da177e4SLinus Torvalds ReadErrorCount = 0; 2971da177e4SLinus Torvalds DeviceErrorCount = 0; 2981da177e4SLinus Torvalds 2991da177e4SLinus Torvalds if (numboards) { 300819a3ebaSChristophe Lucas ret = misc_register(&ac_miscdev); 301819a3ebaSChristophe Lucas if (ret) { 302819a3ebaSChristophe Lucas printk(KERN_WARNING "ac.o: Unable to register misc device\n"); 303819a3ebaSChristophe Lucas goto out; 304819a3ebaSChristophe Lucas } 3051da177e4SLinus Torvalds for (i = 0; i < MAX_BOARD; i++) { 3061da177e4SLinus Torvalds int serial; 3071da177e4SLinus Torvalds char boardname[(SERIAL_NUMBER - TYPE_CARD) + 1]; 3081da177e4SLinus Torvalds 3091da177e4SLinus Torvalds if (!apbs[i].RamIO) 3101da177e4SLinus Torvalds continue; 3111da177e4SLinus Torvalds 3121da177e4SLinus Torvalds for (serial = 0; serial < SERIAL_NUMBER - TYPE_CARD; serial++) 3131da177e4SLinus Torvalds boardname[serial] = readb(apbs[i].RamIO + TYPE_CARD + serial); 3141da177e4SLinus Torvalds 3151da177e4SLinus Torvalds boardname[serial] = 0; 3161da177e4SLinus Torvalds 3171da177e4SLinus Torvalds 3181da177e4SLinus Torvalds printk(KERN_INFO "Applicom board %d: %s, PROM V%d.%d", 3191da177e4SLinus Torvalds i+1, boardname, 3201da177e4SLinus Torvalds (int)(readb(apbs[i].RamIO + VERS) >> 4), 3211da177e4SLinus Torvalds (int)(readb(apbs[i].RamIO + VERS) & 0xF)); 3221da177e4SLinus Torvalds 3231da177e4SLinus Torvalds serial = (readb(apbs[i].RamIO + SERIAL_NUMBER) << 16) + 3241da177e4SLinus Torvalds (readb(apbs[i].RamIO + SERIAL_NUMBER + 1) << 8) + 3251da177e4SLinus Torvalds (readb(apbs[i].RamIO + SERIAL_NUMBER + 2) ); 3261da177e4SLinus Torvalds 3271da177e4SLinus Torvalds if (serial != 0) 3281da177e4SLinus Torvalds printk(" S/N %d\n", serial); 3291da177e4SLinus Torvalds else 3301da177e4SLinus Torvalds printk("\n"); 3311da177e4SLinus Torvalds } 3321da177e4SLinus Torvalds return 0; 3331da177e4SLinus Torvalds } 3341da177e4SLinus Torvalds 3351da177e4SLinus Torvalds else 3361da177e4SLinus Torvalds return -ENXIO; 337819a3ebaSChristophe Lucas 338819a3ebaSChristophe Lucas out: 339819a3ebaSChristophe Lucas for (i = 0; i < MAX_BOARD; i++) { 340819a3ebaSChristophe Lucas if (!apbs[i].RamIO) 341819a3ebaSChristophe Lucas continue; 342819a3ebaSChristophe Lucas if (apbs[i].irq) 343819a3ebaSChristophe Lucas free_irq(apbs[i].irq, &dummy); 344819a3ebaSChristophe Lucas iounmap(apbs[i].RamIO); 345819a3ebaSChristophe Lucas } 346819a3ebaSChristophe Lucas pci_disable_device(dev); 347819a3ebaSChristophe Lucas return ret; 3481da177e4SLinus Torvalds } 3491da177e4SLinus Torvalds 3502e611390SAdrian Bunk module_init(applicom_init); 3512e611390SAdrian Bunk module_exit(applicom_exit); 3521da177e4SLinus Torvalds 3531da177e4SLinus Torvalds 3541da177e4SLinus Torvalds static ssize_t ac_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos) 3551da177e4SLinus Torvalds { 3561da177e4SLinus Torvalds unsigned int NumCard; /* Board number 1 -> 8 */ 3571da177e4SLinus Torvalds unsigned int IndexCard; /* Index board number 0 -> 7 */ 3581da177e4SLinus Torvalds unsigned char TicCard; /* Board TIC to send */ 3591da177e4SLinus Torvalds unsigned long flags; /* Current priority */ 3601da177e4SLinus Torvalds struct st_ram_io st_loc; 3611da177e4SLinus Torvalds struct mailbox tmpmailbox; 3621da177e4SLinus Torvalds #ifdef DEBUG 3631da177e4SLinus Torvalds int c; 3641da177e4SLinus Torvalds #endif 3651da177e4SLinus Torvalds DECLARE_WAITQUEUE(wait, current); 3661da177e4SLinus Torvalds 3671da177e4SLinus Torvalds if (count != sizeof(struct st_ram_io) + sizeof(struct mailbox)) { 3681da177e4SLinus Torvalds static int warncount = 5; 3691da177e4SLinus Torvalds if (warncount) { 3701da177e4SLinus Torvalds printk(KERN_INFO "Hmmm. write() of Applicom card, length %zd != expected %zd\n", 3711da177e4SLinus Torvalds count, sizeof(struct st_ram_io) + sizeof(struct mailbox)); 3721da177e4SLinus Torvalds warncount--; 3731da177e4SLinus Torvalds } 3741da177e4SLinus Torvalds return -EINVAL; 3751da177e4SLinus Torvalds } 3761da177e4SLinus Torvalds 3771da177e4SLinus Torvalds if(copy_from_user(&st_loc, buf, sizeof(struct st_ram_io))) 3781da177e4SLinus Torvalds return -EFAULT; 3791da177e4SLinus Torvalds 3801da177e4SLinus Torvalds if(copy_from_user(&tmpmailbox, &buf[sizeof(struct st_ram_io)], 3811da177e4SLinus Torvalds sizeof(struct mailbox))) 3821da177e4SLinus Torvalds return -EFAULT; 3831da177e4SLinus Torvalds 3841da177e4SLinus Torvalds NumCard = st_loc.num_card; /* board number to send */ 3851da177e4SLinus Torvalds TicCard = st_loc.tic_des_from_pc; /* tic number to send */ 3861da177e4SLinus Torvalds IndexCard = NumCard - 1; 3871da177e4SLinus Torvalds 3881da177e4SLinus Torvalds if((NumCard < 1) || (NumCard > MAX_BOARD) || !apbs[IndexCard].RamIO) 3891da177e4SLinus Torvalds return -EINVAL; 3901da177e4SLinus Torvalds 3911da177e4SLinus Torvalds #ifdef DEBUG 3921da177e4SLinus Torvalds printk("Write to applicom card #%d. struct st_ram_io follows:", 3931da177e4SLinus Torvalds IndexCard+1); 3941da177e4SLinus Torvalds 3951da177e4SLinus Torvalds for (c = 0; c < sizeof(struct st_ram_io);) { 3961da177e4SLinus Torvalds 3971da177e4SLinus Torvalds printk("\n%5.5X: %2.2X", c, ((unsigned char *) &st_loc)[c]); 3981da177e4SLinus Torvalds 3991da177e4SLinus Torvalds for (c++; c % 8 && c < sizeof(struct st_ram_io); c++) { 4001da177e4SLinus Torvalds printk(" %2.2X", ((unsigned char *) &st_loc)[c]); 4011da177e4SLinus Torvalds } 4021da177e4SLinus Torvalds } 4031da177e4SLinus Torvalds 4041da177e4SLinus Torvalds printk("\nstruct mailbox follows:"); 4051da177e4SLinus Torvalds 4061da177e4SLinus Torvalds for (c = 0; c < sizeof(struct mailbox);) { 4071da177e4SLinus Torvalds printk("\n%5.5X: %2.2X", c, ((unsigned char *) &tmpmailbox)[c]); 4081da177e4SLinus Torvalds 4091da177e4SLinus Torvalds for (c++; c % 8 && c < sizeof(struct mailbox); c++) { 4101da177e4SLinus Torvalds printk(" %2.2X", ((unsigned char *) &tmpmailbox)[c]); 4111da177e4SLinus Torvalds } 4121da177e4SLinus Torvalds } 4131da177e4SLinus Torvalds 4141da177e4SLinus Torvalds printk("\n"); 4151da177e4SLinus Torvalds #endif 4161da177e4SLinus Torvalds 4171da177e4SLinus Torvalds spin_lock_irqsave(&apbs[IndexCard].mutex, flags); 4181da177e4SLinus Torvalds 4191da177e4SLinus Torvalds /* Test octet ready correct */ 4201da177e4SLinus Torvalds if(readb(apbs[IndexCard].RamIO + DATA_FROM_PC_READY) > 2) { 4211da177e4SLinus Torvalds Dummy = readb(apbs[IndexCard].RamIO + VERS); 4221da177e4SLinus Torvalds spin_unlock_irqrestore(&apbs[IndexCard].mutex, flags); 4231da177e4SLinus Torvalds printk(KERN_WARNING "APPLICOM driver write error board %d, DataFromPcReady = %d\n", 4241da177e4SLinus Torvalds IndexCard,(int)readb(apbs[IndexCard].RamIO + DATA_FROM_PC_READY)); 4251da177e4SLinus Torvalds DeviceErrorCount++; 4261da177e4SLinus Torvalds return -EIO; 4271da177e4SLinus Torvalds } 4281da177e4SLinus Torvalds 4291da177e4SLinus Torvalds /* Place ourselves on the wait queue */ 4301da177e4SLinus Torvalds set_current_state(TASK_INTERRUPTIBLE); 4311da177e4SLinus Torvalds add_wait_queue(&apbs[IndexCard].FlagSleepSend, &wait); 4321da177e4SLinus Torvalds 4331da177e4SLinus Torvalds /* Check whether the card is ready for us */ 4341da177e4SLinus Torvalds while (readb(apbs[IndexCard].RamIO + DATA_FROM_PC_READY) != 0) { 4351da177e4SLinus Torvalds Dummy = readb(apbs[IndexCard].RamIO + VERS); 4361da177e4SLinus Torvalds /* It's busy. Sleep. */ 4371da177e4SLinus Torvalds 4381da177e4SLinus Torvalds spin_unlock_irqrestore(&apbs[IndexCard].mutex, flags); 4391da177e4SLinus Torvalds schedule(); 4401da177e4SLinus Torvalds if (signal_pending(current)) { 4411da177e4SLinus Torvalds remove_wait_queue(&apbs[IndexCard].FlagSleepSend, 4421da177e4SLinus Torvalds &wait); 4431da177e4SLinus Torvalds return -EINTR; 4441da177e4SLinus Torvalds } 4451da177e4SLinus Torvalds spin_lock_irqsave(&apbs[IndexCard].mutex, flags); 4461da177e4SLinus Torvalds set_current_state(TASK_INTERRUPTIBLE); 4471da177e4SLinus Torvalds } 4481da177e4SLinus Torvalds 4491da177e4SLinus Torvalds /* We may not have actually slept */ 4501da177e4SLinus Torvalds set_current_state(TASK_RUNNING); 4511da177e4SLinus Torvalds remove_wait_queue(&apbs[IndexCard].FlagSleepSend, &wait); 4521da177e4SLinus Torvalds 4531da177e4SLinus Torvalds writeb(1, apbs[IndexCard].RamIO + DATA_FROM_PC_READY); 4541da177e4SLinus Torvalds 4551da177e4SLinus Torvalds /* Which is best - lock down the pages with rawio and then 4561da177e4SLinus Torvalds copy directly, or use bounce buffers? For now we do the latter 4571da177e4SLinus Torvalds because it works with 2.2 still */ 4581da177e4SLinus Torvalds { 4591da177e4SLinus Torvalds unsigned char *from = (unsigned char *) &tmpmailbox; 4601da177e4SLinus Torvalds void __iomem *to = apbs[IndexCard].RamIO + RAM_FROM_PC; 4611da177e4SLinus Torvalds int c; 4621da177e4SLinus Torvalds 4631da177e4SLinus Torvalds for (c = 0; c < sizeof(struct mailbox); c++) 4641da177e4SLinus Torvalds writeb(*(from++), to++); 4651da177e4SLinus Torvalds } 4661da177e4SLinus Torvalds 4671da177e4SLinus Torvalds writeb(0x20, apbs[IndexCard].RamIO + TIC_OWNER_FROM_PC); 4681da177e4SLinus Torvalds writeb(0xff, apbs[IndexCard].RamIO + NUMCARD_OWNER_FROM_PC); 4691da177e4SLinus Torvalds writeb(TicCard, apbs[IndexCard].RamIO + TIC_DES_FROM_PC); 4701da177e4SLinus Torvalds writeb(NumCard, apbs[IndexCard].RamIO + NUMCARD_DES_FROM_PC); 4711da177e4SLinus Torvalds writeb(2, apbs[IndexCard].RamIO + DATA_FROM_PC_READY); 4721da177e4SLinus Torvalds writeb(1, apbs[IndexCard].RamIO + RAM_IT_FROM_PC); 4731da177e4SLinus Torvalds Dummy = readb(apbs[IndexCard].RamIO + VERS); 4741da177e4SLinus Torvalds spin_unlock_irqrestore(&apbs[IndexCard].mutex, flags); 4751da177e4SLinus Torvalds return 0; 4761da177e4SLinus Torvalds } 4771da177e4SLinus Torvalds 4781da177e4SLinus Torvalds static int do_ac_read(int IndexCard, char __user *buf, 4791da177e4SLinus Torvalds struct st_ram_io *st_loc, struct mailbox *mailbox) 4801da177e4SLinus Torvalds { 4811da177e4SLinus Torvalds void __iomem *from = apbs[IndexCard].RamIO + RAM_TO_PC; 482bc20589bSAndrew Morton unsigned char *to = (unsigned char *)mailbox; 4831da177e4SLinus Torvalds #ifdef DEBUG 4841da177e4SLinus Torvalds int c; 4851da177e4SLinus Torvalds #endif 4861da177e4SLinus Torvalds 4871da177e4SLinus Torvalds st_loc->tic_owner_to_pc = readb(apbs[IndexCard].RamIO + TIC_OWNER_TO_PC); 4881da177e4SLinus Torvalds st_loc->numcard_owner_to_pc = readb(apbs[IndexCard].RamIO + NUMCARD_OWNER_TO_PC); 4891da177e4SLinus Torvalds 4901da177e4SLinus Torvalds 4911da177e4SLinus Torvalds { 4921da177e4SLinus Torvalds int c; 4931da177e4SLinus Torvalds 4941da177e4SLinus Torvalds for (c = 0; c < sizeof(struct mailbox); c++) 4951da177e4SLinus Torvalds *(to++) = readb(from++); 4961da177e4SLinus Torvalds } 4971da177e4SLinus Torvalds writeb(1, apbs[IndexCard].RamIO + ACK_FROM_PC_READY); 4981da177e4SLinus Torvalds writeb(1, apbs[IndexCard].RamIO + TYP_ACK_FROM_PC); 4991da177e4SLinus Torvalds writeb(IndexCard+1, apbs[IndexCard].RamIO + NUMCARD_ACK_FROM_PC); 5001da177e4SLinus Torvalds writeb(readb(apbs[IndexCard].RamIO + TIC_OWNER_TO_PC), 5011da177e4SLinus Torvalds apbs[IndexCard].RamIO + TIC_ACK_FROM_PC); 5021da177e4SLinus Torvalds writeb(2, apbs[IndexCard].RamIO + ACK_FROM_PC_READY); 5031da177e4SLinus Torvalds writeb(0, apbs[IndexCard].RamIO + DATA_TO_PC_READY); 5041da177e4SLinus Torvalds writeb(2, apbs[IndexCard].RamIO + RAM_IT_FROM_PC); 5051da177e4SLinus Torvalds Dummy = readb(apbs[IndexCard].RamIO + VERS); 5061da177e4SLinus Torvalds 5071da177e4SLinus Torvalds #ifdef DEBUG 5081da177e4SLinus Torvalds printk("Read from applicom card #%d. struct st_ram_io follows:", NumCard); 5091da177e4SLinus Torvalds 5101da177e4SLinus Torvalds for (c = 0; c < sizeof(struct st_ram_io);) { 5111da177e4SLinus Torvalds printk("\n%5.5X: %2.2X", c, ((unsigned char *)st_loc)[c]); 5121da177e4SLinus Torvalds 5131da177e4SLinus Torvalds for (c++; c % 8 && c < sizeof(struct st_ram_io); c++) { 5141da177e4SLinus Torvalds printk(" %2.2X", ((unsigned char *)st_loc)[c]); 5151da177e4SLinus Torvalds } 5161da177e4SLinus Torvalds } 5171da177e4SLinus Torvalds 5181da177e4SLinus Torvalds printk("\nstruct mailbox follows:"); 5191da177e4SLinus Torvalds 5201da177e4SLinus Torvalds for (c = 0; c < sizeof(struct mailbox);) { 5211da177e4SLinus Torvalds printk("\n%5.5X: %2.2X", c, ((unsigned char *)mailbox)[c]); 5221da177e4SLinus Torvalds 5231da177e4SLinus Torvalds for (c++; c % 8 && c < sizeof(struct mailbox); c++) { 5241da177e4SLinus Torvalds printk(" %2.2X", ((unsigned char *)mailbox)[c]); 5251da177e4SLinus Torvalds } 5261da177e4SLinus Torvalds } 5271da177e4SLinus Torvalds printk("\n"); 5281da177e4SLinus Torvalds #endif 5291da177e4SLinus Torvalds return (sizeof(struct st_ram_io) + sizeof(struct mailbox)); 5301da177e4SLinus Torvalds } 5311da177e4SLinus Torvalds 5321da177e4SLinus Torvalds static ssize_t ac_read (struct file *filp, char __user *buf, size_t count, loff_t *ptr) 5331da177e4SLinus Torvalds { 5341da177e4SLinus Torvalds unsigned long flags; 5351da177e4SLinus Torvalds unsigned int i; 5361da177e4SLinus Torvalds unsigned char tmp; 5371da177e4SLinus Torvalds int ret = 0; 5381da177e4SLinus Torvalds DECLARE_WAITQUEUE(wait, current); 5391da177e4SLinus Torvalds #ifdef DEBUG 5401da177e4SLinus Torvalds int loopcount=0; 5411da177e4SLinus Torvalds #endif 5421da177e4SLinus Torvalds /* No need to ratelimit this. Only root can trigger it anyway */ 5431da177e4SLinus Torvalds if (count != sizeof(struct st_ram_io) + sizeof(struct mailbox)) { 5441da177e4SLinus Torvalds printk( KERN_WARNING "Hmmm. read() of Applicom card, length %zd != expected %zd\n", 5451da177e4SLinus Torvalds count,sizeof(struct st_ram_io) + sizeof(struct mailbox)); 5461da177e4SLinus Torvalds return -EINVAL; 5471da177e4SLinus Torvalds } 5481da177e4SLinus Torvalds 5491da177e4SLinus Torvalds while(1) { 5501da177e4SLinus Torvalds /* Stick ourself on the wait queue */ 5511da177e4SLinus Torvalds set_current_state(TASK_INTERRUPTIBLE); 5521da177e4SLinus Torvalds add_wait_queue(&FlagSleepRec, &wait); 5531da177e4SLinus Torvalds 5541da177e4SLinus Torvalds /* Scan each board, looking for one which has a packet for us */ 5551da177e4SLinus Torvalds for (i=0; i < MAX_BOARD; i++) { 5561da177e4SLinus Torvalds if (!apbs[i].RamIO) 5571da177e4SLinus Torvalds continue; 5581da177e4SLinus Torvalds spin_lock_irqsave(&apbs[i].mutex, flags); 5591da177e4SLinus Torvalds 5601da177e4SLinus Torvalds tmp = readb(apbs[i].RamIO + DATA_TO_PC_READY); 5611da177e4SLinus Torvalds 5621da177e4SLinus Torvalds if (tmp == 2) { 5631da177e4SLinus Torvalds struct st_ram_io st_loc; 5641da177e4SLinus Torvalds struct mailbox mailbox; 5651da177e4SLinus Torvalds 5661da177e4SLinus Torvalds /* Got a packet for us */ 5671da177e4SLinus Torvalds ret = do_ac_read(i, buf, &st_loc, &mailbox); 5681da177e4SLinus Torvalds spin_unlock_irqrestore(&apbs[i].mutex, flags); 5691da177e4SLinus Torvalds set_current_state(TASK_RUNNING); 5701da177e4SLinus Torvalds remove_wait_queue(&FlagSleepRec, &wait); 5711da177e4SLinus Torvalds 5721da177e4SLinus Torvalds if (copy_to_user(buf, &st_loc, sizeof(st_loc))) 5731da177e4SLinus Torvalds return -EFAULT; 5741da177e4SLinus Torvalds if (copy_to_user(buf + sizeof(st_loc), &mailbox, sizeof(mailbox))) 5751da177e4SLinus Torvalds return -EFAULT; 5761da177e4SLinus Torvalds return tmp; 5771da177e4SLinus Torvalds } 5781da177e4SLinus Torvalds 5791da177e4SLinus Torvalds if (tmp > 2) { 5801da177e4SLinus Torvalds /* Got an error */ 5811da177e4SLinus Torvalds Dummy = readb(apbs[i].RamIO + VERS); 5821da177e4SLinus Torvalds 5831da177e4SLinus Torvalds spin_unlock_irqrestore(&apbs[i].mutex, flags); 5841da177e4SLinus Torvalds set_current_state(TASK_RUNNING); 5851da177e4SLinus Torvalds remove_wait_queue(&FlagSleepRec, &wait); 5861da177e4SLinus Torvalds 5871da177e4SLinus Torvalds printk(KERN_WARNING "APPLICOM driver read error board %d, DataToPcReady = %d\n", 5881da177e4SLinus Torvalds i,(int)readb(apbs[i].RamIO + DATA_TO_PC_READY)); 5891da177e4SLinus Torvalds DeviceErrorCount++; 5901da177e4SLinus Torvalds return -EIO; 5911da177e4SLinus Torvalds } 5921da177e4SLinus Torvalds 5931da177e4SLinus Torvalds /* Nothing for us. Try the next board */ 5941da177e4SLinus Torvalds Dummy = readb(apbs[i].RamIO + VERS); 5951da177e4SLinus Torvalds spin_unlock_irqrestore(&apbs[i].mutex, flags); 5961da177e4SLinus Torvalds 5971da177e4SLinus Torvalds } /* per board */ 5981da177e4SLinus Torvalds 5991da177e4SLinus Torvalds /* OK - No boards had data for us. Sleep now */ 6001da177e4SLinus Torvalds 6011da177e4SLinus Torvalds schedule(); 6021da177e4SLinus Torvalds remove_wait_queue(&FlagSleepRec, &wait); 6031da177e4SLinus Torvalds 6041da177e4SLinus Torvalds if (signal_pending(current)) 6051da177e4SLinus Torvalds return -EINTR; 6061da177e4SLinus Torvalds 6071da177e4SLinus Torvalds #ifdef DEBUG 6081da177e4SLinus Torvalds if (loopcount++ > 2) { 60956003191SDomen Puncer printk(KERN_DEBUG "Looping in ac_read. loopcount %d\n", loopcount); 6101da177e4SLinus Torvalds } 6111da177e4SLinus Torvalds #endif 6121da177e4SLinus Torvalds } 6131da177e4SLinus Torvalds } 6141da177e4SLinus Torvalds 6157d12e780SDavid Howells static irqreturn_t ac_interrupt(int vec, void *dev_instance) 6161da177e4SLinus Torvalds { 6171da177e4SLinus Torvalds unsigned int i; 6181da177e4SLinus Torvalds unsigned int FlagInt; 6191da177e4SLinus Torvalds unsigned int LoopCount; 6201da177e4SLinus Torvalds int handled = 0; 6211da177e4SLinus Torvalds 6221da177e4SLinus Torvalds // printk("Applicom interrupt on IRQ %d occurred\n", vec); 6231da177e4SLinus Torvalds 6241da177e4SLinus Torvalds LoopCount = 0; 6251da177e4SLinus Torvalds 6261da177e4SLinus Torvalds do { 6271da177e4SLinus Torvalds FlagInt = 0; 6281da177e4SLinus Torvalds for (i = 0; i < MAX_BOARD; i++) { 6291da177e4SLinus Torvalds 6301da177e4SLinus Torvalds /* Skip if this board doesn't exist */ 6311da177e4SLinus Torvalds if (!apbs[i].RamIO) 6321da177e4SLinus Torvalds continue; 6331da177e4SLinus Torvalds 6341da177e4SLinus Torvalds spin_lock(&apbs[i].mutex); 6351da177e4SLinus Torvalds 6361da177e4SLinus Torvalds /* Skip if this board doesn't want attention */ 6371da177e4SLinus Torvalds if(readb(apbs[i].RamIO + RAM_IT_TO_PC) == 0) { 6381da177e4SLinus Torvalds spin_unlock(&apbs[i].mutex); 6391da177e4SLinus Torvalds continue; 6401da177e4SLinus Torvalds } 6411da177e4SLinus Torvalds 6421da177e4SLinus Torvalds handled = 1; 6431da177e4SLinus Torvalds FlagInt = 1; 6441da177e4SLinus Torvalds writeb(0, apbs[i].RamIO + RAM_IT_TO_PC); 6451da177e4SLinus Torvalds 6461da177e4SLinus Torvalds if (readb(apbs[i].RamIO + DATA_TO_PC_READY) > 2) { 6471da177e4SLinus Torvalds printk(KERN_WARNING "APPLICOM driver interrupt err board %d, DataToPcReady = %d\n", 6481da177e4SLinus Torvalds i+1,(int)readb(apbs[i].RamIO + DATA_TO_PC_READY)); 6491da177e4SLinus Torvalds DeviceErrorCount++; 6501da177e4SLinus Torvalds } 6511da177e4SLinus Torvalds 6521da177e4SLinus Torvalds if((readb(apbs[i].RamIO + DATA_FROM_PC_READY) > 2) && 6531da177e4SLinus Torvalds (readb(apbs[i].RamIO + DATA_FROM_PC_READY) != 6)) { 6541da177e4SLinus Torvalds 6551da177e4SLinus Torvalds printk(KERN_WARNING "APPLICOM driver interrupt err board %d, DataFromPcReady = %d\n", 6561da177e4SLinus Torvalds i+1,(int)readb(apbs[i].RamIO + DATA_FROM_PC_READY)); 6571da177e4SLinus Torvalds DeviceErrorCount++; 6581da177e4SLinus Torvalds } 6591da177e4SLinus Torvalds 6601da177e4SLinus Torvalds if (readb(apbs[i].RamIO + DATA_TO_PC_READY) == 2) { /* mailbox sent by the card ? */ 6611da177e4SLinus Torvalds if (waitqueue_active(&FlagSleepRec)) { 6621da177e4SLinus Torvalds wake_up_interruptible(&FlagSleepRec); 6631da177e4SLinus Torvalds } 6641da177e4SLinus Torvalds } 6651da177e4SLinus Torvalds 6661da177e4SLinus Torvalds if (readb(apbs[i].RamIO + DATA_FROM_PC_READY) == 0) { /* ram i/o free for write by pc ? */ 6671da177e4SLinus Torvalds if (waitqueue_active(&apbs[i].FlagSleepSend)) { /* process sleep during read ? */ 6681da177e4SLinus Torvalds wake_up_interruptible(&apbs[i].FlagSleepSend); 6691da177e4SLinus Torvalds } 6701da177e4SLinus Torvalds } 6711da177e4SLinus Torvalds Dummy = readb(apbs[i].RamIO + VERS); 6721da177e4SLinus Torvalds 6731da177e4SLinus Torvalds if(readb(apbs[i].RamIO + RAM_IT_TO_PC)) { 6741da177e4SLinus Torvalds /* There's another int waiting on this card */ 6751da177e4SLinus Torvalds spin_unlock(&apbs[i].mutex); 6761da177e4SLinus Torvalds i--; 6771da177e4SLinus Torvalds } else { 6781da177e4SLinus Torvalds spin_unlock(&apbs[i].mutex); 6791da177e4SLinus Torvalds } 6801da177e4SLinus Torvalds } 6811da177e4SLinus Torvalds if (FlagInt) 6821da177e4SLinus Torvalds LoopCount = 0; 6831da177e4SLinus Torvalds else 6841da177e4SLinus Torvalds LoopCount++; 6851da177e4SLinus Torvalds } while(LoopCount < 2); 6861da177e4SLinus Torvalds return IRQ_RETVAL(handled); 6871da177e4SLinus Torvalds } 6881da177e4SLinus Torvalds 6891da177e4SLinus Torvalds 6901da177e4SLinus Torvalds 6911da177e4SLinus Torvalds static int ac_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) 6921da177e4SLinus Torvalds 6931da177e4SLinus Torvalds { /* @ ADG ou ATO selon le cas */ 6941da177e4SLinus Torvalds int i; 6951da177e4SLinus Torvalds unsigned char IndexCard; 6961da177e4SLinus Torvalds void __iomem *pmem; 6971da177e4SLinus Torvalds int ret = 0; 6981da177e4SLinus Torvalds volatile unsigned char byte_reset_it; 6991da177e4SLinus Torvalds struct st_ram_io *adgl; 7001da177e4SLinus Torvalds void __user *argp = (void __user *)arg; 7011da177e4SLinus Torvalds 7021da177e4SLinus Torvalds /* In general, the device is only openable by root anyway, so we're not 7031da177e4SLinus Torvalds particularly concerned that bogus ioctls can flood the console. */ 7041da177e4SLinus Torvalds 7051da177e4SLinus Torvalds adgl = kmalloc(sizeof(struct st_ram_io), GFP_KERNEL); 7061da177e4SLinus Torvalds if (!adgl) 7071da177e4SLinus Torvalds return -ENOMEM; 7081da177e4SLinus Torvalds 7091da177e4SLinus Torvalds if (copy_from_user(adgl, argp, sizeof(struct st_ram_io))) { 7101da177e4SLinus Torvalds kfree(adgl); 7111da177e4SLinus Torvalds return -EFAULT; 7121da177e4SLinus Torvalds } 7131da177e4SLinus Torvalds 7141da177e4SLinus Torvalds IndexCard = adgl->num_card-1; 7151da177e4SLinus Torvalds 716a7be18d4SAlan Cox if(cmd != 6 && ((IndexCard >= MAX_BOARD) || !apbs[IndexCard].RamIO)) { 7171da177e4SLinus Torvalds static int warncount = 10; 7181da177e4SLinus Torvalds if (warncount) { 7191da177e4SLinus Torvalds printk( KERN_WARNING "APPLICOM driver IOCTL, bad board number %d\n",(int)IndexCard+1); 7201da177e4SLinus Torvalds warncount--; 7211da177e4SLinus Torvalds } 7221da177e4SLinus Torvalds kfree(adgl); 7231da177e4SLinus Torvalds return -EINVAL; 7241da177e4SLinus Torvalds } 7251da177e4SLinus Torvalds 7261da177e4SLinus Torvalds switch (cmd) { 7271da177e4SLinus Torvalds 7281da177e4SLinus Torvalds case 0: 7291da177e4SLinus Torvalds pmem = apbs[IndexCard].RamIO; 7301da177e4SLinus Torvalds for (i = 0; i < sizeof(struct st_ram_io); i++) 7311da177e4SLinus Torvalds ((unsigned char *)adgl)[i]=readb(pmem++); 7321da177e4SLinus Torvalds if (copy_to_user(argp, adgl, sizeof(struct st_ram_io))) 7331da177e4SLinus Torvalds ret = -EFAULT; 7341da177e4SLinus Torvalds break; 7351da177e4SLinus Torvalds case 1: 7361da177e4SLinus Torvalds pmem = apbs[IndexCard].RamIO + CONF_END_TEST; 7371da177e4SLinus Torvalds for (i = 0; i < 4; i++) 7381da177e4SLinus Torvalds adgl->conf_end_test[i] = readb(pmem++); 7391da177e4SLinus Torvalds for (i = 0; i < 2; i++) 7401da177e4SLinus Torvalds adgl->error_code[i] = readb(pmem++); 7411da177e4SLinus Torvalds for (i = 0; i < 4; i++) 7421da177e4SLinus Torvalds adgl->parameter_error[i] = readb(pmem++); 7431da177e4SLinus Torvalds pmem = apbs[IndexCard].RamIO + VERS; 7441da177e4SLinus Torvalds adgl->vers = readb(pmem); 7451da177e4SLinus Torvalds pmem = apbs[IndexCard].RamIO + TYPE_CARD; 7461da177e4SLinus Torvalds for (i = 0; i < 20; i++) 7471da177e4SLinus Torvalds adgl->reserv1[i] = readb(pmem++); 7481da177e4SLinus Torvalds *(int *)&adgl->reserv1[20] = 7491da177e4SLinus Torvalds (readb(apbs[IndexCard].RamIO + SERIAL_NUMBER) << 16) + 7501da177e4SLinus Torvalds (readb(apbs[IndexCard].RamIO + SERIAL_NUMBER + 1) << 8) + 7511da177e4SLinus Torvalds (readb(apbs[IndexCard].RamIO + SERIAL_NUMBER + 2) ); 7521da177e4SLinus Torvalds 7531da177e4SLinus Torvalds if (copy_to_user(argp, adgl, sizeof(struct st_ram_io))) 7541da177e4SLinus Torvalds ret = -EFAULT; 7551da177e4SLinus Torvalds break; 7561da177e4SLinus Torvalds case 2: 7571da177e4SLinus Torvalds pmem = apbs[IndexCard].RamIO + CONF_END_TEST; 7581da177e4SLinus Torvalds for (i = 0; i < 10; i++) 7591da177e4SLinus Torvalds writeb(0xff, pmem++); 7601da177e4SLinus Torvalds writeb(adgl->data_from_pc_ready, 7611da177e4SLinus Torvalds apbs[IndexCard].RamIO + DATA_FROM_PC_READY); 7621da177e4SLinus Torvalds 7631da177e4SLinus Torvalds writeb(1, apbs[IndexCard].RamIO + RAM_IT_FROM_PC); 7641da177e4SLinus Torvalds 7651da177e4SLinus Torvalds for (i = 0; i < MAX_BOARD; i++) { 7661da177e4SLinus Torvalds if (apbs[i].RamIO) { 7671da177e4SLinus Torvalds byte_reset_it = readb(apbs[i].RamIO + RAM_IT_TO_PC); 7681da177e4SLinus Torvalds } 7691da177e4SLinus Torvalds } 7701da177e4SLinus Torvalds break; 7711da177e4SLinus Torvalds case 3: 7721da177e4SLinus Torvalds pmem = apbs[IndexCard].RamIO + TIC_DES_FROM_PC; 7731da177e4SLinus Torvalds writeb(adgl->tic_des_from_pc, pmem); 7741da177e4SLinus Torvalds break; 7751da177e4SLinus Torvalds case 4: 7761da177e4SLinus Torvalds pmem = apbs[IndexCard].RamIO + TIC_OWNER_TO_PC; 7771da177e4SLinus Torvalds adgl->tic_owner_to_pc = readb(pmem++); 7781da177e4SLinus Torvalds adgl->numcard_owner_to_pc = readb(pmem); 7791da177e4SLinus Torvalds if (copy_to_user(argp, adgl,sizeof(struct st_ram_io))) 7801da177e4SLinus Torvalds ret = -EFAULT; 7811da177e4SLinus Torvalds break; 7821da177e4SLinus Torvalds case 5: 7831da177e4SLinus Torvalds writeb(adgl->num_card, apbs[IndexCard].RamIO + NUMCARD_OWNER_TO_PC); 7841da177e4SLinus Torvalds writeb(adgl->num_card, apbs[IndexCard].RamIO + NUMCARD_DES_FROM_PC); 7851da177e4SLinus Torvalds writeb(adgl->num_card, apbs[IndexCard].RamIO + NUMCARD_ACK_FROM_PC); 7861da177e4SLinus Torvalds writeb(4, apbs[IndexCard].RamIO + DATA_FROM_PC_READY); 7871da177e4SLinus Torvalds writeb(1, apbs[IndexCard].RamIO + RAM_IT_FROM_PC); 7881da177e4SLinus Torvalds break; 7891da177e4SLinus Torvalds case 6: 7901da177e4SLinus Torvalds printk(KERN_INFO "APPLICOM driver release .... V2.8.0 ($Revision: 1.30 $)\n"); 7911da177e4SLinus Torvalds printk(KERN_INFO "Number of installed boards . %d\n", (int) numboards); 7921da177e4SLinus Torvalds printk(KERN_INFO "Segment of board ........... %X\n", (int) mem); 7931da177e4SLinus Torvalds printk(KERN_INFO "Interrupt IRQ number ....... %d\n", (int) irq); 7941da177e4SLinus Torvalds for (i = 0; i < MAX_BOARD; i++) { 7951da177e4SLinus Torvalds int serial; 7961da177e4SLinus Torvalds char boardname[(SERIAL_NUMBER - TYPE_CARD) + 1]; 7971da177e4SLinus Torvalds 7981da177e4SLinus Torvalds if (!apbs[i].RamIO) 7991da177e4SLinus Torvalds continue; 8001da177e4SLinus Torvalds 8011da177e4SLinus Torvalds for (serial = 0; serial < SERIAL_NUMBER - TYPE_CARD; serial++) 8021da177e4SLinus Torvalds boardname[serial] = readb(apbs[i].RamIO + TYPE_CARD + serial); 8031da177e4SLinus Torvalds boardname[serial] = 0; 8041da177e4SLinus Torvalds 8051da177e4SLinus Torvalds printk(KERN_INFO "Prom version board %d ....... V%d.%d %s", 8061da177e4SLinus Torvalds i+1, 8071da177e4SLinus Torvalds (int)(readb(apbs[IndexCard].RamIO + VERS) >> 4), 8081da177e4SLinus Torvalds (int)(readb(apbs[IndexCard].RamIO + VERS) & 0xF), 8091da177e4SLinus Torvalds boardname); 8101da177e4SLinus Torvalds 8111da177e4SLinus Torvalds 8121da177e4SLinus Torvalds serial = (readb(apbs[i].RamIO + SERIAL_NUMBER) << 16) + 8131da177e4SLinus Torvalds (readb(apbs[i].RamIO + SERIAL_NUMBER + 1) << 8) + 8141da177e4SLinus Torvalds (readb(apbs[i].RamIO + SERIAL_NUMBER + 2) ); 8151da177e4SLinus Torvalds 8161da177e4SLinus Torvalds if (serial != 0) 8171da177e4SLinus Torvalds printk(" S/N %d\n", serial); 8181da177e4SLinus Torvalds else 8191da177e4SLinus Torvalds printk("\n"); 8201da177e4SLinus Torvalds } 8211da177e4SLinus Torvalds if (DeviceErrorCount != 0) 8221da177e4SLinus Torvalds printk(KERN_INFO "DeviceErrorCount ........... %d\n", DeviceErrorCount); 8231da177e4SLinus Torvalds if (ReadErrorCount != 0) 8241da177e4SLinus Torvalds printk(KERN_INFO "ReadErrorCount ............. %d\n", ReadErrorCount); 8251da177e4SLinus Torvalds if (WriteErrorCount != 0) 8261da177e4SLinus Torvalds printk(KERN_INFO "WriteErrorCount ............ %d\n", WriteErrorCount); 8271da177e4SLinus Torvalds if (waitqueue_active(&FlagSleepRec)) 8281da177e4SLinus Torvalds printk(KERN_INFO "Process in read pending\n"); 8291da177e4SLinus Torvalds for (i = 0; i < MAX_BOARD; i++) { 8301da177e4SLinus Torvalds if (apbs[i].RamIO && waitqueue_active(&apbs[i].FlagSleepSend)) 8311da177e4SLinus Torvalds printk(KERN_INFO "Process in write pending board %d\n",i+1); 8321da177e4SLinus Torvalds } 8331da177e4SLinus Torvalds break; 8341da177e4SLinus Torvalds default: 835a7be18d4SAlan Cox ret = -ENOTTY; 8361da177e4SLinus Torvalds break; 8371da177e4SLinus Torvalds } 8381da177e4SLinus Torvalds Dummy = readb(apbs[IndexCard].RamIO + VERS); 8391da177e4SLinus Torvalds kfree(adgl); 8401da177e4SLinus Torvalds return 0; 8411da177e4SLinus Torvalds } 8421da177e4SLinus Torvalds 843