📄 lad_pad.c
字号:
if(pfile->f_mode & FMODE_READ){ up(&ladpad_read_sem); } return -EBUSY; } } /* Log open call */ if (debuglvl >= 3) { printk(KERN_INFO "ladpad opened\n"); } return 0; /* success */}/*************************************************************************** * ladpad_close() - Handles the close() of the ladpad device. * * Give back any semaphores taken for the requested access. ***************************************************************************/static int ladpad_close(struct inode *inode, struct file *pfile){ if(pfile->f_mode & FMODE_READ){ up(&ladpad_read_sem); } if(pfile->f_mode & FMODE_WRITE){ up(&ladpad_write_sem); } /* Log close */ if (debuglvl >= 3) { printk(KERN_INFO "ladpad closed\n"); } return 0;}/*************************************************************************** * ladpad_read() - Read key presses from the keypad * * Transfers the ASCII value of a key press when the user presses a * key. The keypad scanning is done in a routine attached to a * timer. The timer routine and this routine communicate using the * Key_Press variable and a wait_queue. * * This routine blocks until the backgound routine detects a new key * press. Only one keypress is reported at a time. Returns number of * bytes transferred. ***************************************************************************/static ssize_t ladpad_read( struct file *pfile, /* points to our file structure */ char __user *buffer, /* buffer to fill with data */ size_t count, /* number of bytes requested */ loff_t * offset){ ssize_t retval = 0; /* Number of bytes transfered */ /* Wait here until a key press is available */ if (Key_Press == (char) 0) { /* Wait on WaitQ until Key_Press is nonzero */ if(wait_event_interruptible(WaitQ, Key_Press)){ /* Signal caught */ return -ERESTARTSYS; } } /* Deliver ASCII code to the user */ if (Key_Press != (char) 0){ put_user(Key_Press, buffer); *offset++; retval = 1; } Key_Press = (char) 0; /* Empty the one-character 'queue' */ /* Log read() */ if (debuglvl >= 3) { printk(KERN_INFO "ladpad read() returned 0x%02x\n", Key_Press); } return retval;}/*************************************************************************** * keypad_scan() - Timeout function that does a scan of the keypad. * and outputs a single character to the LCD if any are available. * * This routine assumes a four-by-four array of switches. The output * lines to the keypad are the first four data lines. The inputs are * bits 3 to 6 in the parallel port status register. ***************************************************************************/static void keypad_scan(unsigned long ptr){ int value; /* value from parallel port status pins */ char keydown = 0; /* ASCII value of key pressed */ /* Output a character if any are in the circular buffer */ if (ccnt) { out44780(cbuf[oindx++]); oindx = (oindx == CBUFSZ) ? 0 : oindx; ccnt--; if (ccnt < CBUFSZ/2) { wake_up(&SendQ); } } /* Keypad scan puts a zero on one of the first two data * lines and then looks for a zero on the pins from the * status port. The intersection of which data pin and * which status pin identifies which key was pressed. */ outb(0x02, io_base); /* put 0 on row 0 */ value = inb(io_base + 1); /* switch state in bits 3,4 */ if ((value & 0x08) == 0x00) /* remember: closed=0, open=1 */ keydown = 'C'; if ((value & 0x10) == 0x00) /* look at switch on column 1 */ keydown = 'Z'; outb(0x01, io_base); /* put 0 on row 1 */ value = inb(io_base + 1); if ((value & 0x08) == 0x00) /* look at switch on column 0 */ keydown = 'E'; if ((value & 0x10) == 0x00) /* look at switch on column 1 */ keydown = 'D'; /* Shift values for key debounce */ if (last_1 == 0 && last_0 == 0 && keydown != 0 && Key_Press == (char) 0) { Key_Press = keydown; /* New key press is available */ wake_up(&WaitQ); } last_1 = last_0; last_0 = keydown; /* Flash and update LED */ if (led == 0) { led_state = LED0; } else if (led == 0xFF) { led_state = LED1; } else { led_state = (led_counter < led) ? LED0 : LED1; led_counter = (led_counter >= (led * 2)) ? 0 : led_counter + 1; } outb((led_state | rs_state | e_state), io_base + 2); keypad_timer.expires = jiffies + (scan_time * (HZ / 100)); add_timer(&keypad_timer);}/*************************************************************************** * ladpad_poll() - Indicates if read() or write() will succeed * * This routine returns a bit mask to indicate when a character is * ready to be read. A write does not block on this device so we * always return that it is writable. ***************************************************************************/static unsigned int ladpad_poll( struct file *pfile, poll_table *ppt){ int ready_mask = 0; /* Add the device's input queue to the provided poll table. */ poll_wait(pfile, &WaitQ, ppt); /* Add the device's output queue to the provided poll table. */ poll_wait(pfile, &SendQ, ppt); if (Key_Press != (char) 0) { ready_mask |= (POLLIN | POLLRDNORM); } if (ccnt < CBUFSZ) { ready_mask |= (POLLOUT | POLLWRNORM); } /* Log poll output */ if (debuglvl >= 3) { printk(KERN_INFO "ladpad: poll returns 0x%x\n", ready_mask); } return ready_mask;}/*************************************************************************** * ladpad_write() - A write to the LCD display or LED * * Accepts characters from the user for display on the LCD display. * We drop the characters into a circular buffer for output in the timeout * routine. ***************************************************************************/static ssize_t ladpad_write( struct file *pfile, const char __user *buffer, size_t length, loff_t * offset){ int ret; /* number of bytes output */ int out_count = 0; /* byte counter */ int freecnt; /* number of free bytes in circurlar buf */ char next_byte; /* Wait here until a key press is available */ if (CBUFSZ == ccnt) { /* Wait on SendQ until output buffer space is available */ if (wait_event_interruptible(SendQ, (CBUFSZ - ccnt))) { /* Signal caught */ return -ERESTARTSYS; } } /* Compute the amount of free space in the circular buffer */ freecnt = CBUFSZ - ccnt; /* Accept freecnt bytes or length, whichever is lower */ ret = (freecnt < length) ? freecnt : length; if (debuglvl >= 3) { printk(KERN_INFO "ladpad: free=%d len=%d ret=%d in=%d out=%d cnt=%d \n", freecnt, length, ret, iindx, oindx, ccnt); } while (out_count < ret) { /* The macro get_user returns 0 for success or -EFAULT. */ if(get_user(next_byte, buffer)){ return -EFAULT; } cbuf[iindx++] = next_byte; if (iindx == CBUFSZ) { iindx = 0; } /* Character consumed; update local and user pointers. */ buffer++; *offset++; out_count++; } ccnt += ret; /* Return the number of characters read from the buffer */ return ret;}/*************************************************************************** * out44780() - Output a single character to the 44780 LCD display. * * This routine also handles command output to the LCD, and the setting * of the LED flash frequency. * This routine implements a state machine to indicate how to * interpret the next byte read. A state=NORM means that the next character * is to be sent directly to LCD display. If state=CMD, the next character * is a command to send to the LCD display. If state=LED, the next * character is a command for the LED. * The very low power controller on the LCD display can accept commands * and characters at a fairly slow rate so we output a single character * at each timeout. ***************************************************************************/static void out44780( unsigned char outchar){ if (input_state == LAD_LED) { led = outchar; input_state = LAD_NORM; if (debuglvl >= 3) { printk(KERN_INFO "ladpad: led set = 0x%02x\n", led); } } else { if (outchar == LADPAD_CMD) { input_state = LAD_CMD; rs_state = RSCMD; } else if (outchar == LADPAD_LED) { input_state = LAD_LED; } else { /* send char to LCD display */ outb(outchar, io_base); e_state = E1; outb((led_state | rs_state | e_state), io_base + 2); udelay(2); e_state = E0; outb((led_state | rs_state | e_state), io_base + 2); if (debuglvl >= 3) { if ((outchar >= ' ') && (outchar <= '~')) printk(KERN_INFO "ladpad: char 0x%02x '%c'\n", outchar, outchar); else printk(KERN_INFO "ladpad: char 0x%02x\n", outchar); } /* After sending anything to the LCD we go back to LAD_NORM */ input_state = LAD_NORM; rs_state = RSDATA; } }}module_init(ladpad_init);module_exit(ladpad_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -