📄 at2041_inf.c.bak
字号:
/* * Copyright(C) 2004, Pentamicro Inc. All Right Reserved. * * Filename : at2041_inf.c * Description : Linux device driver of AT2041 * * Project : MPEG-4 4-channel SDVR * * Date : Apr., 20. 2004. * Company : Advanced Technology R&D Center * Pentamicro Inc. * * Linux version : */ /** ************************************************************************* ** ** includes ** ************************************************************************* **/#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/slab.h>#include <linux/vmalloc.h>#include <linux/init.h>#include <linux/ioctl.h>#include <linux/major.h>#include <linux/delay.h>#include <asm/errno.h>#include <asm/irq.h>#include <asm/uaccess.h>#include <asm/io.h>#include <asm/delay.h>#include "at2041_inf.h"unsigned short * mux_buf[MAX_BUF_NUM];unsigned short * demux_buf[MAX_BUF_NUM];unsigned short * tx_buf[MAX_TXBUF_NUM];unsigned short * size_buf[MAX_BUF_NUM];unsigned int demux_size_buf[MAX_BUF_NUM];volatile unsigned short enc_txmsg_size = 4;volatile static unsigned short mux_ring_cnt = 0;volatile static unsigned short mux_rd_cnt = 0;volatile static unsigned short mux_wr_cnt = 0; volatile static unsigned short mux_full = 0;volatile static unsigned short demux_ring_cnt = 0;volatile static unsigned short demux_rd_cnt = 0;volatile static unsigned short demux_wr_cnt = 0; volatile static unsigned short txfifo_rd_cnt = 0;volatile static unsigned short txfifo_wr_cnt = 0;volatile static unsigned short txfifo_ring_cnt = 0;static struct semaphore muxfifo_read_sem;static struct semaphore demuxfifo_write_sem;unsigned short * pt;unsigned int ii;/** ************************************************************************* ** ** forward declarations ** ************************************************************************* **/void at2041_ioctl_init() { int count; unsigned short status; unsigned short temp; printk("\t!!! AT2041 driver initialized... "); /* check tx fifo empty */// test for swparkprintk("[at2041_inf]at2041_ioctl_init start\n"); count = 0; do { status = *((unsigned short *)((unsigned int)pt + AT2041_STATUS_REG_ADDR)); count ++; udelay(10); }while ((status & 0x100) && (count < 1000));// test for swparkprintk("[at2041_inf]check status register\n"); if (count == 1000) { printk("ERROR !!!\n"); } else { // test for swparkprintk("[at2041_inf]success check status register\n"); /* data read from Tx_FIFO of the AT2041 */ temp = *((unsigned short *)((unsigned int)pt + AT2041_TX_FIFO_ADDR)); if (temp != 0x8003) { printk("\n!!! the AT2041 Ready Error !!!\n"); } /* TxACK command */ *((unsigned short *)((unsigned int)pt + AT2041_RX_FIFO_ADDR)) = 0x8003; printk("Complete !!!\n"); }}int at2041_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ unsigned short rx_fifo; unsigned short cmd_reg, status_reg;// test for swparkprintk("[at2041_inf]start at2041_ioctl : cmd= %d\n", cmd); switch(cmd) { case READ_Tx_FIFO : put_user(*tx_buf[txfifo_rd_cnt], (unsigned short *) arg); /* txfifo ring buffer control */ if (!txfifo_ring_cnt && txfifo_rd_cnt <= txfifo_wr_cnt) { txfifo_rd_cnt ++; if (txfifo_rd_cnt == MAX_BUF_NUM) { txfifo_ring_cnt --; txfifo_rd_cnt = 0; } } else if (txfifo_ring_cnt) { txfifo_rd_cnt ++; } break; case WRITE_Rx_FIFO : get_user(rx_fifo, (unsigned short *)arg); *((unsigned short *)((unsigned int)pt + AT2041_RX_FIFO_ADDR)) = rx_fifo; break; case WRITE_COMMAND_REG : get_user(cmd_reg, (unsigned short *)arg); *((unsigned short *)((unsigned int)pt + AT2041_COMMAND_REG_ADDR)) = cmd_reg; break; // swpark// case WRITE_CONTROL_REG :// get_user(ctrl_reg, (unsigned short *)arg);// *((unsigned short *)((unsigned int)pt + 0x00002800)) = ctrl_reg;// break; case READ_STATUS_REG : status_reg = *((unsigned short *)((unsigned int)pt + AT2041_STATUS_REG_ADDR)); put_user(status_reg, (unsigned short *) arg); break; case AT2041_INIT : at2041_ioctl_init(); break; default : break; } return 0;}static ssize_t muxfifo_read(struct file *file, char *buffer,size_t length,loff_t * offset) { /* copy mux_buf to user space */ /* real transfer size is size_buf[mux_rd_cnt] * 256bit. * third parameter of copy_to_user() is the 'byte' number to transfer * so, it's calculated size_buf[mux_rd_cnt] * 32 */ unsigned int size; down(&muxfifo_read_sem); size = (*size_buf[mux_rd_cnt] << 5) + (enc_txmsg_size << 1); copy_to_user(buffer, mux_buf[mux_rd_cnt], size); /* multiplex ring buffer control */ if (!mux_ring_cnt && mux_rd_cnt <= mux_wr_cnt) { mux_rd_cnt ++; if (mux_rd_cnt == MAX_BUF_NUM) { mux_ring_cnt --; mux_rd_cnt = 0; } } else if (mux_ring_cnt) { mux_rd_cnt ++; if (mux_rd_cnt == MAX_BUF_NUM) { mux_ring_cnt --; mux_rd_cnt = 0; } } if (mux_full) { /* acknowledge for data ready message */ *((unsigned short *)((unsigned int)pt + AT2041_RX_FIFO_ADDR)) = 0x8803; mux_full = 0; } return 0;}static ssize_t demuxfifo_write(struct file *file,const char *buffer, size_t length, loff_t * offset){ down(&demuxfifo_write_sem); copy_from_user(demux_buf[demux_wr_cnt], buffer, length); demux_size_buf[demux_wr_cnt] = length; /* de-multiplex ring buffer control */ if (!demux_ring_cnt) { demux_wr_cnt ++; if (demux_wr_cnt == MAX_BUF_NUM) { demux_ring_cnt ++; demux_wr_cnt = 0; } } else if (demux_ring_cnt && demux_wr_cnt < demux_rd_cnt) { demux_wr_cnt ++; } return 0;}static int at2041_open(struct inode* inode, struct file* filp){ printk("the AT2041 Open!!!\n"); MOD_INC_USE_COUNT; return 0;}static int at2041_release(struct inode* inode, struct file* filp){ printk("the AT2041 Release!!!\n"); MOD_DEC_USE_COUNT; return 0;}/* the AT2041 file operations */#if 0static struct file_operations at2041_fops = { read: muxfifo_read, write: demuxfifo_write, ioctl: at2041_ioctl, open: at2041_open, release: at2041_release,};#elsestruct file_operations device_fops = { NULL, read: muxfifo_read, write: demuxfifo_write, NULL, ioctl: at2041_ioctl, NULL, open: at2041_open, NULL, release: at2041_release};#endifstatic void at2041_interrupt_handle(int irq, void *dev_id, struct pt_regs * regs){ unsigned short tx_data; unsigned short temp; unsigned int data_size = 0; /* data read from Tx_FIFO of the AT2041 */ tx_data = *((unsigned short *)((unsigned int)pt + AT2041_TX_FIFO_ADDR)); /* check whether first tx message is 'data ready message' * or 'data request message' */ if (tx_data == 0x8803) { /* if first tx message is 'data ready message', * read three tx message sequentially. * the contents of second tx_message are 'data type', 'channel ID', * 'skip', 'loss' and 'output buffer full', etc. */ /* check tx fifo empty */ if ( !(*((unsigned short *)((unsigned int)pt + AT2041_STATUS_REG_ADDR)) & 0x100) ) { /* read the second parameter of Tx_FIFO */ mux_buf[mux_wr_cnt][0] = *((unsigned short *)((unsigned int)pt + AT2041_TX_FIFO_ADDR)); } else { printk("[saa7146] It can't read tx0 register\n"); /* TxACK command */ *((unsigned short *)((unsigned int)pt + AT2041_RX_FIFO_ADDR)) = 0x8003; } if ( !(*((unsigned short *)((unsigned int)pt + AT2041_STATUS_REG_ADDR)) & 0x100) ) { /* read the third parameter of Tx_FIFO */ /* the contents of the third tx_message are 'output data size' */ mux_buf[mux_wr_cnt][1] = *((unsigned short *)((unsigned int)pt + AT2041_TX_FIFO_ADDR)); } else { printk("[saa7146] It can't read tx1 register\n"); /* TxACK command */ *((unsigned short *)((unsigned int)pt + AT2041_RX_FIFO_ADDR)) = 0x8003; } if ( !(*((unsigned short *)((unsigned int)pt + AT2041_STATUS_REG_ADDR)) & 0x100) ) { /* read the fourth parameter of Tx_FIFO */ /* the contents of the fourth tx_message are 'reserved' */ mux_buf[mux_wr_cnt][2] = *((unsigned short *)((unsigned int)pt + AT2041_TX_FIFO_ADDR)); } else { printk("[saa7146] It can't read tx2 register\n"); } /* calculate data size to transfer */ *size_buf[mux_wr_cnt] = mux_buf[mux_wr_cnt][1]; data_size = ((*size_buf[mux_wr_cnt] & 0xffff) << 4) + enc_txmsg_size; /* data read from multiplex FIFO of the AT2041 */ /* write multiplex data from the AT2041 to d/d's buffer */ for (ii = enc_txmsg_size; ii < data_size; ii ++) { mux_buf[mux_wr_cnt][ii] = *((unsigned short *)((unsigned int)pt + AT2041_MUX_FIFO_ADDR)); } up(&muxfifo_read_sem); /* multiplex ring buffer control */ if (!mux_ring_cnt) { mux_wr_cnt ++; if (mux_wr_cnt == MAX_BUF_NUM) { mux_ring_cnt ++; mux_wr_cnt = 0; } } else if (mux_ring_cnt && mux_wr_cnt < mux_rd_cnt) { mux_wr_cnt ++; } else { printk("!!![MUX][%02d][%02d][%02d]\n", mux_wr_cnt, mux_rd_cnt, mux_ring_cnt); } /* TxACK command */ *((unsigned short *)((unsigned int)pt + AT2041_RX_FIFO_ADDR)) = 0x8003; if (mux_ring_cnt && mux_wr_cnt == mux_rd_cnt) { mux_full = 1; printk("!!!!!!!! MUX FULL !!!!!!!!!\n"); } else { /* acknowledge for data ready message */ *((unsigned short *)((unsigned int)pt + AT2041_RX_FIFO_ADDR)) = 0x8803; } } else if (tx_data == 0x9003) { /* data write to de-multiplex FIFO of the AT2041 */ if (!demux_ring_cnt && (demux_wr_cnt == demux_rd_cnt)) { /* check tx fifo empty */ if (!(*((unsigned short *)((unsigned int)pt + AT2041_STATUS_REG_ADDR)) & 0x100)) { /* txfifo ring buffer control */ temp = *((unsigned short *)((unsigned int)pt + AT2041_TX_FIFO_ADDR)); } else { printk("[saa7146] It can't read tx0 register\n"); /* TxACK command */ *((unsigned short *)((unsigned int)pt + AT2041_RX_FIFO_ADDR)) = 0x8003; } /* TxACK command */ *((unsigned short *)((unsigned int)pt + AT2041_RX_FIFO_ADDR)) = 0x8003; /* acknowledge for data request message */ *((unsigned short *)((unsigned int)pt + AT2041_RX_FIFO_ADDR)) = 0x9003; return; } /* check tx fifo empty */ if (!(*((unsigned short *)((unsigned int)pt + AT2041_STATUS_REG_ADDR)) & 0x100)) { /* txfifo ring buffer control */ temp = *((unsigned short *)((unsigned int)pt + AT2041_TX_FIFO_ADDR)); } else { printk("[saa7146] It can't read tx0 register\n"); *((unsigned short *)((unsigned int)pt + AT2041_RX_FIFO_ADDR)) = 0x8003; } /* write de-multiplex data from d/d's buffer to the AT2041 */ for (ii = 0; ii < (demux_size_buf[demux_rd_cnt] + 256) / 2; ii ++) { *((unsigned short *)((unsigned int)pt + AT2041_DEMUX_FIFO_ADDR)) = demux_buf[demux_rd_cnt][ii]; } /* de-multiplex ring buffer control */ if (!demux_ring_cnt && demux_rd_cnt <= demux_wr_cnt) { demux_rd_cnt ++; if (demux_rd_cnt == MAX_BUF_NUM) { demux_ring_cnt --; demux_rd_cnt = 0; } } else if (demux_ring_cnt) { demux_rd_cnt ++; if (demux_rd_cnt == MAX_BUF_NUM) { demux_ring_cnt --; demux_rd_cnt = 0; } } up(&demuxfifo_write_sem); /* TxACK command */ *((unsigned short *)((unsigned int)pt + AT2041_RX_FIFO_ADDR)) = 0x8003; /* acknowledge for data request message */ *((unsigned short *)((unsigned int)pt + AT2041_RX_FIFO_ADDR)) = 0x9003; } else { /* TxACK command */ *((unsigned short *)((unsigned int)pt + AT2041_RX_FIFO_ADDR)) = 0x8003; }}int at2041_init_module(void){ int ret, kk; pt = (unsigned short *)ioremap(AT2041BASE, AT2041REMAP_SIZE); printk("init_at2041 %p\n",pt); ret = register_chrdev(AT2041_MAJOR, "at2041", &at2041_fops); init_MUTEX_LOCKED(&muxfifo_read_sem); sema_init(&demuxfifo_write_sem, MAX_BUF_NUM); if (ret < 0) { printk("at2041: at2041 register failed\n"); return ret; } /* mux_buf & demux_buf allocation */ for (kk = 0; kk < MAX_BUF_NUM; kk ++){ if (!(mux_buf[kk] = (unsigned short *) kmalloc(MAX_BUF_SIZE + (enc_txmsg_size << 1), GFP_KERNEL))) { printk("AT2041 : mux_buf kmalloc failed...\n"); return -ENOMEM; } if (!(demux_buf[kk] = (unsigned short *) kmalloc(MAX_BUF_SIZE, GFP_KERNEL))) { printk("AT2041 : demux_buf kmalloc failed...\n"); return -ENOMEM; } if (!(size_buf[kk] = (unsigned short *) vmalloc(sizeof(unsigned short)))) { printk("AT2041 : size_buf kmalloc failed...\n"); return -ENOMEM; } } printk("the AT2041 driver initialized...\n"); /* AT2041_IRQ = 27, Fast interrupt, No interrupt sharing */ if(request_irq(AT2041_IRQ, at2041_interrupt_handle, SA_INTERRUPT, "at2041", NULL)) { printk(KERN_ERR "at2041 : cannot register IRQ %d\n", AT2041_IRQ); return -EIO; } return 0;}void at2041_cleanup_module(void){ volatile int ret; free_irq(AT2041_IRQ, NULL); ret = unregister_chrdev(AT2041_MAJOR, "at2041"); if (ret < 0) { printk("at2041: at2041 unregister failed\n"); return; } for (ii = 0; ii < MAX_BUF_NUM; ii ++) { kfree(mux_buf[ii]); kfree(demux_buf[ii]); vfree(size_buf[ii]); } iounmap((void *)pt); ret = unregister_chrdev(AT2041_MAJOR, "at2041"); if (ret < 0) { printk("at2041: at2041 unregister failed\n"); return; } printk("at2041: at2041 unloaded\n"); return;}module_init(at2041_init_module);module_exit(at2041_cleanup_module);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -