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

📄 vlsi_ir.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 4 页
字号:
			break;		case SIOCSMEDIABUSY:			if (!capable(CAP_NET_ADMIN)) {				ret = -EPERM;				break;			}			irda_device_set_media_busy(ndev, TRUE);			break;		case SIOCGRECEIVING:			/* the best we can do: check whether there are any bytes in rx fifo.			 * The trustable window (in case some data arrives just afterwards)			 * may be as short as 1usec or so at 4Mbps.			 */			fifocnt = inw(ndev->base_addr+VLSI_PIO_RCVBCNT) & RCVBCNT_MASK;			irq->ifr_receiving = (fifocnt!=0) ? 1 : 0;			break;		default:			IRDA_WARNING("%s: notsupp - cmd=%04x\n",				     __FUNCTION__, cmd);			ret = -EOPNOTSUPP;	}			return ret;}/********************************************************/static irqreturn_t vlsi_interrupt(int irq, void *dev_instance,					struct pt_regs *regs){	struct net_device *ndev = dev_instance;	vlsi_irda_dev_t *idev = ndev->priv;	unsigned	iobase;	u8		irintr;	int 		boguscount = 5;	unsigned long	flags;	int		handled = 0;	iobase = ndev->base_addr;	spin_lock_irqsave(&idev->lock,flags);	do {		irintr = inb(iobase+VLSI_PIO_IRINTR);		mb();		outb(irintr, iobase+VLSI_PIO_IRINTR);	/* acknowledge asap */		if (!(irintr&=IRINTR_INT_MASK))		/* not our INT - probably shared */			break;		handled = 1;		if (unlikely(!(irintr & ~IRINTR_ACTIVITY)))			break;				/* nothing todo if only activity */		if (irintr&IRINTR_RPKTINT)			vlsi_rx_interrupt(ndev);		if (irintr&IRINTR_TPKTINT)			vlsi_tx_interrupt(ndev);	} while (--boguscount > 0);	spin_unlock_irqrestore(&idev->lock,flags);	if (boguscount <= 0)		IRDA_MESSAGE("%s: too much work in interrupt!\n",			     __FUNCTION__);	return IRQ_RETVAL(handled);}/********************************************************/static int vlsi_open(struct net_device *ndev){	vlsi_irda_dev_t *idev = ndev->priv;	int	err = -EAGAIN;	char	hwname[32];	if (pci_request_regions(idev->pdev, drivername)) {		IRDA_WARNING("%s: io resource busy\n", __FUNCTION__);		goto errout;	}	ndev->base_addr = pci_resource_start(idev->pdev,0);	ndev->irq = idev->pdev->irq;	/* under some rare occasions the chip apparently comes up with	 * IRQ's pending. We better w/c pending IRQ and disable them all	 */	outb(IRINTR_INT_MASK, ndev->base_addr+VLSI_PIO_IRINTR);	if (request_irq(ndev->irq, vlsi_interrupt, SA_SHIRQ,			drivername, ndev)) {		IRDA_WARNING("%s: couldn't get IRQ: %d\n",			     __FUNCTION__, ndev->irq);		goto errout_io;	}	if ((err = vlsi_create_hwif(idev)) != 0)		goto errout_irq;	sprintf(hwname, "VLSI-FIR @ 0x%04x", (unsigned)ndev->base_addr);	idev->irlap = irlap_open(ndev,&idev->qos,hwname);	if (!idev->irlap)		goto errout_free_ring;	do_gettimeofday(&idev->last_rx);  /* first mtt may start from now on */	idev->new_baud = 9600;		/* start with IrPHY using 9600(SIR) mode */	if ((err = vlsi_start_hw(idev)) != 0)		goto errout_close_irlap;	netif_start_queue(ndev);	IRDA_MESSAGE("%s: device %s operational\n", __FUNCTION__, ndev->name);	return 0;errout_close_irlap:	irlap_close(idev->irlap);errout_free_ring:	vlsi_destroy_hwif(idev);errout_irq:	free_irq(ndev->irq,ndev);errout_io:	pci_release_regions(idev->pdev);errout:	return err;}static int vlsi_close(struct net_device *ndev){	vlsi_irda_dev_t *idev = ndev->priv;	netif_stop_queue(ndev);	if (idev->irlap)		irlap_close(idev->irlap);	idev->irlap = NULL;	vlsi_stop_hw(idev);	vlsi_destroy_hwif(idev);	free_irq(ndev->irq,ndev);	pci_release_regions(idev->pdev);	IRDA_MESSAGE("%s: device %s stopped\n", __FUNCTION__, ndev->name);	return 0;}static int vlsi_irda_init(struct net_device *ndev){	vlsi_irda_dev_t *idev = ndev->priv;	struct pci_dev *pdev = idev->pdev;	SET_MODULE_OWNER(ndev);	ndev->irq = pdev->irq;	ndev->base_addr = pci_resource_start(pdev,0);	/* PCI busmastering	 * see include file for details why we need these 2 masks, in this order!	 */	if (pci_set_dma_mask(pdev,DMA_MASK_USED_BY_HW)	    || pci_set_dma_mask(pdev,DMA_MASK_MSTRPAGE)) {		IRDA_ERROR("%s: aborting due to PCI BM-DMA address limitations\n", __FUNCTION__);		return -1;	}	irda_init_max_qos_capabilies(&idev->qos);	/* the VLSI82C147 does not support 576000! */	idev->qos.baud_rate.bits = IR_2400 | IR_9600		| IR_19200 | IR_38400 | IR_57600 | IR_115200		| IR_1152000 | (IR_4000000 << 8);	idev->qos.min_turn_time.bits = qos_mtt_bits;	irda_qos_bits_to_value(&idev->qos);	/* currently no public media definitions for IrDA */	ndev->flags |= IFF_PORTSEL | IFF_AUTOMEDIA;	ndev->if_port = IF_PORT_UNKNOWN; 	ndev->open	      = vlsi_open;	ndev->stop	      = vlsi_close;	ndev->get_stats	      = vlsi_get_stats;	ndev->hard_start_xmit = vlsi_hard_start_xmit;	ndev->do_ioctl	      = vlsi_ioctl;	ndev->tx_timeout      = vlsi_tx_timeout;	ndev->watchdog_timeo  = 500*HZ/1000;	/* max. allowed turn time for IrLAP */	SET_NETDEV_DEV(ndev, &pdev->dev);	return 0;}	/**************************************************************/static int __devinitvlsi_irda_probe(struct pci_dev *pdev, const struct pci_device_id *id){	struct net_device	*ndev;	vlsi_irda_dev_t		*idev;	if (pci_enable_device(pdev))		goto out;	else		pdev->current_state = 0; /* hw must be running now */	IRDA_MESSAGE("%s: IrDA PCI controller %s detected\n",		     drivername, PCIDEV_NAME(pdev));	if ( !pci_resource_start(pdev,0)	     || !(pci_resource_flags(pdev,0) & IORESOURCE_IO) ) {		IRDA_ERROR("%s: bar 0 invalid", __FUNCTION__);		goto out_disable;	}	ndev = alloc_irdadev(sizeof(*idev));	if (ndev==NULL) {		IRDA_ERROR("%s: Unable to allocate device memory.\n",			   __FUNCTION__);		goto out_disable;	}	idev = ndev->priv;	spin_lock_init(&idev->lock);	init_MUTEX(&idev->sem);	down(&idev->sem);	idev->pdev = pdev;	if (vlsi_irda_init(ndev) < 0)		goto out_freedev;	if (register_netdev(ndev) < 0) {		IRDA_ERROR("%s: register_netdev failed\n", __FUNCTION__);		goto out_freedev;	}	if (vlsi_proc_root != NULL) {		struct proc_dir_entry *ent;		ent = create_proc_entry(ndev->name, S_IFREG|S_IRUGO, vlsi_proc_root);		if (!ent) {			IRDA_WARNING("%s: failed to create proc entry\n",				     __FUNCTION__);		} else {			ent->data = ndev;			ent->proc_fops = VLSI_PROC_FOPS;			ent->size = 0;		}		idev->proc_entry = ent;	}	IRDA_MESSAGE("%s: registered device %s\n", drivername, ndev->name);	pci_set_drvdata(pdev, ndev);	up(&idev->sem);	return 0;out_freedev:	up(&idev->sem);	free_netdev(ndev);out_disable:	pci_disable_device(pdev);out:	pci_set_drvdata(pdev, NULL);	return -ENODEV;}static void __devexit vlsi_irda_remove(struct pci_dev *pdev){	struct net_device *ndev = pci_get_drvdata(pdev);	vlsi_irda_dev_t *idev;	if (!ndev) {		IRDA_ERROR("%s: lost netdevice?\n", drivername);		return;	}	unregister_netdev(ndev);	idev = ndev->priv;	down(&idev->sem);	if (idev->proc_entry) {		remove_proc_entry(ndev->name, vlsi_proc_root);		idev->proc_entry = NULL;	}	up(&idev->sem);	free_netdev(ndev);	pci_set_drvdata(pdev, NULL);	IRDA_MESSAGE("%s: %s removed\n", drivername, PCIDEV_NAME(pdev));}#ifdef CONFIG_PM/* The Controller doesn't provide PCI PM capabilities as defined by PCI specs. * Some of the Linux PCI-PM code however depends on this, for example in * pci_set_power_state(). So we have to take care to perform the required * operations on our own (particularly reflecting the pdev->current_state) * otherwise we might get cheated by pci-pm. */static int vlsi_irda_suspend(struct pci_dev *pdev, pm_message_t state){	struct net_device *ndev = pci_get_drvdata(pdev);	vlsi_irda_dev_t *idev;	if (!ndev) {		IRDA_ERROR("%s - %s: no netdevice \n",			   __FUNCTION__, PCIDEV_NAME(pdev));		return 0;	}	idev = ndev->priv;		down(&idev->sem);	if (pdev->current_state != 0) {			/* already suspended */		if (state.event > pdev->current_state) {	/* simply go deeper */			pci_set_power_state(pdev, pci_choose_state(pdev, state));			pdev->current_state = state.event;		}		else			IRDA_ERROR("%s - %s: invalid suspend request %u -> %u\n", __FUNCTION__, PCIDEV_NAME(pdev), pdev->current_state, state.event);		up(&idev->sem);		return 0;	}	if (netif_running(ndev)) {		netif_device_detach(ndev);		vlsi_stop_hw(idev);		pci_save_state(pdev);		if (!idev->new_baud)			/* remember speed settings to restore on resume */			idev->new_baud = idev->baud;	}	pci_set_power_state(pdev, pci_choose_state(pdev, state));	pdev->current_state = state.event;	idev->resume_ok = 1;	up(&idev->sem);	return 0;}static int vlsi_irda_resume(struct pci_dev *pdev){	struct net_device *ndev = pci_get_drvdata(pdev);	vlsi_irda_dev_t	*idev;	if (!ndev) {		IRDA_ERROR("%s - %s: no netdevice \n",			   __FUNCTION__, PCIDEV_NAME(pdev));		return 0;	}	idev = ndev->priv;		down(&idev->sem);	if (pdev->current_state == 0) {		up(&idev->sem);		IRDA_WARNING("%s - %s: already resumed\n",			     __FUNCTION__, PCIDEV_NAME(pdev));		return 0;	}		pci_set_power_state(pdev, PCI_D0);	pdev->current_state = PM_EVENT_ON;	if (!idev->resume_ok) {		/* should be obsolete now - but used to happen due to:		 * - pci layer initially setting pdev->current_state = 4 (unknown)		 * - pci layer did not walk the save_state-tree (might be APM problem)		 *   so we could not refuse to suspend from undefined state		 * - vlsi_irda_suspend detected invalid state and refused to save		 *   configuration for resume - but was too late to stop suspending		 * - vlsi_irda_resume got screwed when trying to resume from garbage		 *		 * now we explicitly set pdev->current_state = 0 after enabling the		 * device and independently resume_ok should catch any garbage config.		 */		IRDA_WARNING("%s - hm, nothing to resume?\n", __FUNCTION__);		up(&idev->sem);		return 0;	}	if (netif_running(ndev)) {		pci_restore_state(pdev);		vlsi_start_hw(idev);		netif_device_attach(ndev);	}	idev->resume_ok = 0;	up(&idev->sem);	return 0;}#endif /* CONFIG_PM *//*********************************************************/static struct pci_driver vlsi_irda_driver = {	.name		= drivername,	.id_table	= vlsi_irda_table,	.probe		= vlsi_irda_probe,	.remove		= __devexit_p(vlsi_irda_remove),#ifdef CONFIG_PM	.suspend	= vlsi_irda_suspend,	.resume		= vlsi_irda_resume,#endif};#define PROC_DIR ("driver/" DRIVER_NAME)static int __init vlsi_mod_init(void){	int	i, ret;	if (clksrc < 0  ||  clksrc > 3) {		IRDA_ERROR("%s: invalid clksrc=%d\n", drivername, clksrc);		return -1;	}	for (i = 0; i < 2; i++) {		switch(ringsize[i]) {			case 4:			case 8:			case 16:			case 32:			case 64:				break;			default:				IRDA_WARNING("%s: invalid %s ringsize %d, using default=8", drivername, (i)?"rx":"tx", ringsize[i]);				ringsize[i] = 8;				break;		}	} 	sirpulse = !!sirpulse;	/* proc_mkdir returns NULL if !CONFIG_PROC_FS.	 * Failure to create the procfs entry is handled like running	 * without procfs - it's not required for the driver to work.	 */	vlsi_proc_root = proc_mkdir(PROC_DIR, NULL);	if (vlsi_proc_root) {		/* protect registered procdir against module removal.		 * Because we are in the module init path there's no race		 * window after create_proc_entry (and no barrier needed).		 */		vlsi_proc_root->owner = THIS_MODULE;	}	ret = pci_module_init(&vlsi_irda_driver);	if (ret && vlsi_proc_root)		remove_proc_entry(PROC_DIR, NULL);	return ret;}static void __exit vlsi_mod_exit(void){	pci_unregister_driver(&vlsi_irda_driver);	if (vlsi_proc_root)		remove_proc_entry(PROC_DIR, NULL);}module_init(vlsi_mod_init);module_exit(vlsi_mod_exit);

⌨️ 快捷键说明

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