⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 applicom.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* 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       *//* adresses 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                               *//*****************************************************************************/#include <linux/kernel.h>#include <linux/module.h>#include <linux/interrupt.h>#include <linux/slab.h>#include <linux/errno.h>#include <linux/miscdevice.h>#include <linux/pci.h>#include <linux/wait.h>#include <linux/init.h>#include <linux/fs.h>#include <asm/io.h>#include <asm/uaccess.h>#include "applicom.h"/* 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#define AC_MINOR 157#ifndef PCI_VENDOR_ID_APPLICOM#define PCI_VENDOR_ID_APPLICOM                0x1389#define PCI_DEVICE_ID_APPLICOM_PCIGENERIC     0x0001#define PCI_DEVICE_ID_APPLICOM_PCI2000IBS_CAN 0x0002#define PCI_DEVICE_ID_APPLICOM_PCI2000PFB     0x0003#endif#define MAX_PCI_DEVICE_NUM 3static char *applicom_pci_devnames[] = {	"PCI board",	"PCI2000IBS / PCI2000CAN",	"PCI2000PFB"};static struct pci_device_id applicom_pci_tbl[] = {	{ PCI_VENDOR_ID_APPLICOM, PCI_DEVICE_ID_APPLICOM_PCIGENERIC,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	{ PCI_VENDOR_ID_APPLICOM, PCI_DEVICE_ID_APPLICOM_PCI2000IBS_CAN,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	{ PCI_VENDOR_ID_APPLICOM, PCI_DEVICE_ID_APPLICOM_PCI2000PFB,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	{ 0 }};MODULE_DEVICE_TABLE(pci, applicom_pci_tbl);MODULE_AUTHOR("David Woodhouse & Applicom International");MODULE_DESCRIPTION("Driver for Applicom Profibus card");MODULE_LICENSE("GPL");MODULE_SUPPORTED_DEVICE("ac");static struct applicom_board {	unsigned long PhysIO;	void __iomem *RamIO;	wait_queue_head_t FlagSleepSend;	long irq;	spinlock_t mutex;} apbs[MAX_BOARD];static unsigned int irq = 0;	/* interrupt number IRQ       */static unsigned long mem = 0;	/* physical segment of board  */module_param(irq, uint, 0);MODULE_PARM_DESC(irq, "IRQ of the Applicom board");module_param(mem, ulong, 0);MODULE_PARM_DESC(mem, "Shared Memory Address of Applicom board");static unsigned int numboards;	/* number of installed boards */static volatile unsigned char Dummy;static DECLARE_WAIT_QUEUE_HEAD(FlagSleepRec);static unsigned int WriteErrorCount;	/* number of write error      */static unsigned int ReadErrorCount;	/* number of read error       */static unsigned int DeviceErrorCount;	/* number of device error     */static ssize_t ac_read (struct file *, char __user *, size_t, loff_t *);static ssize_t ac_write (struct file *, const char __user *, size_t, loff_t *);static int ac_ioctl(struct inode *, struct file *, unsigned int,		    unsigned long);static irqreturn_t ac_interrupt(int, void *);static const struct file_operations ac_fops = {	.owner = THIS_MODULE,	.llseek = no_llseek,	.read = ac_read,	.write = ac_write,	.ioctl = ac_ioctl,};static struct miscdevice ac_miscdev = {	AC_MINOR,	"ac",	&ac_fops};static int dummy;	/* dev_id for request_irq() */static int ac_register_board(unsigned long physloc, void __iomem *loc, 		      unsigned char boardno){	volatile unsigned char byte_reset_it;	if((readb(loc + CONF_END_TEST)     != 0x00) ||	   (readb(loc + CONF_END_TEST + 1) != 0x55) ||	   (readb(loc + CONF_END_TEST + 2) != 0xAA) ||	   (readb(loc + CONF_END_TEST + 3) != 0xFF))		return 0;	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 (apbs[boardno - 1].RamIO) {		printk(KERN_WARNING "Board #%d (at 0x%lx) conflicts with previous board #%d (at 0x%lx)\n", 		       boardno, physloc, boardno, apbs[boardno-1].PhysIO);		return 0;	}	boardno--;	apbs[boardno].PhysIO = physloc;	apbs[boardno].RamIO = loc;	init_waitqueue_head(&apbs[boardno].FlagSleepSend);	spin_lock_init(&apbs[boardno].mutex);	byte_reset_it = readb(loc + RAM_IT_TO_PC);	numboards++;	return boardno + 1;}static void __exit applicom_exit(void){	unsigned int i;	misc_deregister(&ac_miscdev);	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);	}}static int __init applicom_init(void){	int i, numisa = 0;	struct pci_dev *dev = NULL;	void __iomem *RamIO;	int boardno, ret;	printk(KERN_INFO "Applicom driver: $Id: ac.c,v 1.30 2000/03/22 16:03:57 dwmw2 Exp $\n");	/* No mem and irq given - check for a PCI card */	while ( (dev = pci_get_class(PCI_CLASS_OTHERS << 16, dev))) {		if (dev->vendor != PCI_VENDOR_ID_APPLICOM)			continue;				if (dev->device  > MAX_PCI_DEVICE_NUM || dev->device == 0)			continue;				if (pci_enable_device(dev))			return -EIO;		RamIO = ioremap(dev->resource[0].start, LEN_RAM_IO);		if (!RamIO) {			printk(KERN_INFO "ac.o: Failed to ioremap PCI memory "				"space at 0x%llx\n",				(unsigned long long)dev->resource[0].start);			pci_disable_device(dev);			return -EIO;		}		printk(KERN_INFO "Applicom %s found at mem 0x%llx, irq %d\n",		       applicom_pci_devnames[dev->device-1],			   (unsigned long long)dev->resource[0].start,		       dev->irq);		boardno = ac_register_board(dev->resource[0].start, RamIO,0);		if (!boardno) {			printk(KERN_INFO "ac.o: PCI Applicom device doesn't have correct signature.\n");			iounmap(RamIO);			pci_disable_device(dev);			continue;		}		if (request_irq(dev->irq, &ac_interrupt, IRQF_SHARED, "Applicom PCI", &dummy)) {			printk(KERN_INFO "Could not allocate IRQ %d for PCI Applicom device.\n", dev->irq);			iounmap(RamIO);			pci_disable_device(dev);			apbs[boardno - 1].RamIO = NULL;			continue;		}		/* Enable interrupts. */		writeb(0x40, apbs[boardno - 1].RamIO + RAM_IT_FROM_PC);		apbs[boardno - 1].irq = 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((unsigned long)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); fin:	init_waitqueue_head(&FlagSleepRec);	WriteErrorCount = 0;	ReadErrorCount = 0;	DeviceErrorCount = 0;	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);			boardname[serial] = 0;			printk(KERN_INFO "Applicom board %d: %s, PROM V%d.%d",			       i+1, boardname,			       (int)(readb(apbs[i].RamIO + VERS) >> 4),			       (int)(readb(apbs[i].RamIO + VERS) & 0xF));						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");		}		return 0;	}	else		return -ENXIO;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);	}	pci_disable_device(dev);	return ret;}module_init(applicom_init);module_exit(applicom_exit);static ssize_t ac_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos){	unsigned int NumCard;	/* Board number 1 -> 8           */	unsigned int IndexCard;	/* Index board number 0 -> 7     */	unsigned char TicCard;	/* Board TIC to send             */	unsigned long flags;	/* Current priority              */	struct st_ram_io st_loc;	struct mailbox tmpmailbox;#ifdef DEBUG	int c;#endif	DECLARE_WAITQUEUE(wait, current);	if (count != sizeof(struct st_ram_io) + sizeof(struct mailbox)) {		static int warncount = 5;		if (warncount) {			printk(KERN_INFO "Hmmm. write() of Applicom card, length %zd != expected %zd\n",			       count, sizeof(struct st_ram_io) + sizeof(struct mailbox));			warncount--;		}		return -EINVAL;	}	if(copy_from_user(&st_loc, buf, sizeof(struct st_ram_io))) 		return -EFAULT;		if(copy_from_user(&tmpmailbox, &buf[sizeof(struct st_ram_io)],			  sizeof(struct mailbox))) 		return -EFAULT;	NumCard = st_loc.num_card;	/* board number to send          */	TicCard = st_loc.tic_des_from_pc;	/* tic number to send            */	IndexCard = NumCard - 1;	if((NumCard < 1) || (NumCard > MAX_BOARD) || !apbs[IndexCard].RamIO)		return -EINVAL;#ifdef DEBUG	printk("Write to applicom card #%d. struct st_ram_io follows:",	       IndexCard+1);		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	spin_lock_irqsave(&apbs[IndexCard].mutex, flags);	/* Test octet ready correct */	if(readb(apbs[IndexCard].RamIO + DATA_FROM_PC_READY) > 2) { 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -