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

📄 cosa.c

📁 优龙2410linux2.6.8内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	}	/* Update the name of the region now we know the type of card */ 	release_region(base, is_8bit(cosa)?2:4);	if (!request_region(base, is_8bit(cosa)?2:4, cosa->type)) {		printk(KERN_DEBUG "cosa: changing name at 0x%x failed.\n", base);		return -1;	}	/* Now do IRQ autoprobe */	if (irq < 0) {		unsigned long irqs;/*		printk(KERN_INFO "IRQ autoprobe\n"); */		irqs = probe_irq_on();		/* 		 * Enable interrupt on tx buffer empty (it sure is) 		 * really sure ?		 * FIXME: When this code is not used as module, we should		 * probably call udelay() instead of the interruptible sleep.		 */		current->state = TASK_INTERRUPTIBLE;		cosa_putstatus(cosa, SR_TX_INT_ENA);		schedule_timeout(30);		irq = probe_irq_off(irqs);		/* Disable all IRQs from the card */		cosa_putstatus(cosa, 0);		/* Empty the received data register */		cosa_getdata8(cosa);		if (irq < 0) {			printk (KERN_INFO "cosa IRQ autoprobe: multiple interrupts obtained (%d, board at 0x%x)\n",				irq, cosa->datareg);			err = -1;			goto err_out;		}		if (irq == 0) {			printk (KERN_INFO "cosa IRQ autoprobe: no interrupt obtained (board at 0x%x)\n",				cosa->datareg);		/*	return -1; */		}	}	cosa->irq = irq;	cosa->num = nr_cards;	cosa->usage = 0;	cosa->nchannels = 2;	/* FIXME: how to determine this? */	if (request_irq(cosa->irq, cosa_interrupt, 0, cosa->type, cosa)) {		err = -1;		goto err_out;	}	if (request_dma(cosa->dma, cosa->type)) {		err = -1;		goto err_out1;	}		cosa->bouncebuf = kmalloc(COSA_MTU, GFP_KERNEL|GFP_DMA);	if (!cosa->bouncebuf) {		err = -ENOMEM;		goto err_out2;	}	sprintf(cosa->name, "cosa%d", cosa->num);	/* Initialize the per-channel data */	cosa->chan = kmalloc(sizeof(struct channel_data)*cosa->nchannels,			     GFP_KERNEL);	if (!cosa->chan) {	        err = -ENOMEM;		goto err_out3;	}	memset(cosa->chan, 0, sizeof(struct channel_data)*cosa->nchannels);	for (i=0; i<cosa->nchannels; i++) {		cosa->chan[i].cosa = cosa;		cosa->chan[i].num = i;		channel_init(cosa->chan+i);	}	printk (KERN_INFO "cosa%d: %s (%s at 0x%x irq %d dma %d), %d channels\n",		cosa->num, cosa->id_string, cosa->type,		cosa->datareg, cosa->irq, cosa->dma, cosa->nchannels);	return nr_cards++;err_out3:	kfree(cosa->bouncebuf);err_out2:	free_dma(cosa->dma);err_out1:	free_irq(cosa->irq, cosa);err_out:		release_region(cosa->datareg,is_8bit(cosa)?2:4);	printk(KERN_NOTICE "cosa%d: allocating resources failed\n",	       cosa->num);	return err;}/*---------- SPPP/HDLC netdevice ---------- */static void cosa_setup(struct net_device *d){	d->open = cosa_sppp_open;	d->stop = cosa_sppp_close;	d->hard_start_xmit = cosa_sppp_tx;	d->do_ioctl = cosa_sppp_ioctl;	d->get_stats = cosa_net_stats;	d->tx_timeout = cosa_sppp_timeout;	d->watchdog_timeo = TX_TIMEOUT;}static void sppp_channel_init(struct channel_data *chan){	struct net_device *d;	chan->if_ptr = &chan->pppdev;	d = alloc_netdev(0, chan->name, cosa_setup);	if (!d) {		printk(KERN_WARNING "%s: alloc_netdev failed.\n", chan->name);		return;	}	chan->pppdev.dev = d;	sppp_attach(&chan->pppdev);	d->base_addr = chan->cosa->datareg;	d->irq = chan->cosa->irq;	d->dma = chan->cosa->dma;	d->priv = chan;	if (register_netdev(d)) {		printk(KERN_WARNING "%s: register_netdev failed.\n", d->name);		sppp_detach(d);		free_netdev(d);		chan->pppdev.dev = NULL;		return;	}}static void sppp_channel_delete(struct channel_data *chan){	unregister_netdev(chan->pppdev.dev);	sppp_detach(chan->pppdev.dev);	free_netdev(chan->pppdev.dev);	chan->pppdev.dev = NULL;}static int cosa_sppp_open(struct net_device *d){	struct channel_data *chan = d->priv;	int err;	unsigned long flags;	if (!(chan->cosa->firmware_status & COSA_FW_START)) {		printk(KERN_NOTICE "%s: start the firmware first (status %d)\n",			chan->cosa->name, chan->cosa->firmware_status);		return -EPERM;	}	spin_lock_irqsave(&chan->cosa->lock, flags);	if (chan->usage != 0) {		printk(KERN_WARNING "%s: sppp_open called with usage count %d\n",			chan->name, chan->usage);		spin_unlock_irqrestore(&chan->cosa->lock, flags);		return -EBUSY;	}	chan->setup_rx = sppp_setup_rx;	chan->tx_done = sppp_tx_done;	chan->rx_done = sppp_rx_done;	chan->usage=-1;	chan->cosa->usage++;	spin_unlock_irqrestore(&chan->cosa->lock, flags);	err = sppp_open(d);	if (err) {		spin_lock_irqsave(&chan->cosa->lock, flags);		chan->usage=0;		chan->cosa->usage--;				spin_unlock_irqrestore(&chan->cosa->lock, flags);		return err;	}	netif_start_queue(d);	cosa_enable_rx(chan);	return 0;}static int cosa_sppp_tx(struct sk_buff *skb, struct net_device *dev){	struct channel_data *chan = dev->priv;	netif_stop_queue(dev);	chan->tx_skb = skb;	cosa_start_tx(chan, skb->data, skb->len);	return 0;}static void cosa_sppp_timeout(struct net_device *dev){	struct channel_data *chan = dev->priv;	if (test_bit(RXBIT, &chan->cosa->rxtx)) {		chan->stats.rx_errors++;		chan->stats.rx_missed_errors++;	} else {		chan->stats.tx_errors++;		chan->stats.tx_aborted_errors++;	}	cosa_kick(chan->cosa);	if (chan->tx_skb) {		dev_kfree_skb(chan->tx_skb);		chan->tx_skb = NULL;	}	netif_wake_queue(dev);}static int cosa_sppp_close(struct net_device *d){	struct channel_data *chan = d->priv;	unsigned long flags;	netif_stop_queue(d);	sppp_close(d);	cosa_disable_rx(chan);	spin_lock_irqsave(&chan->cosa->lock, flags);	if (chan->rx_skb) {		kfree_skb(chan->rx_skb);		chan->rx_skb = NULL;	}	if (chan->tx_skb) {		kfree_skb(chan->tx_skb);		chan->tx_skb = NULL;	}	chan->usage=0;	chan->cosa->usage--;	spin_unlock_irqrestore(&chan->cosa->lock, flags);	return 0;}static char *sppp_setup_rx(struct channel_data *chan, int size){	/*	 * We can safely fall back to non-dma-able memory, because we have	 * the cosa->bouncebuf pre-allocated.	 */	if (chan->rx_skb)		kfree_skb(chan->rx_skb);	chan->rx_skb = dev_alloc_skb(size);	if (chan->rx_skb == NULL) {		printk(KERN_NOTICE "%s: Memory squeeze, dropping packet\n",			chan->name);		chan->stats.rx_dropped++;		return NULL;	}	chan->pppdev.dev->trans_start = jiffies;	return skb_put(chan->rx_skb, size);}static int sppp_rx_done(struct channel_data *chan){	if (!chan->rx_skb) {		printk(KERN_WARNING "%s: rx_done with empty skb!\n",			chan->name);		chan->stats.rx_errors++;		chan->stats.rx_frame_errors++;		return 0;	}	chan->rx_skb->protocol = htons(ETH_P_WAN_PPP);	chan->rx_skb->dev = chan->pppdev.dev;	chan->rx_skb->mac.raw = chan->rx_skb->data;	chan->stats.rx_packets++;	chan->stats.rx_bytes += chan->cosa->rxsize;	netif_rx(chan->rx_skb);	chan->rx_skb = NULL;	chan->pppdev.dev->last_rx = jiffies;	return 0;}/* ARGSUSED */static int sppp_tx_done(struct channel_data *chan, int size){	if (!chan->tx_skb) {		printk(KERN_WARNING "%s: tx_done with empty skb!\n",			chan->name);		chan->stats.tx_errors++;		chan->stats.tx_aborted_errors++;		return 1;	}	dev_kfree_skb_irq(chan->tx_skb);	chan->tx_skb = NULL;	chan->stats.tx_packets++;	chan->stats.tx_bytes += size;	netif_wake_queue(chan->pppdev.dev);	return 1;}static struct net_device_stats *cosa_net_stats(struct net_device *dev){	struct channel_data *chan = dev->priv;	return &chan->stats;}/*---------- Character device ---------- */static void chardev_channel_init(struct channel_data *chan){	init_MUTEX(&chan->rsem);	init_MUTEX(&chan->wsem);}static ssize_t cosa_read(struct file *file,	char __user *buf, size_t count, loff_t *ppos){	DECLARE_WAITQUEUE(wait, current);	unsigned long flags;	struct channel_data *chan = file->private_data;	struct cosa_data *cosa = chan->cosa;	char *kbuf;	if (!(cosa->firmware_status & COSA_FW_START)) {		printk(KERN_NOTICE "%s: start the firmware first (status %d)\n",			cosa->name, cosa->firmware_status);		return -EPERM;	}	if (down_interruptible(&chan->rsem))		return -ERESTARTSYS;		if ((chan->rxdata = kmalloc(COSA_MTU, GFP_DMA|GFP_KERNEL)) == NULL) {		printk(KERN_INFO "%s: cosa_read() - OOM\n", cosa->name);		up(&chan->rsem);		return -ENOMEM;	}	chan->rx_status = 0;	cosa_enable_rx(chan);	spin_lock_irqsave(&cosa->lock, flags);	add_wait_queue(&chan->rxwaitq, &wait);	while(!chan->rx_status) {		current->state = TASK_INTERRUPTIBLE;		spin_unlock_irqrestore(&cosa->lock, flags);		schedule();		spin_lock_irqsave(&cosa->lock, flags);		if (signal_pending(current) && chan->rx_status == 0) {			chan->rx_status = 1;			remove_wait_queue(&chan->rxwaitq, &wait);			current->state = TASK_RUNNING;			spin_unlock_irqrestore(&cosa->lock, flags);			up(&chan->rsem);			return -ERESTARTSYS;		}	}	remove_wait_queue(&chan->rxwaitq, &wait);	current->state = TASK_RUNNING;	kbuf = chan->rxdata;	count = chan->rxsize;	spin_unlock_irqrestore(&cosa->lock, flags);	up(&chan->rsem);	if (copy_to_user(buf, kbuf, count)) {		kfree(kbuf);		return -EFAULT;	}	kfree(kbuf);	return count;}static char *chrdev_setup_rx(struct channel_data *chan, int size){	/* Expect size <= COSA_MTU */	chan->rxsize = size;	return chan->rxdata;}static int chrdev_rx_done(struct channel_data *chan){	if (chan->rx_status) { /* Reader has died */		kfree(chan->rxdata);		up(&chan->wsem);	}	chan->rx_status = 1;	wake_up_interruptible(&chan->rxwaitq);	return 1;}static ssize_t cosa_write(struct file *file,	const char __user *buf, size_t count, loff_t *ppos){	DECLARE_WAITQUEUE(wait, current);	struct channel_data *chan = file->private_data;	struct cosa_data *cosa = chan->cosa;	unsigned long flags;	char *kbuf;	if (!(cosa->firmware_status & COSA_FW_START)) {		printk(KERN_NOTICE "%s: start the firmware first (status %d)\n",			cosa->name, cosa->firmware_status);		return -EPERM;	}	if (down_interruptible(&chan->wsem))		return -ERESTARTSYS;	if (count > COSA_MTU)		count = COSA_MTU;		/* Allocate the buffer */	if ((kbuf = kmalloc(count, GFP_KERNEL|GFP_DMA)) == NULL) {		printk(KERN_NOTICE "%s: cosa_write() OOM - dropping packet\n",			cosa->name);		up(&chan->wsem);		return -ENOMEM;	}	if (copy_from_user(kbuf, buf, count)) {		up(&chan->wsem);		kfree(kbuf);		return -EFAULT;	}	chan->tx_status=0;	cosa_start_tx(chan, kbuf, count);	spin_lock_irqsave(&cosa->lock, flags);	add_wait_queue(&chan->txwaitq, &wait);	while(!chan->tx_status) {		current->state = TASK_INTERRUPTIBLE;		spin_unlock_irqrestore(&cosa->lock, flags);		schedule();		spin_lock_irqsave(&cosa->lock, flags);		if (signal_pending(current) && chan->tx_status == 0) {			chan->tx_status = 1;			remove_wait_queue(&chan->txwaitq, &wait);			current->state = TASK_RUNNING;			chan->tx_status = 1;			spin_unlock_irqrestore(&cosa->lock, flags);			return -ERESTARTSYS;		}	}	remove_wait_queue(&chan->txwaitq, &wait);	current->state = TASK_RUNNING;	up(&chan->wsem);	spin_unlock_irqrestore(&cosa->lock, flags);	kfree(kbuf);	return count;}static int chrdev_tx_done(struct channel_data *chan, int size){	if (chan->tx_status) { /* Writer was interrupted */		kfree(chan->txbuf);		up(&chan->wsem);	}	chan->tx_status = 1;	wake_up_interruptible(&chan->txwaitq);	return 1;}static unsigned int cosa_poll(struct file *file, poll_table *poll){	printk(KERN_INFO "cosa_poll is here\n");	return 0;}static int cosa_open(struct inode *inode, struct file *file){	struct cosa_data *cosa;	struct channel_data *chan;	unsigned long flags;	int n;	if ((n=iminor(file->f_dentry->d_inode)>>CARD_MINOR_BITS)		>= nr_cards)		return -ENODEV;	cosa = cosa_cards+n;	if ((n=iminor(file->f_dentry->d_inode)		& ((1<<CARD_MINOR_BITS)-1)) >= cosa->nchannels)		return -ENODEV;	chan = cosa->chan + n;		file->private_data = chan;	spin_lock_irqsave(&cosa->lock, flags);	if (chan->usage < 0) { /* in netdev mode */		spin_unlock_irqrestore(&cosa->lock, flags);		return -EBUSY;	}	cosa->usage++;	chan->usage++;	chan->tx_done = chrdev_tx_done;	chan->setup_rx = chrdev_setup_rx;	chan->rx_done = chrdev_rx_done;	spin_unlock_irqrestore(&cosa->lock, flags);	return 0;}static int cosa_release(struct inode *inode, struct file *file){	struct channel_data *channel = file->private_data;	struct cosa_data *cosa;	unsigned long flags;	cosa = channel->cosa;	spin_lock_irqsave(&cosa->lock, flags);	cosa->usage--;	channel->usage--;	spin_unlock_irqrestore(&cosa->lock, flags);	return 0;}#ifdef COSA_FASYNC_WORKINGstatic struct fasync_struct *fasync[256] = { NULL, };/* To be done ... */static int cosa_fasync(struct inode *inode, struct file *file, int on){        int port = iminor(inode);        int rv = fasync_helper(inode, file, on, &fasync[port]);        return rv < 0 ? rv : 0;}#endif/* ---------- Ioctls ---------- *//* * Ioctl subroutines can safely be made inline, because they are called * only from cosa_ioctl(). */static inline int cosa_reset(struct cosa_data *cosa){

⌨️ 快捷键说明

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