📄 au1k_ir.c
字号:
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 + -