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

📄 au1k_ir.c

📁 《linux驱动程序设计从入门到精通》一书中所有的程序代码含驱动和相应的应用程序
💻 C
📖 第 1 页 / 共 2 页
字号:
	ps->tx_bytes += pkt_len;	if (status & IR_TX_ERROR) {		ps->tx_errors++;		ps->tx_aborted_errors++;	}}static void au1k_tx_ack(struct net_device *dev){	struct au1k_private *aup = netdev_priv(dev);	volatile ring_dest_t *ptxd;	ptxd = aup->tx_ring[aup->tx_tail];	while (!(ptxd->flags & AU_OWN) && (aup->tx_tail != aup->tx_head)) {		update_tx_stats(dev, ptxd->flags, 				ptxd->count_1<<8 | ptxd->count_0);		ptxd->count_0 = 0;		ptxd->count_1 = 0;		au_sync();		aup->tx_tail = (aup->tx_tail + 1) & (NUM_IR_DESC - 1);		ptxd = aup->tx_ring[aup->tx_tail];		if (aup->tx_full) {			aup->tx_full = 0;			netif_wake_queue(dev);		}	}	if (aup->tx_tail == aup->tx_head) {		if (aup->newspeed) {			au1k_irda_set_speed(dev, aup->newspeed);			aup->newspeed = 0;		}		else {			writel(read_ir_reg(IR_CONFIG_1) & ~IR_TX_ENABLE, 					IR_CONFIG_1); 			au_sync();			writel(read_ir_reg(IR_CONFIG_1) | IR_RX_ENABLE, 					IR_CONFIG_1); 			writel(0, IR_RING_PROMPT);			au_sync();		}	}}/* * Au1000 transmit routine. */static int au1k_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev){	struct au1k_private *aup = netdev_priv(dev);	int speed = irda_get_next_speed(skb);	volatile ring_dest_t *ptxd;	u32 len;	u32 flags;	db_dest_t *pDB;	if (speed != aup->speed && speed != -1) {		aup->newspeed = speed;	}	if ((skb->len == 0) && (aup->newspeed)) {		if (aup->tx_tail == aup->tx_head) {			au1k_irda_set_speed(dev, speed);			aup->newspeed = 0;		}		dev_kfree_skb(skb);		return 0;	}	ptxd = aup->tx_ring[aup->tx_head];	flags = ptxd->flags;	if (flags & AU_OWN) {		printk(KERN_DEBUG "%s: tx_full\n", dev->name);		netif_stop_queue(dev);		aup->tx_full = 1;		return 1;	}	else if (((aup->tx_head + 1) & (NUM_IR_DESC - 1)) == aup->tx_tail) {		printk(KERN_DEBUG "%s: tx_full\n", dev->name);		netif_stop_queue(dev);		aup->tx_full = 1;		return 1;	}	pDB = aup->tx_db_inuse[aup->tx_head];#if 0	if (read_ir_reg(IR_RX_BYTE_CNT) != 0) {		printk("tx warning: rx byte cnt %x\n", 				read_ir_reg(IR_RX_BYTE_CNT));	}#endif		if (aup->speed == 4000000) {		/* FIR */		memcpy((void *)pDB->vaddr, skb->data, skb->len);		ptxd->count_0 = skb->len & 0xff;		ptxd->count_1 = (skb->len >> 8) & 0xff;	}	else {		/* SIR */		len = async_wrap_skb(skb, (u8 *)pDB->vaddr, MAX_BUF_SIZE);		ptxd->count_0 = len & 0xff;		ptxd->count_1 = (len >> 8) & 0xff;		ptxd->flags |= IR_DIS_CRC;		au_writel(au_readl(0xae00000c) & ~(1<<13), 0xae00000c);	}	ptxd->flags |= AU_OWN;	au_sync();	writel(read_ir_reg(IR_CONFIG_1) | IR_TX_ENABLE, IR_CONFIG_1); 	writel(0, IR_RING_PROMPT);	au_sync();	dev_kfree_skb(skb);	aup->tx_head = (aup->tx_head + 1) & (NUM_IR_DESC - 1);	dev->trans_start = jiffies;	return 0;}static inline void update_rx_stats(struct net_device *dev, u32 status, u32 count){	struct au1k_private *aup = netdev_priv(dev);	struct net_device_stats *ps = &aup->stats;	ps->rx_packets++;	if (status & IR_RX_ERROR) {		ps->rx_errors++;		if (status & (IR_PHY_ERROR|IR_FIFO_OVER))			ps->rx_missed_errors++;		if (status & IR_MAX_LEN)			ps->rx_length_errors++;		if (status & IR_CRC_ERROR)			ps->rx_crc_errors++;	}	else 		ps->rx_bytes += count;}/* * Au1000 receive routine. */static int au1k_irda_rx(struct net_device *dev){	struct au1k_private *aup = netdev_priv(dev);	struct sk_buff *skb;	volatile ring_dest_t *prxd;	u32 flags, count;	db_dest_t *pDB;	prxd = aup->rx_ring[aup->rx_head];	flags = prxd->flags;	while (!(flags & AU_OWN))  {		pDB = aup->rx_db_inuse[aup->rx_head];		count = prxd->count_1<<8 | prxd->count_0;		if (!(flags & IR_RX_ERROR))  {			/* good frame */			update_rx_stats(dev, flags, count);			skb=alloc_skb(count+1,GFP_ATOMIC);			if (skb == NULL) {				aup->stats.rx_dropped++;				continue;			}			skb_reserve(skb, 1);			if (aup->speed == 4000000)				skb_put(skb, count);			else				skb_put(skb, count-2);			memcpy(skb->data, (void *)pDB->vaddr, count-2);			skb->dev = dev;			skb->mac.raw = skb->data;			skb->protocol = htons(ETH_P_IRDA);			netif_rx(skb);			prxd->count_0 = 0;			prxd->count_1 = 0;		}		prxd->flags |= AU_OWN;		aup->rx_head = (aup->rx_head + 1) & (NUM_IR_DESC - 1);		writel(0, IR_RING_PROMPT);		au_sync();		/* next descriptor */		prxd = aup->rx_ring[aup->rx_head];		flags = prxd->flags;		dev->last_rx = jiffies;	}	return 0;}void au1k_irda_interrupt(int irq, void *dev_id){	struct net_device *dev = (struct net_device *) dev_id;	if (dev == NULL) {		printk(KERN_ERR "%s: isr: null dev ptr\n", dev->name);		return;	}	writel(0, IR_INT_CLEAR); /* ack irda interrupts */	au1k_irda_rx(dev);	au1k_tx_ack(dev);}/* * The Tx ring has been full longer than the watchdog timeout * value. The transmitter must be hung? */static void au1k_tx_timeout(struct net_device *dev){	u32 speed;	struct au1k_private *aup = netdev_priv(dev);	printk(KERN_ERR "%s: tx timeout\n", dev->name);	speed = aup->speed;	aup->speed = 0;	au1k_irda_set_speed(dev, speed);	aup->tx_full = 0;	netif_wake_queue(dev);}/* * Set the IrDA communications speed. */static int au1k_irda_set_speed(struct net_device *dev, int speed){	unsigned long flags;	struct au1k_private *aup = netdev_priv(dev);	u32 control;	int ret = 0, timeout = 10, i;	volatile ring_dest_t *ptxd;#if defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100)	unsigned long irda_resets;#endif	if (speed == aup->speed)		return ret;	spin_lock_irqsave(&ir_lock, flags);	/* disable PHY first */	writel(read_ir_reg(IR_ENABLE) & ~0x8000, IR_ENABLE);	/* disable RX/TX */	writel(read_ir_reg(IR_CONFIG_1) & ~(IR_RX_ENABLE|IR_TX_ENABLE), 			IR_CONFIG_1);	au_sync_delay(1);	while (read_ir_reg(IR_ENABLE) & (IR_RX_STATUS | IR_TX_STATUS)) {		mdelay(1);		if (!timeout--) {			printk(KERN_ERR "%s: rx/tx disable timeout\n",					dev->name);			break;		}	}	/* disable DMA */	writel(read_ir_reg(IR_CONFIG_1) & ~IR_DMA_ENABLE, IR_CONFIG_1);	au_sync_delay(1);	/* 	 *  After we disable tx/rx. the index pointers 	 * go back to zero.	 */	aup->tx_head = aup->tx_tail = aup->rx_head = 0;	for (i=0; i<NUM_IR_DESC; i++) {		ptxd = aup->tx_ring[i];		ptxd->flags = 0;		ptxd->count_0 = 0;		ptxd->count_1 = 0;	}	for (i=0; i<NUM_IR_DESC; i++) {		ptxd = aup->rx_ring[i];		ptxd->count_0 = 0;		ptxd->count_1 = 0;		ptxd->flags = AU_OWN;	}	if (speed == 4000000) {#if defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100)		bcsr->resets |= BCSR_RESETS_FIR_SEL;#else /* Pb1000 and Pb1100 */		writel(1<<13, CPLD_AUX1);#endif	}	else {#if defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100)		bcsr->resets &= ~BCSR_RESETS_FIR_SEL;#else /* Pb1000 and Pb1100 */		writel(readl(CPLD_AUX1) & ~(1<<13), CPLD_AUX1);#endif	}	switch (speed) {	case 9600:			writel(11<<10 | 12<<5, IR_WRITE_PHY_CONFIG); 		writel(IR_SIR_MODE, IR_CONFIG_1); 		break;	case 19200:			writel(5<<10 | 12<<5, IR_WRITE_PHY_CONFIG); 		writel(IR_SIR_MODE, IR_CONFIG_1); 		break;	case 38400:		writel(2<<10 | 12<<5, IR_WRITE_PHY_CONFIG); 		writel(IR_SIR_MODE, IR_CONFIG_1); 		break;	case 57600:			writel(1<<10 | 12<<5, IR_WRITE_PHY_CONFIG); 		writel(IR_SIR_MODE, IR_CONFIG_1); 		break;	case 115200: 		writel(12<<5, IR_WRITE_PHY_CONFIG); 		writel(IR_SIR_MODE, IR_CONFIG_1); 		break;	case 4000000:		writel(0xF, IR_WRITE_PHY_CONFIG);		writel(IR_FIR|IR_DMA_ENABLE|IR_RX_ENABLE, IR_CONFIG_1); 		break;	default:		printk(KERN_ERR "%s unsupported speed %x\n", dev->name, speed);		ret = -EINVAL;		break;	}	aup->speed = speed;	writel(read_ir_reg(IR_ENABLE) | 0x8000, IR_ENABLE);	au_sync();	control = read_ir_reg(IR_ENABLE);	writel(0, IR_RING_PROMPT);	au_sync();	if (control & (1<<14)) {		printk(KERN_ERR "%s: configuration error\n", dev->name);	}	else {		if (control & (1<<11))			printk(KERN_DEBUG "%s Valid SIR config\n", dev->name);		if (control & (1<<12))			printk(KERN_DEBUG "%s Valid MIR config\n", dev->name);		if (control & (1<<13))			printk(KERN_DEBUG "%s Valid FIR config\n", dev->name);		if (control & (1<<10))			printk(KERN_DEBUG "%s TX enabled\n", dev->name);		if (control & (1<<9))			printk(KERN_DEBUG "%s RX enabled\n", dev->name);	}	spin_unlock_irqrestore(&ir_lock, flags);	return ret;}static int au1k_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd){	struct if_irda_req *rq = (struct if_irda_req *)ifreq;	struct au1k_private *aup = netdev_priv(dev);	int ret = -EOPNOTSUPP;	switch (cmd) {	case SIOCSBANDWIDTH:		if (capable(CAP_NET_ADMIN)) {			/*			 * We are unable to set the speed if the			 * device is not running.			 */			if (aup->open)				ret = au1k_irda_set_speed(dev,						rq->ifr_baudrate);			else {				printk(KERN_ERR "%s ioctl: !netif_running\n",						dev->name);				ret = 0;			}		}		break;	case SIOCSMEDIABUSY:		ret = -EPERM;		if (capable(CAP_NET_ADMIN)) {			irda_device_set_media_busy(dev, TRUE);			ret = 0;		}		break;	case SIOCGRECEIVING:		rq->ifr_receiving = 0;		break;	default:		break;	}	return ret;}static struct net_device_stats *au1k_irda_stats(struct net_device *dev){	struct au1k_private *aup = netdev_priv(dev);	return &aup->stats;}MODULE_AUTHOR("Pete Popov <ppopov@mvista.com>");MODULE_DESCRIPTION("Au1000 IrDA Device Driver");module_init(au1k_irda_init);module_exit(au1k_irda_exit);

⌨️ 快捷键说明

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