// SPDX-License-Identifier: GPL-2.0-only /* Derived from Applicom driver ac.c for SCO Unix */ /* Ported by David Woodhouse, Axiom (Cambridge) Ltd. */ /* dwmw2@infradead.org 30/8/98 */ /* $Id: ac.c,v 1.30 2000/03/22 16:03:57 dwmw2 Exp $ */ /* This module is for Linux 2.1 and 2.2 series kernels. */ /*****************************************************************************/ /* J PAGET 18/02/94 passage V2.4.2 ioctl avec code 2 reset to les interrupt */ /* ceci pour reseter correctement apres une sortie sauvage */ /* J PAGET 02/05/94 passage V2.4.3 dans le traitement de d'interruption, */ /* LoopCount n'etait pas initialise a 0. */ /* F LAFORSE 04/07/95 version V2.6.0 lecture bidon apres acces a une carte */ /* pour liberer le bus */ /* J.PAGET 19/11/95 version V2.6.1 Nombre, addresse,irq n'est plus configure */ /* et passe en argument a acinit, mais est scrute sur le bus pour s'adapter */ /* au nombre de cartes presentes sur le bus. IOCL code 6 affichait V2.4.3 */ /* F.LAFORSE 28/11/95 creation de fichiers acXX.o avec les differentes */ /* addresses de base des cartes, IOCTL 6 plus complet */ /* J.PAGET le 19/08/96 copie de la version V2.6 en V2.8.0 sans modification */ /* de code autre que le texte V2.6.1 en V2.8.0 */ /*****************************************************************************/
/* NOTE: We use for loops with {write,read}b() instead of memcpy_{from,to}io throughout this driver. This is because the board doesn't correctly handle word accesses - only bytes.
*/
#undef DEBUG
#define MAX_BOARD 8 /* maximum of pc board possible */ #define MAX_ISA_BOARD 4 #define LEN_RAM_IO 0x800
staticunsignedint irq; /* interrupt number IRQ */ staticunsignedlong mem; /* physical segment of board */
module_param_hw(irq, uint, irq, 0);
MODULE_PARM_DESC(irq, "IRQ of the Applicom board");
module_param_hw(mem, ulong, iomem, 0);
MODULE_PARM_DESC(mem, "Shared Memory Address of Applicom board");
staticunsignedint numboards; /* number of installed boards */ staticvolatileunsignedchar Dummy; static DECLARE_WAIT_QUEUE_HEAD(FlagSleepRec); staticunsignedint WriteErrorCount; /* number of write error */ staticunsignedint ReadErrorCount; /* number of read error */ staticunsignedint DeviceErrorCount; /* number of device error */
if (!boardno)
boardno = readb(loc + NUMCARD_OWNER_TO_PC);
if (!boardno || boardno > MAX_BOARD) {
printk(KERN_WARNING "Board #%d (at 0x%lx) is out of range (1 <= x <= %d).\n",
boardno, physloc, MAX_BOARD); return 0;
}
if (!RamIO) {
printk(KERN_INFO "ac.o: Failed to ioremap PCI memory " "space at 0x%llx\n",
(unsignedlonglong)pci_resource_start(dev, 0));
pci_disable_device(dev);
pci_dev_put(dev); return -EIO;
}
printk(KERN_INFO "Applicom %s found at mem 0x%llx, irq %d\n",
applicom_pci_devnames[dev->device-1],
(unsignedlonglong)pci_resource_start(dev, 0),
dev->irq);
/* Finished with PCI cards. If none registered,
* and there was no mem/irq specified, exit */
if (!mem || !irq) { if (numboards) goto fin; else {
printk(KERN_INFO "ac.o: No PCI boards found.\n");
printk(KERN_INFO "ac.o: For an ISA board you must supply memory and irq parameters.\n"); return -ENXIO;
}
}
/* Now try the specified ISA cards */
for (i = 0; i < MAX_ISA_BOARD; i++) {
RamIO = ioremap(mem + (LEN_RAM_IO * i), LEN_RAM_IO);
if (!RamIO) {
printk(KERN_INFO "ac.o: Failed to ioremap the ISA card's memory space (slot #%d)\n", i + 1); continue;
}
if (!(boardno = ac_register_board((unsignedlong)mem+ (LEN_RAM_IO*i),
RamIO,i+1))) {
iounmap(RamIO); continue;
}
printk(KERN_NOTICE "Applicom ISA card found at mem 0x%lx, irq %d\n", mem + (LEN_RAM_IO*i), irq);
if (!numisa) { if (request_irq(irq, &ac_interrupt, IRQF_SHARED, "Applicom ISA", &dummy)) {
printk(KERN_WARNING "Could not allocate IRQ %d for ISA Applicom device.\n", irq);
iounmap(RamIO);
apbs[boardno - 1].RamIO = NULL;
} else
apbs[boardno - 1].irq = irq;
} else
apbs[boardno - 1].irq = 0;
numisa++;
}
if (!numisa)
printk(KERN_WARNING "ac.o: No valid ISA Applicom boards found " "at mem 0x%lx\n", mem);
if (numboards) {
ret = misc_register(&ac_miscdev); if (ret) {
printk(KERN_WARNING "ac.o: Unable to register misc device\n"); goto out;
} for (i = 0; i < MAX_BOARD; i++) { int serial; char boardname[(SERIAL_NUMBER - TYPE_CARD) + 1];
if (!apbs[i].RamIO) continue;
for (serial = 0; serial < SERIAL_NUMBER - TYPE_CARD; serial++)
boardname[serial] = readb(apbs[i].RamIO + TYPE_CARD + serial);
out: for (i = 0; i < MAX_BOARD; i++) { if (!apbs[i].RamIO) continue; if (apbs[i].irq)
free_irq(apbs[i].irq, &dummy);
iounmap(apbs[i].RamIO);
} return ret;
}
/* Which is best - lock down the pages with rawio and then copy directly, or use bounce buffers? For now we do the latter
because it works with 2.2 still */
{ unsignedchar *from = (unsignedchar *) &tmpmailbox; void __iomem *to = apbs[IndexCard].RamIO + RAM_FROM_PC; int c;
for (c = 0; c < sizeof(struct mailbox); c++)
writeb(*(from++), to++);
}
for (c = 0; c < sizeof(struct st_ram_io);) {
printk("\n%5.5X: %2.2X", c, ((unsignedchar *)st_loc)[c]);
for (c++; c % 8 && c < sizeof(struct st_ram_io); c++) {
printk(" %2.2X", ((unsignedchar *)st_loc)[c]);
}
}
printk("\nstruct mailbox follows:");
for (c = 0; c < sizeof(struct mailbox);) {
printk("\n%5.5X: %2.2X", c, ((unsignedchar *)mailbox)[c]);
for (c++; c % 8 && c < sizeof(struct mailbox); c++) {
printk(" %2.2X", ((unsignedchar *)mailbox)[c]);
}
}
printk("\n"); #endif return (sizeof(struct st_ram_io) + sizeof(struct mailbox));
}
static ssize_t ac_read (struct file *filp, char __user *buf, size_t count, loff_t *ptr)
{ unsignedlong flags; unsignedint i; unsignedchar tmp; int ret = 0;
DECLARE_WAITQUEUE(wait, current); #ifdef DEBUG int loopcount=0; #endif /* No need to ratelimit this. Only root can trigger it anyway */ if (count != sizeof(struct st_ram_io) + sizeof(struct mailbox)) {
printk( KERN_WARNING "Hmmm. read() of Applicom card, length %zd != expected %zd\n",
count,sizeof(struct st_ram_io) + sizeof(struct mailbox)); return -EINVAL;
}
while(1) { /* Stick ourself on the wait queue */
set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&FlagSleepRec, &wait);
/* Scan each board, looking for one which has a packet for us */ for (i=0; i < MAX_BOARD; i++) { if (!apbs[i].RamIO) continue;
spin_lock_irqsave(&apbs[i].mutex, flags);
if (readb(apbs[i].RamIO + DATA_TO_PC_READY) == 2) { /* mailbox sent by the card ? */ if (waitqueue_active(&FlagSleepRec)) {
wake_up_interruptible(&FlagSleepRec);
}
}
if (readb(apbs[i].RamIO + DATA_FROM_PC_READY) == 0) { /* ram i/o free for write by pc ? */ if (waitqueue_active(&apbs[i].FlagSleepSend)) { /* process sleep during read ? */
wake_up_interruptible(&apbs[i].FlagSleepSend);
}
}
Dummy = readb(apbs[i].RamIO + VERS);
if(readb(apbs[i].RamIO + RAM_IT_TO_PC)) { /* There's another int waiting on this card */
spin_unlock(&apbs[i].mutex);
i--;
} else {
spin_unlock(&apbs[i].mutex);
}
} if (FlagInt)
LoopCount = 0; else
LoopCount++;
} while(LoopCount < 2); return IRQ_RETVAL(handled);
}
{ /* @ ADG ou ATO selon le cas */ int i; unsignedchar IndexCard; void __iomem *pmem; int ret = 0; staticint warncount = 10; volatileunsignedchar byte_reset_it; struct st_ram_io *adgl; void __user *argp = (void __user *)arg;
/* In general, the device is only openable by root anyway, so we're not
particularly concerned that bogus ioctls can flood the console. */
adgl = memdup_user(argp, sizeof(struct st_ram_io)); if (IS_ERR(adgl)) return PTR_ERR(adgl);
case 0:
pmem = apbs[IndexCard].RamIO; for (i = 0; i < sizeof(struct st_ram_io); i++)
((unsignedchar *)adgl)[i]=readb(pmem++); if (copy_to_user(argp, adgl, sizeof(struct st_ram_io)))
ret = -EFAULT; break; case 1:
pmem = apbs[IndexCard].RamIO + CONF_END_TEST; for (i = 0; i < 4; i++)
adgl->conf_end_test[i] = readb(pmem++); for (i = 0; i < 2; i++)
adgl->error_code[i] = readb(pmem++); for (i = 0; i < 4; i++)
adgl->parameter_error[i] = readb(pmem++);
pmem = apbs[IndexCard].RamIO + VERS;
adgl->vers = readb(pmem);
pmem = apbs[IndexCard].RamIO + TYPE_CARD; for (i = 0; i < 20; i++)
adgl->reserv1[i] = readb(pmem++);
*(int *)&adgl->reserv1[20] =
(readb(apbs[IndexCard].RamIO + SERIAL_NUMBER) << 16) +
(readb(apbs[IndexCard].RamIO + SERIAL_NUMBER + 1) << 8) +
(readb(apbs[IndexCard].RamIO + SERIAL_NUMBER + 2) );
if (copy_to_user(argp, adgl, sizeof(struct st_ram_io)))
ret = -EFAULT; break; case 2:
pmem = apbs[IndexCard].RamIO + CONF_END_TEST; for (i = 0; i < 10; i++)
writeb(0xff, pmem++);
writeb(adgl->data_from_pc_ready,
apbs[IndexCard].RamIO + DATA_FROM_PC_READY);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.