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"); 781da177e4SLinus Torvalds 791da177e4SLinus Torvalds MODULE_SUPPORTED_DEVICE("ac"); 801da177e4SLinus Torvalds 811da177e4SLinus Torvalds 821da177e4SLinus Torvalds static struct applicom_board { 831da177e4SLinus Torvalds unsigned long PhysIO; 841da177e4SLinus Torvalds void __iomem *RamIO; 851da177e4SLinus Torvalds wait_queue_head_t FlagSleepSend; 861da177e4SLinus Torvalds long irq; 871da177e4SLinus Torvalds spinlock_t mutex; 881da177e4SLinus Torvalds } apbs[MAX_BOARD]; 891da177e4SLinus Torvalds 901da177e4SLinus Torvalds static unsigned int irq = 0; /* interrupt number IRQ */ 911da177e4SLinus Torvalds static unsigned long mem = 0; /* physical segment of board */ 921da177e4SLinus Torvalds 931da177e4SLinus Torvalds module_param(irq, uint, 0); 941da177e4SLinus Torvalds MODULE_PARM_DESC(irq, "IRQ of the Applicom board"); 951da177e4SLinus Torvalds module_param(mem, ulong, 0); 961da177e4SLinus Torvalds MODULE_PARM_DESC(mem, "Shared Memory Address of Applicom board"); 971da177e4SLinus Torvalds 981da177e4SLinus Torvalds static unsigned int numboards; /* number of installed boards */ 991da177e4SLinus Torvalds static volatile unsigned char Dummy; 1001da177e4SLinus Torvalds static DECLARE_WAIT_QUEUE_HEAD(FlagSleepRec); 1011da177e4SLinus Torvalds static unsigned int WriteErrorCount; /* number of write error */ 1021da177e4SLinus Torvalds static unsigned int ReadErrorCount; /* number of read error */ 1031da177e4SLinus Torvalds static unsigned int DeviceErrorCount; /* number of device error */ 1041da177e4SLinus Torvalds 1051da177e4SLinus Torvalds static ssize_t ac_read (struct file *, char __user *, size_t, loff_t *); 1061da177e4SLinus Torvalds static ssize_t ac_write (struct file *, const char __user *, size_t, loff_t *); 1071da177e4SLinus Torvalds static int ac_ioctl(struct inode *, struct file *, unsigned int, 1081da177e4SLinus Torvalds unsigned long); 1097d12e780SDavid Howells static irqreturn_t ac_interrupt(int, void *); 1101da177e4SLinus Torvalds 11162322d25SArjan van de Ven static const struct file_operations ac_fops = { 1121da177e4SLinus Torvalds .owner = THIS_MODULE, 1131da177e4SLinus Torvalds .llseek = no_llseek, 1141da177e4SLinus Torvalds .read = ac_read, 1151da177e4SLinus Torvalds .write = ac_write, 1161da177e4SLinus Torvalds .ioctl = ac_ioctl, 1171da177e4SLinus Torvalds }; 1181da177e4SLinus Torvalds 1191da177e4SLinus Torvalds static struct miscdevice ac_miscdev = { 1201da177e4SLinus Torvalds AC_MINOR, 1211da177e4SLinus Torvalds "ac", 1221da177e4SLinus Torvalds &ac_fops 1231da177e4SLinus Torvalds }; 1241da177e4SLinus Torvalds 1251da177e4SLinus Torvalds static int dummy; /* dev_id for request_irq() */ 1261da177e4SLinus Torvalds 1271da177e4SLinus Torvalds static int ac_register_board(unsigned long physloc, void __iomem *loc, 1281da177e4SLinus Torvalds unsigned char boardno) 1291da177e4SLinus Torvalds { 1301da177e4SLinus Torvalds volatile unsigned char byte_reset_it; 1311da177e4SLinus Torvalds 1321da177e4SLinus Torvalds if((readb(loc + CONF_END_TEST) != 0x00) || 1331da177e4SLinus Torvalds (readb(loc + CONF_END_TEST + 1) != 0x55) || 1341da177e4SLinus Torvalds (readb(loc + CONF_END_TEST + 2) != 0xAA) || 1351da177e4SLinus Torvalds (readb(loc + CONF_END_TEST + 3) != 0xFF)) 1361da177e4SLinus Torvalds return 0; 1371da177e4SLinus Torvalds 1381da177e4SLinus Torvalds if (!boardno) 1391da177e4SLinus Torvalds boardno = readb(loc + NUMCARD_OWNER_TO_PC); 1401da177e4SLinus Torvalds 141e60b6e2fSEric Sesterhenn if (!boardno || boardno > MAX_BOARD) { 1421da177e4SLinus Torvalds printk(KERN_WARNING "Board #%d (at 0x%lx) is out of range (1 <= x <= %d).\n", 1431da177e4SLinus Torvalds boardno, physloc, MAX_BOARD); 1441da177e4SLinus Torvalds return 0; 1451da177e4SLinus Torvalds } 1461da177e4SLinus Torvalds 1471da177e4SLinus Torvalds if (apbs[boardno - 1].RamIO) { 1481da177e4SLinus Torvalds printk(KERN_WARNING "Board #%d (at 0x%lx) conflicts with previous board #%d (at 0x%lx)\n", 1491da177e4SLinus Torvalds boardno, physloc, boardno, apbs[boardno-1].PhysIO); 1501da177e4SLinus Torvalds return 0; 1511da177e4SLinus Torvalds } 1521da177e4SLinus Torvalds 1531da177e4SLinus Torvalds boardno--; 1541da177e4SLinus Torvalds 1551da177e4SLinus Torvalds apbs[boardno].PhysIO = physloc; 1561da177e4SLinus Torvalds apbs[boardno].RamIO = loc; 1571da177e4SLinus Torvalds init_waitqueue_head(&apbs[boardno].FlagSleepSend); 1581da177e4SLinus Torvalds spin_lock_init(&apbs[boardno].mutex); 1591da177e4SLinus Torvalds byte_reset_it = readb(loc + RAM_IT_TO_PC); 1601da177e4SLinus Torvalds 1611da177e4SLinus Torvalds numboards++; 1621da177e4SLinus Torvalds return boardno + 1; 1631da177e4SLinus Torvalds } 1641da177e4SLinus Torvalds 1652e611390SAdrian Bunk static void __exit applicom_exit(void) 1661da177e4SLinus Torvalds { 167819a3ebaSChristophe Lucas unsigned int i; 1681da177e4SLinus Torvalds 1691da177e4SLinus Torvalds misc_deregister(&ac_miscdev); 1701da177e4SLinus Torvalds 1711da177e4SLinus Torvalds for (i = 0; i < MAX_BOARD; i++) { 1721da177e4SLinus Torvalds 1731da177e4SLinus Torvalds if (!apbs[i].RamIO) 1741da177e4SLinus Torvalds continue; 1751da177e4SLinus Torvalds 1761da177e4SLinus Torvalds if (apbs[i].irq) 1771da177e4SLinus Torvalds free_irq(apbs[i].irq, &dummy); 1781da177e4SLinus Torvalds 1791da177e4SLinus Torvalds iounmap(apbs[i].RamIO); 1801da177e4SLinus Torvalds } 1811da177e4SLinus Torvalds } 1821da177e4SLinus Torvalds 1832e611390SAdrian Bunk static int __init applicom_init(void) 1841da177e4SLinus Torvalds { 1851da177e4SLinus Torvalds int i, numisa = 0; 1861da177e4SLinus Torvalds struct pci_dev *dev = NULL; 1871da177e4SLinus Torvalds void __iomem *RamIO; 188819a3ebaSChristophe Lucas int boardno, ret; 1891da177e4SLinus Torvalds 1901da177e4SLinus Torvalds printk(KERN_INFO "Applicom driver: $Id: ac.c,v 1.30 2000/03/22 16:03:57 dwmw2 Exp $\n"); 1911da177e4SLinus Torvalds 1921da177e4SLinus Torvalds /* No mem and irq given - check for a PCI card */ 1931da177e4SLinus Torvalds 1941da177e4SLinus Torvalds while ( (dev = pci_get_class(PCI_CLASS_OTHERS << 16, dev))) { 1951da177e4SLinus Torvalds 19653a7a1bbSJiri Slaby if (!pci_match_id(applicom_pci_tbl, dev)) 1971da177e4SLinus Torvalds continue; 1981da177e4SLinus Torvalds 1991da177e4SLinus Torvalds if (pci_enable_device(dev)) 2001da177e4SLinus Torvalds return -EIO; 2011da177e4SLinus Torvalds 20224cb2335SAlan Cox RamIO = ioremap_nocache(pci_resource_start(dev, 0), LEN_RAM_IO); 2031da177e4SLinus Torvalds 2041da177e4SLinus Torvalds if (!RamIO) { 205e29419ffSGreg Kroah-Hartman printk(KERN_INFO "ac.o: Failed to ioremap PCI memory " 206e29419ffSGreg Kroah-Hartman "space at 0x%llx\n", 20755b29a72SJiri Slaby (unsigned long long)pci_resource_start(dev, 0)); 2081da177e4SLinus Torvalds pci_disable_device(dev); 2091da177e4SLinus Torvalds return -EIO; 2101da177e4SLinus Torvalds } 2111da177e4SLinus Torvalds 212e29419ffSGreg Kroah-Hartman printk(KERN_INFO "Applicom %s found at mem 0x%llx, irq %d\n", 213e29419ffSGreg Kroah-Hartman applicom_pci_devnames[dev->device-1], 21455b29a72SJiri Slaby (unsigned long long)pci_resource_start(dev, 0), 2151da177e4SLinus Torvalds dev->irq); 2161da177e4SLinus Torvalds 21755b29a72SJiri Slaby boardno = ac_register_board(pci_resource_start(dev, 0), 21855b29a72SJiri Slaby RamIO, 0); 2191da177e4SLinus Torvalds if (!boardno) { 2201da177e4SLinus Torvalds printk(KERN_INFO "ac.o: PCI Applicom device doesn't have correct signature.\n"); 2211da177e4SLinus Torvalds iounmap(RamIO); 2221da177e4SLinus Torvalds pci_disable_device(dev); 2231da177e4SLinus Torvalds continue; 2241da177e4SLinus Torvalds } 2251da177e4SLinus Torvalds 2260f2ed4c6SThomas Gleixner if (request_irq(dev->irq, &ac_interrupt, IRQF_SHARED, "Applicom PCI", &dummy)) { 2271da177e4SLinus Torvalds printk(KERN_INFO "Could not allocate IRQ %d for PCI Applicom device.\n", dev->irq); 2281da177e4SLinus Torvalds iounmap(RamIO); 2291da177e4SLinus Torvalds pci_disable_device(dev); 2301da177e4SLinus Torvalds apbs[boardno - 1].RamIO = NULL; 2311da177e4SLinus Torvalds continue; 2321da177e4SLinus Torvalds } 2331da177e4SLinus Torvalds 2341da177e4SLinus Torvalds /* Enable interrupts. */ 2351da177e4SLinus Torvalds 2361da177e4SLinus Torvalds writeb(0x40, apbs[boardno - 1].RamIO + RAM_IT_FROM_PC); 2371da177e4SLinus Torvalds 2381da177e4SLinus Torvalds apbs[boardno - 1].irq = dev->irq; 2391da177e4SLinus Torvalds } 2401da177e4SLinus Torvalds 2411da177e4SLinus Torvalds /* Finished with PCI cards. If none registered, 2421da177e4SLinus Torvalds * and there was no mem/irq specified, exit */ 2431da177e4SLinus Torvalds 2441da177e4SLinus Torvalds if (!mem || !irq) { 2451da177e4SLinus Torvalds if (numboards) 2461da177e4SLinus Torvalds goto fin; 2471da177e4SLinus Torvalds else { 2481da177e4SLinus Torvalds printk(KERN_INFO "ac.o: No PCI boards found.\n"); 2491da177e4SLinus Torvalds printk(KERN_INFO "ac.o: For an ISA board you must supply memory and irq parameters.\n"); 2501da177e4SLinus Torvalds return -ENXIO; 2511da177e4SLinus Torvalds } 2521da177e4SLinus Torvalds } 2531da177e4SLinus Torvalds 2541da177e4SLinus Torvalds /* Now try the specified ISA cards */ 2551da177e4SLinus Torvalds 2561da177e4SLinus Torvalds for (i = 0; i < MAX_ISA_BOARD; i++) { 25724cb2335SAlan Cox RamIO = ioremap_nocache(mem + (LEN_RAM_IO * i), LEN_RAM_IO); 2581da177e4SLinus Torvalds 2591da177e4SLinus Torvalds if (!RamIO) { 2601da177e4SLinus Torvalds printk(KERN_INFO "ac.o: Failed to ioremap the ISA card's memory space (slot #%d)\n", i + 1); 2611da177e4SLinus Torvalds continue; 2621da177e4SLinus Torvalds } 2631da177e4SLinus Torvalds 2641da177e4SLinus Torvalds if (!(boardno = ac_register_board((unsigned long)mem+ (LEN_RAM_IO*i), 2651da177e4SLinus Torvalds RamIO,i+1))) { 2661da177e4SLinus Torvalds iounmap(RamIO); 2671da177e4SLinus Torvalds continue; 2681da177e4SLinus Torvalds } 2691da177e4SLinus Torvalds 2701da177e4SLinus Torvalds printk(KERN_NOTICE "Applicom ISA card found at mem 0x%lx, irq %d\n", mem + (LEN_RAM_IO*i), irq); 2711da177e4SLinus Torvalds 2721da177e4SLinus Torvalds if (!numisa) { 2730f2ed4c6SThomas Gleixner if (request_irq(irq, &ac_interrupt, IRQF_SHARED, "Applicom ISA", &dummy)) { 2741da177e4SLinus Torvalds printk(KERN_WARNING "Could not allocate IRQ %d for ISA Applicom device.\n", irq); 2751da177e4SLinus Torvalds iounmap(RamIO); 2761da177e4SLinus Torvalds apbs[boardno - 1].RamIO = NULL; 2771da177e4SLinus Torvalds } 2781da177e4SLinus Torvalds else 2791da177e4SLinus Torvalds apbs[boardno - 1].irq = irq; 2801da177e4SLinus Torvalds } 2811da177e4SLinus Torvalds else 2821da177e4SLinus Torvalds apbs[boardno - 1].irq = 0; 2831da177e4SLinus Torvalds 2841da177e4SLinus Torvalds numisa++; 2851da177e4SLinus Torvalds } 2861da177e4SLinus Torvalds 2871da177e4SLinus Torvalds if (!numisa) 288819a3ebaSChristophe Lucas printk(KERN_WARNING "ac.o: No valid ISA Applicom boards found " 289819a3ebaSChristophe Lucas "at mem 0x%lx\n", mem); 2901da177e4SLinus Torvalds 2911da177e4SLinus Torvalds fin: 2921da177e4SLinus Torvalds init_waitqueue_head(&FlagSleepRec); 2931da177e4SLinus Torvalds 2941da177e4SLinus Torvalds WriteErrorCount = 0; 2951da177e4SLinus Torvalds ReadErrorCount = 0; 2961da177e4SLinus Torvalds DeviceErrorCount = 0; 2971da177e4SLinus Torvalds 2981da177e4SLinus Torvalds if (numboards) { 299819a3ebaSChristophe Lucas ret = misc_register(&ac_miscdev); 300819a3ebaSChristophe Lucas if (ret) { 301819a3ebaSChristophe Lucas printk(KERN_WARNING "ac.o: Unable to register misc device\n"); 302819a3ebaSChristophe Lucas goto out; 303819a3ebaSChristophe Lucas } 3041da177e4SLinus Torvalds for (i = 0; i < MAX_BOARD; i++) { 3051da177e4SLinus Torvalds int serial; 3061da177e4SLinus Torvalds char boardname[(SERIAL_NUMBER - TYPE_CARD) + 1]; 3071da177e4SLinus Torvalds 3081da177e4SLinus Torvalds if (!apbs[i].RamIO) 3091da177e4SLinus Torvalds continue; 3101da177e4SLinus Torvalds 3111da177e4SLinus Torvalds for (serial = 0; serial < SERIAL_NUMBER - TYPE_CARD; serial++) 3121da177e4SLinus Torvalds boardname[serial] = readb(apbs[i].RamIO + TYPE_CARD + serial); 3131da177e4SLinus Torvalds 3141da177e4SLinus Torvalds boardname[serial] = 0; 3151da177e4SLinus Torvalds 3161da177e4SLinus Torvalds 3171da177e4SLinus Torvalds printk(KERN_INFO "Applicom board %d: %s, PROM V%d.%d", 3181da177e4SLinus Torvalds i+1, boardname, 3191da177e4SLinus Torvalds (int)(readb(apbs[i].RamIO + VERS) >> 4), 3201da177e4SLinus Torvalds (int)(readb(apbs[i].RamIO + VERS) & 0xF)); 3211da177e4SLinus Torvalds 3221da177e4SLinus Torvalds serial = (readb(apbs[i].RamIO + SERIAL_NUMBER) << 16) + 3231da177e4SLinus Torvalds (readb(apbs[i].RamIO + SERIAL_NUMBER + 1) << 8) + 3241da177e4SLinus Torvalds (readb(apbs[i].RamIO + SERIAL_NUMBER + 2) ); 3251da177e4SLinus Torvalds 3261da177e4SLinus Torvalds if (serial != 0) 3271da177e4SLinus Torvalds printk(" S/N %d\n", serial); 3281da177e4SLinus Torvalds else 3291da177e4SLinus Torvalds printk("\n"); 3301da177e4SLinus Torvalds } 3311da177e4SLinus Torvalds return 0; 3321da177e4SLinus Torvalds } 3331da177e4SLinus Torvalds 3341da177e4SLinus Torvalds else 3351da177e4SLinus Torvalds return -ENXIO; 336819a3ebaSChristophe Lucas 337819a3ebaSChristophe Lucas out: 338819a3ebaSChristophe Lucas for (i = 0; i < MAX_BOARD; i++) { 339819a3ebaSChristophe Lucas if (!apbs[i].RamIO) 340819a3ebaSChristophe Lucas continue; 341819a3ebaSChristophe Lucas if (apbs[i].irq) 342819a3ebaSChristophe Lucas free_irq(apbs[i].irq, &dummy); 343819a3ebaSChristophe Lucas iounmap(apbs[i].RamIO); 344819a3ebaSChristophe Lucas } 345819a3ebaSChristophe Lucas pci_disable_device(dev); 346819a3ebaSChristophe Lucas return ret; 3471da177e4SLinus Torvalds } 3481da177e4SLinus Torvalds 3492e611390SAdrian Bunk module_init(applicom_init); 3502e611390SAdrian Bunk module_exit(applicom_exit); 3511da177e4SLinus Torvalds 3521da177e4SLinus Torvalds 3531da177e4SLinus Torvalds static ssize_t ac_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos) 3541da177e4SLinus Torvalds { 3551da177e4SLinus Torvalds unsigned int NumCard; /* Board number 1 -> 8 */ 3561da177e4SLinus Torvalds unsigned int IndexCard; /* Index board number 0 -> 7 */ 3571da177e4SLinus Torvalds unsigned char TicCard; /* Board TIC to send */ 3581da177e4SLinus Torvalds unsigned long flags; /* Current priority */ 3591da177e4SLinus Torvalds struct st_ram_io st_loc; 3601da177e4SLinus Torvalds struct mailbox tmpmailbox; 3611da177e4SLinus Torvalds #ifdef DEBUG 3621da177e4SLinus Torvalds int c; 3631da177e4SLinus Torvalds #endif 3641da177e4SLinus Torvalds DECLARE_WAITQUEUE(wait, current); 3651da177e4SLinus Torvalds 3661da177e4SLinus Torvalds if (count != sizeof(struct st_ram_io) + sizeof(struct mailbox)) { 3671da177e4SLinus Torvalds static int warncount = 5; 3681da177e4SLinus Torvalds if (warncount) { 3691da177e4SLinus Torvalds printk(KERN_INFO "Hmmm. write() of Applicom card, length %zd != expected %zd\n", 3701da177e4SLinus Torvalds count, sizeof(struct st_ram_io) + sizeof(struct mailbox)); 3711da177e4SLinus Torvalds warncount--; 3721da177e4SLinus Torvalds } 3731da177e4SLinus Torvalds return -EINVAL; 3741da177e4SLinus Torvalds } 3751da177e4SLinus Torvalds 3761da177e4SLinus Torvalds if(copy_from_user(&st_loc, buf, sizeof(struct st_ram_io))) 3771da177e4SLinus Torvalds return -EFAULT; 3781da177e4SLinus Torvalds 3791da177e4SLinus Torvalds if(copy_from_user(&tmpmailbox, &buf[sizeof(struct st_ram_io)], 3801da177e4SLinus Torvalds sizeof(struct mailbox))) 3811da177e4SLinus Torvalds return -EFAULT; 3821da177e4SLinus Torvalds 3831da177e4SLinus Torvalds NumCard = st_loc.num_card; /* board number to send */ 3841da177e4SLinus Torvalds TicCard = st_loc.tic_des_from_pc; /* tic number to send */ 3851da177e4SLinus Torvalds IndexCard = NumCard - 1; 3861da177e4SLinus Torvalds 3871da177e4SLinus Torvalds if((NumCard < 1) || (NumCard > MAX_BOARD) || !apbs[IndexCard].RamIO) 3881da177e4SLinus Torvalds return -EINVAL; 3891da177e4SLinus Torvalds 3901da177e4SLinus Torvalds #ifdef DEBUG 3911da177e4SLinus Torvalds printk("Write to applicom card #%d. struct st_ram_io follows:", 3921da177e4SLinus Torvalds IndexCard+1); 3931da177e4SLinus Torvalds 3941da177e4SLinus Torvalds for (c = 0; c < sizeof(struct st_ram_io);) { 3951da177e4SLinus Torvalds 3961da177e4SLinus Torvalds printk("\n%5.5X: %2.2X", c, ((unsigned char *) &st_loc)[c]); 3971da177e4SLinus Torvalds 3981da177e4SLinus Torvalds for (c++; c % 8 && c < sizeof(struct st_ram_io); c++) { 3991da177e4SLinus Torvalds printk(" %2.2X", ((unsigned char *) &st_loc)[c]); 4001da177e4SLinus Torvalds } 4011da177e4SLinus Torvalds } 4021da177e4SLinus Torvalds 4031da177e4SLinus Torvalds printk("\nstruct mailbox follows:"); 4041da177e4SLinus Torvalds 4051da177e4SLinus Torvalds for (c = 0; c < sizeof(struct mailbox);) { 4061da177e4SLinus Torvalds printk("\n%5.5X: %2.2X", c, ((unsigned char *) &tmpmailbox)[c]); 4071da177e4SLinus Torvalds 4081da177e4SLinus Torvalds for (c++; c % 8 && c < sizeof(struct mailbox); c++) { 4091da177e4SLinus Torvalds printk(" %2.2X", ((unsigned char *) &tmpmailbox)[c]); 4101da177e4SLinus Torvalds } 4111da177e4SLinus Torvalds } 4121da177e4SLinus Torvalds 4131da177e4SLinus Torvalds printk("\n"); 4141da177e4SLinus Torvalds #endif 4151da177e4SLinus Torvalds 4161da177e4SLinus Torvalds spin_lock_irqsave(&apbs[IndexCard].mutex, flags); 4171da177e4SLinus Torvalds 4181da177e4SLinus Torvalds /* Test octet ready correct */ 4191da177e4SLinus Torvalds if(readb(apbs[IndexCard].RamIO + DATA_FROM_PC_READY) > 2) { 4201da177e4SLinus Torvalds Dummy = readb(apbs[IndexCard].RamIO + VERS); 4211da177e4SLinus Torvalds spin_unlock_irqrestore(&apbs[IndexCard].mutex, flags); 4221da177e4SLinus Torvalds printk(KERN_WARNING "APPLICOM driver write error board %d, DataFromPcReady = %d\n", 4231da177e4SLinus Torvalds IndexCard,(int)readb(apbs[IndexCard].RamIO + DATA_FROM_PC_READY)); 4241da177e4SLinus Torvalds DeviceErrorCount++; 4251da177e4SLinus Torvalds return -EIO; 4261da177e4SLinus Torvalds } 4271da177e4SLinus Torvalds 4281da177e4SLinus Torvalds /* Place ourselves on the wait queue */ 4291da177e4SLinus Torvalds set_current_state(TASK_INTERRUPTIBLE); 4301da177e4SLinus Torvalds add_wait_queue(&apbs[IndexCard].FlagSleepSend, &wait); 4311da177e4SLinus Torvalds 4321da177e4SLinus Torvalds /* Check whether the card is ready for us */ 4331da177e4SLinus Torvalds while (readb(apbs[IndexCard].RamIO + DATA_FROM_PC_READY) != 0) { 4341da177e4SLinus Torvalds Dummy = readb(apbs[IndexCard].RamIO + VERS); 4351da177e4SLinus Torvalds /* It's busy. Sleep. */ 4361da177e4SLinus Torvalds 4371da177e4SLinus Torvalds spin_unlock_irqrestore(&apbs[IndexCard].mutex, flags); 4381da177e4SLinus Torvalds schedule(); 4391da177e4SLinus Torvalds if (signal_pending(current)) { 4401da177e4SLinus Torvalds remove_wait_queue(&apbs[IndexCard].FlagSleepSend, 4411da177e4SLinus Torvalds &wait); 4421da177e4SLinus Torvalds return -EINTR; 4431da177e4SLinus Torvalds } 4441da177e4SLinus Torvalds spin_lock_irqsave(&apbs[IndexCard].mutex, flags); 4451da177e4SLinus Torvalds set_current_state(TASK_INTERRUPTIBLE); 4461da177e4SLinus Torvalds } 4471da177e4SLinus Torvalds 4481da177e4SLinus Torvalds /* We may not have actually slept */ 4491da177e4SLinus Torvalds set_current_state(TASK_RUNNING); 4501da177e4SLinus Torvalds remove_wait_queue(&apbs[IndexCard].FlagSleepSend, &wait); 4511da177e4SLinus Torvalds 4521da177e4SLinus Torvalds writeb(1, apbs[IndexCard].RamIO + DATA_FROM_PC_READY); 4531da177e4SLinus Torvalds 4541da177e4SLinus Torvalds /* Which is best - lock down the pages with rawio and then 4551da177e4SLinus Torvalds copy directly, or use bounce buffers? For now we do the latter 4561da177e4SLinus Torvalds because it works with 2.2 still */ 4571da177e4SLinus Torvalds { 4581da177e4SLinus Torvalds unsigned char *from = (unsigned char *) &tmpmailbox; 4591da177e4SLinus Torvalds void __iomem *to = apbs[IndexCard].RamIO + RAM_FROM_PC; 4601da177e4SLinus Torvalds int c; 4611da177e4SLinus Torvalds 4621da177e4SLinus Torvalds for (c = 0; c < sizeof(struct mailbox); c++) 4631da177e4SLinus Torvalds writeb(*(from++), to++); 4641da177e4SLinus Torvalds } 4651da177e4SLinus Torvalds 4661da177e4SLinus Torvalds writeb(0x20, apbs[IndexCard].RamIO + TIC_OWNER_FROM_PC); 4671da177e4SLinus Torvalds writeb(0xff, apbs[IndexCard].RamIO + NUMCARD_OWNER_FROM_PC); 4681da177e4SLinus Torvalds writeb(TicCard, apbs[IndexCard].RamIO + TIC_DES_FROM_PC); 4691da177e4SLinus Torvalds writeb(NumCard, apbs[IndexCard].RamIO + NUMCARD_DES_FROM_PC); 4701da177e4SLinus Torvalds writeb(2, apbs[IndexCard].RamIO + DATA_FROM_PC_READY); 4711da177e4SLinus Torvalds writeb(1, apbs[IndexCard].RamIO + RAM_IT_FROM_PC); 4721da177e4SLinus Torvalds Dummy = readb(apbs[IndexCard].RamIO + VERS); 4731da177e4SLinus Torvalds spin_unlock_irqrestore(&apbs[IndexCard].mutex, flags); 4741da177e4SLinus Torvalds return 0; 4751da177e4SLinus Torvalds } 4761da177e4SLinus Torvalds 4771da177e4SLinus Torvalds static int do_ac_read(int IndexCard, char __user *buf, 4781da177e4SLinus Torvalds struct st_ram_io *st_loc, struct mailbox *mailbox) 4791da177e4SLinus Torvalds { 4801da177e4SLinus Torvalds void __iomem *from = apbs[IndexCard].RamIO + RAM_TO_PC; 4811da177e4SLinus Torvalds unsigned char *to = (unsigned char *)&mailbox; 4821da177e4SLinus Torvalds #ifdef DEBUG 4831da177e4SLinus Torvalds int c; 4841da177e4SLinus Torvalds #endif 4851da177e4SLinus Torvalds 4861da177e4SLinus Torvalds st_loc->tic_owner_to_pc = readb(apbs[IndexCard].RamIO + TIC_OWNER_TO_PC); 4871da177e4SLinus Torvalds st_loc->numcard_owner_to_pc = readb(apbs[IndexCard].RamIO + NUMCARD_OWNER_TO_PC); 4881da177e4SLinus Torvalds 4891da177e4SLinus Torvalds 4901da177e4SLinus Torvalds { 4911da177e4SLinus Torvalds int c; 4921da177e4SLinus Torvalds 4931da177e4SLinus Torvalds for (c = 0; c < sizeof(struct mailbox); c++) 4941da177e4SLinus Torvalds *(to++) = readb(from++); 4951da177e4SLinus Torvalds } 4961da177e4SLinus Torvalds writeb(1, apbs[IndexCard].RamIO + ACK_FROM_PC_READY); 4971da177e4SLinus Torvalds writeb(1, apbs[IndexCard].RamIO + TYP_ACK_FROM_PC); 4981da177e4SLinus Torvalds writeb(IndexCard+1, apbs[IndexCard].RamIO + NUMCARD_ACK_FROM_PC); 4991da177e4SLinus Torvalds writeb(readb(apbs[IndexCard].RamIO + TIC_OWNER_TO_PC), 5001da177e4SLinus Torvalds apbs[IndexCard].RamIO + TIC_ACK_FROM_PC); 5011da177e4SLinus Torvalds writeb(2, apbs[IndexCard].RamIO + ACK_FROM_PC_READY); 5021da177e4SLinus Torvalds writeb(0, apbs[IndexCard].RamIO + DATA_TO_PC_READY); 5031da177e4SLinus Torvalds writeb(2, apbs[IndexCard].RamIO + RAM_IT_FROM_PC); 5041da177e4SLinus Torvalds Dummy = readb(apbs[IndexCard].RamIO + VERS); 5051da177e4SLinus Torvalds 5061da177e4SLinus Torvalds #ifdef DEBUG 5071da177e4SLinus Torvalds printk("Read from applicom card #%d. struct st_ram_io follows:", NumCard); 5081da177e4SLinus Torvalds 5091da177e4SLinus Torvalds for (c = 0; c < sizeof(struct st_ram_io);) { 5101da177e4SLinus Torvalds printk("\n%5.5X: %2.2X", c, ((unsigned char *)st_loc)[c]); 5111da177e4SLinus Torvalds 5121da177e4SLinus Torvalds for (c++; c % 8 && c < sizeof(struct st_ram_io); c++) { 5131da177e4SLinus Torvalds printk(" %2.2X", ((unsigned char *)st_loc)[c]); 5141da177e4SLinus Torvalds } 5151da177e4SLinus Torvalds } 5161da177e4SLinus Torvalds 5171da177e4SLinus Torvalds printk("\nstruct mailbox follows:"); 5181da177e4SLinus Torvalds 5191da177e4SLinus Torvalds for (c = 0; c < sizeof(struct mailbox);) { 5201da177e4SLinus Torvalds printk("\n%5.5X: %2.2X", c, ((unsigned char *)mailbox)[c]); 5211da177e4SLinus Torvalds 5221da177e4SLinus Torvalds for (c++; c % 8 && c < sizeof(struct mailbox); c++) { 5231da177e4SLinus Torvalds printk(" %2.2X", ((unsigned char *)mailbox)[c]); 5241da177e4SLinus Torvalds } 5251da177e4SLinus Torvalds } 5261da177e4SLinus Torvalds printk("\n"); 5271da177e4SLinus Torvalds #endif 5281da177e4SLinus Torvalds return (sizeof(struct st_ram_io) + sizeof(struct mailbox)); 5291da177e4SLinus Torvalds } 5301da177e4SLinus Torvalds 5311da177e4SLinus Torvalds static ssize_t ac_read (struct file *filp, char __user *buf, size_t count, loff_t *ptr) 5321da177e4SLinus Torvalds { 5331da177e4SLinus Torvalds unsigned long flags; 5341da177e4SLinus Torvalds unsigned int i; 5351da177e4SLinus Torvalds unsigned char tmp; 5361da177e4SLinus Torvalds int ret = 0; 5371da177e4SLinus Torvalds DECLARE_WAITQUEUE(wait, current); 5381da177e4SLinus Torvalds #ifdef DEBUG 5391da177e4SLinus Torvalds int loopcount=0; 5401da177e4SLinus Torvalds #endif 5411da177e4SLinus Torvalds /* No need to ratelimit this. Only root can trigger it anyway */ 5421da177e4SLinus Torvalds if (count != sizeof(struct st_ram_io) + sizeof(struct mailbox)) { 5431da177e4SLinus Torvalds printk( KERN_WARNING "Hmmm. read() of Applicom card, length %zd != expected %zd\n", 5441da177e4SLinus Torvalds count,sizeof(struct st_ram_io) + sizeof(struct mailbox)); 5451da177e4SLinus Torvalds return -EINVAL; 5461da177e4SLinus Torvalds } 5471da177e4SLinus Torvalds 5481da177e4SLinus Torvalds while(1) { 5491da177e4SLinus Torvalds /* Stick ourself on the wait queue */ 5501da177e4SLinus Torvalds set_current_state(TASK_INTERRUPTIBLE); 5511da177e4SLinus Torvalds add_wait_queue(&FlagSleepRec, &wait); 5521da177e4SLinus Torvalds 5531da177e4SLinus Torvalds /* Scan each board, looking for one which has a packet for us */ 5541da177e4SLinus Torvalds for (i=0; i < MAX_BOARD; i++) { 5551da177e4SLinus Torvalds if (!apbs[i].RamIO) 5561da177e4SLinus Torvalds continue; 5571da177e4SLinus Torvalds spin_lock_irqsave(&apbs[i].mutex, flags); 5581da177e4SLinus Torvalds 5591da177e4SLinus Torvalds tmp = readb(apbs[i].RamIO + DATA_TO_PC_READY); 5601da177e4SLinus Torvalds 5611da177e4SLinus Torvalds if (tmp == 2) { 5621da177e4SLinus Torvalds struct st_ram_io st_loc; 5631da177e4SLinus Torvalds struct mailbox mailbox; 5641da177e4SLinus Torvalds 5651da177e4SLinus Torvalds /* Got a packet for us */ 5661da177e4SLinus Torvalds ret = do_ac_read(i, buf, &st_loc, &mailbox); 5671da177e4SLinus Torvalds spin_unlock_irqrestore(&apbs[i].mutex, flags); 5681da177e4SLinus Torvalds set_current_state(TASK_RUNNING); 5691da177e4SLinus Torvalds remove_wait_queue(&FlagSleepRec, &wait); 5701da177e4SLinus Torvalds 5711da177e4SLinus Torvalds if (copy_to_user(buf, &st_loc, sizeof(st_loc))) 5721da177e4SLinus Torvalds return -EFAULT; 5731da177e4SLinus Torvalds if (copy_to_user(buf + sizeof(st_loc), &mailbox, sizeof(mailbox))) 5741da177e4SLinus Torvalds return -EFAULT; 5751da177e4SLinus Torvalds return tmp; 5761da177e4SLinus Torvalds } 5771da177e4SLinus Torvalds 5781da177e4SLinus Torvalds if (tmp > 2) { 5791da177e4SLinus Torvalds /* Got an error */ 5801da177e4SLinus Torvalds Dummy = readb(apbs[i].RamIO + VERS); 5811da177e4SLinus Torvalds 5821da177e4SLinus Torvalds spin_unlock_irqrestore(&apbs[i].mutex, flags); 5831da177e4SLinus Torvalds set_current_state(TASK_RUNNING); 5841da177e4SLinus Torvalds remove_wait_queue(&FlagSleepRec, &wait); 5851da177e4SLinus Torvalds 5861da177e4SLinus Torvalds printk(KERN_WARNING "APPLICOM driver read error board %d, DataToPcReady = %d\n", 5871da177e4SLinus Torvalds i,(int)readb(apbs[i].RamIO + DATA_TO_PC_READY)); 5881da177e4SLinus Torvalds DeviceErrorCount++; 5891da177e4SLinus Torvalds return -EIO; 5901da177e4SLinus Torvalds } 5911da177e4SLinus Torvalds 5921da177e4SLinus Torvalds /* Nothing for us. Try the next board */ 5931da177e4SLinus Torvalds Dummy = readb(apbs[i].RamIO + VERS); 5941da177e4SLinus Torvalds spin_unlock_irqrestore(&apbs[i].mutex, flags); 5951da177e4SLinus Torvalds 5961da177e4SLinus Torvalds } /* per board */ 5971da177e4SLinus Torvalds 5981da177e4SLinus Torvalds /* OK - No boards had data for us. Sleep now */ 5991da177e4SLinus Torvalds 6001da177e4SLinus Torvalds schedule(); 6011da177e4SLinus Torvalds remove_wait_queue(&FlagSleepRec, &wait); 6021da177e4SLinus Torvalds 6031da177e4SLinus Torvalds if (signal_pending(current)) 6041da177e4SLinus Torvalds return -EINTR; 6051da177e4SLinus Torvalds 6061da177e4SLinus Torvalds #ifdef DEBUG 6071da177e4SLinus Torvalds if (loopcount++ > 2) { 60856003191SDomen Puncer printk(KERN_DEBUG "Looping in ac_read. loopcount %d\n", loopcount); 6091da177e4SLinus Torvalds } 6101da177e4SLinus Torvalds #endif 6111da177e4SLinus Torvalds } 6121da177e4SLinus Torvalds } 6131da177e4SLinus Torvalds 6147d12e780SDavid Howells static irqreturn_t ac_interrupt(int vec, void *dev_instance) 6151da177e4SLinus Torvalds { 6161da177e4SLinus Torvalds unsigned int i; 6171da177e4SLinus Torvalds unsigned int FlagInt; 6181da177e4SLinus Torvalds unsigned int LoopCount; 6191da177e4SLinus Torvalds int handled = 0; 6201da177e4SLinus Torvalds 6211da177e4SLinus Torvalds // printk("Applicom interrupt on IRQ %d occurred\n", vec); 6221da177e4SLinus Torvalds 6231da177e4SLinus Torvalds LoopCount = 0; 6241da177e4SLinus Torvalds 6251da177e4SLinus Torvalds do { 6261da177e4SLinus Torvalds FlagInt = 0; 6271da177e4SLinus Torvalds for (i = 0; i < MAX_BOARD; i++) { 6281da177e4SLinus Torvalds 6291da177e4SLinus Torvalds /* Skip if this board doesn't exist */ 6301da177e4SLinus Torvalds if (!apbs[i].RamIO) 6311da177e4SLinus Torvalds continue; 6321da177e4SLinus Torvalds 6331da177e4SLinus Torvalds spin_lock(&apbs[i].mutex); 6341da177e4SLinus Torvalds 6351da177e4SLinus Torvalds /* Skip if this board doesn't want attention */ 6361da177e4SLinus Torvalds if(readb(apbs[i].RamIO + RAM_IT_TO_PC) == 0) { 6371da177e4SLinus Torvalds spin_unlock(&apbs[i].mutex); 6381da177e4SLinus Torvalds continue; 6391da177e4SLinus Torvalds } 6401da177e4SLinus Torvalds 6411da177e4SLinus Torvalds handled = 1; 6421da177e4SLinus Torvalds FlagInt = 1; 6431da177e4SLinus Torvalds writeb(0, apbs[i].RamIO + RAM_IT_TO_PC); 6441da177e4SLinus Torvalds 6451da177e4SLinus Torvalds if (readb(apbs[i].RamIO + DATA_TO_PC_READY) > 2) { 6461da177e4SLinus Torvalds printk(KERN_WARNING "APPLICOM driver interrupt err board %d, DataToPcReady = %d\n", 6471da177e4SLinus Torvalds i+1,(int)readb(apbs[i].RamIO + DATA_TO_PC_READY)); 6481da177e4SLinus Torvalds DeviceErrorCount++; 6491da177e4SLinus Torvalds } 6501da177e4SLinus Torvalds 6511da177e4SLinus Torvalds if((readb(apbs[i].RamIO + DATA_FROM_PC_READY) > 2) && 6521da177e4SLinus Torvalds (readb(apbs[i].RamIO + DATA_FROM_PC_READY) != 6)) { 6531da177e4SLinus Torvalds 6541da177e4SLinus Torvalds printk(KERN_WARNING "APPLICOM driver interrupt err board %d, DataFromPcReady = %d\n", 6551da177e4SLinus Torvalds i+1,(int)readb(apbs[i].RamIO + DATA_FROM_PC_READY)); 6561da177e4SLinus Torvalds DeviceErrorCount++; 6571da177e4SLinus Torvalds } 6581da177e4SLinus Torvalds 6591da177e4SLinus Torvalds if (readb(apbs[i].RamIO + DATA_TO_PC_READY) == 2) { /* mailbox sent by the card ? */ 6601da177e4SLinus Torvalds if (waitqueue_active(&FlagSleepRec)) { 6611da177e4SLinus Torvalds wake_up_interruptible(&FlagSleepRec); 6621da177e4SLinus Torvalds } 6631da177e4SLinus Torvalds } 6641da177e4SLinus Torvalds 6651da177e4SLinus Torvalds if (readb(apbs[i].RamIO + DATA_FROM_PC_READY) == 0) { /* ram i/o free for write by pc ? */ 6661da177e4SLinus Torvalds if (waitqueue_active(&apbs[i].FlagSleepSend)) { /* process sleep during read ? */ 6671da177e4SLinus Torvalds wake_up_interruptible(&apbs[i].FlagSleepSend); 6681da177e4SLinus Torvalds } 6691da177e4SLinus Torvalds } 6701da177e4SLinus Torvalds Dummy = readb(apbs[i].RamIO + VERS); 6711da177e4SLinus Torvalds 6721da177e4SLinus Torvalds if(readb(apbs[i].RamIO + RAM_IT_TO_PC)) { 6731da177e4SLinus Torvalds /* There's another int waiting on this card */ 6741da177e4SLinus Torvalds spin_unlock(&apbs[i].mutex); 6751da177e4SLinus Torvalds i--; 6761da177e4SLinus Torvalds } else { 6771da177e4SLinus Torvalds spin_unlock(&apbs[i].mutex); 6781da177e4SLinus Torvalds } 6791da177e4SLinus Torvalds } 6801da177e4SLinus Torvalds if (FlagInt) 6811da177e4SLinus Torvalds LoopCount = 0; 6821da177e4SLinus Torvalds else 6831da177e4SLinus Torvalds LoopCount++; 6841da177e4SLinus Torvalds } while(LoopCount < 2); 6851da177e4SLinus Torvalds return IRQ_RETVAL(handled); 6861da177e4SLinus Torvalds } 6871da177e4SLinus Torvalds 6881da177e4SLinus Torvalds 6891da177e4SLinus Torvalds 6901da177e4SLinus Torvalds static int ac_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) 6911da177e4SLinus Torvalds 6921da177e4SLinus Torvalds { /* @ ADG ou ATO selon le cas */ 6931da177e4SLinus Torvalds int i; 6941da177e4SLinus Torvalds unsigned char IndexCard; 6951da177e4SLinus Torvalds void __iomem *pmem; 6961da177e4SLinus Torvalds int ret = 0; 6971da177e4SLinus Torvalds volatile unsigned char byte_reset_it; 6981da177e4SLinus Torvalds struct st_ram_io *adgl; 6991da177e4SLinus Torvalds void __user *argp = (void __user *)arg; 7001da177e4SLinus Torvalds 7011da177e4SLinus Torvalds /* In general, the device is only openable by root anyway, so we're not 7021da177e4SLinus Torvalds particularly concerned that bogus ioctls can flood the console. */ 7031da177e4SLinus Torvalds 7041da177e4SLinus Torvalds adgl = kmalloc(sizeof(struct st_ram_io), GFP_KERNEL); 7051da177e4SLinus Torvalds if (!adgl) 7061da177e4SLinus Torvalds return -ENOMEM; 7071da177e4SLinus Torvalds 7081da177e4SLinus Torvalds if (copy_from_user(adgl, argp, sizeof(struct st_ram_io))) { 7091da177e4SLinus Torvalds kfree(adgl); 7101da177e4SLinus Torvalds return -EFAULT; 7111da177e4SLinus Torvalds } 7121da177e4SLinus Torvalds 7131da177e4SLinus Torvalds IndexCard = adgl->num_card-1; 7141da177e4SLinus Torvalds 715a7be18d4SAlan Cox if(cmd != 6 && ((IndexCard >= MAX_BOARD) || !apbs[IndexCard].RamIO)) { 7161da177e4SLinus Torvalds static int warncount = 10; 7171da177e4SLinus Torvalds if (warncount) { 7181da177e4SLinus Torvalds printk( KERN_WARNING "APPLICOM driver IOCTL, bad board number %d\n",(int)IndexCard+1); 7191da177e4SLinus Torvalds warncount--; 7201da177e4SLinus Torvalds } 7211da177e4SLinus Torvalds kfree(adgl); 7221da177e4SLinus Torvalds return -EINVAL; 7231da177e4SLinus Torvalds } 7241da177e4SLinus Torvalds 7251da177e4SLinus Torvalds switch (cmd) { 7261da177e4SLinus Torvalds 7271da177e4SLinus Torvalds case 0: 7281da177e4SLinus Torvalds pmem = apbs[IndexCard].RamIO; 7291da177e4SLinus Torvalds for (i = 0; i < sizeof(struct st_ram_io); i++) 7301da177e4SLinus Torvalds ((unsigned char *)adgl)[i]=readb(pmem++); 7311da177e4SLinus Torvalds if (copy_to_user(argp, adgl, sizeof(struct st_ram_io))) 7321da177e4SLinus Torvalds ret = -EFAULT; 7331da177e4SLinus Torvalds break; 7341da177e4SLinus Torvalds case 1: 7351da177e4SLinus Torvalds pmem = apbs[IndexCard].RamIO + CONF_END_TEST; 7361da177e4SLinus Torvalds for (i = 0; i < 4; i++) 7371da177e4SLinus Torvalds adgl->conf_end_test[i] = readb(pmem++); 7381da177e4SLinus Torvalds for (i = 0; i < 2; i++) 7391da177e4SLinus Torvalds adgl->error_code[i] = readb(pmem++); 7401da177e4SLinus Torvalds for (i = 0; i < 4; i++) 7411da177e4SLinus Torvalds adgl->parameter_error[i] = readb(pmem++); 7421da177e4SLinus Torvalds pmem = apbs[IndexCard].RamIO + VERS; 7431da177e4SLinus Torvalds adgl->vers = readb(pmem); 7441da177e4SLinus Torvalds pmem = apbs[IndexCard].RamIO + TYPE_CARD; 7451da177e4SLinus Torvalds for (i = 0; i < 20; i++) 7461da177e4SLinus Torvalds adgl->reserv1[i] = readb(pmem++); 7471da177e4SLinus Torvalds *(int *)&adgl->reserv1[20] = 7481da177e4SLinus Torvalds (readb(apbs[IndexCard].RamIO + SERIAL_NUMBER) << 16) + 7491da177e4SLinus Torvalds (readb(apbs[IndexCard].RamIO + SERIAL_NUMBER + 1) << 8) + 7501da177e4SLinus Torvalds (readb(apbs[IndexCard].RamIO + SERIAL_NUMBER + 2) ); 7511da177e4SLinus Torvalds 7521da177e4SLinus Torvalds if (copy_to_user(argp, adgl, sizeof(struct st_ram_io))) 7531da177e4SLinus Torvalds ret = -EFAULT; 7541da177e4SLinus Torvalds break; 7551da177e4SLinus Torvalds case 2: 7561da177e4SLinus Torvalds pmem = apbs[IndexCard].RamIO + CONF_END_TEST; 7571da177e4SLinus Torvalds for (i = 0; i < 10; i++) 7581da177e4SLinus Torvalds writeb(0xff, pmem++); 7591da177e4SLinus Torvalds writeb(adgl->data_from_pc_ready, 7601da177e4SLinus Torvalds apbs[IndexCard].RamIO + DATA_FROM_PC_READY); 7611da177e4SLinus Torvalds 7621da177e4SLinus Torvalds writeb(1, apbs[IndexCard].RamIO + RAM_IT_FROM_PC); 7631da177e4SLinus Torvalds 7641da177e4SLinus Torvalds for (i = 0; i < MAX_BOARD; i++) { 7651da177e4SLinus Torvalds if (apbs[i].RamIO) { 7661da177e4SLinus Torvalds byte_reset_it = readb(apbs[i].RamIO + RAM_IT_TO_PC); 7671da177e4SLinus Torvalds } 7681da177e4SLinus Torvalds } 7691da177e4SLinus Torvalds break; 7701da177e4SLinus Torvalds case 3: 7711da177e4SLinus Torvalds pmem = apbs[IndexCard].RamIO + TIC_DES_FROM_PC; 7721da177e4SLinus Torvalds writeb(adgl->tic_des_from_pc, pmem); 7731da177e4SLinus Torvalds break; 7741da177e4SLinus Torvalds case 4: 7751da177e4SLinus Torvalds pmem = apbs[IndexCard].RamIO + TIC_OWNER_TO_PC; 7761da177e4SLinus Torvalds adgl->tic_owner_to_pc = readb(pmem++); 7771da177e4SLinus Torvalds adgl->numcard_owner_to_pc = readb(pmem); 7781da177e4SLinus Torvalds if (copy_to_user(argp, adgl,sizeof(struct st_ram_io))) 7791da177e4SLinus Torvalds ret = -EFAULT; 7801da177e4SLinus Torvalds break; 7811da177e4SLinus Torvalds case 5: 7821da177e4SLinus Torvalds writeb(adgl->num_card, apbs[IndexCard].RamIO + NUMCARD_OWNER_TO_PC); 7831da177e4SLinus Torvalds writeb(adgl->num_card, apbs[IndexCard].RamIO + NUMCARD_DES_FROM_PC); 7841da177e4SLinus Torvalds writeb(adgl->num_card, apbs[IndexCard].RamIO + NUMCARD_ACK_FROM_PC); 7851da177e4SLinus Torvalds writeb(4, apbs[IndexCard].RamIO + DATA_FROM_PC_READY); 7861da177e4SLinus Torvalds writeb(1, apbs[IndexCard].RamIO + RAM_IT_FROM_PC); 7871da177e4SLinus Torvalds break; 7881da177e4SLinus Torvalds case 6: 7891da177e4SLinus Torvalds printk(KERN_INFO "APPLICOM driver release .... V2.8.0 ($Revision: 1.30 $)\n"); 7901da177e4SLinus Torvalds printk(KERN_INFO "Number of installed boards . %d\n", (int) numboards); 7911da177e4SLinus Torvalds printk(KERN_INFO "Segment of board ........... %X\n", (int) mem); 7921da177e4SLinus Torvalds printk(KERN_INFO "Interrupt IRQ number ....... %d\n", (int) irq); 7931da177e4SLinus Torvalds for (i = 0; i < MAX_BOARD; i++) { 7941da177e4SLinus Torvalds int serial; 7951da177e4SLinus Torvalds char boardname[(SERIAL_NUMBER - TYPE_CARD) + 1]; 7961da177e4SLinus Torvalds 7971da177e4SLinus Torvalds if (!apbs[i].RamIO) 7981da177e4SLinus Torvalds continue; 7991da177e4SLinus Torvalds 8001da177e4SLinus Torvalds for (serial = 0; serial < SERIAL_NUMBER - TYPE_CARD; serial++) 8011da177e4SLinus Torvalds boardname[serial] = readb(apbs[i].RamIO + TYPE_CARD + serial); 8021da177e4SLinus Torvalds boardname[serial] = 0; 8031da177e4SLinus Torvalds 8041da177e4SLinus Torvalds printk(KERN_INFO "Prom version board %d ....... V%d.%d %s", 8051da177e4SLinus Torvalds i+1, 8061da177e4SLinus Torvalds (int)(readb(apbs[IndexCard].RamIO + VERS) >> 4), 8071da177e4SLinus Torvalds (int)(readb(apbs[IndexCard].RamIO + VERS) & 0xF), 8081da177e4SLinus Torvalds boardname); 8091da177e4SLinus Torvalds 8101da177e4SLinus Torvalds 8111da177e4SLinus Torvalds serial = (readb(apbs[i].RamIO + SERIAL_NUMBER) << 16) + 8121da177e4SLinus Torvalds (readb(apbs[i].RamIO + SERIAL_NUMBER + 1) << 8) + 8131da177e4SLinus Torvalds (readb(apbs[i].RamIO + SERIAL_NUMBER + 2) ); 8141da177e4SLinus Torvalds 8151da177e4SLinus Torvalds if (serial != 0) 8161da177e4SLinus Torvalds printk(" S/N %d\n", serial); 8171da177e4SLinus Torvalds else 8181da177e4SLinus Torvalds printk("\n"); 8191da177e4SLinus Torvalds } 8201da177e4SLinus Torvalds if (DeviceErrorCount != 0) 8211da177e4SLinus Torvalds printk(KERN_INFO "DeviceErrorCount ........... %d\n", DeviceErrorCount); 8221da177e4SLinus Torvalds if (ReadErrorCount != 0) 8231da177e4SLinus Torvalds printk(KERN_INFO "ReadErrorCount ............. %d\n", ReadErrorCount); 8241da177e4SLinus Torvalds if (WriteErrorCount != 0) 8251da177e4SLinus Torvalds printk(KERN_INFO "WriteErrorCount ............ %d\n", WriteErrorCount); 8261da177e4SLinus Torvalds if (waitqueue_active(&FlagSleepRec)) 8271da177e4SLinus Torvalds printk(KERN_INFO "Process in read pending\n"); 8281da177e4SLinus Torvalds for (i = 0; i < MAX_BOARD; i++) { 8291da177e4SLinus Torvalds if (apbs[i].RamIO && waitqueue_active(&apbs[i].FlagSleepSend)) 8301da177e4SLinus Torvalds printk(KERN_INFO "Process in write pending board %d\n",i+1); 8311da177e4SLinus Torvalds } 8321da177e4SLinus Torvalds break; 8331da177e4SLinus Torvalds default: 834a7be18d4SAlan Cox ret = -ENOTTY; 8351da177e4SLinus Torvalds break; 8361da177e4SLinus Torvalds } 8371da177e4SLinus Torvalds Dummy = readb(apbs[IndexCard].RamIO + VERS); 8381da177e4SLinus Torvalds kfree(adgl); 8391da177e4SLinus Torvalds return 0; 8401da177e4SLinus Torvalds } 8411da177e4SLinus Torvalds 842