📄 bfin_ppifcd.c
字号:
* INPUTS/OUTPUTS: * in_fd - File descriptor of openned file. * in_filp - Description of openned file. * * RETURN: * * FUNCTION(S) CALLED: * * GLOBAL VARIABLES REFERENCED: ppiinfo * * GLOBAL VARIABLES MODIFIED: NIL * * DESCRIPTION: It is invoked when user changes status of sync * it resister a hook in system. When there is * data coming, user program would get a signal. * * CAUTION: */static int ppi_fasync(int fd, struct file *filp, int on){ ppi_device_t *pdev = filp->private_data; return fasync_helper(fd, filp, on, &(pdev->fasyc));}/* * FUNCTION NAME: ppi_read * * INPUTS/OUTPUTS: * in_filp - Description of openned file. * in_count - how many bytes user wants to get. * out_buf - data would be write to this address. * * RETURN * positive number: bytes read back * -EINVIL When word size is set to 16, reading odd bytes. * -EAGAIN When reading mode is set to non block and there is no rx data. * * FUNCTION(S) CALLED: * * GLOBAL VARIABLES REFERENCED: ppiinfo * * GLOBAL VARIABLES MODIFIED: NIL * * DESCRIPTION: It is invoked when user call 'read' system call * to read from system. * * CAUTION: */static ssize_t ppi_read(struct file *filp, char *buf, size_t count, loff_t * pos){ int ierr; ppi_device_t *pdev = filp->private_data;//printk(KERN_INFO "PPI_read: Start\n"); pr_debug("ppi_read:\n"); if (count <= 0) return 0; pdev->done = 0; /* Invalidate allocated memory in Data Cache */ blackfin_dcache_invalidate_range((u_long) buf, (u_long) (buf + count));//printk(KERN_INFO "PPI_read: blackfin_dcache_invalidate_range: DONE\n"); pr_debug("ppi_read: blackfin_dcache_invalidate_range : DONE\n"); /* configure ppi port for DMA RX */ set_dma_config(CH_PPI, pdev->dma_config); set_dma_start_addr(CH_PPI, (u_long) buf); if (pdev->bpp == 8 && pdev->ppi_control & PACK_EN) {//printk(KERN_INFO "PPI_read: Set DMA X count = %d\n", pdev->pixel_per_line/2); set_dma_x_count(CH_PPI, pdev->pixel_per_line / 2); // Div 2 because of 16-bit packing } else {//printk(KERN_INFO "PPI_read: Set DMA X count = %d\n", pdev->pixel_per_line); set_dma_x_count(CH_PPI, pdev->pixel_per_line); }//printk(KERN_INFO "PPI_read: Set DMA Y count = %d\n", pdev->lines_per_frame); set_dma_y_count(CH_PPI, pdev->lines_per_frame); if (pdev->bpp > 8 || pdev->dma_config & WDSIZE_16){//printk(KERN_INFO "PPI_read: Set DMA modify = 2\n"); set_dma_x_modify(CH_PPI, 2); set_dma_y_modify(CH_PPI, 2); } else {//printk(KERN_INFO "PPI_read: Set DMA modify = 1\n"); set_dma_x_modify(CH_PPI, 1); set_dma_y_modify(CH_PPI, 1); }//printk(KERN_INFO "PPI_read: Setup DMA: DONE\n"); pr_debug("ppi_read: SETUP DMA : DONE\n");//printk(KERN_INFO "PPI_read: Enable DMA for PPI channel\n"); enable_dma(CH_PPI); //SSYNC(); /* Enable PPI *///printk(KERN_INFO "PPI_read: Enable PPI with data length mask: 0x%x\n", pdev->ppi_control & DLENGTH); bfin_write_PPI_CONTROL(bfin_read_PPI_CONTROL() | PORT_EN); SSYNC(); if (pdev->ppi_trigger_gpio > NO_TRIGGER) { gpio_set_value(pdev->ppi_trigger_gpio, 1); udelay(1); gpio_set_value(pdev->ppi_trigger_gpio, 0); }//printk(KERN_INFO "PPI_read: PPI0 enabled: DONE\n"); pr_debug("ppi_read: PPI ENABLED : DONE\n"); /* Wait for data available *///printk(KERN_INFO "PPI_read: Wait for data available\n"); if (1) { if (pdev->nonblock) {//printk(KERN_INFO "PPI_read: Use nonblocking mode, return Try Again (Fix me)\n"); return -EAGAIN; } else {//printk(KERN_INFO "PPI_read: PPI wait_event_interruptible\n"); pr_debug("PPI wait_event_interruptible\n"); ierr = wait_event_interruptible(*(pdev->rx_avail), pdev->done); if (ierr) { /* waiting is broken by a signal *///printk(KERN_INFO "PPI_read: waiting is broken by a signal (Fix me); PPI wait_event_interruptible ierr; Return\n"); pr_debug("PPI wait_event_interruptible ierr\n"); return ierr; } } }//printk(KERN_INFO "PPI_read: PPI wait_event_interruptible done\n"); pr_debug("PPI wait_event_interruptible done\n");//printk(KERN_INFO "PPI_read: Disable DMA for PPI0 channel\n"); disable_dma(CH_PPI);//printk(KERN_INFO "PPI_read: Return %d bytes\n", count); pr_debug("ppi_read: return\n"); return count;}/* * FUNCTION NAME: ppi_open * * INPUTS/OUTPUTS: * in_inode - Description of openned file. * in_filp - Description of openned file. * * RETURN * 0: Open ok. * -ENXIO No such device * * FUNCTION(S) CALLED: * * GLOBAL VARIABLES REFERENCED: ppiinfo * * GLOBAL VARIABLES MODIFIED: NIL * * DESCRIPTION: It is invoked when user call 'open' system call * to open ppi device. * * CAUTION: */static int ppi_open(struct inode *inode, struct file *filp){ char intname[20]; unsigned long flags; int minor = MINOR(inode->i_rdev);//printk(KERN_INFO "PPI_open: Start\n"); pr_debug("ppi_open:\n"); /* PPI ? */ if (minor != PPI1_MINOR) {//printk(KERN_ERR "PPI_open: Error: wrong minor. Correct is %d\n", minor); return -ENXIO; } spin_lock_irqsave(&ppifcd_lock, flags); if (ppiinfo.opened) { spin_unlock_irqrestore(&ppifcd_lock, flags); return -EMFILE; }//printk(KERN_INFO "PPI_open: Clear configuration\n"); /* Clear configuration information */ memset(&ppiinfo, 0, sizeof(ppi_device_t)); if (filp->f_flags & O_NONBLOCK) ppiinfo.nonblock = 1; ppiinfo.opened = 1; ppiinfo.done = 0; ppiinfo.dma_config = (DMA_FLOW_MODE | WNR | RESTART | DMA_WDSIZE | DMA2D | DI_EN); ppiinfo.pixel_per_line = PIXEL_PER_LINE; // Does it need to be minus 1??? ppiinfo.lines_per_frame = LINES_PER_FRAME; ppiinfo.bpp = 8; ppiinfo.ppi_control = POL_S | POL_C | PPI_DATA_LEN | PPI_PACKING | CFG_GP_Input_3Syncs | GP_Input_Mode; ppiinfo.ppi_status = 0; ppiinfo.ppi_delay = 0; ppiinfo.ppi_trigger_gpio = NO_TRIGGER; ppiinfo.rx_avail = &ppirxq0; strcpy(intname, PPI_INTNAME); ppiinfo.irqnum = IRQ_PPI; filp->private_data = &ppiinfo; ppifcd_reg_reset(filp->private_data); /* Request DMA channel, and pass the interrupt handler *///printk(KERN_INFO "PPI_open: Request DMA channel, and pass the interrupt handler\n"); if (request_dma(CH_PPI, "BF561_PPI_DMA") < 0) { panic("Unable to attach BlackFin PPI DMA channel\n"); ppiinfo.opened = 0; spin_unlock_irqrestore(&ppifcd_lock, flags); return -EFAULT; } else {//printk(KERN_INFO "PPI_open: Set DMA callback when data transfer complete (PPI interrupt trigger)\n"); set_dma_callback(CH_PPI, (void *)ppifcd_irq, filp->private_data); }//printk(KERN_INFO "PPI_open: Request interupt\n"); request_irq(IRQ_PPI_ERROR, (void *)ppifcd_irq_error, IRQF_DISABLED, "PPI ERROR", filp->private_data); spin_unlock_irqrestore(&ppifcd_lock, flags);//printk(KERN_INFO "PPI_open: Return\n"); pr_debug("ppi_open: return\n"); return 0;}/* * FUNCTION NAME: ppi_release * * INPUTS/OUTPUTS: * in_inode - Description of openned file. * in_filp - Description of openned file. * * RETURN * Always 0 * * FUNCTION(S) CALLED: * * GLOBAL VARIABLES REFERENCED: ppiinfo * * GLOBAL VARIABLES MODIFIED: NIL * * DESCRIPTION: It is invoked when user call 'close' system call * to close device. * * CAUTION: */static int ppi_release(struct inode *inode, struct file *filp){ unsigned long flags; ppi_device_t *pdev = filp->private_data; pr_debug("ppi_release: close()\n"); spin_lock_irqsave(&ppifcd_lock, flags); /* After finish DMA, release it. */ free_dma(CH_PPI); free_irq(IRQ_PPI_ERROR, filp->private_data); if (pdev->ppi_trigger_gpio > NO_TRIGGER) gpio_free(pdev->ppi_trigger_gpio); ppifcd_reg_reset(pdev); pdev->opened = 0; spin_unlock_irqrestore(&ppifcd_lock, flags); ppi_fasync(-1, filp, 0); pr_debug("ppi_release: close() return\n"); return 0;}static struct file_operations ppi_fops = { owner: THIS_MODULE, read: ppi_read, ioctl: ppi_ioctl, open: ppi_open, release: ppi_release, fasync: ppi_fasync,};static struct miscdevice bfin_ppi_dev = { PPI1_MINOR, "ppi", &ppi_fops};/* * FUNCTION NAME: ppifcd_init / init_module * * INPUTS/OUTPUTS: * * RETURN: * 0 if module init ok. * -1 init fail. * * FUNCTION(S) CALLED: * * GLOBAL VARIABLES REFERENCED: ppiinfo * * GLOBAL VARIABLES MODIFIED: NIL * * DESCRIPTION: It will be invoked when using 'insmod' command. * or invoke it directly if ppi module is needed. * * CAUTION: */int __init ppifcd_init(void){ int result; if (peripheral_request_list(ppifcd_ppi_req, PPI_DEVNAME)) { printk(KERN_ERR "Requesting Peripherals PPI faild\n"); return -EFAULT; } result = misc_register(&bfin_ppi_dev); if (result < 0) { printk(KERN_WARNING "PPI: can't get minor %d\n", PPI1_MINOR); return result; } printk(KERN_INFO "PPI: ADSP PPI Frame Capture Driver IRQ:%d \n", IRQ_PPI); return 0;}/* * FUNCTION NAME: ppifcd_uninit / cleanup_module * * INPUTS/OUTPUTS: * * RETURN: * * FUNCTION(S) CALLED: * * GLOBAL VARIABLES REFERENCED: ppiinfo * * GLOBAL VARIABLES MODIFIED: NIL * * DESCRIPTION: It will be invoked when using 'rmmod' command. * or, you invoke it directly when it needs remove * ppi module. * * CAUTION: */void __exit ppifcd_uninit(void){ if (ppiinfo.ppi_trigger_gpio != NO_TRIGGER) gpio_free(ppiinfo.ppi_trigger_gpio); peripheral_free_list(ppifcd_ppi_req); misc_deregister(&bfin_ppi_dev); printk(KERN_ALERT "Goodbye PPI\n");}module_init(ppifcd_init);module_exit(ppifcd_uninit);MODULE_AUTHOR("Michael Hennerich");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -