📄 applicom.c
字号:
spin_unlock_irqrestore(&apbs[IndexCard].mutex, flags); schedule(); if (signal_pending(current)) { remove_wait_queue(&apbs[IndexCard].FlagSleepSend, &wait); return -EINTR; } spin_lock_irqsave(&apbs[IndexCard].mutex, flags); } /* We may not have actually slept */ current->state = TASK_RUNNING; remove_wait_queue(&apbs[IndexCard].FlagSleepSend, &wait); writeb(1, apbs[IndexCard].RamIO + DATA_FROM_PC_READY); /* 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 */ { unsigned char *from = (unsigned char *) &tmpmailbox; unsigned long to = (unsigned long) apbs[IndexCard].RamIO + RAM_FROM_PC; int c; for (c = 0; c < sizeof(struct mailbox); c++) writeb(*(from++), to++); } writeb(0x20, apbs[IndexCard].RamIO + TIC_OWNER_FROM_PC); writeb(0xff, apbs[IndexCard].RamIO + NUMCARD_OWNER_FROM_PC); writeb(TicCard, apbs[IndexCard].RamIO + TIC_DES_FROM_PC); writeb(NumCard, apbs[IndexCard].RamIO + NUMCARD_DES_FROM_PC); writeb(2, apbs[IndexCard].RamIO + DATA_FROM_PC_READY); writeb(1, apbs[IndexCard].RamIO + RAM_IT_FROM_PC); Dummy = readb(apbs[IndexCard].RamIO + VERS); spin_unlock_irqrestore(&apbs[IndexCard].mutex, flags); return 0;}static int do_ac_read(int IndexCard, char *buf){ struct st_ram_io st_loc; struct mailbox tmpmailbox; /* bounce buffer - can't copy to user space with cli() */ unsigned long from = (unsigned long)apbs[IndexCard].RamIO + RAM_TO_PC; unsigned char *to = (unsigned char *)&tmpmailbox;#ifdef DEBUG int c;#endif st_loc.tic_owner_to_pc = readb(apbs[IndexCard].RamIO + TIC_OWNER_TO_PC); st_loc.numcard_owner_to_pc = readb(apbs[IndexCard].RamIO + NUMCARD_OWNER_TO_PC); { int c; for (c = 0; c < sizeof(struct mailbox); c++) *(to++) = readb(from++); } writeb(1, apbs[IndexCard].RamIO + ACK_FROM_PC_READY); writeb(1, apbs[IndexCard].RamIO + TYP_ACK_FROM_PC); writeb(IndexCard+1, apbs[IndexCard].RamIO + NUMCARD_ACK_FROM_PC); writeb(readb(apbs[IndexCard].RamIO + TIC_OWNER_TO_PC), apbs[IndexCard].RamIO + TIC_ACK_FROM_PC); writeb(2, apbs[IndexCard].RamIO + ACK_FROM_PC_READY); writeb(0, apbs[IndexCard].RamIO + DATA_TO_PC_READY); writeb(2, apbs[IndexCard].RamIO + RAM_IT_FROM_PC); Dummy = readb(apbs[IndexCard].RamIO + VERS);#ifdef DEBUG printk("Read from applicom card #%d. struct st_ram_io follows:", NumCard); for (c = 0; c < sizeof(struct st_ram_io);) { printk("\n%5.5X: %2.2X", c, ((unsigned char *) &st_loc)[c]); for (c++; c % 8 && c < sizeof(struct st_ram_io); c++) { printk(" %2.2X", ((unsigned char *) &st_loc)[c]); } } printk("\nstruct mailbox follows:"); for (c = 0; c < sizeof(struct mailbox);) { printk("\n%5.5X: %2.2X", c, ((unsigned char *) &tmpmailbox)[c]); for (c++; c % 8 && c < sizeof(struct mailbox); c++) { printk(" %2.2X", ((unsigned char *) &tmpmailbox)[c]); } } printk("\n");#endif /* Je suis stupide. DW. */ if (copy_to_user(buf, &st_loc, sizeof(struct st_ram_io))) return -EFAULT; if (copy_to_user(&buf[sizeof(struct st_ram_io)], &tmpmailbox, sizeof(struct mailbox))) return -EFAULT; return (sizeof(struct st_ram_io) + sizeof(struct mailbox));}static ssize_t ac_read (struct file *filp, char *buf, size_t count, loff_t *ptr){ unsigned long flags; unsigned int i; unsigned char 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 %d != expected %d\n", count,sizeof(struct st_ram_io) + sizeof(struct mailbox)); return -EINVAL; } while(1) { /* Stick ourself on the wait queue */ 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); tmp = readb(apbs[i].RamIO + DATA_TO_PC_READY); if (tmp == 2) { /* Got a packet for us */ ret = do_ac_read(i, buf); spin_unlock_irqrestore(&apbs[i].mutex, flags); current->state = TASK_RUNNING; remove_wait_queue(&FlagSleepRec, &wait); return tmp; } if (tmp > 2) { /* Got an error */ Dummy = readb(apbs[i].RamIO + VERS); spin_unlock_irqrestore(&apbs[i].mutex, flags); current->state = TASK_RUNNING; remove_wait_queue(&FlagSleepRec, &wait); printk(KERN_WARNING "APPLICOM driver read error board %d, DataToPcReady = %d\n", i,(int)readb(apbs[i].RamIO + DATA_TO_PC_READY)); DeviceErrorCount++; return -EIO; } /* Nothing for us. Try the next board */ Dummy = readb(apbs[i].RamIO + VERS); spin_unlock_irqrestore(&apbs[i].mutex, flags); } /* per board */ /* OK - No boards had data for us. Sleep now */ schedule(); remove_wait_queue(&FlagSleepRec, &wait); if (signal_pending(current)) return -EINTR;#ifdef DEBUG if (loopcount++ > 2) { printk("Looping in ac_read. loopcount %d\n", loopcount); }#endif } }static void ac_interrupt(int vec, void *dev_instance, struct pt_regs *regs){ unsigned int i; unsigned int FlagInt; unsigned int LoopCount; // printk("Applicom interrupt on IRQ %d occurred\n", vec); LoopCount = 0; do { FlagInt = 0; for (i = 0; i < MAX_BOARD; i++) { /* Skip if this board doesn't exist */ if (!apbs[i].RamIO) continue; spin_lock(&apbs[i].mutex); /* Skip if this board doesn't want attention */ if(readb(apbs[i].RamIO + RAM_IT_TO_PC) == 0) { spin_unlock(&apbs[i].mutex); continue; } FlagInt = 1; writeb(0, apbs[i].RamIO + RAM_IT_TO_PC); if (readb(apbs[i].RamIO + DATA_TO_PC_READY) > 2) { printk(KERN_WARNING "APPLICOM driver interrupt err board %d, DataToPcReady = %d\n", i+1,(int)readb(apbs[i].RamIO + DATA_TO_PC_READY)); DeviceErrorCount++; } if((readb(apbs[i].RamIO + DATA_FROM_PC_READY) > 2) && (readb(apbs[i].RamIO + DATA_FROM_PC_READY) != 6)) { printk(KERN_WARNING "APPLICOM driver interrupt err board %d, DataFromPcReady = %d\n", i+1,(int)readb(apbs[i].RamIO + DATA_FROM_PC_READY)); DeviceErrorCount++; } 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);}static int ac_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { /* @ ADG ou ATO selon le cas */ int i; unsigned char IndexCard; unsigned long pmem; int ret = 0; volatile unsigned char byte_reset_it; struct st_ram_io *adgl; /* In general, the device is only openable by root anyway, so we're not particularly concerned that bogus ioctls can flood the console. */ adgl = kmalloc(sizeof(struct st_ram_io), GFP_KERNEL); if (!adgl) return -ENOMEM; if (copy_from_user(adgl, (void *)arg,sizeof(struct st_ram_io))) { kfree(adgl); return -EFAULT; } IndexCard = adgl->num_card-1; if(cmd != 0 && cmd != 6 && ((IndexCard >= MAX_BOARD) || !apbs[IndexCard].RamIO)) { static int warncount = 10; if (warncount) { printk( KERN_WARNING "APPLICOM driver IOCTL, bad board number %d\n",(int)IndexCard+1); warncount--; } kfree(adgl); return -EINVAL; } switch (cmd) { case 0: pmem = apbs[IndexCard].RamIO; for (i = 0; i < sizeof(struct st_ram_io); i++) ((unsigned char *)adgl)[i]=readb(pmem++); if (copy_to_user((void *)arg, 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((void *)arg, 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); writeb(1, apbs[IndexCard].RamIO + RAM_IT_FROM_PC); for (i = 0; i < MAX_BOARD; i++) { if (apbs[i].RamIO) { byte_reset_it = readb(apbs[i].RamIO + RAM_IT_TO_PC); } } break; case 3: pmem = apbs[IndexCard].RamIO + TIC_DES_FROM_PC; writeb(adgl->tic_des_from_pc, pmem); break; case 4: pmem = apbs[IndexCard].RamIO + TIC_OWNER_TO_PC; adgl->tic_owner_to_pc = readb(pmem++); adgl->numcard_owner_to_pc = readb(pmem); if (copy_to_user((void *)arg, adgl,sizeof(struct st_ram_io))) ret = -EFAULT; break; case 5: writeb(adgl->num_card, apbs[IndexCard].RamIO + NUMCARD_OWNER_TO_PC); writeb(adgl->num_card, apbs[IndexCard].RamIO + NUMCARD_DES_FROM_PC); writeb(adgl->num_card, apbs[IndexCard].RamIO + NUMCARD_ACK_FROM_PC); writeb(4, apbs[IndexCard].RamIO + DATA_FROM_PC_READY); writeb(1, apbs[IndexCard].RamIO + RAM_IT_FROM_PC); break; case 6: printk(KERN_INFO "APPLICOM driver release .... V2.8.0 ($Revision: 1.30 $)\n"); printk(KERN_INFO "Number of installed boards . %d\n", (int) numboards); printk(KERN_INFO "Segment of board ........... %X\n", (int) mem); printk(KERN_INFO "Interrupt IRQ number ....... %d\n", (int) irq); 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); boardname[serial] = 0; printk(KERN_INFO "Prom version board %d ....... V%d.%d %s", i+1, (int)(readb(apbs[IndexCard].RamIO + VERS) >> 4), (int)(readb(apbs[IndexCard].RamIO + VERS) & 0xF), boardname); serial = (readb(apbs[i].RamIO + SERIAL_NUMBER) << 16) + (readb(apbs[i].RamIO + SERIAL_NUMBER + 1) << 8) + (readb(apbs[i].RamIO + SERIAL_NUMBER + 2) ); if (serial != 0) printk(" S/N %d\n", serial); else printk("\n"); } if (DeviceErrorCount != 0) printk(KERN_INFO "DeviceErrorCount ........... %d\n", DeviceErrorCount); if (ReadErrorCount != 0) printk(KERN_INFO "ReadErrorCount ............. %d\n", ReadErrorCount); if (WriteErrorCount != 0) printk(KERN_INFO "WriteErrorCount ............ %d\n", WriteErrorCount); if (waitqueue_active(&FlagSleepRec)) printk(KERN_INFO "Process in read pending\n"); for (i = 0; i < MAX_BOARD; i++) { if (apbs[i].RamIO && waitqueue_active(&apbs[i].FlagSleepSend)) printk(KERN_INFO "Process in write pending board %d\n",i+1); } break; default: printk(KERN_INFO "APPLICOM driver ioctl, unknown function code %d\n",cmd) ; ret = -EINVAL; break; } Dummy = readb(apbs[IndexCard].RamIO + VERS); kfree(adgl); return 0;}#ifndef MODULEstatic int __init applicom_setup(char *str){ int ints[4]; (void) get_options(str, 4, ints); if (ints[0] > 2) { printk(KERN_WARNING "Too many arguments to 'applicom=', expected mem,irq only.\n"); } if (ints[0] < 2) { printk(KERN_INFO"applicom numargs: %d\n", ints[0]); return 0; } mem = ints[1]; irq = ints[2]; return 1;}__setup("applicom=", applicom_setup);#endif /* MODULE */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -