📄 fipkernel.c
字号:
int uart_printf(const char *fmt, ...);int strlen(const char *str);#endif /* __KERNEL__ */#define FIP_DEV_NAME "fip"static void fip_write_reg(unsigned int offset, unsigned int val);static unsigned int fip_read_reg(unsigned int offset);#ifdef __KERNEL__ #define CMDQ_SIZE 256/* Private data structure */struct cmd_request { unsigned int cmd; unsigned int data;};struct fip_private { unsigned long *buffer; /* Circular buffer */ unsigned p_idx; /* Index of producer */ unsigned c_idx; /* Index of consumer */ unsigned ref_cnt; /* Reference count */ spinlock_t lock; /* Spin lock */ unsigned char b_mode; /* Blocking mode or not */ unsigned long last_jiffies; /* Timestamp for last reception */#ifdef ENABLE_WRITE_INTR struct cmd_request cmds[CMDQ_SIZE]; unsigned cmd_pidx; unsigned cmd_cidx; unsigned cmdq_empty;#endif};static struct file_operations fip_fops = { open: fip_open, read: fip_read, ioctl: fip_ioctl, poll: fip_poll, write: fip_write, release: fip_release, owner: THIS_MODULE,};static void fip_push_key(struct fip_private *priv, unsigned long key);#ifdef ENABLE_WRITE_INTRstatic void fip_issue_command(struct fip_private *priv);static void fip_queue_command(unsigned int cmd, unsigned int data);#endif/* Global data */static struct fip_private fip_priv;static devfs_handle_t devfs_handle = NULL;static int fip_major = FIP_DEV_MAJOR;#endif /* __KERNEL__ */static char *fip_devname = FIP_DEV_NAME;static int brightness = BRIGHTNESS;static unsigned long fip_base = (unsigned long)FIP_BASE;static char fipram[MAX_FIP_RAM] = {0};#ifdef __KERNEL__static void fip_isr(int irq, void *dev_id, struct pt_regs *regs){ struct fip_private *priv = (struct fip_private *)dev_id; unsigned long stat; unsigned long key; if (irq == fip_irq) { __raw_writel(IRQMASKOF(irq), REG_BASE_CPU + CPU_edge_rawstat); stat = (fip_read_reg(FIP_INT) & 0x3); fip_write_reg(FIP_INT, stat); /* Clear the interrupt */ if (!is_fip_busy_nowait()) { if (stat & 0x2) { key = fip_read_reg(FIP_KEY_DATA1); fip_push_key(priv, key); }#ifdef ENABLE_WRITE_INTR fip_issue_command(priv);#endif } } else printk("Unknown IRQ %d\n", irq);}static void fip_poll_key(unsigned long devid){ struct fip_private *priv = (struct fip_private *)devid; /* Sending command, and later ISR will pick up the interrupt and read the key */ if (!is_fip_busy_nowait()) { fip_write_reg(FIP_COMMAND, FIP_CMD_DATA_SET_RW_MODE_READ_KEYS);#ifdef ENABLE_WRITE_INTR if (priv->cmdq_empty != 0) { fip_issue_command(priv); }#endif } if (priv->ref_cnt != 0) { mod_timer(&fip_timer, jiffies + (HZ / poll_per_sec));#if 0 queue_task(&immediate, &tq_immediate); mark_bh(IMMEDIATE_BH);#endif }}/* Produce data */static void fip_push_key(struct fip_private *priv, unsigned long key){ unsigned pidx; static unsigned long oldkey = 0; spin_lock(&priv->lock); if ((key == 0) || (key == 0xffffffff)) { oldkey = 0; goto out; } else if (((priv->last_jiffies + wait_period) > jiffies) && (key == oldkey)) goto out; else priv->last_jiffies = jiffies; printk(KERN_DEBUG "%s: got data 0x%08lx\n", fip_devname, key); pidx = priv->p_idx; /* Save the old index before proceeding */ /* Save it to buffer */ if (((priv->p_idx + 1) % buffer_size) == priv->c_idx) { /* Adjust consumer index since buffer is full */ /* Keep the latest one and drop the oldest one */ priv->c_idx = (priv->c_idx + 1) % buffer_size; printk(KERN_WARNING "%s: buffer full\n", fip_devname); } priv->buffer[priv->p_idx] = oldkey = key; priv->p_idx = (priv->p_idx + 1) % buffer_size; /* Buffer was empty and block mode is on, wake up the reader */ if ((priv->b_mode != 0) && (priv->c_idx == pidx)) wake_up_interruptible(&fip_wq);out: spin_unlock(&priv->lock);}/* Reading from driver's buffer, note that it can return read size less than specified */static int fip_consume(void *dev_id, unsigned long *buf, int count){ struct fip_private *priv = (struct fip_private *)dev_id; int cnt; unsigned long flags; spin_lock_irqsave(&priv->lock, flags); /* If block mode is on, check the emptiness of buffer */ if (priv->b_mode != 0) { /* Sleep when buffer is empty */ while (priv->c_idx == priv->p_idx) { spin_unlock_irqrestore(&priv->lock, flags); interruptible_sleep_on(&fip_wq); spin_lock_irqsave(&priv->lock, flags); } } /* Get the data out and adjust consumer index */ for (cnt = 0; (priv->c_idx != priv->p_idx) && (cnt < count); cnt++) { *buf = priv->buffer[priv->c_idx]; priv->c_idx = (priv->c_idx + 1) % buffer_size; buf++; } spin_unlock_irqrestore(&priv->lock, flags); return(cnt);}/* Poll function */static unsigned int fip_poll(struct file *fptr, struct poll_table_struct *ptable){ struct fip_private *priv = (struct fip_private *)fptr->private_data; unsigned int mask = 0; poll_wait(fptr, &fip_wq, ptable); if (priv->c_idx != priv->p_idx) mask |= (POLLIN | POLLRDNORM); return(mask);}#ifdef ENABLE_WRITE_INTRstatic void fip_issue_command(struct fip_private *priv){ unsigned long flags; spin_lock_irqsave(&priv->lock, flags); if (priv->cmd_pidx == priv->cmd_cidx) { priv->cmdq_empty = 1; goto out; } else if (!is_fip_busy_nowait()) { priv->cmdq_empty = 0; fip_wait_ready(); fip_write_reg(FIP_DISPLAY_DATA, priv->cmds[priv->cmd_cidx].data); fip_wait_ready(); fip_write_reg(FIP_COMMAND, priv->cmds[priv->cmd_cidx].cmd); fip_wait_ready(); priv->cmd_cidx = ((priv->cmd_cidx + 1) % CMDQ_SIZE); if (priv->cmd_pidx == priv->cmd_cidx) priv->cmdq_empty = 1; }out: spin_unlock_irqrestore(&priv->lock, flags);}#endifstatic int fip_open(struct inode *inode_ptr, struct file *fptr){ MOD_INC_USE_COUNT; /* This device is exclusive, that is, only one process can use it */ if (fip_priv.ref_cnt != 0) { printk(KERN_WARNING "%s: exclusive access only\n", fip_devname); return(-EIO); } /* Set the block mode and increase reference count */ fip_priv.ref_cnt++; fip_priv.b_mode = ((fptr->f_flags & O_NONBLOCK) ? 0 : 1); fip_priv.last_jiffies = jiffies; /* Flush the buffer */ fip_priv.p_idx = fip_priv.c_idx = 0; fptr->f_op = &fip_fops; fptr->private_data = (void *)&fip_priv; fip_timer.function = fip_poll_key; fip_timer.data = (unsigned long)&fip_priv; fip_timer.expires = jiffies + (HZ / poll_per_sec); add_timer(&fip_timer);#if 0 immediate.sync = 0; immediate.data = (void *)&fip_priv; immediate.routine = fip_poll_key; queue_task(&immediate, &tq_immediate); mark_bh(IMMEDIATE_BH);#endif fip_clear(); return(0);}static int fip_release(struct inode *inode_ptr, struct file *fptr) { unsigned long start = 0; MOD_DEC_USE_COUNT; /* Adjust reference count */ fip_priv.ref_cnt--; /* Wait for timer expiration */ for (start = jiffies; (start + 2 * (HZ / poll_per_sec)) > jiffies;); del_timer_sync(&fip_timer); return(0);}static int fip_read(struct file *fptr, char *bufptr, size_t size, loff_t *fp){ unsigned long buf[buffer_size]; int count = 0; /* Check the alignment */ if (size % sizeof(unsigned long)) { printk(KERN_WARNING "%s: read size not aligned to %ld\n", fip_devname, sizeof(unsigned long)); return(-EIO); } count = fip_consume(fptr->private_data, &buf[0], size / sizeof(unsigned long)) * sizeof(unsigned long); /* Get the data to user */ if (copy_to_user(bufptr, (char *)&buf[0], count)) return(-EFAULT); return(count);}static int fip_write(struct file *fptr, const char *bufptr, size_t size, loff_t *fp){ fip_wait_ready(); fip_write_text(0, bufptr, FIP_CENTER); fip_wait_ready(); return(size);}static int fip_ioctl(struct inode *inode, struct file *fptr, unsigned int cmd, unsigned long arg){ int on = 0; int symbol; int i, j, k; switch(cmd) { case FIP_IOCSHOWSYMBOL: on = ((arg & 0x80000000)) == 0 ? 0 : 1; symbol = (int)(arg & 0xff); fip_display_symbol(symbol, on); break; case FIP_IOCSHOWHMS: k = (int)(arg & 0xff); j = (int)((arg >> 8) & 0xff); i = (int)((arg >> 16) & 0xff); fip_show_hms(i, j, k); break; case FIP_IOCDISPCHAR: k = (int)(arg & 0xff); j = (int)((arg >> 8) & 0xff); fip_display_character(j, k); break; case FIP_IOCDISPRAW: on = ((arg & 0x80000000)) == 0 ? 0 : 1; k = (int)(arg & 0xff); j = (int)((arg >> 8) & 0xff); fip_display_raw(j, k, on); break; case FIP_IOCDISPTEXT: printk("%s: ioctl FIP_IOCDISPTEXT not implemented.\n", fip_devname); return(-EIO); case FIP_IOCCLEAR: fip_clear(); break; case FIP_IOCGETFPTYPE: { unsigned long *ptr = (unsigned long *)arg; unsigned long type = 0;#if defined(CONFIG_EM86XX_FIP_REF1) type = 1;#elif defined(CONFIG_EM86XX_FIP_REF2) type = 2;#else return(-EIO);#endif if (copy_to_user(ptr, (char *)&type, sizeof(unsigned long))) return(-EFAULT); } break; case FIP_IOCSETLED: k = (int)(arg & 0xff); fip_setled(k); break; default: return(-EIO); } return(0);}#endif /* __KERNEL__ *//* Micro-second sleep */static void fip_usleep(unsigned usec){#ifdef __KERNEL__ udelay(usec);#else em86xx_usleep(usec);#endif /* __KERNEL__ */}static unsigned int fip_read_reg(unsigned int offset){ unsigned int val = *((volatile unsigned int *)(fip_base + offset)); return(val);}static void fip_write_reg(unsigned int offset, unsigned int val){ fip_wait_ready(); *((volatile unsigned int *)(fip_base + offset)) = val; fip_wait_ready();}#ifdef __KERNEL__#ifdef ENABLE_WRITE_INTR/* To queue the write request */static void fip_queue_command(unsigned int cmd, unsigned int data){ unsigned long flags; spin_lock_irqsave(&fip_priv.lock, flags); if (((fip_priv.cmd_pidx + 1) % CMDQ_SIZE) == fip_priv.cmd_cidx) { printk(KERN_ERR "Command queue full.\n"); fip_issue_command(&fip_priv); } else { fip_priv.cmds[fip_priv.cmd_pidx].cmd = cmd; fip_priv.cmds[fip_priv.cmd_pidx].data = data; fip_priv.cmd_pidx = ((fip_priv.cmd_pidx + 1) % CMDQ_SIZE); } spin_unlock_irqrestore(&fip_priv.lock, flags);}#endif#endif#ifdef __KERNEL__static int is_fip_busy_nowait(void){ return((fip_read_reg(FIP_CONFIG) & FIP_BUSY) != 0);}#endif#ifdef __KERNEL__static#endif /* __KERNEL__ */int is_fip_busy(void){#if defined(CONFIG_EM86XX_FIP_REF1) fip_usleep(10);#elif defined(CONFIG_EM86XX_FIP_REF2) fip_usleep(20);#endif return((fip_read_reg(FIP_CONFIG) & FIP_BUSY) != 0);}#ifdef __KERNEL__static#endif /* __KERNEL__ */void fip_wait_ready(void){ while (is_fip_busy());#if defined(CONFIG_EM86XX_FIP_REF2) fip_usleep(20);#endif}static void fip_user_display(int adr, int data){#ifdef __KERNEL__#ifdef ENABLE_WRITE_INTR fip_wait_ready(); fip_queue_command(FIP_CMD_ADR_SETTING | (adr), data);#else fip_wait_ready(); fip_write_reg(FIP_DISPLAY_DATA, data); fip_write_reg(FIP_COMMAND, FIP_CMD_ADR_SETTING | (adr));#endif#else fip_wait_ready(); fip_write_reg(FIP_DISPLAY_DATA, data); fip_wait_ready(); fip_write_reg(FIP_COMMAND, FIP_CMD_ADR_SETTING | (adr)); fip_wait_ready();#endif}#ifdef __KERNEL__static#endif /* __KERNEL__ */int fip_display_character(const int position, const char character) { unsigned int data1,data2; int i, byte1, byte2; unsigned char current_contents0, current_contents1;#if defined(CONFIG_EM86XX_FIP_REF1) const int min_pos = 1;#elif defined(CONFIG_EM86XX_FIP_REF2) const int min_pos = 0;#endif if ((position < min_pos) || (position > NUM_DIGITS)) {#ifdef __KERNEL__ printk(KERN_DEBUG "%s: position %d not available/supported.\n", fip_devname, position);#else uart_printf("%s: position %d not available/supported.\n", fip_devname, position);#endif /* __KERNEL__ */ return(0); } for (i = 0; i < NUM_CHARACTERS; i++) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -