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

📄 cosa.c

📁 优龙2410linux2.6.8内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* $Id: cosa.c,v 1.31 2000/03/08 17:47:16 kas Exp $ *//* *  Copyright (C) 1995-1997  Jan "Yenya" Kasprzak <kas@fi.muni.cz> * *  This program is free software; you can redistribute it and/or modify *  it under the terms of the GNU General Public License as published by *  the Free Software Foundation; either version 2 of the License, or *  (at your option) any later version. * *  This program is distributed in the hope that it will be useful, *  but WITHOUT ANY WARRANTY; without even the implied warranty of *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *  GNU General Public License for more details. * *  You should have received a copy of the GNU General Public License *  along with this program; if not, write to the Free Software *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *//* * The driver for the SRP and COSA synchronous serial cards. * * HARDWARE INFO * * Both cards are developed at the Institute of Computer Science, * Masaryk University (http://www.ics.muni.cz/). The hardware is * developed by Jiri Novotny <novotny@ics.muni.cz>. More information * and the photo of both cards is available at * http://www.pavoucek.cz/cosa.html. The card documentation, firmwares * and other goods can be downloaded from ftp://ftp.ics.muni.cz/pub/cosa/. * For Linux-specific utilities, see below in the "Software info" section. * If you want to order the card, contact Jiri Novotny. * * The SRP (serial port?, the Czech word "srp" means "sickle") card * is a 2-port intelligent (with its own 8-bit CPU) synchronous serial card * with V.24 interfaces up to 80kb/s each. * * The COSA (communication serial adapter?, the Czech word "kosa" means * "scythe") is a next-generation sync/async board with two interfaces * - currently any of V.24, X.21, V.35 and V.36 can be selected. * It has a 16-bit SAB80166 CPU and can do up to 10 Mb/s per channel. * The 8-channels version is in development. * * Both types have downloadable firmware and communicate via ISA DMA. * COSA can be also a bus-mastering device. * * SOFTWARE INFO * * The homepage of the Linux driver is at http://www.fi.muni.cz/~kas/cosa/. * The CVS tree of Linux driver can be viewed there, as well as the * firmware binaries and user-space utilities for downloading the firmware * into the card and setting up the card. * * The Linux driver (unlike the present *BSD drivers :-) can work even * for the COSA and SRP in one computer and allows each channel to work * in one of the three modes (character device, Cisco HDLC, Sync PPP). * * AUTHOR * * The Linux driver was written by Jan "Yenya" Kasprzak <kas@fi.muni.cz>. * * You can mail me bugfixes and even success reports. I am especially * interested in the SMP and/or muliti-channel success/failure reports * (I wonder if I did the locking properly :-). * * THE AUTHOR USED THE FOLLOWING SOURCES WHEN PROGRAMMING THE DRIVER * * The COSA/SRP NetBSD driver by Zdenek Salvet and Ivos Cernohlavek * The skeleton.c by Donald Becker * The SDL Riscom/N2 driver by Mike Natale * The Comtrol Hostess SV11 driver by Alan Cox * The Sync PPP/Cisco HDLC layer (syncppp.c) ported to Linux by Alan Cox *//* *     5/25/1999 : Marcelo Tosatti <marcelo@conectiva.com.br> *             fixed a deadlock in cosa_sppp_open *//* ---------- Headers, macros, data structures ---------- */#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/slab.h>#include <linux/poll.h>#include <linux/fs.h>#include <linux/devfs_fs_kernel.h>#include <linux/interrupt.h>#include <linux/delay.h>#include <linux/errno.h>#include <linux/ioport.h>#include <linux/netdevice.h>#include <linux/spinlock.h>#include <linux/smp_lock.h>#include <linux/device.h>#undef COSA_SLOW_IO	/* for testing purposes only */#undef REALLY_SLOW_IO#include <asm/io.h>#include <asm/dma.h>#include <asm/byteorder.h>#include <net/syncppp.h>#include "cosa.h"/* Maximum length of the identification string. */#define COSA_MAX_ID_STRING	128/* Maximum length of the channel name */#define COSA_MAX_NAME		(sizeof("cosaXXXcXXX")+1)/* Per-channel data structure */struct channel_data {	void *if_ptr;	/* General purpose pointer (used by SPPP) */	int usage;	/* Usage count; >0 for chrdev, -1 for netdev */	int num;	/* Number of the channel */	struct cosa_data *cosa;	/* Pointer to the per-card structure */	int txsize;	/* Size of transmitted data */	char *txbuf;	/* Transmit buffer */	char name[COSA_MAX_NAME];	/* channel name */	/* The HW layer interface */	/* routine called from the RX interrupt */	char *(*setup_rx)(struct channel_data *channel, int size);	/* routine called when the RX is done (from the EOT interrupt) */	int (*rx_done)(struct channel_data *channel);	/* routine called when the TX is done (from the EOT interrupt) */	int (*tx_done)(struct channel_data *channel, int size);	/* Character device parts */	struct semaphore rsem, wsem;	char *rxdata;	int rxsize;	wait_queue_head_t txwaitq, rxwaitq;	int tx_status, rx_status;	/* SPPP/HDLC device parts */	struct ppp_device pppdev;	struct sk_buff *rx_skb, *tx_skb;	struct net_device_stats stats;};/* cosa->firmware_status bits */#define COSA_FW_RESET		(1<<0)	/* Is the ROM monitor active? */#define COSA_FW_DOWNLOAD	(1<<1)	/* Is the microcode downloaded? */#define COSA_FW_START		(1<<2)	/* Is the microcode running? */struct cosa_data {	int num;			/* Card number */	char name[COSA_MAX_NAME];	/* Card name - e.g "cosa0" */	unsigned int datareg, statusreg;	/* I/O ports */	unsigned short irq, dma;	/* IRQ and DMA number */	unsigned short startaddr;	/* Firmware start address */	unsigned short busmaster;	/* Use busmastering? */	int nchannels;			/* # of channels on this card */	int driver_status;		/* For communicating with firware */	int firmware_status;		/* Downloaded, reseted, etc. */	long int rxbitmap, txbitmap;	/* Bitmap of channels who are willing to send/receive data */	long int rxtx;			/* RX or TX in progress? */	int enabled;	int usage;				/* usage count */	int txchan, txsize, rxsize;	struct channel_data *rxchan;	char *bouncebuf;	char *txbuf, *rxbuf;	struct channel_data *chan;	spinlock_t lock;	/* For exclusive operations on this structure */	char id_string[COSA_MAX_ID_STRING];	/* ROM monitor ID string */	char *type;				/* card type */};/* * Define this if you want all the possible ports to be autoprobed. * It is here but it probably is not a good idea to use this. *//* #define COSA_ISA_AUTOPROBE	1 *//* * Character device major number. 117 was allocated for us. * The value of 0 means to allocate a first free one. */static int cosa_major = 117;/* * Encoding of the minor numbers: * The lowest CARD_MINOR_BITS bits means the channel on the single card, * the highest bits means the card number. */#define CARD_MINOR_BITS	4	/* How many bits in minor number are reserved				 * for the single card *//* * The following depends on CARD_MINOR_BITS. Unfortunately, the "MODULE_STRING" * macro doesn't like anything other than the raw number as an argument :-( */#define MAX_CARDS	16/* #define MAX_CARDS	(1 << (8-CARD_MINOR_BITS)) */#define DRIVER_RX_READY		0x0001#define DRIVER_TX_READY		0x0002#define DRIVER_TXMAP_SHIFT	2#define DRIVER_TXMAP_MASK	0x0c	/* FIXME: 0xfc for 8-channel version *//* * for cosa->rxtx - indicates whether either transmit or receive is * in progress. These values are mean number of the bit. */#define TXBIT 0#define RXBIT 1#define IRQBIT 2#define COSA_MTU 2000	/* FIXME: I don't know this exactly */#undef DEBUG_DATA //1	/* Dump the data read or written to the channel */#undef DEBUG_IRQS //1	/* Print the message when the IRQ is received */#undef DEBUG_IO   //1	/* Dump the I/O traffic */#define TX_TIMEOUT	(5*HZ)/* Maybe the following should be allocated dynamically */static struct cosa_data cosa_cards[MAX_CARDS];static int nr_cards;#ifdef COSA_ISA_AUTOPROBEstatic int io[MAX_CARDS+1]  = { 0x220, 0x228, 0x210, 0x218, 0, };/* NOTE: DMA is not autoprobed!!! */static int dma[MAX_CARDS+1] = { 1, 7, 1, 7, 1, 7, 1, 7, 0, };#elsestatic int io[MAX_CARDS+1];static int dma[MAX_CARDS+1];#endif/* IRQ can be safely autoprobed */static int irq[MAX_CARDS+1] = { -1, -1, -1, -1, -1, -1, 0, };/* for class stuff*/static struct class_simple *cosa_class;#ifdef MODULEMODULE_PARM(io, "1-" __MODULE_STRING(MAX_CARDS) "i");MODULE_PARM_DESC(io, "The I/O bases of the COSA or SRP cards");MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_CARDS) "i");MODULE_PARM_DESC(irq, "The IRQ lines of the COSA or SRP cards");MODULE_PARM(dma, "1-" __MODULE_STRING(MAX_CARDS) "i");MODULE_PARM_DESC(dma, "The DMA channels of the COSA or SRP cards");MODULE_AUTHOR("Jan \"Yenya\" Kasprzak, <kas@fi.muni.cz>");MODULE_DESCRIPTION("Modular driver for the COSA or SRP synchronous card");MODULE_LICENSE("GPL");#endif/* I use this mainly for testing purposes */#ifdef COSA_SLOW_IO#define cosa_outb outb_p#define cosa_outw outw_p#define cosa_inb  inb_p#define cosa_inw  inw_p#else#define cosa_outb outb#define cosa_outw outw#define cosa_inb  inb#define cosa_inw  inw#endif#define is_8bit(cosa)		(!(cosa->datareg & 0x08))#define cosa_getstatus(cosa)	(cosa_inb(cosa->statusreg))#define cosa_putstatus(cosa, stat)	(cosa_outb(stat, cosa->statusreg))#define cosa_getdata16(cosa)	(cosa_inw(cosa->datareg))#define cosa_getdata8(cosa)	(cosa_inb(cosa->datareg))#define cosa_putdata16(cosa, dt)	(cosa_outw(dt, cosa->datareg))#define cosa_putdata8(cosa, dt)	(cosa_outb(dt, cosa->datareg))/* Initialization stuff */static int cosa_probe(int ioaddr, int irq, int dma);/* HW interface */static void cosa_enable_rx(struct channel_data *chan);static void cosa_disable_rx(struct channel_data *chan);static int cosa_start_tx(struct channel_data *channel, char *buf, int size);static void cosa_kick(struct cosa_data *cosa);static int cosa_dma_able(struct channel_data *chan, char *buf, int data);/* SPPP/HDLC stuff */static void sppp_channel_init(struct channel_data *chan);static void sppp_channel_delete(struct channel_data *chan);static int cosa_sppp_open(struct net_device *d);static int cosa_sppp_close(struct net_device *d);static void cosa_sppp_timeout(struct net_device *d);static int cosa_sppp_tx(struct sk_buff *skb, struct net_device *d);static char *sppp_setup_rx(struct channel_data *channel, int size);static int sppp_rx_done(struct channel_data *channel);static int sppp_tx_done(struct channel_data *channel, int size);static int cosa_sppp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);static struct net_device_stats *cosa_net_stats(struct net_device *dev);/* Character device */static void chardev_channel_init(struct channel_data *chan);static char *chrdev_setup_rx(struct channel_data *channel, int size);static int chrdev_rx_done(struct channel_data *channel);static int chrdev_tx_done(struct channel_data *channel, int size);static ssize_t cosa_read(struct file *file,	char __user *buf, size_t count, loff_t *ppos);static ssize_t cosa_write(struct file *file,	const char __user *buf, size_t count, loff_t *ppos);static unsigned int cosa_poll(struct file *file, poll_table *poll);static int cosa_open(struct inode *inode, struct file *file);static int cosa_release(struct inode *inode, struct file *file);static int cosa_chardev_ioctl(struct inode *inode, struct file *file,	unsigned int cmd, unsigned long arg);#ifdef COSA_FASYNC_WORKINGstatic int cosa_fasync(struct inode *inode, struct file *file, int on);#endifstatic struct file_operations cosa_fops = {	.owner		= THIS_MODULE,	.llseek		= no_llseek,	.read		= cosa_read,	.write		= cosa_write,	.poll		= cosa_poll,	.ioctl		= cosa_chardev_ioctl,	.open		= cosa_open,	.release	= cosa_release,#ifdef COSA_FASYNC_WORKING	.fasync		= cosa_fasync,#endif};/* Ioctls */static int cosa_start(struct cosa_data *cosa, int address);static int cosa_reset(struct cosa_data *cosa);static int cosa_download(struct cosa_data *cosa, void __user *a);static int cosa_readmem(struct cosa_data *cosa, void __user *a);/* COSA/SRP ROM monitor */static int download(struct cosa_data *cosa, const char __user *data, int addr, int len);static int startmicrocode(struct cosa_data *cosa, int address);static int readmem(struct cosa_data *cosa, char __user *data, int addr, int len);static int cosa_reset_and_read_id(struct cosa_data *cosa, char *id);/* Auxilliary functions */static int get_wait_data(struct cosa_data *cosa);static int put_wait_data(struct cosa_data *cosa, int data);static int puthexnumber(struct cosa_data *cosa, int number);static void put_driver_status(struct cosa_data *cosa);static void put_driver_status_nolock(struct cosa_data *cosa);/* Interrupt handling */static irqreturn_t cosa_interrupt(int irq, void *cosa, struct pt_regs *regs);/* I/O ops debugging */#ifdef DEBUG_IOstatic void debug_data_in(struct cosa_data *cosa, int data);static void debug_data_out(struct cosa_data *cosa, int data);static void debug_data_cmd(struct cosa_data *cosa, int data);static void debug_status_in(struct cosa_data *cosa, int status);static void debug_status_out(struct cosa_data *cosa, int status);#endif/* ---------- Initialization stuff ---------- */static int __init cosa_init(void){	int i, err = 0;	printk(KERN_INFO "cosa v1.08 (c) 1997-2000 Jan Kasprzak <kas@fi.muni.cz>\n");#ifdef CONFIG_SMP	printk(KERN_INFO "cosa: SMP found. Please mail any success/failure reports to the author.\n");#endif	if (cosa_major > 0) {		if (register_chrdev(cosa_major, "cosa", &cosa_fops)) {			printk(KERN_WARNING "cosa: unable to get major %d\n",				cosa_major);			err = -EIO;			goto out;		}	} else {		if (!(cosa_major=register_chrdev(0, "cosa", &cosa_fops))) {			printk(KERN_WARNING "cosa: unable to register chardev\n");			err = -EIO;			goto out;		}	}	for (i=0; i<MAX_CARDS; i++)		cosa_cards[i].num = -1;	for (i=0; io[i] != 0 && i < MAX_CARDS; i++)		cosa_probe(io[i], irq[i], dma[i]);	if (!nr_cards) {		printk(KERN_WARNING "cosa: no devices found.\n");		unregister_chrdev(cosa_major, "cosa");		err = -ENODEV;		goto out;	}	devfs_mk_dir("cosa");	cosa_class = class_simple_create(THIS_MODULE, "cosa");	if (IS_ERR(cosa_class)) {		err = PTR_ERR(cosa_class);		goto out_chrdev;	}	for (i=0; i<nr_cards; i++) {		class_simple_device_add(cosa_class, MKDEV(cosa_major, i),				NULL, "cosa%d", i);		err = devfs_mk_cdev(MKDEV(cosa_major, i),				S_IFCHR|S_IRUSR|S_IWUSR,				"cosa/%d", i);		if (err) {			class_simple_device_remove(MKDEV(cosa_major, i));			goto out_chrdev;				}	}	err = 0;	goto out;	out_chrdev:	unregister_chrdev(cosa_major, "cosa");out:	return err;}module_init(cosa_init);static void __exit cosa_exit(void){	struct cosa_data *cosa;	int i;	printk(KERN_INFO "Unloading the cosa module\n");	for (i=0; i<nr_cards; i++) {		class_simple_device_remove(MKDEV(cosa_major, i));		devfs_remove("cosa/%d", i);	}	class_simple_destroy(cosa_class);	devfs_remove("cosa");	for (cosa=cosa_cards; nr_cards--; cosa++) {		/* Clean up the per-channel data */		for (i=0; i<cosa->nchannels; i++) {			/* Chardev driver has no alloc'd per-channel data */			sppp_channel_delete(cosa->chan+i);		}		/* Clean up the per-card data */		kfree(cosa->chan);		kfree(cosa->bouncebuf);		free_irq(cosa->irq, cosa);		free_dma(cosa->dma);		release_region(cosa->datareg,is_8bit(cosa)?2:4);	}	unregister_chrdev(cosa_major, "cosa");}module_exit(cosa_exit);/* * This function should register all the net devices needed for the * single channel. */static __inline__ void channel_init(struct channel_data *chan){	sprintf(chan->name, "cosa%dc%d", chan->cosa->num, chan->num);	/* Initialize the chardev data structures */	chardev_channel_init(chan);	/* Register the sppp interface */	sppp_channel_init(chan);}	static int cosa_probe(int base, int irq, int dma){	struct cosa_data *cosa = cosa_cards+nr_cards;	int i, err = 0;	memset(cosa, 0, sizeof(struct cosa_data));	/* Checking validity of parameters: */	/* IRQ should be 2-7 or 10-15; negative IRQ means autoprobe */	if ((irq >= 0  && irq < 2) || irq > 15 || (irq < 10 && irq > 7)) {		printk (KERN_INFO "cosa_probe: invalid IRQ %d\n", irq);		return -1;	}	/* I/O address should be between 0x100 and 0x3ff and should be	 * multiple of 8. */	if (base < 0x100 || base > 0x3ff || base & 0x7) {		printk (KERN_INFO "cosa_probe: invalid I/O address 0x%x\n",			base);		return -1;	}	/* DMA should be 0,1 or 3-7 */	if (dma < 0 || dma == 4 || dma > 7) {		printk (KERN_INFO "cosa_probe: invalid DMA %d\n", dma);		return -1;	}	/* and finally, on 16-bit COSA DMA should be 4-7 and 	 * I/O base should not be multiple of 0x10 */	if (((base & 0x8) && dma < 4) || (!(base & 0x8) && dma > 3)) {		printk (KERN_INFO "cosa_probe: 8/16 bit base and DMA mismatch"			" (base=0x%x, dma=%d)\n", base, dma);		return -1;	}	cosa->dma = dma;	cosa->datareg = base;	cosa->statusreg = is_8bit(cosa)?base+1:base+2;	spin_lock_init(&cosa->lock);	if (!request_region(base, is_8bit(cosa)?2:4,"cosa"))		return -1;		if (cosa_reset_and_read_id(cosa, cosa->id_string) < 0) {		printk(KERN_DEBUG "cosa: probe at 0x%x failed.\n", base);		err = -1;		goto err_out;	}	/* Test the validity of identification string */	if (!strncmp(cosa->id_string, "SRP", 3))		cosa->type = "srp";	else if (!strncmp(cosa->id_string, "COSA", 4))		cosa->type = is_8bit(cosa)? "cosa8": "cosa16";	else {/* Print a warning only if we are not autoprobing */#ifndef COSA_ISA_AUTOPROBE		printk(KERN_INFO "cosa: valid signature not found at 0x%x.\n",			base);#endif		err = -1;		goto err_out;

⌨️ 快捷键说明

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