📄 pxa_ir.c
字号:
break; } __ECHO_OUT; return ret;}static struct net_device_stats *pxa250_irda_stats(struct net_device *dev){ struct pxa250_irda *si = dev->priv; return &si->stats;}#ifdef CONFIG_ARCH_FS_PXA255 #ifdef CONFIG_LEDS #include <asm/leds.h> #define irda_led_start() leds_event(led_amber_on) #define irda_led_stop() leds_event(led_amber_off) #else #define irda_led_start() //use gpio operations(GPIO12) #define irda_led_stop() //use gpio operations(GPIO12) #endif#endifstatic int pxa250_irda_start(struct net_device *dev){ struct pxa250_irda *si = dev->priv; int err; unsigned long flags; #ifdef CONFIG_ARCH_FS_PXA255 irda_led_start();#endif __ECHO_IN; si->speed = 9600; //modified by hzh, 9600->115200 local_irq_save(flags); err = request_irq(si->fir_irq, pxa250_irda_fir_irq, 0, dev->name, dev); if (err) goto err_fir_irq; err = request_irq(dev->irq, pxa250_irda_irq, 0, dev->name, dev); if (err) goto err_irq; /* * The interrupt must remain disabled for now. */ disable_irq(dev->irq); disable_irq(si->fir_irq); local_irq_restore(flags); /* Allocate DMA channel for receiver (not used) */ err = pxa_request_dma("IrDA receive", DMA_PRIO_LOW, pxa250_irda_rxdma_irq, dev); if (err < 0 ) goto err_rx_dma; si->rxdma_ch=err; DRCMRRXICDR = DRCMR_MAPVLD | si->rxdma_ch; /* Allocate DMA channel for transmit */ err = pxa_request_dma("IrDA transmit", DMA_PRIO_LOW, pxa250_irda_txdma_irq , dev); if (err < 0 ) goto err_tx_dma; si->txdma_ch=err; /* * Make sure that ICP will be able * to assert the transmit dma request bit * through the peripherals request bus (PREQ) */ DRCMRTXICDR = DRCMR_MAPVLD | si->txdma_ch; DBG("rx(not used) channel=%d tx channel=%d\n",si->rxdma_ch,si->txdma_ch); /* allocate consistent buffers for dma access * buffers have to be aligned and situated in dma capable memory region; */ si->rxbuf_dma_virt = dma_alloc_writecombine(si->dev, HPSIR_MAX_RXLEN, &si->rxbuf_dma, GFP_KERNEL); if (! si->rxbuf_dma_virt ) goto err_rxbuf_dma; si->txbuf_dma_virt = dma_alloc_writecombine(si->dev, HPSIR_MAX_TXLEN, &si->txbuf_dma, GFP_KERNEL); if (! si->txbuf_dma_virt ) goto err_txbuf_dma; /* Alocate skb for receiver */ err=pxa250_irda_rx_alloc(si); if (err) goto err_rx_alloc; /* * Setup the serial port for the specified config. */ err = pxa250_irda_startup(dev); if (err) goto err_startup; pxa250_irda_set_speed(dev,si->speed = 9600); //modified by hzh, 9600->115200 /* * Open a new IrLAP layer instance. */ si->irlap = irlap_open(dev, &si->qos, "pxa250"); err = -ENOMEM; if (!si->irlap) goto err_irlap; /* * Now enable the interrupt and start the queue */ si->open = 1; enable_irq(dev->irq); netif_start_queue(dev); return 0;err_irlap: si->open = 0; pxa250_sir_irda_shutdown(si);err_startup: dev_kfree_skb(si->rxskb);err_rx_alloc: dma_free_writecombine(si->dev, HPSIR_MAX_TXLEN, si->txbuf_dma_virt, si->txbuf_dma);err_txbuf_dma: dma_free_writecombine(si->dev, HPSIR_MAX_RXLEN, si->rxbuf_dma_virt, si->rxbuf_dma);err_rxbuf_dma: pxa_free_dma(si->txdma_ch);err_tx_dma: pxa_free_dma(si->rxdma_ch);err_rx_dma: free_irq(dev->irq, dev);err_irq: free_irq(si->fir_irq, dev);err_fir_irq: // MOD_DEC_USE_COUNT; return err;}static int pxa250_irda_stop(struct net_device *dev){ struct pxa250_irda *si = dev->priv; printk(KERN_ERR "Irda stop... RX = %d TX = %d\n",rx_count,tx_count); disable_irq(dev->irq); disable_irq(si->fir_irq); /* pxa250_irda_shutdown(si); */ /* * If we have been doing DMA receive, make sure we * tidy that up cleanly. */ if (si->rxskb) { dev_kfree_skb(si->rxskb); si->rxskb = NULL; } /* Stop IrLAP */ if (si->irlap) { irlap_close(si->irlap); si->irlap = NULL; } dma_free_writecombine(si->dev, HPSIR_MAX_TXLEN, si->txbuf_dma_virt, si->txbuf_dma); dma_free_writecombine(si->dev, HPSIR_MAX_RXLEN, si->rxbuf_dma_virt, si->rxbuf_dma); pxa_free_dma(si->txdma_ch); pxa_free_dma(si->rxdma_ch); netif_stop_queue(dev); si->open = 0; /* * Free resources */ free_irq(dev->irq, dev); free_irq(si->fir_irq, dev);#ifdef CONFIG_ARCH_FS_PXA255 irda_led_stop();#endif return 0;}static int pxa250_irda_init_iobuf(iobuff_t *io, int size){ io->head = kmalloc(size, GFP_KERNEL | GFP_DMA); if (io->head != NULL) { io->truesize = size; io->in_frame = FALSE; io->state = OUTSIDE_FRAME; io->data = io->head; } return io->head ? 0 : -ENOMEM;}static int pxa250_stop_fir(struct net_device *dev){ struct pxa250_irda *si = dev->priv; unsigned int flag; save_flags(flag); cli(); pxa250_dma_stop(si->txdma_ch); pxa250_dma_stop(si->rxdma_ch); if (si->txskb) dev_kfree_skb_irq(si->txskb); ICCR0 &= ~(ICCR0_RXE | ICCR0_TXE ); disable_irq(si->fir_irq); CKEN &= ~CKEN13_FICP; restore_flags(flag); return 0;}static int pxa250_irda_set_speed(struct net_device *dev, int speed){ struct pxa250_irda *si = dev->priv; int brd, ret = -EINVAL; static int last_fir_speed=0; __ECHO_IN; switch (speed) { case 9600: case 19200: case 38400: case 57600: case 115200: /* Baud rate fixed - Clo */ /* * FIXME */ if (last_fir_speed) { pxa250_stop_fir(dev); pxa_gpio_mode (GPIO46_STRXD_MD); pxa_gpio_mode (GPIO47_STTXD_MD); enable_irq(dev->irq); netif_wake_queue(dev); last_fir_speed=0; } #ifndef CONFIG_ARCH_FS_PXA255 //we don't remap FPGA, so can't do this,hzh LUB_MISC_WR &= ~(1 << 4);#endif brd = 14745600 / (16 * speed); STLCR |= LCR_DLAB; STDLH = brd >> 8; /* Clo: set Divisor Latch High */ STDLL = brd & 0xFF; /* Clo: set Devisor Latch Low */ STLCR &= ~LCR_DLAB; /* Clo: clear DLAB bit */ STMCR = MCR_OUT2; CKEN |= CKEN5_STUART; ICMR |= ( 1 << 20 ); STLCR = LCR_WLS1 | LCR_WLS0; SET_SIR_MODE; STFCR = FCR_TRFIFOE | FCR_RESETTF | FCR_RESETRF | FCR_ITL_1 ;// | FCR_ITL_16; STIER = IER_UUE | IER_RAVIE | IER_RTIOE; si->speed = speed; ret = 0; break; case 4000000: if (last_fir_speed) goto speed_out; disable_irq(dev->irq); pxa250_sir_irda_shutdown(si); pxa250_fir_irda_startup(si); pxa250_irda_rx_alloc(si); ICCR0=0; pxa250_start_rx_dma(dev); pxa250_ficp_rx_start(); enable_irq(si->fir_irq); DBG("enable FIR \n"); si->speed = speed; netif_wake_queue(dev); last_fir_speed=1;speed_out: ret=0; break; default: break; } __ECHO_OUT; return ret;}static int pxa250_irda_net_init(struct net_device *dev, struct platform_device *pdev){ struct pxa250_irda *si = dev->priv; unsigned int baudrate_mask; int err = -ENOMEM; si->dev = &pdev->dev; /* * Initialise the HP-SIR buffers */ err = pxa250_irda_init_iobuf(&si->rx_buff, 14384); if (err) goto out; err = pxa250_irda_init_iobuf(&si->tx_buff, 4000); if (err) goto out_free_rx; si->fir_irq = IRQ_ICP; dev->priv = si; dev->hard_start_xmit = pxa250_irda_hard_xmit; dev->open = pxa250_irda_start; dev->stop = pxa250_irda_stop; dev->do_ioctl = pxa250_irda_ioctl; dev->get_stats = pxa250_irda_stats; dev->irq = IRQ_STUART; irda_init_max_qos_capabilies(&si->qos); /* * We support original IRDA up to 115k2. (we don't currently * support 4Mbps). Min Turn Time set to 1ms or greater. */ baudrate_mask = IR_9600|IR_19200|IR_38400|IR_57600|IR_115200; baudrate_mask |= IR_4000000 << 8; si->qos.baud_rate.bits &= baudrate_mask; si->qos.min_turn_time.bits = 7; irda_qos_bits_to_value(&si->qos); //register_netdev in drivers/net/net_init.c, register_netdevice in net/core/... err = register_netdev(dev); //err = register_netdevice(dev); if(err == 0) { dev_set_drvdata(&pdev->dev, dev); //use dev not si, error in sa1100_ir.c#ifdef CONFIG_PM /* * Power-Management is optional. */ si->pmdev = pm_register(PM_SYS_DEV, PM_SYS_IRDA, pxa250_irda_pmproc); if (si->pmdev) si->pmdev->data = dev;#endif } else { kfree(si->tx_buff.head);out_free_rx: kfree(si->rx_buff.head); }out: return err;}/* * Remove all traces of this driver module from the kernel, so we can't be * called. Note that the device has already been stopped, so we don't have * to worry about interrupts or dma. */static void pxa250_irda_net_uninit(struct net_device *dev){ struct pxa250_irda *si = dev->priv;// dev->hard_start_xmit = NULL;// dev->open = NULL;// dev->stop = NULL;// dev->do_ioctl = NULL;// dev->get_stats = NULL;// dev->priv = NULL;// dev->irq = 0;#ifdef CONFIG_PM pm_unregister(si->pmdev);#endif dev_set_drvdata(si->dev, NULL); kfree(si->tx_buff.head); kfree(si->rx_buff.head);}static void __exit pxa25x_irda_release(struct device *dev){}static int __init pxa25x_irda_probe(struct device *_dev){ struct platform_device *pdev = to_platform_device(_dev); struct net_device *dev; int err; /* STUART */ err = request_mem_region(__PREG(STRBR), 0x24, "IrDA") ? 0 : -EBUSY; if (err) goto err_mem_1; /* FIR */ err = request_mem_region(__PREG(ICCR0), 0x1c, "IrDA") ? 0 : -EBUSY; if (err) goto err_mem_2; //rtnl_lock(); //can't register_netdev if rtnl_lock!!! dev = alloc_irdadev(sizeof(struct pxa250_irda)); if (dev) { err = pxa250_irda_net_init(dev, pdev); if (err) free_netdev(dev); else { netdev = dev; _dev->release = pxa25x_irda_release; } } //rtnl_unlock(); if (err) { release_mem_region(__PREG(ICCR0), 0x1c);err_mem_2: release_mem_region(__PREG(STRBR), 0x24); }err_mem_1: return err;}static int __exit pxa25x_irda_remove(struct device *_dev){ struct net_device *dev = dev_get_drvdata(_dev); netdev = NULL; if (dev) { // rtnl_lock(); unregister_netdev(dev); //unregister_netdevice(dev); pxa250_irda_net_uninit(dev); free_netdev(dev); // rtnl_unlock(); } release_mem_region(__PREG(ICCR0), 0x1c); release_mem_region(__PREG(STRBR), 0x24); /* * We now know that the netdevice is no longer in use, and all * references to our driver have been removed. The only structure * which may still be present is the netdevice, which will get * cleaned up by net/core/dev.c */ return 0;}static struct device_driver pxa25x_ir_driver = { .name = "pxa25x-ir", .bus = &platform_bus_type, .probe = pxa25x_irda_probe, .remove = pxa25x_irda_remove,#ifdef CONFIG_PM .suspend = pxa250_irda_suspend, .resume = pxa250_irda_resume,#endif};static u64 pxa25x_irda_dma_mask = 0xffffffffUL;static struct platform_device pxa25x_ir_device = { .name = "pxa25x-ir", .id = 0, .dev = { .dma_mask = &pxa25x_irda_dma_mask, .coherent_dma_mask = 0xffffffff, },};static int __init pxa25x_irda_init(void){ int ret; ret = driver_register(&pxa25x_ir_driver); if (ret == 0) { ret = platform_device_register(&pxa25x_ir_device); if (ret) driver_unregister(&pxa25x_ir_driver); } return ret;}static void __exit pxa25x_irda_exit(void){ driver_unregister(&pxa25x_ir_driver); platform_device_unregister(&pxa25x_ir_device);}module_init(pxa25x_irda_init);module_exit(pxa25x_irda_exit);MODULE_AUTHOR("Alexey Lugovskoy Frasenyak Dmitrij");MODULE_DESCRIPTION("PXA250 SIR/FIR");MODULE_LICENSE("GPL");//EXPORT_NO_SYMBOLS;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -