^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /* Derived from Applicom driver ac.c for SCO Unix */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) /* Ported by David Woodhouse, Axiom (Cambridge) Ltd. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) /* dwmw2@infradead.org 30/8/98 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) /* $Id: ac.c,v 1.30 2000/03/22 16:03:57 dwmw2 Exp $ */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) /* This module is for Linux 2.1 and 2.2 series kernels. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) /*****************************************************************************/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) /* J PAGET 18/02/94 passage V2.4.2 ioctl avec code 2 reset to les interrupt */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) /* ceci pour reseter correctement apres une sortie sauvage */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) /* J PAGET 02/05/94 passage V2.4.3 dans le traitement de d'interruption, */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) /* LoopCount n'etait pas initialise a 0. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) /* F LAFORSE 04/07/95 version V2.6.0 lecture bidon apres acces a une carte */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) /* pour liberer le bus */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) /* J.PAGET 19/11/95 version V2.6.1 Nombre, addresse,irq n'est plus configure */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) /* et passe en argument a acinit, mais est scrute sur le bus pour s'adapter */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) /* au nombre de cartes presentes sur le bus. IOCL code 6 affichait V2.4.3 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) /* F.LAFORSE 28/11/95 creation de fichiers acXX.o avec les differentes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) /* addresses de base des cartes, IOCTL 6 plus complet */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) /* J.PAGET le 19/08/96 copie de la version V2.6 en V2.8.0 sans modification */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) /* de code autre que le texte V2.6.1 en V2.8.0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) /*****************************************************************************/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <linux/sched/signal.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include <linux/mutex.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #include <linux/miscdevice.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #include <linux/pci.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #include <linux/wait.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #include <linux/fs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #include <linux/nospec.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #include <asm/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #include "applicom.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) /* NOTE: We use for loops with {write,read}b() instead of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) memcpy_{from,to}io throughout this driver. This is because
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) the board doesn't correctly handle word accesses - only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) bytes.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) #undef DEBUG
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) #define MAX_BOARD 8 /* maximum of pc board possible */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) #define MAX_ISA_BOARD 4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) #define LEN_RAM_IO 0x800
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) #ifndef PCI_VENDOR_ID_APPLICOM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) #define PCI_VENDOR_ID_APPLICOM 0x1389
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) #define PCI_DEVICE_ID_APPLICOM_PCIGENERIC 0x0001
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) #define PCI_DEVICE_ID_APPLICOM_PCI2000IBS_CAN 0x0002
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) #define PCI_DEVICE_ID_APPLICOM_PCI2000PFB 0x0003
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) static DEFINE_MUTEX(ac_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) static char *applicom_pci_devnames[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) "PCI board",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) "PCI2000IBS / PCI2000CAN",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) "PCI2000PFB"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) static const struct pci_device_id applicom_pci_tbl[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) { PCI_VDEVICE(APPLICOM, PCI_DEVICE_ID_APPLICOM_PCIGENERIC) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) { PCI_VDEVICE(APPLICOM, PCI_DEVICE_ID_APPLICOM_PCI2000IBS_CAN) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) { PCI_VDEVICE(APPLICOM, PCI_DEVICE_ID_APPLICOM_PCI2000PFB) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) { 0 }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) MODULE_DEVICE_TABLE(pci, applicom_pci_tbl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) MODULE_AUTHOR("David Woodhouse & Applicom International");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) MODULE_DESCRIPTION("Driver for Applicom Profibus card");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) MODULE_ALIAS_MISCDEV(AC_MINOR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) MODULE_SUPPORTED_DEVICE("ac");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) static struct applicom_board {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) unsigned long PhysIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) void __iomem *RamIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) wait_queue_head_t FlagSleepSend;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) long irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) spinlock_t mutex;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) } apbs[MAX_BOARD];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) static unsigned int irq = 0; /* interrupt number IRQ */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) static unsigned long mem = 0; /* physical segment of board */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) module_param_hw(irq, uint, irq, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) MODULE_PARM_DESC(irq, "IRQ of the Applicom board");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) module_param_hw(mem, ulong, iomem, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) MODULE_PARM_DESC(mem, "Shared Memory Address of Applicom board");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) static unsigned int numboards; /* number of installed boards */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) static volatile unsigned char Dummy;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) static DECLARE_WAIT_QUEUE_HEAD(FlagSleepRec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) static unsigned int WriteErrorCount; /* number of write error */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) static unsigned int ReadErrorCount; /* number of read error */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) static unsigned int DeviceErrorCount; /* number of device error */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) static ssize_t ac_read (struct file *, char __user *, size_t, loff_t *);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) static ssize_t ac_write (struct file *, const char __user *, size_t, loff_t *);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) static long ac_ioctl(struct file *, unsigned int, unsigned long);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) static irqreturn_t ac_interrupt(int, void *);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) static const struct file_operations ac_fops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) .llseek = no_llseek,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) .read = ac_read,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) .write = ac_write,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) .unlocked_ioctl = ac_ioctl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) static struct miscdevice ac_miscdev = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) AC_MINOR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) "ac",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) &ac_fops
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) static int dummy; /* dev_id for request_irq() */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) static int ac_register_board(unsigned long physloc, void __iomem *loc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) unsigned char boardno)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) volatile unsigned char byte_reset_it;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) if((readb(loc + CONF_END_TEST) != 0x00) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) (readb(loc + CONF_END_TEST + 1) != 0x55) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) (readb(loc + CONF_END_TEST + 2) != 0xAA) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) (readb(loc + CONF_END_TEST + 3) != 0xFF))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) if (!boardno)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) boardno = readb(loc + NUMCARD_OWNER_TO_PC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) if (!boardno || boardno > MAX_BOARD) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) printk(KERN_WARNING "Board #%d (at 0x%lx) is out of range (1 <= x <= %d).\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) boardno, physloc, MAX_BOARD);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) if (apbs[boardno - 1].RamIO) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) printk(KERN_WARNING "Board #%d (at 0x%lx) conflicts with previous board #%d (at 0x%lx)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) boardno, physloc, boardno, apbs[boardno-1].PhysIO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) boardno--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) apbs[boardno].PhysIO = physloc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) apbs[boardno].RamIO = loc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) init_waitqueue_head(&apbs[boardno].FlagSleepSend);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) spin_lock_init(&apbs[boardno].mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) byte_reset_it = readb(loc + RAM_IT_TO_PC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) numboards++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) return boardno + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) static void __exit applicom_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) misc_deregister(&ac_miscdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) for (i = 0; i < MAX_BOARD; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) if (!apbs[i].RamIO)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) if (apbs[i].irq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) free_irq(apbs[i].irq, &dummy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) iounmap(apbs[i].RamIO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) static int __init applicom_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) int i, numisa = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) struct pci_dev *dev = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) void __iomem *RamIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) int boardno, ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) printk(KERN_INFO "Applicom driver: $Id: ac.c,v 1.30 2000/03/22 16:03:57 dwmw2 Exp $\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) /* No mem and irq given - check for a PCI card */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) while ( (dev = pci_get_class(PCI_CLASS_OTHERS << 16, dev))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) if (!pci_match_id(applicom_pci_tbl, dev))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) if (pci_enable_device(dev))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) RamIO = ioremap(pci_resource_start(dev, 0), LEN_RAM_IO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) if (!RamIO) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) printk(KERN_INFO "ac.o: Failed to ioremap PCI memory "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) "space at 0x%llx\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) (unsigned long long)pci_resource_start(dev, 0));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) pci_disable_device(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) printk(KERN_INFO "Applicom %s found at mem 0x%llx, irq %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) applicom_pci_devnames[dev->device-1],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) (unsigned long long)pci_resource_start(dev, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) dev->irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) boardno = ac_register_board(pci_resource_start(dev, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) RamIO, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) if (!boardno) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) printk(KERN_INFO "ac.o: PCI Applicom device doesn't have correct signature.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) iounmap(RamIO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) pci_disable_device(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) if (request_irq(dev->irq, &ac_interrupt, IRQF_SHARED, "Applicom PCI", &dummy)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) printk(KERN_INFO "Could not allocate IRQ %d for PCI Applicom device.\n", dev->irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) iounmap(RamIO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) pci_disable_device(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) apbs[boardno - 1].RamIO = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) /* Enable interrupts. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) writeb(0x40, apbs[boardno - 1].RamIO + RAM_IT_FROM_PC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) apbs[boardno - 1].irq = dev->irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) /* Finished with PCI cards. If none registered,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) * and there was no mem/irq specified, exit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) if (!mem || !irq) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) if (numboards)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) goto fin;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) printk(KERN_INFO "ac.o: No PCI boards found.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) printk(KERN_INFO "ac.o: For an ISA board you must supply memory and irq parameters.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) return -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) /* Now try the specified ISA cards */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) for (i = 0; i < MAX_ISA_BOARD; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) RamIO = ioremap(mem + (LEN_RAM_IO * i), LEN_RAM_IO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) if (!RamIO) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) printk(KERN_INFO "ac.o: Failed to ioremap the ISA card's memory space (slot #%d)\n", i + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) if (!(boardno = ac_register_board((unsigned long)mem+ (LEN_RAM_IO*i),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) RamIO,i+1))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) iounmap(RamIO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) printk(KERN_NOTICE "Applicom ISA card found at mem 0x%lx, irq %d\n", mem + (LEN_RAM_IO*i), irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) if (!numisa) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) if (request_irq(irq, &ac_interrupt, IRQF_SHARED, "Applicom ISA", &dummy)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) printk(KERN_WARNING "Could not allocate IRQ %d for ISA Applicom device.\n", irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) iounmap(RamIO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) apbs[boardno - 1].RamIO = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) apbs[boardno - 1].irq = irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) apbs[boardno - 1].irq = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) numisa++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) if (!numisa)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) printk(KERN_WARNING "ac.o: No valid ISA Applicom boards found "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) "at mem 0x%lx\n", mem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) fin:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) init_waitqueue_head(&FlagSleepRec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) WriteErrorCount = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) ReadErrorCount = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) DeviceErrorCount = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) if (numboards) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) ret = misc_register(&ac_miscdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) printk(KERN_WARNING "ac.o: Unable to register misc device\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) for (i = 0; i < MAX_BOARD; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) int serial;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) char boardname[(SERIAL_NUMBER - TYPE_CARD) + 1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) if (!apbs[i].RamIO)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) for (serial = 0; serial < SERIAL_NUMBER - TYPE_CARD; serial++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) boardname[serial] = readb(apbs[i].RamIO + TYPE_CARD + serial);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) boardname[serial] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) printk(KERN_INFO "Applicom board %d: %s, PROM V%d.%d",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) i+1, boardname,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) (int)(readb(apbs[i].RamIO + VERS) >> 4),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) (int)(readb(apbs[i].RamIO + VERS) & 0xF));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) serial = (readb(apbs[i].RamIO + SERIAL_NUMBER) << 16) +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) (readb(apbs[i].RamIO + SERIAL_NUMBER + 1) << 8) +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) (readb(apbs[i].RamIO + SERIAL_NUMBER + 2) );
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) if (serial != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) printk(" S/N %d\n", serial);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) printk("\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) return -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) for (i = 0; i < MAX_BOARD; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) if (!apbs[i].RamIO)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) if (apbs[i].irq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) free_irq(apbs[i].irq, &dummy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) iounmap(apbs[i].RamIO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) module_init(applicom_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) module_exit(applicom_exit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) static ssize_t ac_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) unsigned int NumCard; /* Board number 1 -> 8 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) unsigned int IndexCard; /* Index board number 0 -> 7 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) unsigned char TicCard; /* Board TIC to send */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) unsigned long flags; /* Current priority */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) struct st_ram_io st_loc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) struct mailbox tmpmailbox;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) #ifdef DEBUG
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) int c;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) DECLARE_WAITQUEUE(wait, current);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) if (count != sizeof(struct st_ram_io) + sizeof(struct mailbox)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) static int warncount = 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) if (warncount) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) printk(KERN_INFO "Hmmm. write() of Applicom card, length %zd != expected %zd\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) count, sizeof(struct st_ram_io) + sizeof(struct mailbox));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) warncount--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) if(copy_from_user(&st_loc, buf, sizeof(struct st_ram_io)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) if(copy_from_user(&tmpmailbox, &buf[sizeof(struct st_ram_io)],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) sizeof(struct mailbox)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) NumCard = st_loc.num_card; /* board number to send */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) TicCard = st_loc.tic_des_from_pc; /* tic number to send */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) IndexCard = NumCard - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) if (IndexCard >= MAX_BOARD)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) IndexCard = array_index_nospec(IndexCard, MAX_BOARD);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) if (!apbs[IndexCard].RamIO)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) #ifdef DEBUG
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) printk("Write to applicom card #%d. struct st_ram_io follows:",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) IndexCard+1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) for (c = 0; c < sizeof(struct st_ram_io);) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) printk("\n%5.5X: %2.2X", c, ((unsigned char *) &st_loc)[c]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) for (c++; c % 8 && c < sizeof(struct st_ram_io); c++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) printk(" %2.2X", ((unsigned char *) &st_loc)[c]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) printk("\nstruct mailbox follows:");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) for (c = 0; c < sizeof(struct mailbox);) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) printk("\n%5.5X: %2.2X", c, ((unsigned char *) &tmpmailbox)[c]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) for (c++; c % 8 && c < sizeof(struct mailbox); c++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) printk(" %2.2X", ((unsigned char *) &tmpmailbox)[c]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) printk("\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) spin_lock_irqsave(&apbs[IndexCard].mutex, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) /* Test octet ready correct */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) if(readb(apbs[IndexCard].RamIO + DATA_FROM_PC_READY) > 2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) Dummy = readb(apbs[IndexCard].RamIO + VERS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) spin_unlock_irqrestore(&apbs[IndexCard].mutex, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) printk(KERN_WARNING "APPLICOM driver write error board %d, DataFromPcReady = %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) IndexCard,(int)readb(apbs[IndexCard].RamIO + DATA_FROM_PC_READY));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) DeviceErrorCount++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) /* Place ourselves on the wait queue */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) set_current_state(TASK_INTERRUPTIBLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) add_wait_queue(&apbs[IndexCard].FlagSleepSend, &wait);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) /* Check whether the card is ready for us */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) while (readb(apbs[IndexCard].RamIO + DATA_FROM_PC_READY) != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) Dummy = readb(apbs[IndexCard].RamIO + VERS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) /* It's busy. Sleep. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) spin_unlock_irqrestore(&apbs[IndexCard].mutex, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) schedule();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) if (signal_pending(current)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) remove_wait_queue(&apbs[IndexCard].FlagSleepSend,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) &wait);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) return -EINTR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) spin_lock_irqsave(&apbs[IndexCard].mutex, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) set_current_state(TASK_INTERRUPTIBLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) /* We may not have actually slept */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) set_current_state(TASK_RUNNING);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) remove_wait_queue(&apbs[IndexCard].FlagSleepSend, &wait);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) writeb(1, apbs[IndexCard].RamIO + DATA_FROM_PC_READY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) /* Which is best - lock down the pages with rawio and then
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) copy directly, or use bounce buffers? For now we do the latter
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) because it works with 2.2 still */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) unsigned char *from = (unsigned char *) &tmpmailbox;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) void __iomem *to = apbs[IndexCard].RamIO + RAM_FROM_PC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) int c;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) for (c = 0; c < sizeof(struct mailbox); c++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) writeb(*(from++), to++);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) writeb(0x20, apbs[IndexCard].RamIO + TIC_OWNER_FROM_PC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) writeb(0xff, apbs[IndexCard].RamIO + NUMCARD_OWNER_FROM_PC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) writeb(TicCard, apbs[IndexCard].RamIO + TIC_DES_FROM_PC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) writeb(NumCard, apbs[IndexCard].RamIO + NUMCARD_DES_FROM_PC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) writeb(2, apbs[IndexCard].RamIO + DATA_FROM_PC_READY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) writeb(1, apbs[IndexCard].RamIO + RAM_IT_FROM_PC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) Dummy = readb(apbs[IndexCard].RamIO + VERS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) spin_unlock_irqrestore(&apbs[IndexCard].mutex, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) static int do_ac_read(int IndexCard, char __user *buf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) struct st_ram_io *st_loc, struct mailbox *mailbox)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) void __iomem *from = apbs[IndexCard].RamIO + RAM_TO_PC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) unsigned char *to = (unsigned char *)mailbox;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) #ifdef DEBUG
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) int c;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) st_loc->tic_owner_to_pc = readb(apbs[IndexCard].RamIO + TIC_OWNER_TO_PC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) st_loc->numcard_owner_to_pc = readb(apbs[IndexCard].RamIO + NUMCARD_OWNER_TO_PC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) int c;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) for (c = 0; c < sizeof(struct mailbox); c++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) *(to++) = readb(from++);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) writeb(1, apbs[IndexCard].RamIO + ACK_FROM_PC_READY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) writeb(1, apbs[IndexCard].RamIO + TYP_ACK_FROM_PC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) writeb(IndexCard+1, apbs[IndexCard].RamIO + NUMCARD_ACK_FROM_PC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) writeb(readb(apbs[IndexCard].RamIO + TIC_OWNER_TO_PC),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) apbs[IndexCard].RamIO + TIC_ACK_FROM_PC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) writeb(2, apbs[IndexCard].RamIO + ACK_FROM_PC_READY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) writeb(0, apbs[IndexCard].RamIO + DATA_TO_PC_READY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) writeb(2, apbs[IndexCard].RamIO + RAM_IT_FROM_PC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) Dummy = readb(apbs[IndexCard].RamIO + VERS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) #ifdef DEBUG
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) printk("Read from applicom card #%d. struct st_ram_io follows:", NumCard);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) for (c = 0; c < sizeof(struct st_ram_io);) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) printk("\n%5.5X: %2.2X", c, ((unsigned char *)st_loc)[c]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) for (c++; c % 8 && c < sizeof(struct st_ram_io); c++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) printk(" %2.2X", ((unsigned char *)st_loc)[c]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) printk("\nstruct mailbox follows:");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) for (c = 0; c < sizeof(struct mailbox);) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) printk("\n%5.5X: %2.2X", c, ((unsigned char *)mailbox)[c]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) for (c++; c % 8 && c < sizeof(struct mailbox); c++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) printk(" %2.2X", ((unsigned char *)mailbox)[c]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) printk("\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) return (sizeof(struct st_ram_io) + sizeof(struct mailbox));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) static ssize_t ac_read (struct file *filp, char __user *buf, size_t count, loff_t *ptr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) unsigned char tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) DECLARE_WAITQUEUE(wait, current);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) #ifdef DEBUG
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) int loopcount=0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) /* No need to ratelimit this. Only root can trigger it anyway */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) if (count != sizeof(struct st_ram_io) + sizeof(struct mailbox)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) printk( KERN_WARNING "Hmmm. read() of Applicom card, length %zd != expected %zd\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) count,sizeof(struct st_ram_io) + sizeof(struct mailbox));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) while(1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) /* Stick ourself on the wait queue */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) set_current_state(TASK_INTERRUPTIBLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) add_wait_queue(&FlagSleepRec, &wait);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) /* Scan each board, looking for one which has a packet for us */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) for (i=0; i < MAX_BOARD; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) if (!apbs[i].RamIO)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) spin_lock_irqsave(&apbs[i].mutex, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) tmp = readb(apbs[i].RamIO + DATA_TO_PC_READY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) if (tmp == 2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) struct st_ram_io st_loc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) struct mailbox mailbox;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) /* Got a packet for us */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) memset(&st_loc, 0, sizeof(st_loc));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) ret = do_ac_read(i, buf, &st_loc, &mailbox);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) spin_unlock_irqrestore(&apbs[i].mutex, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) set_current_state(TASK_RUNNING);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) remove_wait_queue(&FlagSleepRec, &wait);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) if (copy_to_user(buf, &st_loc, sizeof(st_loc)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) if (copy_to_user(buf + sizeof(st_loc), &mailbox, sizeof(mailbox)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) return tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) if (tmp > 2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) /* Got an error */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) Dummy = readb(apbs[i].RamIO + VERS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) spin_unlock_irqrestore(&apbs[i].mutex, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) set_current_state(TASK_RUNNING);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) remove_wait_queue(&FlagSleepRec, &wait);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) printk(KERN_WARNING "APPLICOM driver read error board %d, DataToPcReady = %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) i,(int)readb(apbs[i].RamIO + DATA_TO_PC_READY));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) DeviceErrorCount++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) /* Nothing for us. Try the next board */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) Dummy = readb(apbs[i].RamIO + VERS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) spin_unlock_irqrestore(&apbs[i].mutex, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) } /* per board */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) /* OK - No boards had data for us. Sleep now */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) schedule();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) remove_wait_queue(&FlagSleepRec, &wait);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) if (signal_pending(current))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) return -EINTR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) #ifdef DEBUG
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) if (loopcount++ > 2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) printk(KERN_DEBUG "Looping in ac_read. loopcount %d\n", loopcount);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) static irqreturn_t ac_interrupt(int vec, void *dev_instance)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) unsigned int FlagInt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) unsigned int LoopCount;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) int handled = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) // printk("Applicom interrupt on IRQ %d occurred\n", vec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) LoopCount = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) FlagInt = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) for (i = 0; i < MAX_BOARD; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) /* Skip if this board doesn't exist */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) if (!apbs[i].RamIO)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) spin_lock(&apbs[i].mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) /* Skip if this board doesn't want attention */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) if(readb(apbs[i].RamIO + RAM_IT_TO_PC) == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) spin_unlock(&apbs[i].mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) handled = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) FlagInt = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) writeb(0, apbs[i].RamIO + RAM_IT_TO_PC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) if (readb(apbs[i].RamIO + DATA_TO_PC_READY) > 2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) printk(KERN_WARNING "APPLICOM driver interrupt err board %d, DataToPcReady = %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) i+1,(int)readb(apbs[i].RamIO + DATA_TO_PC_READY));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) DeviceErrorCount++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) if((readb(apbs[i].RamIO + DATA_FROM_PC_READY) > 2) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) (readb(apbs[i].RamIO + DATA_FROM_PC_READY) != 6)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) printk(KERN_WARNING "APPLICOM driver interrupt err board %d, DataFromPcReady = %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) i+1,(int)readb(apbs[i].RamIO + DATA_FROM_PC_READY));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) DeviceErrorCount++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) if (readb(apbs[i].RamIO + DATA_TO_PC_READY) == 2) { /* mailbox sent by the card ? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) if (waitqueue_active(&FlagSleepRec)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) wake_up_interruptible(&FlagSleepRec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) if (readb(apbs[i].RamIO + DATA_FROM_PC_READY) == 0) { /* ram i/o free for write by pc ? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) if (waitqueue_active(&apbs[i].FlagSleepSend)) { /* process sleep during read ? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) wake_up_interruptible(&apbs[i].FlagSleepSend);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) Dummy = readb(apbs[i].RamIO + VERS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) if(readb(apbs[i].RamIO + RAM_IT_TO_PC)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) /* There's another int waiting on this card */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) spin_unlock(&apbs[i].mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) i--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) spin_unlock(&apbs[i].mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) if (FlagInt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) LoopCount = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) LoopCount++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) } while(LoopCount < 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) return IRQ_RETVAL(handled);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) static long ac_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) { /* @ ADG ou ATO selon le cas */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) unsigned char IndexCard;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) void __iomem *pmem;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) static int warncount = 10;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) volatile unsigned char byte_reset_it;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) struct st_ram_io *adgl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) void __user *argp = (void __user *)arg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) /* In general, the device is only openable by root anyway, so we're not
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) particularly concerned that bogus ioctls can flood the console. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) adgl = memdup_user(argp, sizeof(struct st_ram_io));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) if (IS_ERR(adgl))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) return PTR_ERR(adgl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) mutex_lock(&ac_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) IndexCard = adgl->num_card-1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) if (cmd != 6 && IndexCard >= MAX_BOARD)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) IndexCard = array_index_nospec(IndexCard, MAX_BOARD);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) if (cmd != 6 && !apbs[IndexCard].RamIO)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) switch (cmd) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) case 0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) pmem = apbs[IndexCard].RamIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) for (i = 0; i < sizeof(struct st_ram_io); i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) ((unsigned char *)adgl)[i]=readb(pmem++);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) if (copy_to_user(argp, adgl, sizeof(struct st_ram_io)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) ret = -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) case 1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) pmem = apbs[IndexCard].RamIO + CONF_END_TEST;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) for (i = 0; i < 4; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) adgl->conf_end_test[i] = readb(pmem++);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) for (i = 0; i < 2; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) adgl->error_code[i] = readb(pmem++);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) for (i = 0; i < 4; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) adgl->parameter_error[i] = readb(pmem++);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) pmem = apbs[IndexCard].RamIO + VERS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) adgl->vers = readb(pmem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) pmem = apbs[IndexCard].RamIO + TYPE_CARD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) for (i = 0; i < 20; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) adgl->reserv1[i] = readb(pmem++);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) *(int *)&adgl->reserv1[20] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) (readb(apbs[IndexCard].RamIO + SERIAL_NUMBER) << 16) +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) (readb(apbs[IndexCard].RamIO + SERIAL_NUMBER + 1) << 8) +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) (readb(apbs[IndexCard].RamIO + SERIAL_NUMBER + 2) );
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) if (copy_to_user(argp, adgl, sizeof(struct st_ram_io)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) ret = -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) case 2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) pmem = apbs[IndexCard].RamIO + CONF_END_TEST;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) for (i = 0; i < 10; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) writeb(0xff, pmem++);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) writeb(adgl->data_from_pc_ready,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) apbs[IndexCard].RamIO + DATA_FROM_PC_READY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) writeb(1, apbs[IndexCard].RamIO + RAM_IT_FROM_PC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) for (i = 0; i < MAX_BOARD; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) if (apbs[i].RamIO) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) byte_reset_it = readb(apbs[i].RamIO + RAM_IT_TO_PC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) case 3:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) pmem = apbs[IndexCard].RamIO + TIC_DES_FROM_PC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) writeb(adgl->tic_des_from_pc, pmem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) case 4:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) pmem = apbs[IndexCard].RamIO + TIC_OWNER_TO_PC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) adgl->tic_owner_to_pc = readb(pmem++);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) adgl->numcard_owner_to_pc = readb(pmem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) if (copy_to_user(argp, adgl,sizeof(struct st_ram_io)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) ret = -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) case 5:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) writeb(adgl->num_card, apbs[IndexCard].RamIO + NUMCARD_OWNER_TO_PC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) writeb(adgl->num_card, apbs[IndexCard].RamIO + NUMCARD_DES_FROM_PC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) writeb(adgl->num_card, apbs[IndexCard].RamIO + NUMCARD_ACK_FROM_PC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) writeb(4, apbs[IndexCard].RamIO + DATA_FROM_PC_READY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) writeb(1, apbs[IndexCard].RamIO + RAM_IT_FROM_PC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) case 6:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) printk(KERN_INFO "APPLICOM driver release .... V2.8.0 ($Revision: 1.30 $)\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) printk(KERN_INFO "Number of installed boards . %d\n", (int) numboards);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) printk(KERN_INFO "Segment of board ........... %X\n", (int) mem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) printk(KERN_INFO "Interrupt IRQ number ....... %d\n", (int) irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) for (i = 0; i < MAX_BOARD; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) int serial;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) char boardname[(SERIAL_NUMBER - TYPE_CARD) + 1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) if (!apbs[i].RamIO)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) for (serial = 0; serial < SERIAL_NUMBER - TYPE_CARD; serial++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) boardname[serial] = readb(apbs[i].RamIO + TYPE_CARD + serial);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) boardname[serial] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) printk(KERN_INFO "Prom version board %d ....... V%d.%d %s",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) i+1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) (int)(readb(apbs[i].RamIO + VERS) >> 4),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) (int)(readb(apbs[i].RamIO + VERS) & 0xF),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) boardname);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) serial = (readb(apbs[i].RamIO + SERIAL_NUMBER) << 16) +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) (readb(apbs[i].RamIO + SERIAL_NUMBER + 1) << 8) +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) (readb(apbs[i].RamIO + SERIAL_NUMBER + 2) );
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) if (serial != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) printk(" S/N %d\n", serial);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) printk("\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) if (DeviceErrorCount != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) printk(KERN_INFO "DeviceErrorCount ........... %d\n", DeviceErrorCount);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) if (ReadErrorCount != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) printk(KERN_INFO "ReadErrorCount ............. %d\n", ReadErrorCount);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) if (WriteErrorCount != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) printk(KERN_INFO "WriteErrorCount ............ %d\n", WriteErrorCount);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) if (waitqueue_active(&FlagSleepRec))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) printk(KERN_INFO "Process in read pending\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) for (i = 0; i < MAX_BOARD; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) if (apbs[i].RamIO && waitqueue_active(&apbs[i].FlagSleepSend))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) printk(KERN_INFO "Process in write pending board %d\n",i+1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) ret = -ENOTTY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) Dummy = readb(apbs[IndexCard].RamIO + VERS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) kfree(adgl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) mutex_unlock(&ac_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) err:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) if (warncount) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) pr_warn("APPLICOM driver IOCTL, bad board number %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) (int)IndexCard + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) warncount--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) kfree(adgl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) mutex_unlock(&ac_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855)