162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* Derived from Applicom driver ac.c for SCO Unix */ 362306a36Sopenharmony_ci/* Ported by David Woodhouse, Axiom (Cambridge) Ltd. */ 462306a36Sopenharmony_ci/* dwmw2@infradead.org 30/8/98 */ 562306a36Sopenharmony_ci/* $Id: ac.c,v 1.30 2000/03/22 16:03:57 dwmw2 Exp $ */ 662306a36Sopenharmony_ci/* This module is for Linux 2.1 and 2.2 series kernels. */ 762306a36Sopenharmony_ci/*****************************************************************************/ 862306a36Sopenharmony_ci/* J PAGET 18/02/94 passage V2.4.2 ioctl avec code 2 reset to les interrupt */ 962306a36Sopenharmony_ci/* ceci pour reseter correctement apres une sortie sauvage */ 1062306a36Sopenharmony_ci/* J PAGET 02/05/94 passage V2.4.3 dans le traitement de d'interruption, */ 1162306a36Sopenharmony_ci/* LoopCount n'etait pas initialise a 0. */ 1262306a36Sopenharmony_ci/* F LAFORSE 04/07/95 version V2.6.0 lecture bidon apres acces a une carte */ 1362306a36Sopenharmony_ci/* pour liberer le bus */ 1462306a36Sopenharmony_ci/* J.PAGET 19/11/95 version V2.6.1 Nombre, addresse,irq n'est plus configure */ 1562306a36Sopenharmony_ci/* et passe en argument a acinit, mais est scrute sur le bus pour s'adapter */ 1662306a36Sopenharmony_ci/* au nombre de cartes presentes sur le bus. IOCL code 6 affichait V2.4.3 */ 1762306a36Sopenharmony_ci/* F.LAFORSE 28/11/95 creation de fichiers acXX.o avec les differentes */ 1862306a36Sopenharmony_ci/* addresses de base des cartes, IOCTL 6 plus complet */ 1962306a36Sopenharmony_ci/* J.PAGET le 19/08/96 copie de la version V2.6 en V2.8.0 sans modification */ 2062306a36Sopenharmony_ci/* de code autre que le texte V2.6.1 en V2.8.0 */ 2162306a36Sopenharmony_ci/*****************************************************************************/ 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#include <linux/kernel.h> 2562306a36Sopenharmony_ci#include <linux/module.h> 2662306a36Sopenharmony_ci#include <linux/interrupt.h> 2762306a36Sopenharmony_ci#include <linux/sched/signal.h> 2862306a36Sopenharmony_ci#include <linux/slab.h> 2962306a36Sopenharmony_ci#include <linux/errno.h> 3062306a36Sopenharmony_ci#include <linux/mutex.h> 3162306a36Sopenharmony_ci#include <linux/miscdevice.h> 3262306a36Sopenharmony_ci#include <linux/pci.h> 3362306a36Sopenharmony_ci#include <linux/wait.h> 3462306a36Sopenharmony_ci#include <linux/init.h> 3562306a36Sopenharmony_ci#include <linux/fs.h> 3662306a36Sopenharmony_ci#include <linux/nospec.h> 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci#include <asm/io.h> 3962306a36Sopenharmony_ci#include <linux/uaccess.h> 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci#include "applicom.h" 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci/* NOTE: We use for loops with {write,read}b() instead of 4562306a36Sopenharmony_ci memcpy_{from,to}io throughout this driver. This is because 4662306a36Sopenharmony_ci the board doesn't correctly handle word accesses - only 4762306a36Sopenharmony_ci bytes. 4862306a36Sopenharmony_ci*/ 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci#undef DEBUG 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci#define MAX_BOARD 8 /* maximum of pc board possible */ 5462306a36Sopenharmony_ci#define MAX_ISA_BOARD 4 5562306a36Sopenharmony_ci#define LEN_RAM_IO 0x800 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci#ifndef PCI_VENDOR_ID_APPLICOM 5862306a36Sopenharmony_ci#define PCI_VENDOR_ID_APPLICOM 0x1389 5962306a36Sopenharmony_ci#define PCI_DEVICE_ID_APPLICOM_PCIGENERIC 0x0001 6062306a36Sopenharmony_ci#define PCI_DEVICE_ID_APPLICOM_PCI2000IBS_CAN 0x0002 6162306a36Sopenharmony_ci#define PCI_DEVICE_ID_APPLICOM_PCI2000PFB 0x0003 6262306a36Sopenharmony_ci#endif 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistatic DEFINE_MUTEX(ac_mutex); 6562306a36Sopenharmony_cistatic char *applicom_pci_devnames[] = { 6662306a36Sopenharmony_ci "PCI board", 6762306a36Sopenharmony_ci "PCI2000IBS / PCI2000CAN", 6862306a36Sopenharmony_ci "PCI2000PFB" 6962306a36Sopenharmony_ci}; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistatic const struct pci_device_id applicom_pci_tbl[] = { 7262306a36Sopenharmony_ci { PCI_VDEVICE(APPLICOM, PCI_DEVICE_ID_APPLICOM_PCIGENERIC) }, 7362306a36Sopenharmony_ci { PCI_VDEVICE(APPLICOM, PCI_DEVICE_ID_APPLICOM_PCI2000IBS_CAN) }, 7462306a36Sopenharmony_ci { PCI_VDEVICE(APPLICOM, PCI_DEVICE_ID_APPLICOM_PCI2000PFB) }, 7562306a36Sopenharmony_ci { 0 } 7662306a36Sopenharmony_ci}; 7762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, applicom_pci_tbl); 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ciMODULE_AUTHOR("David Woodhouse & Applicom International"); 8062306a36Sopenharmony_ciMODULE_DESCRIPTION("Driver for Applicom Profibus card"); 8162306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 8262306a36Sopenharmony_ciMODULE_ALIAS_MISCDEV(AC_MINOR); 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_cistatic struct applicom_board { 8562306a36Sopenharmony_ci unsigned long PhysIO; 8662306a36Sopenharmony_ci void __iomem *RamIO; 8762306a36Sopenharmony_ci wait_queue_head_t FlagSleepSend; 8862306a36Sopenharmony_ci long irq; 8962306a36Sopenharmony_ci spinlock_t mutex; 9062306a36Sopenharmony_ci} apbs[MAX_BOARD]; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cistatic unsigned int irq; /* interrupt number IRQ */ 9362306a36Sopenharmony_cistatic unsigned long mem; /* physical segment of board */ 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cimodule_param_hw(irq, uint, irq, 0); 9662306a36Sopenharmony_ciMODULE_PARM_DESC(irq, "IRQ of the Applicom board"); 9762306a36Sopenharmony_cimodule_param_hw(mem, ulong, iomem, 0); 9862306a36Sopenharmony_ciMODULE_PARM_DESC(mem, "Shared Memory Address of Applicom board"); 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_cistatic unsigned int numboards; /* number of installed boards */ 10162306a36Sopenharmony_cistatic volatile unsigned char Dummy; 10262306a36Sopenharmony_cistatic DECLARE_WAIT_QUEUE_HEAD(FlagSleepRec); 10362306a36Sopenharmony_cistatic unsigned int WriteErrorCount; /* number of write error */ 10462306a36Sopenharmony_cistatic unsigned int ReadErrorCount; /* number of read error */ 10562306a36Sopenharmony_cistatic unsigned int DeviceErrorCount; /* number of device error */ 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_cistatic ssize_t ac_read (struct file *, char __user *, size_t, loff_t *); 10862306a36Sopenharmony_cistatic ssize_t ac_write (struct file *, const char __user *, size_t, loff_t *); 10962306a36Sopenharmony_cistatic long ac_ioctl(struct file *, unsigned int, unsigned long); 11062306a36Sopenharmony_cistatic irqreturn_t ac_interrupt(int, void *); 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_cistatic const struct file_operations ac_fops = { 11362306a36Sopenharmony_ci .owner = THIS_MODULE, 11462306a36Sopenharmony_ci .llseek = no_llseek, 11562306a36Sopenharmony_ci .read = ac_read, 11662306a36Sopenharmony_ci .write = ac_write, 11762306a36Sopenharmony_ci .unlocked_ioctl = ac_ioctl, 11862306a36Sopenharmony_ci}; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_cistatic struct miscdevice ac_miscdev = { 12162306a36Sopenharmony_ci AC_MINOR, 12262306a36Sopenharmony_ci "ac", 12362306a36Sopenharmony_ci &ac_fops 12462306a36Sopenharmony_ci}; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_cistatic int dummy; /* dev_id for request_irq() */ 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_cistatic int ac_register_board(unsigned long physloc, void __iomem *loc, 12962306a36Sopenharmony_ci unsigned char boardno) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci volatile unsigned char byte_reset_it; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci if((readb(loc + CONF_END_TEST) != 0x00) || 13462306a36Sopenharmony_ci (readb(loc + CONF_END_TEST + 1) != 0x55) || 13562306a36Sopenharmony_ci (readb(loc + CONF_END_TEST + 2) != 0xAA) || 13662306a36Sopenharmony_ci (readb(loc + CONF_END_TEST + 3) != 0xFF)) 13762306a36Sopenharmony_ci return 0; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci if (!boardno) 14062306a36Sopenharmony_ci boardno = readb(loc + NUMCARD_OWNER_TO_PC); 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci if (!boardno || boardno > MAX_BOARD) { 14362306a36Sopenharmony_ci printk(KERN_WARNING "Board #%d (at 0x%lx) is out of range (1 <= x <= %d).\n", 14462306a36Sopenharmony_ci boardno, physloc, MAX_BOARD); 14562306a36Sopenharmony_ci return 0; 14662306a36Sopenharmony_ci } 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci if (apbs[boardno - 1].RamIO) { 14962306a36Sopenharmony_ci printk(KERN_WARNING "Board #%d (at 0x%lx) conflicts with previous board #%d (at 0x%lx)\n", 15062306a36Sopenharmony_ci boardno, physloc, boardno, apbs[boardno-1].PhysIO); 15162306a36Sopenharmony_ci return 0; 15262306a36Sopenharmony_ci } 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci boardno--; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci apbs[boardno].PhysIO = physloc; 15762306a36Sopenharmony_ci apbs[boardno].RamIO = loc; 15862306a36Sopenharmony_ci init_waitqueue_head(&apbs[boardno].FlagSleepSend); 15962306a36Sopenharmony_ci spin_lock_init(&apbs[boardno].mutex); 16062306a36Sopenharmony_ci byte_reset_it = readb(loc + RAM_IT_TO_PC); 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci numboards++; 16362306a36Sopenharmony_ci return boardno + 1; 16462306a36Sopenharmony_ci} 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_cistatic void __exit applicom_exit(void) 16762306a36Sopenharmony_ci{ 16862306a36Sopenharmony_ci unsigned int i; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci misc_deregister(&ac_miscdev); 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci for (i = 0; i < MAX_BOARD; i++) { 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci if (!apbs[i].RamIO) 17562306a36Sopenharmony_ci continue; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci if (apbs[i].irq) 17862306a36Sopenharmony_ci free_irq(apbs[i].irq, &dummy); 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci iounmap(apbs[i].RamIO); 18162306a36Sopenharmony_ci } 18262306a36Sopenharmony_ci} 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_cistatic int __init applicom_init(void) 18562306a36Sopenharmony_ci{ 18662306a36Sopenharmony_ci int i, numisa = 0; 18762306a36Sopenharmony_ci struct pci_dev *dev = NULL; 18862306a36Sopenharmony_ci void __iomem *RamIO; 18962306a36Sopenharmony_ci int boardno, ret; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci printk(KERN_INFO "Applicom driver: $Id: ac.c,v 1.30 2000/03/22 16:03:57 dwmw2 Exp $\n"); 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci /* No mem and irq given - check for a PCI card */ 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci while ( (dev = pci_get_class(PCI_CLASS_OTHERS << 16, dev))) { 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci if (!pci_match_id(applicom_pci_tbl, dev)) 19862306a36Sopenharmony_ci continue; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci if (pci_enable_device(dev)) { 20162306a36Sopenharmony_ci pci_dev_put(dev); 20262306a36Sopenharmony_ci return -EIO; 20362306a36Sopenharmony_ci } 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci RamIO = ioremap(pci_resource_start(dev, 0), LEN_RAM_IO); 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci if (!RamIO) { 20862306a36Sopenharmony_ci printk(KERN_INFO "ac.o: Failed to ioremap PCI memory " 20962306a36Sopenharmony_ci "space at 0x%llx\n", 21062306a36Sopenharmony_ci (unsigned long long)pci_resource_start(dev, 0)); 21162306a36Sopenharmony_ci pci_disable_device(dev); 21262306a36Sopenharmony_ci pci_dev_put(dev); 21362306a36Sopenharmony_ci return -EIO; 21462306a36Sopenharmony_ci } 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci printk(KERN_INFO "Applicom %s found at mem 0x%llx, irq %d\n", 21762306a36Sopenharmony_ci applicom_pci_devnames[dev->device-1], 21862306a36Sopenharmony_ci (unsigned long long)pci_resource_start(dev, 0), 21962306a36Sopenharmony_ci dev->irq); 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci boardno = ac_register_board(pci_resource_start(dev, 0), 22262306a36Sopenharmony_ci RamIO, 0); 22362306a36Sopenharmony_ci if (!boardno) { 22462306a36Sopenharmony_ci printk(KERN_INFO "ac.o: PCI Applicom device doesn't have correct signature.\n"); 22562306a36Sopenharmony_ci iounmap(RamIO); 22662306a36Sopenharmony_ci pci_disable_device(dev); 22762306a36Sopenharmony_ci continue; 22862306a36Sopenharmony_ci } 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci if (request_irq(dev->irq, &ac_interrupt, IRQF_SHARED, "Applicom PCI", &dummy)) { 23162306a36Sopenharmony_ci printk(KERN_INFO "Could not allocate IRQ %d for PCI Applicom device.\n", dev->irq); 23262306a36Sopenharmony_ci iounmap(RamIO); 23362306a36Sopenharmony_ci pci_disable_device(dev); 23462306a36Sopenharmony_ci apbs[boardno - 1].RamIO = NULL; 23562306a36Sopenharmony_ci continue; 23662306a36Sopenharmony_ci } 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci /* Enable interrupts. */ 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci writeb(0x40, apbs[boardno - 1].RamIO + RAM_IT_FROM_PC); 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci apbs[boardno - 1].irq = dev->irq; 24362306a36Sopenharmony_ci } 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci /* Finished with PCI cards. If none registered, 24662306a36Sopenharmony_ci * and there was no mem/irq specified, exit */ 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci if (!mem || !irq) { 24962306a36Sopenharmony_ci if (numboards) 25062306a36Sopenharmony_ci goto fin; 25162306a36Sopenharmony_ci else { 25262306a36Sopenharmony_ci printk(KERN_INFO "ac.o: No PCI boards found.\n"); 25362306a36Sopenharmony_ci printk(KERN_INFO "ac.o: For an ISA board you must supply memory and irq parameters.\n"); 25462306a36Sopenharmony_ci return -ENXIO; 25562306a36Sopenharmony_ci } 25662306a36Sopenharmony_ci } 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci /* Now try the specified ISA cards */ 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci for (i = 0; i < MAX_ISA_BOARD; i++) { 26162306a36Sopenharmony_ci RamIO = ioremap(mem + (LEN_RAM_IO * i), LEN_RAM_IO); 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci if (!RamIO) { 26462306a36Sopenharmony_ci printk(KERN_INFO "ac.o: Failed to ioremap the ISA card's memory space (slot #%d)\n", i + 1); 26562306a36Sopenharmony_ci continue; 26662306a36Sopenharmony_ci } 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci if (!(boardno = ac_register_board((unsigned long)mem+ (LEN_RAM_IO*i), 26962306a36Sopenharmony_ci RamIO,i+1))) { 27062306a36Sopenharmony_ci iounmap(RamIO); 27162306a36Sopenharmony_ci continue; 27262306a36Sopenharmony_ci } 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci printk(KERN_NOTICE "Applicom ISA card found at mem 0x%lx, irq %d\n", mem + (LEN_RAM_IO*i), irq); 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci if (!numisa) { 27762306a36Sopenharmony_ci if (request_irq(irq, &ac_interrupt, IRQF_SHARED, "Applicom ISA", &dummy)) { 27862306a36Sopenharmony_ci printk(KERN_WARNING "Could not allocate IRQ %d for ISA Applicom device.\n", irq); 27962306a36Sopenharmony_ci iounmap(RamIO); 28062306a36Sopenharmony_ci apbs[boardno - 1].RamIO = NULL; 28162306a36Sopenharmony_ci } 28262306a36Sopenharmony_ci else 28362306a36Sopenharmony_ci apbs[boardno - 1].irq = irq; 28462306a36Sopenharmony_ci } 28562306a36Sopenharmony_ci else 28662306a36Sopenharmony_ci apbs[boardno - 1].irq = 0; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci numisa++; 28962306a36Sopenharmony_ci } 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci if (!numisa) 29262306a36Sopenharmony_ci printk(KERN_WARNING "ac.o: No valid ISA Applicom boards found " 29362306a36Sopenharmony_ci "at mem 0x%lx\n", mem); 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci fin: 29662306a36Sopenharmony_ci init_waitqueue_head(&FlagSleepRec); 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci WriteErrorCount = 0; 29962306a36Sopenharmony_ci ReadErrorCount = 0; 30062306a36Sopenharmony_ci DeviceErrorCount = 0; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci if (numboards) { 30362306a36Sopenharmony_ci ret = misc_register(&ac_miscdev); 30462306a36Sopenharmony_ci if (ret) { 30562306a36Sopenharmony_ci printk(KERN_WARNING "ac.o: Unable to register misc device\n"); 30662306a36Sopenharmony_ci goto out; 30762306a36Sopenharmony_ci } 30862306a36Sopenharmony_ci for (i = 0; i < MAX_BOARD; i++) { 30962306a36Sopenharmony_ci int serial; 31062306a36Sopenharmony_ci char boardname[(SERIAL_NUMBER - TYPE_CARD) + 1]; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci if (!apbs[i].RamIO) 31362306a36Sopenharmony_ci continue; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci for (serial = 0; serial < SERIAL_NUMBER - TYPE_CARD; serial++) 31662306a36Sopenharmony_ci boardname[serial] = readb(apbs[i].RamIO + TYPE_CARD + serial); 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci boardname[serial] = 0; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci printk(KERN_INFO "Applicom board %d: %s, PROM V%d.%d", 32262306a36Sopenharmony_ci i+1, boardname, 32362306a36Sopenharmony_ci (int)(readb(apbs[i].RamIO + VERS) >> 4), 32462306a36Sopenharmony_ci (int)(readb(apbs[i].RamIO + VERS) & 0xF)); 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci serial = (readb(apbs[i].RamIO + SERIAL_NUMBER) << 16) + 32762306a36Sopenharmony_ci (readb(apbs[i].RamIO + SERIAL_NUMBER + 1) << 8) + 32862306a36Sopenharmony_ci (readb(apbs[i].RamIO + SERIAL_NUMBER + 2) ); 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci if (serial != 0) 33162306a36Sopenharmony_ci printk(" S/N %d\n", serial); 33262306a36Sopenharmony_ci else 33362306a36Sopenharmony_ci printk("\n"); 33462306a36Sopenharmony_ci } 33562306a36Sopenharmony_ci return 0; 33662306a36Sopenharmony_ci } 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci else 33962306a36Sopenharmony_ci return -ENXIO; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ciout: 34262306a36Sopenharmony_ci for (i = 0; i < MAX_BOARD; i++) { 34362306a36Sopenharmony_ci if (!apbs[i].RamIO) 34462306a36Sopenharmony_ci continue; 34562306a36Sopenharmony_ci if (apbs[i].irq) 34662306a36Sopenharmony_ci free_irq(apbs[i].irq, &dummy); 34762306a36Sopenharmony_ci iounmap(apbs[i].RamIO); 34862306a36Sopenharmony_ci } 34962306a36Sopenharmony_ci return ret; 35062306a36Sopenharmony_ci} 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_cimodule_init(applicom_init); 35362306a36Sopenharmony_cimodule_exit(applicom_exit); 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_cistatic ssize_t ac_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos) 35762306a36Sopenharmony_ci{ 35862306a36Sopenharmony_ci unsigned int NumCard; /* Board number 1 -> 8 */ 35962306a36Sopenharmony_ci unsigned int IndexCard; /* Index board number 0 -> 7 */ 36062306a36Sopenharmony_ci unsigned char TicCard; /* Board TIC to send */ 36162306a36Sopenharmony_ci unsigned long flags; /* Current priority */ 36262306a36Sopenharmony_ci struct st_ram_io st_loc; 36362306a36Sopenharmony_ci struct mailbox tmpmailbox; 36462306a36Sopenharmony_ci#ifdef DEBUG 36562306a36Sopenharmony_ci int c; 36662306a36Sopenharmony_ci#endif 36762306a36Sopenharmony_ci DECLARE_WAITQUEUE(wait, current); 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci if (count != sizeof(struct st_ram_io) + sizeof(struct mailbox)) { 37062306a36Sopenharmony_ci static int warncount = 5; 37162306a36Sopenharmony_ci if (warncount) { 37262306a36Sopenharmony_ci printk(KERN_INFO "Hmmm. write() of Applicom card, length %zd != expected %zd\n", 37362306a36Sopenharmony_ci count, sizeof(struct st_ram_io) + sizeof(struct mailbox)); 37462306a36Sopenharmony_ci warncount--; 37562306a36Sopenharmony_ci } 37662306a36Sopenharmony_ci return -EINVAL; 37762306a36Sopenharmony_ci } 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci if(copy_from_user(&st_loc, buf, sizeof(struct st_ram_io))) 38062306a36Sopenharmony_ci return -EFAULT; 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci if(copy_from_user(&tmpmailbox, &buf[sizeof(struct st_ram_io)], 38362306a36Sopenharmony_ci sizeof(struct mailbox))) 38462306a36Sopenharmony_ci return -EFAULT; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci NumCard = st_loc.num_card; /* board number to send */ 38762306a36Sopenharmony_ci TicCard = st_loc.tic_des_from_pc; /* tic number to send */ 38862306a36Sopenharmony_ci IndexCard = NumCard - 1; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci if (IndexCard >= MAX_BOARD) 39162306a36Sopenharmony_ci return -EINVAL; 39262306a36Sopenharmony_ci IndexCard = array_index_nospec(IndexCard, MAX_BOARD); 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci if (!apbs[IndexCard].RamIO) 39562306a36Sopenharmony_ci return -EINVAL; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci#ifdef DEBUG 39862306a36Sopenharmony_ci printk("Write to applicom card #%d. struct st_ram_io follows:", 39962306a36Sopenharmony_ci IndexCard+1); 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci for (c = 0; c < sizeof(struct st_ram_io);) { 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci printk("\n%5.5X: %2.2X", c, ((unsigned char *) &st_loc)[c]); 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci for (c++; c % 8 && c < sizeof(struct st_ram_io); c++) { 40662306a36Sopenharmony_ci printk(" %2.2X", ((unsigned char *) &st_loc)[c]); 40762306a36Sopenharmony_ci } 40862306a36Sopenharmony_ci } 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci printk("\nstruct mailbox follows:"); 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci for (c = 0; c < sizeof(struct mailbox);) { 41362306a36Sopenharmony_ci printk("\n%5.5X: %2.2X", c, ((unsigned char *) &tmpmailbox)[c]); 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci for (c++; c % 8 && c < sizeof(struct mailbox); c++) { 41662306a36Sopenharmony_ci printk(" %2.2X", ((unsigned char *) &tmpmailbox)[c]); 41762306a36Sopenharmony_ci } 41862306a36Sopenharmony_ci } 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci printk("\n"); 42162306a36Sopenharmony_ci#endif 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci spin_lock_irqsave(&apbs[IndexCard].mutex, flags); 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci /* Test octet ready correct */ 42662306a36Sopenharmony_ci if(readb(apbs[IndexCard].RamIO + DATA_FROM_PC_READY) > 2) { 42762306a36Sopenharmony_ci Dummy = readb(apbs[IndexCard].RamIO + VERS); 42862306a36Sopenharmony_ci spin_unlock_irqrestore(&apbs[IndexCard].mutex, flags); 42962306a36Sopenharmony_ci printk(KERN_WARNING "APPLICOM driver write error board %d, DataFromPcReady = %d\n", 43062306a36Sopenharmony_ci IndexCard,(int)readb(apbs[IndexCard].RamIO + DATA_FROM_PC_READY)); 43162306a36Sopenharmony_ci DeviceErrorCount++; 43262306a36Sopenharmony_ci return -EIO; 43362306a36Sopenharmony_ci } 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci /* Place ourselves on the wait queue */ 43662306a36Sopenharmony_ci set_current_state(TASK_INTERRUPTIBLE); 43762306a36Sopenharmony_ci add_wait_queue(&apbs[IndexCard].FlagSleepSend, &wait); 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci /* Check whether the card is ready for us */ 44062306a36Sopenharmony_ci while (readb(apbs[IndexCard].RamIO + DATA_FROM_PC_READY) != 0) { 44162306a36Sopenharmony_ci Dummy = readb(apbs[IndexCard].RamIO + VERS); 44262306a36Sopenharmony_ci /* It's busy. Sleep. */ 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci spin_unlock_irqrestore(&apbs[IndexCard].mutex, flags); 44562306a36Sopenharmony_ci schedule(); 44662306a36Sopenharmony_ci if (signal_pending(current)) { 44762306a36Sopenharmony_ci remove_wait_queue(&apbs[IndexCard].FlagSleepSend, 44862306a36Sopenharmony_ci &wait); 44962306a36Sopenharmony_ci return -EINTR; 45062306a36Sopenharmony_ci } 45162306a36Sopenharmony_ci spin_lock_irqsave(&apbs[IndexCard].mutex, flags); 45262306a36Sopenharmony_ci set_current_state(TASK_INTERRUPTIBLE); 45362306a36Sopenharmony_ci } 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci /* We may not have actually slept */ 45662306a36Sopenharmony_ci set_current_state(TASK_RUNNING); 45762306a36Sopenharmony_ci remove_wait_queue(&apbs[IndexCard].FlagSleepSend, &wait); 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci writeb(1, apbs[IndexCard].RamIO + DATA_FROM_PC_READY); 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci /* Which is best - lock down the pages with rawio and then 46262306a36Sopenharmony_ci copy directly, or use bounce buffers? For now we do the latter 46362306a36Sopenharmony_ci because it works with 2.2 still */ 46462306a36Sopenharmony_ci { 46562306a36Sopenharmony_ci unsigned char *from = (unsigned char *) &tmpmailbox; 46662306a36Sopenharmony_ci void __iomem *to = apbs[IndexCard].RamIO + RAM_FROM_PC; 46762306a36Sopenharmony_ci int c; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci for (c = 0; c < sizeof(struct mailbox); c++) 47062306a36Sopenharmony_ci writeb(*(from++), to++); 47162306a36Sopenharmony_ci } 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci writeb(0x20, apbs[IndexCard].RamIO + TIC_OWNER_FROM_PC); 47462306a36Sopenharmony_ci writeb(0xff, apbs[IndexCard].RamIO + NUMCARD_OWNER_FROM_PC); 47562306a36Sopenharmony_ci writeb(TicCard, apbs[IndexCard].RamIO + TIC_DES_FROM_PC); 47662306a36Sopenharmony_ci writeb(NumCard, apbs[IndexCard].RamIO + NUMCARD_DES_FROM_PC); 47762306a36Sopenharmony_ci writeb(2, apbs[IndexCard].RamIO + DATA_FROM_PC_READY); 47862306a36Sopenharmony_ci writeb(1, apbs[IndexCard].RamIO + RAM_IT_FROM_PC); 47962306a36Sopenharmony_ci Dummy = readb(apbs[IndexCard].RamIO + VERS); 48062306a36Sopenharmony_ci spin_unlock_irqrestore(&apbs[IndexCard].mutex, flags); 48162306a36Sopenharmony_ci return 0; 48262306a36Sopenharmony_ci} 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_cistatic int do_ac_read(int IndexCard, char __user *buf, 48562306a36Sopenharmony_ci struct st_ram_io *st_loc, struct mailbox *mailbox) 48662306a36Sopenharmony_ci{ 48762306a36Sopenharmony_ci void __iomem *from = apbs[IndexCard].RamIO + RAM_TO_PC; 48862306a36Sopenharmony_ci unsigned char *to = (unsigned char *)mailbox; 48962306a36Sopenharmony_ci#ifdef DEBUG 49062306a36Sopenharmony_ci int c; 49162306a36Sopenharmony_ci#endif 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci st_loc->tic_owner_to_pc = readb(apbs[IndexCard].RamIO + TIC_OWNER_TO_PC); 49462306a36Sopenharmony_ci st_loc->numcard_owner_to_pc = readb(apbs[IndexCard].RamIO + NUMCARD_OWNER_TO_PC); 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci { 49862306a36Sopenharmony_ci int c; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci for (c = 0; c < sizeof(struct mailbox); c++) 50162306a36Sopenharmony_ci *(to++) = readb(from++); 50262306a36Sopenharmony_ci } 50362306a36Sopenharmony_ci writeb(1, apbs[IndexCard].RamIO + ACK_FROM_PC_READY); 50462306a36Sopenharmony_ci writeb(1, apbs[IndexCard].RamIO + TYP_ACK_FROM_PC); 50562306a36Sopenharmony_ci writeb(IndexCard+1, apbs[IndexCard].RamIO + NUMCARD_ACK_FROM_PC); 50662306a36Sopenharmony_ci writeb(readb(apbs[IndexCard].RamIO + TIC_OWNER_TO_PC), 50762306a36Sopenharmony_ci apbs[IndexCard].RamIO + TIC_ACK_FROM_PC); 50862306a36Sopenharmony_ci writeb(2, apbs[IndexCard].RamIO + ACK_FROM_PC_READY); 50962306a36Sopenharmony_ci writeb(0, apbs[IndexCard].RamIO + DATA_TO_PC_READY); 51062306a36Sopenharmony_ci writeb(2, apbs[IndexCard].RamIO + RAM_IT_FROM_PC); 51162306a36Sopenharmony_ci Dummy = readb(apbs[IndexCard].RamIO + VERS); 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci#ifdef DEBUG 51462306a36Sopenharmony_ci printk("Read from applicom card #%d. struct st_ram_io follows:", NumCard); 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci for (c = 0; c < sizeof(struct st_ram_io);) { 51762306a36Sopenharmony_ci printk("\n%5.5X: %2.2X", c, ((unsigned char *)st_loc)[c]); 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci for (c++; c % 8 && c < sizeof(struct st_ram_io); c++) { 52062306a36Sopenharmony_ci printk(" %2.2X", ((unsigned char *)st_loc)[c]); 52162306a36Sopenharmony_ci } 52262306a36Sopenharmony_ci } 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci printk("\nstruct mailbox follows:"); 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci for (c = 0; c < sizeof(struct mailbox);) { 52762306a36Sopenharmony_ci printk("\n%5.5X: %2.2X", c, ((unsigned char *)mailbox)[c]); 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci for (c++; c % 8 && c < sizeof(struct mailbox); c++) { 53062306a36Sopenharmony_ci printk(" %2.2X", ((unsigned char *)mailbox)[c]); 53162306a36Sopenharmony_ci } 53262306a36Sopenharmony_ci } 53362306a36Sopenharmony_ci printk("\n"); 53462306a36Sopenharmony_ci#endif 53562306a36Sopenharmony_ci return (sizeof(struct st_ram_io) + sizeof(struct mailbox)); 53662306a36Sopenharmony_ci} 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_cistatic ssize_t ac_read (struct file *filp, char __user *buf, size_t count, loff_t *ptr) 53962306a36Sopenharmony_ci{ 54062306a36Sopenharmony_ci unsigned long flags; 54162306a36Sopenharmony_ci unsigned int i; 54262306a36Sopenharmony_ci unsigned char tmp; 54362306a36Sopenharmony_ci int ret = 0; 54462306a36Sopenharmony_ci DECLARE_WAITQUEUE(wait, current); 54562306a36Sopenharmony_ci#ifdef DEBUG 54662306a36Sopenharmony_ci int loopcount=0; 54762306a36Sopenharmony_ci#endif 54862306a36Sopenharmony_ci /* No need to ratelimit this. Only root can trigger it anyway */ 54962306a36Sopenharmony_ci if (count != sizeof(struct st_ram_io) + sizeof(struct mailbox)) { 55062306a36Sopenharmony_ci printk( KERN_WARNING "Hmmm. read() of Applicom card, length %zd != expected %zd\n", 55162306a36Sopenharmony_ci count,sizeof(struct st_ram_io) + sizeof(struct mailbox)); 55262306a36Sopenharmony_ci return -EINVAL; 55362306a36Sopenharmony_ci } 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci while(1) { 55662306a36Sopenharmony_ci /* Stick ourself on the wait queue */ 55762306a36Sopenharmony_ci set_current_state(TASK_INTERRUPTIBLE); 55862306a36Sopenharmony_ci add_wait_queue(&FlagSleepRec, &wait); 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci /* Scan each board, looking for one which has a packet for us */ 56162306a36Sopenharmony_ci for (i=0; i < MAX_BOARD; i++) { 56262306a36Sopenharmony_ci if (!apbs[i].RamIO) 56362306a36Sopenharmony_ci continue; 56462306a36Sopenharmony_ci spin_lock_irqsave(&apbs[i].mutex, flags); 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci tmp = readb(apbs[i].RamIO + DATA_TO_PC_READY); 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci if (tmp == 2) { 56962306a36Sopenharmony_ci struct st_ram_io st_loc; 57062306a36Sopenharmony_ci struct mailbox mailbox; 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci /* Got a packet for us */ 57362306a36Sopenharmony_ci memset(&st_loc, 0, sizeof(st_loc)); 57462306a36Sopenharmony_ci ret = do_ac_read(i, buf, &st_loc, &mailbox); 57562306a36Sopenharmony_ci spin_unlock_irqrestore(&apbs[i].mutex, flags); 57662306a36Sopenharmony_ci set_current_state(TASK_RUNNING); 57762306a36Sopenharmony_ci remove_wait_queue(&FlagSleepRec, &wait); 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci if (copy_to_user(buf, &st_loc, sizeof(st_loc))) 58062306a36Sopenharmony_ci return -EFAULT; 58162306a36Sopenharmony_ci if (copy_to_user(buf + sizeof(st_loc), &mailbox, sizeof(mailbox))) 58262306a36Sopenharmony_ci return -EFAULT; 58362306a36Sopenharmony_ci return tmp; 58462306a36Sopenharmony_ci } 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci if (tmp > 2) { 58762306a36Sopenharmony_ci /* Got an error */ 58862306a36Sopenharmony_ci Dummy = readb(apbs[i].RamIO + VERS); 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci spin_unlock_irqrestore(&apbs[i].mutex, flags); 59162306a36Sopenharmony_ci set_current_state(TASK_RUNNING); 59262306a36Sopenharmony_ci remove_wait_queue(&FlagSleepRec, &wait); 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci printk(KERN_WARNING "APPLICOM driver read error board %d, DataToPcReady = %d\n", 59562306a36Sopenharmony_ci i,(int)readb(apbs[i].RamIO + DATA_TO_PC_READY)); 59662306a36Sopenharmony_ci DeviceErrorCount++; 59762306a36Sopenharmony_ci return -EIO; 59862306a36Sopenharmony_ci } 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci /* Nothing for us. Try the next board */ 60162306a36Sopenharmony_ci Dummy = readb(apbs[i].RamIO + VERS); 60262306a36Sopenharmony_ci spin_unlock_irqrestore(&apbs[i].mutex, flags); 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci } /* per board */ 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci /* OK - No boards had data for us. Sleep now */ 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci schedule(); 60962306a36Sopenharmony_ci remove_wait_queue(&FlagSleepRec, &wait); 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci if (signal_pending(current)) 61262306a36Sopenharmony_ci return -EINTR; 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci#ifdef DEBUG 61562306a36Sopenharmony_ci if (loopcount++ > 2) { 61662306a36Sopenharmony_ci printk(KERN_DEBUG "Looping in ac_read. loopcount %d\n", loopcount); 61762306a36Sopenharmony_ci } 61862306a36Sopenharmony_ci#endif 61962306a36Sopenharmony_ci } 62062306a36Sopenharmony_ci} 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_cistatic irqreturn_t ac_interrupt(int vec, void *dev_instance) 62362306a36Sopenharmony_ci{ 62462306a36Sopenharmony_ci unsigned int i; 62562306a36Sopenharmony_ci unsigned int FlagInt; 62662306a36Sopenharmony_ci unsigned int LoopCount; 62762306a36Sopenharmony_ci int handled = 0; 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci // printk("Applicom interrupt on IRQ %d occurred\n", vec); 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci LoopCount = 0; 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci do { 63462306a36Sopenharmony_ci FlagInt = 0; 63562306a36Sopenharmony_ci for (i = 0; i < MAX_BOARD; i++) { 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci /* Skip if this board doesn't exist */ 63862306a36Sopenharmony_ci if (!apbs[i].RamIO) 63962306a36Sopenharmony_ci continue; 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci spin_lock(&apbs[i].mutex); 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci /* Skip if this board doesn't want attention */ 64462306a36Sopenharmony_ci if(readb(apbs[i].RamIO + RAM_IT_TO_PC) == 0) { 64562306a36Sopenharmony_ci spin_unlock(&apbs[i].mutex); 64662306a36Sopenharmony_ci continue; 64762306a36Sopenharmony_ci } 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci handled = 1; 65062306a36Sopenharmony_ci FlagInt = 1; 65162306a36Sopenharmony_ci writeb(0, apbs[i].RamIO + RAM_IT_TO_PC); 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci if (readb(apbs[i].RamIO + DATA_TO_PC_READY) > 2) { 65462306a36Sopenharmony_ci printk(KERN_WARNING "APPLICOM driver interrupt err board %d, DataToPcReady = %d\n", 65562306a36Sopenharmony_ci i+1,(int)readb(apbs[i].RamIO + DATA_TO_PC_READY)); 65662306a36Sopenharmony_ci DeviceErrorCount++; 65762306a36Sopenharmony_ci } 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci if((readb(apbs[i].RamIO + DATA_FROM_PC_READY) > 2) && 66062306a36Sopenharmony_ci (readb(apbs[i].RamIO + DATA_FROM_PC_READY) != 6)) { 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci printk(KERN_WARNING "APPLICOM driver interrupt err board %d, DataFromPcReady = %d\n", 66362306a36Sopenharmony_ci i+1,(int)readb(apbs[i].RamIO + DATA_FROM_PC_READY)); 66462306a36Sopenharmony_ci DeviceErrorCount++; 66562306a36Sopenharmony_ci } 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci if (readb(apbs[i].RamIO + DATA_TO_PC_READY) == 2) { /* mailbox sent by the card ? */ 66862306a36Sopenharmony_ci if (waitqueue_active(&FlagSleepRec)) { 66962306a36Sopenharmony_ci wake_up_interruptible(&FlagSleepRec); 67062306a36Sopenharmony_ci } 67162306a36Sopenharmony_ci } 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci if (readb(apbs[i].RamIO + DATA_FROM_PC_READY) == 0) { /* ram i/o free for write by pc ? */ 67462306a36Sopenharmony_ci if (waitqueue_active(&apbs[i].FlagSleepSend)) { /* process sleep during read ? */ 67562306a36Sopenharmony_ci wake_up_interruptible(&apbs[i].FlagSleepSend); 67662306a36Sopenharmony_ci } 67762306a36Sopenharmony_ci } 67862306a36Sopenharmony_ci Dummy = readb(apbs[i].RamIO + VERS); 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci if(readb(apbs[i].RamIO + RAM_IT_TO_PC)) { 68162306a36Sopenharmony_ci /* There's another int waiting on this card */ 68262306a36Sopenharmony_ci spin_unlock(&apbs[i].mutex); 68362306a36Sopenharmony_ci i--; 68462306a36Sopenharmony_ci } else { 68562306a36Sopenharmony_ci spin_unlock(&apbs[i].mutex); 68662306a36Sopenharmony_ci } 68762306a36Sopenharmony_ci } 68862306a36Sopenharmony_ci if (FlagInt) 68962306a36Sopenharmony_ci LoopCount = 0; 69062306a36Sopenharmony_ci else 69162306a36Sopenharmony_ci LoopCount++; 69262306a36Sopenharmony_ci } while(LoopCount < 2); 69362306a36Sopenharmony_ci return IRQ_RETVAL(handled); 69462306a36Sopenharmony_ci} 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_cistatic long ac_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci{ /* @ ADG ou ATO selon le cas */ 70162306a36Sopenharmony_ci int i; 70262306a36Sopenharmony_ci unsigned char IndexCard; 70362306a36Sopenharmony_ci void __iomem *pmem; 70462306a36Sopenharmony_ci int ret = 0; 70562306a36Sopenharmony_ci static int warncount = 10; 70662306a36Sopenharmony_ci volatile unsigned char byte_reset_it; 70762306a36Sopenharmony_ci struct st_ram_io *adgl; 70862306a36Sopenharmony_ci void __user *argp = (void __user *)arg; 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci /* In general, the device is only openable by root anyway, so we're not 71162306a36Sopenharmony_ci particularly concerned that bogus ioctls can flood the console. */ 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci adgl = memdup_user(argp, sizeof(struct st_ram_io)); 71462306a36Sopenharmony_ci if (IS_ERR(adgl)) 71562306a36Sopenharmony_ci return PTR_ERR(adgl); 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci mutex_lock(&ac_mutex); 71862306a36Sopenharmony_ci IndexCard = adgl->num_card-1; 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci if (cmd != 6 && IndexCard >= MAX_BOARD) 72162306a36Sopenharmony_ci goto err; 72262306a36Sopenharmony_ci IndexCard = array_index_nospec(IndexCard, MAX_BOARD); 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci if (cmd != 6 && !apbs[IndexCard].RamIO) 72562306a36Sopenharmony_ci goto err; 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci switch (cmd) { 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci case 0: 73062306a36Sopenharmony_ci pmem = apbs[IndexCard].RamIO; 73162306a36Sopenharmony_ci for (i = 0; i < sizeof(struct st_ram_io); i++) 73262306a36Sopenharmony_ci ((unsigned char *)adgl)[i]=readb(pmem++); 73362306a36Sopenharmony_ci if (copy_to_user(argp, adgl, sizeof(struct st_ram_io))) 73462306a36Sopenharmony_ci ret = -EFAULT; 73562306a36Sopenharmony_ci break; 73662306a36Sopenharmony_ci case 1: 73762306a36Sopenharmony_ci pmem = apbs[IndexCard].RamIO + CONF_END_TEST; 73862306a36Sopenharmony_ci for (i = 0; i < 4; i++) 73962306a36Sopenharmony_ci adgl->conf_end_test[i] = readb(pmem++); 74062306a36Sopenharmony_ci for (i = 0; i < 2; i++) 74162306a36Sopenharmony_ci adgl->error_code[i] = readb(pmem++); 74262306a36Sopenharmony_ci for (i = 0; i < 4; i++) 74362306a36Sopenharmony_ci adgl->parameter_error[i] = readb(pmem++); 74462306a36Sopenharmony_ci pmem = apbs[IndexCard].RamIO + VERS; 74562306a36Sopenharmony_ci adgl->vers = readb(pmem); 74662306a36Sopenharmony_ci pmem = apbs[IndexCard].RamIO + TYPE_CARD; 74762306a36Sopenharmony_ci for (i = 0; i < 20; i++) 74862306a36Sopenharmony_ci adgl->reserv1[i] = readb(pmem++); 74962306a36Sopenharmony_ci *(int *)&adgl->reserv1[20] = 75062306a36Sopenharmony_ci (readb(apbs[IndexCard].RamIO + SERIAL_NUMBER) << 16) + 75162306a36Sopenharmony_ci (readb(apbs[IndexCard].RamIO + SERIAL_NUMBER + 1) << 8) + 75262306a36Sopenharmony_ci (readb(apbs[IndexCard].RamIO + SERIAL_NUMBER + 2) ); 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci if (copy_to_user(argp, adgl, sizeof(struct st_ram_io))) 75562306a36Sopenharmony_ci ret = -EFAULT; 75662306a36Sopenharmony_ci break; 75762306a36Sopenharmony_ci case 2: 75862306a36Sopenharmony_ci pmem = apbs[IndexCard].RamIO + CONF_END_TEST; 75962306a36Sopenharmony_ci for (i = 0; i < 10; i++) 76062306a36Sopenharmony_ci writeb(0xff, pmem++); 76162306a36Sopenharmony_ci writeb(adgl->data_from_pc_ready, 76262306a36Sopenharmony_ci apbs[IndexCard].RamIO + DATA_FROM_PC_READY); 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci writeb(1, apbs[IndexCard].RamIO + RAM_IT_FROM_PC); 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci for (i = 0; i < MAX_BOARD; i++) { 76762306a36Sopenharmony_ci if (apbs[i].RamIO) { 76862306a36Sopenharmony_ci byte_reset_it = readb(apbs[i].RamIO + RAM_IT_TO_PC); 76962306a36Sopenharmony_ci } 77062306a36Sopenharmony_ci } 77162306a36Sopenharmony_ci break; 77262306a36Sopenharmony_ci case 3: 77362306a36Sopenharmony_ci pmem = apbs[IndexCard].RamIO + TIC_DES_FROM_PC; 77462306a36Sopenharmony_ci writeb(adgl->tic_des_from_pc, pmem); 77562306a36Sopenharmony_ci break; 77662306a36Sopenharmony_ci case 4: 77762306a36Sopenharmony_ci pmem = apbs[IndexCard].RamIO + TIC_OWNER_TO_PC; 77862306a36Sopenharmony_ci adgl->tic_owner_to_pc = readb(pmem++); 77962306a36Sopenharmony_ci adgl->numcard_owner_to_pc = readb(pmem); 78062306a36Sopenharmony_ci if (copy_to_user(argp, adgl,sizeof(struct st_ram_io))) 78162306a36Sopenharmony_ci ret = -EFAULT; 78262306a36Sopenharmony_ci break; 78362306a36Sopenharmony_ci case 5: 78462306a36Sopenharmony_ci writeb(adgl->num_card, apbs[IndexCard].RamIO + NUMCARD_OWNER_TO_PC); 78562306a36Sopenharmony_ci writeb(adgl->num_card, apbs[IndexCard].RamIO + NUMCARD_DES_FROM_PC); 78662306a36Sopenharmony_ci writeb(adgl->num_card, apbs[IndexCard].RamIO + NUMCARD_ACK_FROM_PC); 78762306a36Sopenharmony_ci writeb(4, apbs[IndexCard].RamIO + DATA_FROM_PC_READY); 78862306a36Sopenharmony_ci writeb(1, apbs[IndexCard].RamIO + RAM_IT_FROM_PC); 78962306a36Sopenharmony_ci break; 79062306a36Sopenharmony_ci case 6: 79162306a36Sopenharmony_ci printk(KERN_INFO "APPLICOM driver release .... V2.8.0 ($Revision: 1.30 $)\n"); 79262306a36Sopenharmony_ci printk(KERN_INFO "Number of installed boards . %d\n", (int) numboards); 79362306a36Sopenharmony_ci printk(KERN_INFO "Segment of board ........... %X\n", (int) mem); 79462306a36Sopenharmony_ci printk(KERN_INFO "Interrupt IRQ number ....... %d\n", (int) irq); 79562306a36Sopenharmony_ci for (i = 0; i < MAX_BOARD; i++) { 79662306a36Sopenharmony_ci int serial; 79762306a36Sopenharmony_ci char boardname[(SERIAL_NUMBER - TYPE_CARD) + 1]; 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci if (!apbs[i].RamIO) 80062306a36Sopenharmony_ci continue; 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci for (serial = 0; serial < SERIAL_NUMBER - TYPE_CARD; serial++) 80362306a36Sopenharmony_ci boardname[serial] = readb(apbs[i].RamIO + TYPE_CARD + serial); 80462306a36Sopenharmony_ci boardname[serial] = 0; 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci printk(KERN_INFO "Prom version board %d ....... V%d.%d %s", 80762306a36Sopenharmony_ci i+1, 80862306a36Sopenharmony_ci (int)(readb(apbs[i].RamIO + VERS) >> 4), 80962306a36Sopenharmony_ci (int)(readb(apbs[i].RamIO + VERS) & 0xF), 81062306a36Sopenharmony_ci boardname); 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci serial = (readb(apbs[i].RamIO + SERIAL_NUMBER) << 16) + 81462306a36Sopenharmony_ci (readb(apbs[i].RamIO + SERIAL_NUMBER + 1) << 8) + 81562306a36Sopenharmony_ci (readb(apbs[i].RamIO + SERIAL_NUMBER + 2) ); 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci if (serial != 0) 81862306a36Sopenharmony_ci printk(" S/N %d\n", serial); 81962306a36Sopenharmony_ci else 82062306a36Sopenharmony_ci printk("\n"); 82162306a36Sopenharmony_ci } 82262306a36Sopenharmony_ci if (DeviceErrorCount != 0) 82362306a36Sopenharmony_ci printk(KERN_INFO "DeviceErrorCount ........... %d\n", DeviceErrorCount); 82462306a36Sopenharmony_ci if (ReadErrorCount != 0) 82562306a36Sopenharmony_ci printk(KERN_INFO "ReadErrorCount ............. %d\n", ReadErrorCount); 82662306a36Sopenharmony_ci if (WriteErrorCount != 0) 82762306a36Sopenharmony_ci printk(KERN_INFO "WriteErrorCount ............ %d\n", WriteErrorCount); 82862306a36Sopenharmony_ci if (waitqueue_active(&FlagSleepRec)) 82962306a36Sopenharmony_ci printk(KERN_INFO "Process in read pending\n"); 83062306a36Sopenharmony_ci for (i = 0; i < MAX_BOARD; i++) { 83162306a36Sopenharmony_ci if (apbs[i].RamIO && waitqueue_active(&apbs[i].FlagSleepSend)) 83262306a36Sopenharmony_ci printk(KERN_INFO "Process in write pending board %d\n",i+1); 83362306a36Sopenharmony_ci } 83462306a36Sopenharmony_ci break; 83562306a36Sopenharmony_ci default: 83662306a36Sopenharmony_ci ret = -ENOTTY; 83762306a36Sopenharmony_ci break; 83862306a36Sopenharmony_ci } 83962306a36Sopenharmony_ci Dummy = readb(apbs[IndexCard].RamIO + VERS); 84062306a36Sopenharmony_ci kfree(adgl); 84162306a36Sopenharmony_ci mutex_unlock(&ac_mutex); 84262306a36Sopenharmony_ci return ret; 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_cierr: 84562306a36Sopenharmony_ci if (warncount) { 84662306a36Sopenharmony_ci pr_warn("APPLICOM driver IOCTL, bad board number %d\n", 84762306a36Sopenharmony_ci (int)IndexCard + 1); 84862306a36Sopenharmony_ci warncount--; 84962306a36Sopenharmony_ci } 85062306a36Sopenharmony_ci kfree(adgl); 85162306a36Sopenharmony_ci mutex_unlock(&ac_mutex); 85262306a36Sopenharmony_ci return -EINVAL; 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci} 85562306a36Sopenharmony_ci 856