# 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> # Include <Linux/delay. h>/* For udelay ()*/ # Include <Linux/time. h> # Include <ASM/delay. h>/* For udelay ()*/ 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; } } /* The kernel will call this processing function when appropriate */ Void buttons_work_func (Struct work_struct* Work) { /* Specific things, depending on the actual situation */ Int I; Static int CNT = 0; Int pre_jiffies, after_jiffies; Printk ("Enter buttons_work_func: % d \ n", CNT ++ ); Printk ("task % s pid = % d \ n", current-> comm, current-> PID ); Pre_jiffies = jiffies; For (I = 0; I <10000; I ++) Udelay (1000);/* 10 S */ // Printk ("after jiffies = % d \ n", jiffies ); After_jiffies = jiffies; Printk ("Two jiffies = % d, % d, Sub: % d \ n", pre_jiffies, after_jiffies, after_jiffies-pre_jiffies ); } /* Define a work queue */ StaticStruct work_structButtons_work; Static irqreturn_t buttons_irq (int irq, void * dev_id) { /* Execute the upper half */ Static int CNT = 0; Cur_kd = (struct key_desc *) dev_id; Cur_kd-> irq_pin_val = s3c2410_gpio_getpin (cur_kd-> pin ); Printk ("Enter buttons_irq: % d \ n", CNT ++ ); Mod_timer (& buttons_timer, jiffies + 5 ); /* Load the file to the inner and linked list to notify the kernel */ Schedule_work (& buttons_work );
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 ); Static declare_mutex (button_sem ); Int buttons_open (struct inode * inode, struct file * file) { Int I; Unsigned long flags; If (file-> f_flags & o_nonblock) { If (down_trylock (& button_sem )) Return-ebusy; } Else { Down (& button_sem ); } /* If no program has obtained the semaphore before, it will succeed. * Otherwise, sleep */ /* 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]); } /* Release the semaphore and wake up the process waiting for the semaphore */ Up (& button_sem ); 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 ); /* Initialize our work queue */ Init_work(& Buttons_work, Buttons_work_func ); 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 "); |