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

📄 via-ircc.c

📁 《linux驱动程序设计从入门到精通》一书中所有的程序代码含驱动和相应的应用程序
💻 C
📖 第 1 页 / 共 3 页
字号:
/******************************************************************** Filename:      via-ircc.c Version:       1.0  Description:   Driver for the VIA VT8231/VT8233 IrDA chipsets Author:        VIA Technologies,inc Date  :	08/06/2003Copyright (c) 1998-2003 VIA Technologies, Inc.This program is free software; you can redistribute it and/or modify it underthe terms of the GNU General Public License as published by the Free SoftwareFoundation; either version 2, or (at your option) any later version.This program is distributed in the hope that it will be useful, but WITHOUTANY WARRANTIES OR REPRESENTATIONS; without even the implied warranty ofMERCHANTABILITY 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 withthis program; if not, write to the Free Software Foundation, Inc.,59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.F01 Oct/02/02: Modify code for V0.11(move out back to back transfer)F02 Oct/28/02: Add SB device ID for 3147 and 3177. Comment :       jul/09/2002 : only implement two kind of dongle currently.       Oct/02/2002 : work on VT8231 and VT8233 .       Aug/06/2003 : change driver format to pci driver .2004-02-16: <sda@bdit.de>- Removed unneeded 'legacy' pci stuff.- Make sure SIR mode is set (hw_init()) before calling mode-dependant stuff.- On speed change from core, don't send SIR frame with new speed.   Use current speed and change speeds later.- Make module-param dongle_id actually work.- New dongle_id 17 (0x11): TDFS4500. Single-ended SIR only.   Tested with home-grown PCB on EPIA boards.- Code cleanup.        ********************************************************************/#include <linux/module.h>#include <linux/kernel.h>#include <linux/types.h>#include <linux/skbuff.h>#include <linux/netdevice.h>#include <linux/ioport.h>#include <linux/delay.h>#include <linux/slab.h>#include <linux/init.h>#include <linux/rtnetlink.h>#include <linux/pci.h>#include <linux/dma-mapping.h>#include <asm/io.h>#include <asm/dma.h>#include <asm/byteorder.h>#include <linux/pm.h>#include <net/irda/wrapper.h>#include <net/irda/irda.h>#include <net/irda/irda_device.h>#include "via-ircc.h"#define VIA_MODULE_NAME "via-ircc"#define CHIP_IO_EXTENT 0x40static char *driver_name = VIA_MODULE_NAME;/* Module parameters */static int qos_mtt_bits = 0x07;	/* 1 ms or more */static int dongle_id = 0;	/* default: probe *//* We can't guess the type of connected dongle, user *must* supply it. */module_param(dongle_id, int, 0);/* FIXME : we should not need this, because instances should be automatically * managed by the PCI layer. Especially that we seem to only be using the * first entry. Jean II *//* Max 4 instances for now */static struct via_ircc_cb *dev_self[] = { NULL, NULL, NULL, NULL };/* Some prototypes */static int via_ircc_open(int i, chipio_t * info, unsigned int id);static int via_ircc_close(struct via_ircc_cb *self);static int via_ircc_dma_receive(struct via_ircc_cb *self);static int via_ircc_dma_receive_complete(struct via_ircc_cb *self,					 int iobase);static int via_ircc_hard_xmit_sir(struct sk_buff *skb,				  struct net_device *dev);static int via_ircc_hard_xmit_fir(struct sk_buff *skb,				  struct net_device *dev);static void via_hw_init(struct via_ircc_cb *self);static void via_ircc_change_speed(struct via_ircc_cb *self, __u32 baud);static irqreturn_t via_ircc_interrupt(int irq, void *dev_id);static int via_ircc_is_receiving(struct via_ircc_cb *self);static int via_ircc_read_dongle_id(int iobase);static int via_ircc_net_open(struct net_device *dev);static int via_ircc_net_close(struct net_device *dev);static int via_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq,			      int cmd);static struct net_device_stats *via_ircc_net_get_stats(struct net_device						       *dev);static void via_ircc_change_dongle_speed(int iobase, int speed,					 int dongle_id);static int RxTimerHandler(struct via_ircc_cb *self, int iobase);static void hwreset(struct via_ircc_cb *self);static int via_ircc_dma_xmit(struct via_ircc_cb *self, u16 iobase);static int upload_rxdata(struct via_ircc_cb *self, int iobase);static int __devinit via_init_one (struct pci_dev *pcidev, const struct pci_device_id *id);static void __devexit via_remove_one (struct pci_dev *pdev);/* FIXME : Should use udelay() instead, even if we are x86 only - Jean II */static void iodelay(int udelay){	u8 data;	int i;	for (i = 0; i < udelay; i++) {		data = inb(0x80);	}}static struct pci_device_id via_pci_tbl[] = {	{ PCI_VENDOR_ID_VIA, 0x8231, PCI_ANY_ID, PCI_ANY_ID,0,0,0 },	{ PCI_VENDOR_ID_VIA, 0x3109, PCI_ANY_ID, PCI_ANY_ID,0,0,1 },	{ PCI_VENDOR_ID_VIA, 0x3074, PCI_ANY_ID, PCI_ANY_ID,0,0,2 },	{ PCI_VENDOR_ID_VIA, 0x3147, PCI_ANY_ID, PCI_ANY_ID,0,0,3 },	{ PCI_VENDOR_ID_VIA, 0x3177, PCI_ANY_ID, PCI_ANY_ID,0,0,4 },	{ 0, }};MODULE_DEVICE_TABLE(pci,via_pci_tbl);static struct pci_driver via_driver = {	.name		= VIA_MODULE_NAME,	.id_table	= via_pci_tbl,	.probe		= via_init_one,	.remove		= __devexit_p(via_remove_one),};/* * Function via_ircc_init () * *    Initialize chip. Just find out chip type and resource. */static int __init via_ircc_init(void){	int rc;	IRDA_DEBUG(3, "%s()\n", __FUNCTION__);	rc = pci_register_driver(&via_driver);	if (rc < 0) {		IRDA_DEBUG(0, "%s(): error rc = %d, returning  -ENODEV...\n",			   __FUNCTION__, rc);		return -ENODEV;	}	return 0;}static int __devinit via_init_one (struct pci_dev *pcidev, const struct pci_device_id *id){	int rc;        u8 temp,oldPCI_40,oldPCI_44,bTmp,bTmp1;	u16 Chipset,FirDRQ1,FirDRQ0,FirIRQ,FirIOBase;	chipio_t info;	IRDA_DEBUG(2, "%s(): Device ID=(0X%X)\n", __FUNCTION__, id->device);	rc = pci_enable_device (pcidev);	if (rc) {		IRDA_DEBUG(0, "%s(): error rc = %d\n", __FUNCTION__, rc);		return -ENODEV;	}	// South Bridge exist        if ( ReadLPCReg(0x20) != 0x3C )		Chipset=0x3096;	else		Chipset=0x3076;	if (Chipset==0x3076) {		IRDA_DEBUG(2, "%s(): Chipset = 3076\n", __FUNCTION__);		WriteLPCReg(7,0x0c );		temp=ReadLPCReg(0x30);//check if BIOS Enable Fir		if((temp&0x01)==1) {   // BIOS close or no FIR			WriteLPCReg(0x1d, 0x82 );			WriteLPCReg(0x23,0x18);			temp=ReadLPCReg(0xF0);			if((temp&0x01)==0) {				temp=(ReadLPCReg(0x74)&0x03);    //DMA				FirDRQ0=temp + 4;				temp=(ReadLPCReg(0x74)&0x0C) >> 2;				FirDRQ1=temp + 4;			} else {				temp=(ReadLPCReg(0x74)&0x0C) >> 2;    //DMA				FirDRQ0=temp + 4;				FirDRQ1=FirDRQ0;			}			FirIRQ=(ReadLPCReg(0x70)&0x0f);		//IRQ			FirIOBase=ReadLPCReg(0x60 ) << 8;	//IO Space :high byte			FirIOBase=FirIOBase| ReadLPCReg(0x61) ;	//low byte			FirIOBase=FirIOBase  ;			info.fir_base=FirIOBase;			info.irq=FirIRQ;			info.dma=FirDRQ1;			info.dma2=FirDRQ0;			pci_read_config_byte(pcidev,0x40,&bTmp);			pci_write_config_byte(pcidev,0x40,((bTmp | 0x08) & 0xfe));			pci_read_config_byte(pcidev,0x42,&bTmp);			pci_write_config_byte(pcidev,0x42,(bTmp | 0xf0));			pci_write_config_byte(pcidev,0x5a,0xc0);			WriteLPCReg(0x28, 0x70 );			if (via_ircc_open(0, &info,0x3076) == 0)				rc=0;		} else			rc = -ENODEV; //IR not turn on	 	} else { //Not VT1211		IRDA_DEBUG(2, "%s(): Chipset = 3096\n", __FUNCTION__);		pci_read_config_byte(pcidev,0x67,&bTmp);//check if BIOS Enable Fir		if((bTmp&0x01)==1) {  // BIOS enable FIR			//Enable Double DMA clock			pci_read_config_byte(pcidev,0x42,&oldPCI_40);			pci_write_config_byte(pcidev,0x42,oldPCI_40 | 0x80);			pci_read_config_byte(pcidev,0x40,&oldPCI_40);			pci_write_config_byte(pcidev,0x40,oldPCI_40 & 0xf7);			pci_read_config_byte(pcidev,0x44,&oldPCI_44);			pci_write_config_byte(pcidev,0x44,0x4e);  //---------- read configuration from Function0 of south bridge			if((bTmp&0x02)==0) {				pci_read_config_byte(pcidev,0x44,&bTmp1); //DMA				FirDRQ0 = (bTmp1 & 0x30) >> 4;				pci_read_config_byte(pcidev,0x44,&bTmp1);				FirDRQ1 = (bTmp1 & 0xc0) >> 6;			} else  {				pci_read_config_byte(pcidev,0x44,&bTmp1);    //DMA				FirDRQ0 = (bTmp1 & 0x30) >> 4 ;				FirDRQ1=0;			}			pci_read_config_byte(pcidev,0x47,&bTmp1);  //IRQ			FirIRQ = bTmp1 & 0x0f;			pci_read_config_byte(pcidev,0x69,&bTmp);			FirIOBase = bTmp << 8;//hight byte			pci_read_config_byte(pcidev,0x68,&bTmp);			FirIOBase = (FirIOBase | bTmp ) & 0xfff0;  //-------------------------			info.fir_base=FirIOBase;			info.irq=FirIRQ;			info.dma=FirDRQ1;			info.dma2=FirDRQ0;			if (via_ircc_open(0, &info,0x3096) == 0)				rc=0;		} else			rc = -ENODEV; //IR not turn on !!!!!	}//Not VT1211	IRDA_DEBUG(2, "%s(): End - rc = %d\n", __FUNCTION__, rc);	return rc;}/* * Function via_ircc_clean () * *    Close all configured chips * */static void via_ircc_clean(void){	int i;	IRDA_DEBUG(3, "%s()\n", __FUNCTION__);	for (i=0; i < ARRAY_SIZE(dev_self); i++) {		if (dev_self[i])			via_ircc_close(dev_self[i]);	}}static void __devexit via_remove_one (struct pci_dev *pdev){	IRDA_DEBUG(3, "%s()\n", __FUNCTION__);	/* FIXME : This is ugly. We should use pci_get_drvdata(pdev);	 * to get our driver instance and call directly via_ircc_close().	 * See vlsi_ir for details...	 * Jean II */	via_ircc_clean();	/* FIXME : This should be in via_ircc_close(), because here we may	 * theoritically disable still configured devices :-( - Jean II */	pci_disable_device(pdev);}static void __exit via_ircc_cleanup(void){	IRDA_DEBUG(3, "%s()\n", __FUNCTION__);	/* FIXME : This should be redundant, as pci_unregister_driver()	 * should call via_remove_one() on each device.	 * Jean II */	via_ircc_clean();	/* Cleanup all instances of the driver */	pci_unregister_driver (&via_driver); }/* * Function via_ircc_open (iobase, irq) * *    Open driver instance * */static __devinit int via_ircc_open(int i, chipio_t * info, unsigned int id){	struct net_device *dev;	struct via_ircc_cb *self;	int err;	IRDA_DEBUG(3, "%s()\n", __FUNCTION__);	if (i >= ARRAY_SIZE(dev_self))		return -ENOMEM;	/* Allocate new instance of the driver */	dev = alloc_irdadev(sizeof(struct via_ircc_cb));	if (dev == NULL) 		return -ENOMEM;	self = dev->priv;	self->netdev = dev;	spin_lock_init(&self->lock);	/* FIXME : We should store our driver instance in the PCI layer,	 * using pci_set_drvdata(), not in this array.	 * See vlsi_ir for details... - Jean II */	/* FIXME : 'i' is always 0 (see via_init_one()) :-( - Jean II */	/* Need to store self somewhere */	dev_self[i] = self;	self->index = i;	/* Initialize Resource */	self->io.cfg_base = info->cfg_base;	self->io.fir_base = info->fir_base;	self->io.irq = info->irq;	self->io.fir_ext = CHIP_IO_EXTENT;	self->io.dma = info->dma;	self->io.dma2 = info->dma2;	self->io.fifo_size = 32;	self->chip_id = id;	self->st_fifo.len = 0;	self->RxDataReady = 0;	/* Reserve the ioports that we need */	if (!request_region(self->io.fir_base, self->io.fir_ext, driver_name)) {		IRDA_DEBUG(0, "%s(), can't get iobase of 0x%03x\n",			   __FUNCTION__, self->io.fir_base);		err = -ENODEV;		goto err_out1;	}		/* Initialize QoS for this device */	irda_init_max_qos_capabilies(&self->qos);	/* Check if user has supplied the dongle id or not */	if (!dongle_id)		dongle_id = via_ircc_read_dongle_id(self->io.fir_base);	self->io.dongle_id = dongle_id;	/* The only value we must override it the baudrate */	/* Maximum speeds and capabilities are dongle-dependant. */	switch( self->io.dongle_id ){	case 0x0d:		self->qos.baud_rate.bits =		    IR_9600 | IR_19200 | IR_38400 | IR_57600 | IR_115200 |		    IR_576000 | IR_1152000 | (IR_4000000 << 8);		break;	default:		self->qos.baud_rate.bits =		    IR_9600 | IR_19200 | IR_38400 | IR_57600 | IR_115200;		break;	}	/* Following was used for testing:	 *	 *   self->qos.baud_rate.bits = IR_9600;	 *	 * Is is no good, as it prohibits (error-prone) speed-changes.	 */	self->qos.min_turn_time.bits = qos_mtt_bits;	irda_qos_bits_to_value(&self->qos);	/* Max DMA buffer size needed = (data_size + 6) * (window_size) + 6; */	self->rx_buff.truesize = 14384 + 2048;	self->tx_buff.truesize = 14384 + 2048;	/* Allocate memory if needed */	self->rx_buff.head =		dma_alloc_coherent(NULL, self->rx_buff.truesize,				   &self->rx_buff_dma, GFP_KERNEL);	if (self->rx_buff.head == NULL) {		err = -ENOMEM;		goto err_out2;	}	memset(self->rx_buff.head, 0, self->rx_buff.truesize);	self->tx_buff.head =		dma_alloc_coherent(NULL, self->tx_buff.truesize,				   &self->tx_buff_dma, GFP_KERNEL);	if (self->tx_buff.head == NULL) {		err = -ENOMEM;		goto err_out3;	}	memset(self->tx_buff.head, 0, self->tx_buff.truesize);	self->rx_buff.in_frame = FALSE;	self->rx_buff.state = OUTSIDE_FRAME;	self->tx_buff.data = self->tx_buff.head;	self->rx_buff.data = self->rx_buff.head;	/* Reset Tx queue info */	self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0;	self->tx_fifo.tail = self->tx_buff.head;	/* Keep track of module usage */	SET_MODULE_OWNER(dev);	/* Override the network functions we need to use */	dev->hard_start_xmit = via_ircc_hard_xmit_sir;	dev->open = via_ircc_net_open;	dev->stop = via_ircc_net_close;	dev->do_ioctl = via_ircc_net_ioctl;	dev->get_stats = via_ircc_net_get_stats;	err = register_netdev(dev);	if (err)		goto err_out4;	IRDA_MESSAGE("IrDA: Registered device %s (via-ircc)\n", dev->name);	/* Initialise the hardware..	*/	self->io.speed = 9600;	via_hw_init(self);	return 0; err_out4:	dma_free_coherent(NULL, self->tx_buff.truesize,			  self->tx_buff.head, self->tx_buff_dma); err_out3:	dma_free_coherent(NULL, self->rx_buff.truesize,			  self->rx_buff.head, self->rx_buff_dma); err_out2:	release_region(self->io.fir_base, self->io.fir_ext); err_out1:	free_netdev(dev);	dev_self[i] = NULL;	return err;}/* * Function via_ircc_close (self) * *    Close driver instance * */static int via_ircc_close(struct via_ircc_cb *self){	int iobase;	IRDA_DEBUG(3, "%s()\n", __FUNCTION__);	IRDA_ASSERT(self != NULL, return -1;);	iobase = self->io.fir_base;	ResetChip(iobase, 5);	//hardware reset.	/* Remove netdevice */	unregister_netdev(self->netdev);	/* Release the PORT that this driver is using */	IRDA_DEBUG(2, "%s(), Releasing Region %03x\n",		   __FUNCTION__, self->io.fir_base);	release_region(self->io.fir_base, self->io.fir_ext);	if (self->tx_buff.head)		dma_free_coherent(NULL, self->tx_buff.truesize,				  self->tx_buff.head, self->tx_buff_dma);	if (self->rx_buff.head)		dma_free_coherent(NULL, self->rx_buff.truesize,				  self->rx_buff.head, self->rx_buff_dma);	dev_self[self->index] = NULL;	free_netdev(self->netdev);	return 0;}/* * Function via_hw_init(self) * *    Returns non-negative on success. * * Formerly via_ircc_setup  */static void via_hw_init(struct via_ircc_cb *self){	int iobase = self->io.fir_base;	IRDA_DEBUG(3, "%s()\n", __FUNCTION__);	SetMaxRxPacketSize(iobase, 0x0fff);	//set to max:4095	// FIFO Init	EnRXFIFOReadyInt(iobase, OFF);	EnRXFIFOHalfLevelInt(iobase, OFF);	EnTXFIFOHalfLevelInt(iobase, OFF);	EnTXFIFOUnderrunEOMInt(iobase, ON);	EnTXFIFOReadyInt(iobase, OFF);	InvertTX(iobase, OFF);	InvertRX(iobase, OFF);	if (ReadLPCReg(0x20) == 0x3c)		WriteLPCReg(0xF0, 0);	// for VT1211	/* Int Init */	EnRXSpecInt(iobase, ON);	/* The following is basically hwreset */	/* If this is the case, why not just call hwreset() ? Jean II */	ResetChip(iobase, 5);	EnableDMA(iobase, OFF);	EnableTX(iobase, OFF);	EnableRX(iobase, OFF);	EnRXDMA(iobase, OFF);	EnTXDMA(iobase, OFF);	RXStart(iobase, OFF);	TXStart(iobase, OFF);	InitCard(iobase);	CommonInit(iobase);	SIRFilter(iobase, ON);	SetSIR(iobase, ON);	CRC16(iobase, ON);	EnTXCRC(iobase, 0);	WriteReg(iobase, I_ST_CT_0, 0x00);	SetBaudRate(iobase, 9600);	SetPulseWidth(iobase, 12);	SetSendPreambleCount(iobase, 0);	self->io.speed = 9600;	self->st_fifo.len = 0;	via_ircc_change_dongle_speed(iobase, self->io.speed,				     self->io.dongle_id);	WriteReg(iobase, I_ST_CT_0, 0x80);}

⌨️ 快捷键说明

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