📄 omap1610-ir.c
字号:
* We are unable to set the speed if the * device is not running. */ if (si->open) { ret = omap1610_irda_set_speed(dev, rq->ifr_baudrate); } else { printk (KERN_ERR "omap_irda_ioctl: SIOCSBANDWIDTH: !netif_running\n"); 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 = rx_state; break; default: break; } __ECHO_OUT; return ret;}static struct net_device_stats *omap1610_irda_stats(struct net_device *dev){ struct omap1610_irda *si = dev->priv; return &si->stats;}static int omap1610_irda_start(struct net_device *dev){ struct omap1610_irda *si = dev->priv; int err; unsigned long flags = 0;#ifdef CONFIG_MACH_OMAP_H3 u8 ioExpanderVal = 0;#endif __ECHO_IN; si->speed = 9600; err = request_irq(dev->irq, omap1610_irda_irq, 0, dev->name, dev); if (err) goto err_irq; /* * The interrupt must remain disabled for now. */ disable_irq(dev->irq); /* Request DMA channels for IrDA hardware */ if (omap_request_dma(OMAP_DMA_UART3_RX, "IrDA Rx DMA", (void *)omap1610_irda_rx_dma_callback, dev, &(si->rx_dma_channel))) { printk(KERN_ERR "Failed to request IrDA Rx DMA \n"); goto err_irq; } if (omap_request_dma(OMAP_DMA_UART3_TX, "IrDA Tx DMA", (void *)omap1610_irda_tx_dma_callback, dev, &(si->tx_dma_channel))) { printk(KERN_ERR "Failed to request IrDA Tx DMA \n"); goto err_irq; } /* Allocate TX and RX buffers for DMA channels */ si->rx_buf_dma_virt = dma_alloc_coherent(NULL, 4096, &(si->rx_buf_dma_phys), flags); si->tx_buf_dma_virt = dma_alloc_coherent(NULL, 4096, &(si->tx_buf_dma_phys), flags); /* * Setup the serial port for the specified config. */#if CONFIG_MACH_OMAP_H3 if ((err = read_gpio_expa(&ioExpanderVal, 0x26))) { printk(KERN_ERR "Error reading from I/O EXPANDER \n"); return err; } ioExpanderVal |= 0x40; /* 'P6' Enable IRDA_TX and IRDA_RX */ if ((err = write_gpio_expa(ioExpanderVal, 0x26))) { printk(KERN_ERR "Error writing to I/O EXPANDER \n"); return err; }#endif err = omap1610_irda_startup(dev); if (err) goto err_startup; omap1610_irda_set_speed(dev, si->speed = 9600); /* * Open a new IrLAP layer instance. */ si->irlap = irlap_open(dev, &si->qos, "omap_sir"); err = -ENOMEM; if (!si->irlap) goto err_irlap; /* Now enable the interrupt and start the queue */ si->open = 1; /* Start RX DMA */ omap1610_irda_start_rx_dma(si); enable_irq(dev->irq); netif_start_queue(dev); __ECHO_OUT; return 0; err_irlap: si->open = 0; omap1610_irda_shutdown(si); err_startup: err_irq: free_irq(dev->irq, dev); MOD_DEC_USE_COUNT; return err;}static int omap1610_irda_stop(struct net_device *dev){ struct omap1610_irda *si = dev->priv; __ECHO_IN; disable_irq(dev->irq); netif_stop_queue(dev); omap_free_dma(si->rx_dma_channel); omap_free_dma(si->tx_dma_channel); dma_free_coherent(NULL, 4096, si->rx_buf_dma_virt, si->rx_buf_dma_phys); dma_free_coherent(NULL, 4096, si->tx_buf_dma_virt, si->tx_buf_dma_phys); omap1610_irda_shutdown(si); /* Stop IrLAP */ if (si->irlap) { irlap_close(si->irlap); si->irlap = NULL; } si->open = 0; /* * Free resources */ free_irq(dev->irq, dev); __ECHO_OUT; return 0;}#ifdef CONFIG_MACH_OMAP_H3static void set_h3_gpio_expa(u8 FIR_SEL, u8 IrDA_INVSEL){ u8 ioExpanderVal = 0; if (read_gpio_expa(&ioExpanderVal, 0x27) != 0) { printk(KERN_ERR "Error reading from I/O EXPANDER \n"); return; } ioExpanderVal &= ~0x03; ioExpanderVal |= FIR_SEL << 1; ioExpanderVal |= IrDA_INVSEL << 0; if (write_gpio_expa(ioExpanderVal, 0x27) != 0) { printk(KERN_ERR "Error writing to I/O EXPANDER \n"); return; } if (read_gpio_expa(&ioExpanderVal, 0x27) != 0) { printk(KERN_ERR "Error reading from I/O EXPANDER \n"); return; }}int which_speed;static void set_h3_gpio_expa_handler(void *data){ int *mode = data; if (*mode == SIR_MODE) set_h3_gpio_expa(0, 1); else if (*mode == MIR_MODE) set_h3_gpio_expa(1, 1); else if (*mode == FIR_MODE) set_h3_gpio_expa(1, 1);}DECLARE_WORK(set_h3_gpio_expa_work, &set_h3_gpio_expa_handler, &which_speed);static inline void set_h3_irda_mode(int mode){ cancel_delayed_work(&set_h3_gpio_expa_work); which_speed = mode; schedule_work(&set_h3_gpio_expa_work);}#else#define set_h3_irda_mode(x)#endifstatic int omap1610_irda_set_speed(struct net_device *dev, int speed){ struct omap1610_irda *si = dev->priv; int divisor; __ECHO_IN; /* Set IrDA speed */ if (speed <= 115200) { /* SIR mode */ if (machine_is_omap_h2()) { omap_set_gpio_dataout(OMAP1610_H2_FIRSEL_GPIO, 0); } if (machine_is_omap_h3()) set_h3_irda_mode(SIR_MODE); printk("Set SIR Mode! Speed: %d\n", speed); omap_writeb(1, UART3_MDR1); /* Set SIR mode */ omap_writeb(1, UART3_EBLR); divisor = 48000000 / (16 * speed); /* Base clock 48 MHz */ HDBG2(1); omap_writeb(1 << 7, UART3_LCR); omap_writeb((divisor & 0xFF), UART3_DLL); omap_writeb((divisor >> 8), UART3_DLH); omap_writeb(0x03, UART3_LCR); omap_writeb(0, UART3_MCR); HDBG2(1); } else if (speed <= 1152000) { /* MIR mode */ printk("Set MIR Mode! Speed: %d\n", speed); omap_writeb((1 << 2) | (1 << 6), UART3_MDR1); /* Set MIR mode with SIP after each frame */ omap_writeb(2, UART3_EBLR); divisor = 48000000 / (41 * speed); /* Base clock 48 MHz */ omap_writeb(1 << 7, UART3_LCR); omap_writeb((divisor & 0xFF), UART3_DLL); omap_writeb((divisor >> 8), UART3_DLH); omap_writeb(0x03, UART3_LCR); if (machine_is_omap_h2()) omap_set_gpio_dataout(OMAP1610_H2_FIRSEL_GPIO, 1); if (machine_is_omap_h3()) set_h3_irda_mode(MIR_MODE); } else { /* FIR mode */ printk("Set FIR Mode! Speed: %d\n", speed); omap_writeb((1 << 2) | (1 << 6) | 1, UART3_MDR1); /* Set FIR mode with SIP after each frame */ if (machine_is_omap_h2()) omap_set_gpio_dataout(OMAP1610_H2_FIRSEL_GPIO, 1); if (machine_is_omap_h3()) set_h3_irda_mode(FIR_MODE); } si->speed = speed; __ECHO_OUT; return 0;}#ifdef CONFIG_PM/* * Suspend the IrDA interface. */static int omap1610_irda_suspend(struct device *_dev, u32 state, u32 level){ struct net_device *dev = dev_get_drvdata(_dev); struct omap1610_irda *si; if (!dev || level != SUSPEND_DISABLE) return 0; si = (struct omap1610_irda *)&dev->priv; if (si->open) { /* * Stop the transmit queue */ netif_device_detach(dev); disable_irq(dev->irq); omap1610_irda_shutdown(si); } return 0;}/* * Resume the IrDA interface. */static int omap1610_irda_resume(struct device *_dev, u32 level){ struct net_device *dev = dev_get_drvdata(_dev); struct omap1610_irda *si; if (!dev || level != RESUME_ENABLE) return 0; si = (struct omap1610_irda *)&dev->priv; if (si->open) { /* * If we missed a speed change, initialise at the new speed * directly. It is debatable whether this is actually * required, but in the interests of continuing from where * we left off it is desireable. The converse argument is * that we should re-negotiate at 9600 baud again. */ if (si->newspeed) { si->speed = si->newspeed; si->newspeed = 0; } omap1610_irda_startup(dev); enable_irq(dev->irq); /* * This automatically wakes up the queue */ netif_device_attach(dev); } return 0;}#else#define omap1610_irda_suspend NULL#define omap1610_irda_resume NULL#endifstatic int omap1610_irda_probe(struct device *_dev){ struct platform_device *pdev = to_platform_device(_dev); struct net_device *dev; struct omap1610_irda *si; unsigned int baudrate_mask; int err = 0; dev = alloc_irdadev(sizeof(struct omap1610_irda)); if (!dev) goto err_mem_1; si = dev->priv; si->dev = &pdev->dev; dev->hard_start_xmit = omap1610_irda_hard_xmit; dev->open = omap1610_irda_start; dev->stop = omap1610_irda_stop; dev->do_ioctl = omap1610_irda_ioctl; dev->get_stats = omap1610_irda_stats; dev->irq = INT_UART3; irda_init_max_qos_capabilies(&si->qos); /* * OMAP1610 supports SIR, MIR, FIR modes, * but actualy supported modes depend on hardware implementation. * OMAP1610 Innovator supports only SIR and * OMAP1610 H2 supports both SIR and FIR */ baudrate_mask = IR_9600 | IR_19200 | IR_38400 | IR_57600 | IR_115200 | IR_576000 | IR_1152000; if (machine_is_omap_h2() || machine_is_omap_h3()) { 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); err = register_netdev(dev); if (!err) dev_set_drvdata(&pdev->dev, dev); else free_netdev(dev); err_mem_1: return err;}static int omap1610_irda_remove(struct device *_dev){ struct net_device *dev = dev_get_drvdata(_dev); #ifdef CONFIG_MACH_OMAP_H3 if (machine_is_omap_h3()) cancel_delayed_work(&set_h3_gpio_expa_work);#endif if (dev) { unregister_netdev(dev); free_netdev(dev); } return 0;}static void irda_dummy_release(struct device *dev){ /* Dummy function to keep the platform driver happy */}static struct device_driver omap1610ir_driver = { .name = "omap1610-ir", .bus = &platform_bus_type, .probe = omap1610_irda_probe, .remove = omap1610_irda_remove, .suspend = omap1610_irda_suspend, .resume = omap1610_irda_resume,};static struct platform_device omap1610ir_device = { .name = "omap1610-ir", .dev.release = irda_dummy_release, .id = 0,};#ifdef MODULEstatic#endifint __init omap1610_irda_init(void){ int ret; ret = driver_register(&omap1610ir_driver); if (ret == 0) { ret = platform_device_register(&omap1610ir_device); if (ret) driver_unregister(&omap1610ir_driver); } return ret;}#ifdef MODULEstatic#endifvoid __exit omap1610_irda_exit(void){ driver_unregister(&omap1610ir_driver); platform_device_unregister(&omap1610ir_device);}module_init(omap1610_irda_init);module_exit(omap1610_irda_exit);MODULE_AUTHOR("MontaVista");MODULE_DESCRIPTION("OMAP IrDA Driver");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -