# Include <Linux/fs. h> # Include <Linux/module. h> # Include <Linux/errno. h> # Include <Linux/kernel. h> # Include <Linux/init. h> # Include <Linux/cdev. h> # Include <Linux/ioport. h> # Include <Linux/PCI. h> # Include <ASM/uaccess. h> # Include <ASM/IO. h> # Include <ASM/IRQ. h> # Include <Linux/interrupt. h> # Include <ASM/Mach/IRQ. h> # Include <ASM/ARCH/regs-gpio.h> # Include <Linux/poll. h> Static int major = 0; Static struct class * CLS; /* Gpecon 0x56000040 */ /* Gpfcon 0x56000050 */ /* Gpgcon 0x56000060 */ Static volatile unsigned long * gpecon; Static volatile unsigned long * gpedat; Static volatile unsigned long * gpfcon; Static volatile unsigned long * gpfdat; Static volatile unsigned long * gpgcon; Static volatile unsigned long * gpgdat; Struct key_desc { Int IRQ; Int pin; Char * Name; Char key_val; Int irq_pin_val; }; Struct key_desc [] = { {Irq_eint0, s3c2410_gpf0, "K10", 1},/* release: 1, press: 0x81 */ {Irq_eint2, s3c2410_gpf2, "K7", 2},/* release: 2, press: 0x82 */ {Irq_eint11, s3c2410_gpg3, "K4", 3},/* release: 3, press: 0x83 */ {Irq_eint19, s3c2410_gpg11, "K1", 4},/* release: 4, press: 0x84 */ }; Volatile char key = 0; Static wait_queue_head_t button_waitq; # Define buf_len 10 Static char key_buf [buf_len]; Static volatile int r = 0, W = 0; Struct fasync_struct * buttons_async; Static struct timer_list buttons_timer; Struct key_desc * cur_kd; Static int isempty (void) { Return (r = W ); } Static int isfull (void) { Return (r = (W + 1) % buf_len )); } Static int putdata (char Val) { If (isfull ()) { Return-1; } Else { Key_buf [w] = val; W = (W + 1) % buf_len; Return 0; } } Static int getdata (char * P) { If (isempty ()) { Return-1; } Else { * P = key_buf [R]; R = (R + 1) % buf_len; Return 0; } } Static irqreturn_t buttons_irq (int irq, void * dev_id) { Cur_kd = (struct key_desc *) dev_id; Cur_kd-> irq_pin_val = s3c2410_gpio_getpin (cur_kd-> pin ); Mod_timer (& buttons_timer, jiffies + 5 );
Return irq_handled; } Static void buttons_timer_function (unsigned long data) { /* Confirm the button: Which button, press or release */ // For (I = 0; I <10000; I ++);/* wasting CPU */ /* Start a Timer: * Two elements: * 1. Time * 2. processing functions */ Char key; Int up; If (! Cur_kd) { Return; } Up = s3c2410_gpio_getpin (cur_kd-> pin); // gpfdat, gpgdat If (up! = Cur_kd-> irq_pin_val) { Return; } If (up) { Key = cur_kd-> key_val; } Else { Key = cur_kd-> key_val | 0x80; } // Printk ("Key = 0x % x \ n", key ); Putdata (key ); /* Wake up the application */ Wake_up_interruptible (& button_waitq ); Kill_fasync (& buttons_async, sigio, poll_in ); // Printk ("buttons_irq current % s, pid = % d \ n", current-> comm, current-> PID ); } Static atomic_t button_can_open = atomic_init (1 ); Int buttons_open (struct inode * inode, struct file * file) { Int I; Unsigned long flags; # If 0 If (! Atomic_dec_and_test (& button_can_open )) { Atomic_inc (& button_can_open ); Return-ebusy; } # Else Atomic_dec(& Button_can_open ); If (atomic_read (& button_can_open )! = 0) { Atomic_inc(& Button_can_open ); Return-ebusy; } # Endif /* Registration interrupted */ For (I = 0; I <4; I ++) { Request_irq (key_desc [I]. IRQ, buttons_irq, Irqf_shared | irqf_trigger_rising | irqf_trigger_falling, Key_desc [I]. Name, & key_desc [I]); } /* Set gpio as the interrupt pin * Set the trigger mode. * Enable interruption */ /* Set kscan0 (gpe11) as the output pin and output 0 */ * Gpecon & = ~ (0x3 <22 ); * Gpecon | = (1 <22 ); * Gpedat & = ~ (1 <11 ); Return 0; } Ssize_t buttons_read (struct file * file, char _ User * Buf, size_t size, loff_t * offset) { /* If no buttons occur, sleep */ /* The Key is equal to 0 to sleep. * The key is not 0 and does not sleep */ // Command // Printk ("Current % s, pid = % d before sleep \ n", current-> comm, current-> PID ); Char key; If (isempty () & (file-> f_flags & o_nonblock )) Return-eagain; Wait_event_interruptible (button_waitq ,! Isempty ()); // Printk ("Current % s, pid = % d after sleep \ n", current-> comm, current-> PID ); /* After being awakened, return the key value to the user program */ Getdata (& Key ); Copy_to_user (BUF, & Key, 1 ); /* Interrupted, key = xxx */ // Key = 0; Return 1; } Int buttons_close (struct inode * inode, struct file * file) { Int I; For (I = 0; I <4; I ++) { Free_irq (key_desc [I]. IRQ, & key_desc [I]); } Atomic_inc (& button_can_open ); Return 0; } Static unsigned int buttons_poll (struct file * file, struct poll_table_struct * Wait) { Static int CNT = 0; Printk ("buttons_poll CNT = % d \ n", CNT ++ ); Poll_wait (file, & button_waitq, wait);/* does not sleep, but only hangs into the queue */ Return isempty ()? 0: Pollin | pollrdnorm; } Static int buttons_fasync (int fd, struct file * filp, int on) { Int retval; Retval = fasync_helper (FD, filp, on, & buttons_async ); If (retval <0) Return retval; Return 0; } Static const struct file_operations buttons_fops = { . Owner = this_module, . Read = buttons_read, . Open = buttons_open,/* set the pin and apply for resources */ . Release = buttons_close, . Poll = buttons_poll, . Fasync = buttons_fasync, }; Int buttons_init (void) { Int I; Major = register_chrdev (0, "buttons", & buttons_fops ); /* Sysfs => mount to/sys */ CLS = class_create (this_module, "buttons_class "); Class_device_create (CLS, null, mkdev (Major, 0), null, "buttons "); // Mdev creates/dev/buttons Based on the content in/sys. Gpecon = ioremap (0x56000040,409 6 ); Gpedat = gpecon + 1; Gpfcon = gpecon + 4; Gpfdat = gpfcon + 1; Gpgcon = gpecon + 8; Gpgdat = gpgcon + 1; Init_waitqueue_head (& button_waitq ); Init_timer (& buttons_timer ); Buttons_timer.function = buttons_timer_function; Buttons_timer.expires = 0; Add_timer (& buttons_timer ); Return 0; } Void buttons_exit (void) { Unregister_chrdev (Major, "buttons "); Class_device_destroy (CLS, mkdev (Major, 0 )); Class_destroy (CLS ); Iounmap (gpecon ); Del_timer (& buttons_timer ); } Module_init (buttons_init ); Module_exit (buttons_exit ); Module_license ("GPL "); |