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

📄 vlsi_ir.c

📁 内核linux2.4.20,可跟rtlinux3.2打补丁 组成实时linux系统,编译内核
💻 C
📖 第 1 页 / 共 3 页
字号:
/********************************************************************* * *	vlsi_ir.c:	VLSI82C147 PCI IrDA controller driver for Linux * *	Version:	0.3a, Nov 10, 2001 * *	Copyright (c) 2001 Martin Diehl * *	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., 59 Temple Place, Suite 330, Boston,  *	MA 02111-1307 USA * ********************************************************************/#include <linux/module.h> #include <linux/kernel.h>#include <linux/init.h>#include <linux/pci.h>#include <linux/slab.h>#include <linux/netdevice.h>#include <linux/skbuff.h>#include <linux/delay.h>#include <linux/time.h>#include <net/irda/irda.h>#include <net/irda/irda_device.h>#include <net/irda/wrapper.h>#include <net/irda/irlap.h>#include <net/irda/vlsi_ir.h>/********************************************************/MODULE_DESCRIPTION("IrDA SIR/MIR/FIR driver for VLSI 82C147");MODULE_AUTHOR("Martin Diehl <info@mdiehl.de>");MODULE_LICENSE("GPL");static /* const */ char drivername[] = "vlsi_ir";#define PCI_CLASS_WIRELESS_IRDA 0x0d00static struct pci_device_id vlsi_irda_table [] __devinitdata = { {	class:          PCI_CLASS_WIRELESS_IRDA << 8,	vendor:         PCI_VENDOR_ID_VLSI,	device:         PCI_DEVICE_ID_VLSI_82C147,	}, { /* all zeroes */ }};MODULE_DEVICE_TABLE(pci, vlsi_irda_table);/********************************************************/MODULE_PARM(clksrc, "i");MODULE_PARM_DESC(clksrc, "clock input source selection");/*	clksrc: which clock source to be used *		0: auto - try PLL, fallback to 40MHz XCLK *		1: on-chip 48MHz PLL *		2: external 48MHz XCLK *		3: external 40MHz XCLK (HP OB-800) */static int clksrc = 0;			/* default is 0(auto) */MODULE_PARM(ringsize, "1-2i");MODULE_PARM_DESC(ringsize, "TX, RX ring descriptor size");/*	ringsize: size of the tx and rx descriptor rings *		independent for tx and rx *		specify as ringsize=tx[,rx] *		allowed values: 4, 8, 16, 32, 64 *		Due to the IrDA 1.x max. allowed window size=7, *		there should be no gain when using rings larger than 8 */static int ringsize[] = {8,8};		/* default is tx=rx=8 */MODULE_PARM(sirpulse, "i");MODULE_PARM_DESC(sirpulse, "SIR pulse width tuning");/*	sirpulse: tuning of the SIR pulse width within IrPHY 1.3 limits *		0: very short, 1.5us (exception: 6us at 2.4 kbaud) *		1: nominal 3/16 bittime width *	note: IrDA compliant peer devices should be happy regardless *		which one is used. Primary goal is to save some power *		on the sender's side - at 9.6kbaud for example the short *		pulse width saves more than 90% of the transmitted IR power. */static int sirpulse = 1;		/* default is 3/16 bittime */MODULE_PARM(qos_mtt_bits, "i");MODULE_PARM_DESC(qos_mtt_bits, "IrLAP bitfield representing min-turn-time");/*	qos_mtt_bits: encoded min-turn-time value we require the peer device *		 to use before transmitting to us. "Type 1" (per-station) *		 bitfield according to IrLAP definition (section 6.6.8) *		 The HP HDLS-1100 requires 1 msec - don't even know *		 if this is the one which is used by my OB800 */static int qos_mtt_bits = 0x04;		/* default is 1 ms *//********************************************************//* some helpers for operations on ring descriptors */static inline int rd_is_active(struct vlsi_ring *r, unsigned i){	return ((r->hw[i].rd_status & RD_STAT_ACTIVE) != 0);}static inline void rd_activate(struct vlsi_ring *r, unsigned i){	r->hw[i].rd_status |= RD_STAT_ACTIVE;}static inline void rd_set_addr_status(struct vlsi_ring *r, unsigned i, dma_addr_t a, u8 s){	struct ring_descr *rd = r->hw +i;	/* ordering is important for two reasons:	 *  - overlayed: writing addr overwrites status	 *  - we want to write status last so we have valid address in	 *    case status has RD_STAT_ACTIVE set	 */	if ((a & ~DMA_MASK_MSTRPAGE) != MSTRPAGE_VALUE)		BUG();	a &= DMA_MASK_MSTRPAGE;  /* clear highbyte to make sure we won't write				  * to status - just in case MSTRPAGE_VALUE!=0				  */	rd->rd_addr = a;	wmb();	rd->rd_status = s;	 /* potentially passes ownership to the hardware */}static inline void rd_set_status(struct vlsi_ring *r, unsigned i, u8 s){	r->hw[i].rd_status = s;}static inline void rd_set_count(struct vlsi_ring *r, unsigned i, u16 c){	r->hw[i].rd_count = c;}static inline u8 rd_get_status(struct vlsi_ring *r, unsigned i){	return r->hw[i].rd_status;}static inline dma_addr_t rd_get_addr(struct vlsi_ring *r, unsigned i){	dma_addr_t	a;	a = (r->hw[i].rd_addr & DMA_MASK_MSTRPAGE) | (MSTRPAGE_VALUE << 24);	return a;}static inline u16 rd_get_count(struct vlsi_ring *r, unsigned i){	return r->hw[i].rd_count;}/* producer advances r->head when descriptor was added for processing by hw */static inline void ring_put(struct vlsi_ring *r){	r->head = (r->head + 1) & r->mask;}/* consumer advances r->tail when descriptor was removed after getting processed by hw */static inline void ring_get(struct vlsi_ring *r){	r->tail = (r->tail + 1) & r->mask;}/********************************************************//* the memory required to hold the 2 descriptor rings */#define RING_AREA_SIZE		(2 * MAX_RING_DESCR * sizeof(struct ring_descr))/* the memory required to hold the rings' buffer entries */#define RING_ENTRY_SIZE		(2 * MAX_RING_DESCR * sizeof(struct ring_entry))/********************************************************//* just dump all registers */static void vlsi_reg_debug(unsigned iobase, const char *s){	int	i;	mb();	printk(KERN_DEBUG "%s: ", s);	for (i = 0; i < 0x20; i++)		printk("%02x", (unsigned)inb((iobase+i)));	printk("\n");}/********************************************************/static int vlsi_set_clock(struct pci_dev *pdev){	u8	clkctl, lock;	int	i, count;	if (clksrc < 2) { /* auto or PLL: try PLL */		clkctl = CLKCTL_NO_PD | CLKCTL_CLKSTP;		pci_write_config_byte(pdev, VLSI_PCI_CLKCTL, clkctl);		/* procedure to detect PLL lock synchronisation:		 * after 0.5 msec initial delay we expect to find 3 PLL lock		 * indications within 10 msec for successful PLL detection.		 */		udelay(500);		count = 0;		for (i = 500; i <= 10000; i += 50) { /* max 10 msec */			pci_read_config_byte(pdev, VLSI_PCI_CLKCTL, &lock);			if (lock&CLKCTL_LOCK) {				if (++count >= 3)					break;			}			udelay(50);		}		if (count < 3) {			if (clksrc == 1) { /* explicitly asked for PLL hence bail out */				printk(KERN_ERR "%s: no PLL or failed to lock!\n",					__FUNCTION__);				clkctl = CLKCTL_CLKSTP;				pci_write_config_byte(pdev, VLSI_PCI_CLKCTL, clkctl);				return -1;			}			else			/* was: clksrc=0(auto) */				clksrc = 3;	/* fallback to 40MHz XCLK (OB800) */			printk(KERN_INFO "%s: PLL not locked, fallback to clksrc=%d\n",				__FUNCTION__, clksrc);		}		else { /* got successful PLL lock */			clksrc = 1;			return 0;		}	}	/* we get here if either no PLL detected in auto-mode or	   the external clock source was explicitly specified */	clkctl = CLKCTL_EXTCLK | CLKCTL_CLKSTP;	if (clksrc == 3)		clkctl |= CLKCTL_XCKSEL;		pci_write_config_byte(pdev, VLSI_PCI_CLKCTL, clkctl);	/* no way to test for working XCLK */	return 0;}static void vlsi_start_clock(struct pci_dev *pdev){	u8	clkctl;	printk(KERN_INFO "%s: start clock using %s as input\n", __FUNCTION__,		(clksrc&2)?((clksrc&1)?"40MHz XCLK":"48MHz XCLK"):"48MHz PLL");	pci_read_config_byte(pdev, VLSI_PCI_CLKCTL, &clkctl);	clkctl &= ~CLKCTL_CLKSTP;	pci_write_config_byte(pdev, VLSI_PCI_CLKCTL, clkctl);}			static void vlsi_stop_clock(struct pci_dev *pdev){	u8	clkctl;	pci_read_config_byte(pdev, VLSI_PCI_CLKCTL, &clkctl);	clkctl |= CLKCTL_CLKSTP;	pci_write_config_byte(pdev, VLSI_PCI_CLKCTL, clkctl);}			static void vlsi_unset_clock(struct pci_dev *pdev){	u8	clkctl;	pci_read_config_byte(pdev, VLSI_PCI_CLKCTL, &clkctl);	if (!(clkctl&CLKCTL_CLKSTP))		/* make sure clock is already stopped */		vlsi_stop_clock(pdev);	clkctl &= ~(CLKCTL_EXTCLK | CLKCTL_NO_PD);	pci_write_config_byte(pdev, VLSI_PCI_CLKCTL, clkctl);}/********************************************************//* ### FIXME: don't use old virt_to_bus() anymore! */static void vlsi_arm_rx(struct vlsi_ring *r){	unsigned	i;	dma_addr_t	ba;	for (i = 0; i < r->size; i++) {		if (r->buf[i].data == NULL)			BUG();		ba = virt_to_bus(r->buf[i].data);		rd_set_addr_status(r, i, ba, RD_STAT_ACTIVE);	}}static int vlsi_alloc_ringbuf(struct vlsi_ring *r){	unsigned	i, j;	r->head = r->tail = 0;	r->mask = r->size - 1;	for (i = 0; i < r->size; i++) {		r->buf[i].skb = NULL;		r->buf[i].data = kmalloc(XFER_BUF_SIZE, GFP_KERNEL|GFP_DMA);		if (r->buf[i].data == NULL) {			for (j = 0; j < i; j++) {				kfree(r->buf[j].data);				r->buf[j].data = NULL;			}			return -ENOMEM;		}	}	return 0;}static void vlsi_free_ringbuf(struct vlsi_ring *r){	unsigned	i;	for (i = 0; i < r->size; i++) {		if (r->buf[i].data == NULL)			continue;		if (r->buf[i].skb) {			dev_kfree_skb(r->buf[i].skb);			r->buf[i].skb = NULL;		}		else			kfree(r->buf[i].data);		r->buf[i].data = NULL;	}}static int vlsi_init_ring(vlsi_irda_dev_t *idev){	char 		 *ringarea;	ringarea = pci_alloc_consistent(idev->pdev, RING_AREA_SIZE, &idev->busaddr);	if (!ringarea) {		printk(KERN_ERR "%s: insufficient memory for descriptor rings\n",			__FUNCTION__);		return -ENOMEM;	}	memset(ringarea, 0, RING_AREA_SIZE);#if 0	printk(KERN_DEBUG "%s: (%d,%d)-ring %p / %p\n", __FUNCTION__,		ringsize[0], ringsize[1], ringarea, 		(void *)(unsigned)idev->busaddr);#endif	idev->rx_ring.size = ringsize[1];	idev->rx_ring.hw = (struct ring_descr *)ringarea;	if (!vlsi_alloc_ringbuf(&idev->rx_ring)) {		idev->tx_ring.size = ringsize[0];		idev->tx_ring.hw = idev->rx_ring.hw + MAX_RING_DESCR;		if (!vlsi_alloc_ringbuf(&idev->tx_ring)) {			idev->virtaddr = ringarea;			return 0;		}		vlsi_free_ringbuf(&idev->rx_ring);	}	pci_free_consistent(idev->pdev, RING_AREA_SIZE,		ringarea, idev->busaddr);	printk(KERN_ERR "%s: insufficient memory for ring buffers\n",		__FUNCTION__);	return -1;}/********************************************************/static int vlsi_set_baud(struct net_device *ndev){	vlsi_irda_dev_t *idev = ndev->priv;	unsigned long flags;	u16 nphyctl;	unsigned iobase; 	u16 config;	unsigned mode;	int	ret;	int	baudrate;	baudrate = idev->new_baud;	iobase = ndev->base_addr;	printk(KERN_DEBUG "%s: %d -> %d\n", __FUNCTION__, idev->baud, idev->new_baud);	spin_lock_irqsave(&idev->lock, flags);	outw(0, iobase+VLSI_PIO_IRENABLE);

⌨️ 快捷键说明

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