# Define delinuxmodule. h # define delinuxinit. h # define delinuxmm. h # define delinuxslab. h # define delinuxtypes. h # define delinuxsemaphore. h # define delinuxcdev. h # define delinuxfs. h # define delinuxsemaphore. h # define delinuxirq. h # includeasm
# Include linux/module. h # include linux/init. h # include linux/mm. h # include linux/slab. h # include linux/types. h # include linux/semaphore. h # include linux/cdev. h # include linux/fs. h # include linux/semaphore. h # include linux/irq. h # include asm
# Include
# Include
# Include
# Include
# Include
# Include
# Include
# Include
# Include
# Include
# Include
# Include
# Include
# Include
# Include
# Include
# Include
# Include
# Include
# Include
# Define LED_MAJOR 250
# Define LED_NAME "leds"
# Define KEY_COUNT 4
# Define KEY_DELAY HZ/50
DECLARE_WAIT_QUEUE_HEAD (r_wait); // initialize the waiting queue
// Wait_queue_head_t r_wait;
// Init_waitqueue_head (& r_wait );
Static struct timer_list key_timers [KEY_COUNT]; // defines the timer.
Static volatile bool ide.pdf;
Static void buttons_timer (unsigned long );
Static unsigned long led_table [] = {
S3C2410_GPB (5 ),
S3C2410_GPB (6 ),
S3C2410_GPB (7 ),
S3C2410_GPB (8 ),
}; // Bit address
Static unsigned int led_cfg_table [] = {
S3C2410_GPIO_OUTPUT,
S3C2410_GPIO_OUTPUT,
S3C2410_GPIO_OUTPUT,
S3C2410_GPIO_OUTPUT,
}; // The led is the input
Struct button_irq_key {
Int irq;
Int pin;
Unsigned long flags;
Char * name;
};
Static struct button_irq_key button_irqs [] = {
{IRQ_EINT8, S3C2410_GPG (0), ir1__trigger_falling, "key1 "},
{IRQ_EINT11, S3C2410_GPG (3), ir1__trigger_falling, "key2 "},
{IRQ_EINT13, S3C2410_GPG (5), ir1__trigger_falling, "key3 "},
{IRQ_EINT14, S3C2410_GPG (6), ir1__trigger_falling, "key4 "},
};
Static volatile int press_cnt [] = {0, 0, 0 };
Static volatile int pressed = 0;
Struct leds_cdev
{
Struct cdev;
Struct semaphore sem;
};
Int leds_major = LED_MAJOR;
Struct leds_cdev dev;
Static irqreturn_t buttons_interrupt (int irq, void * dev_id) // key Interrupt Processing Function
{
// Volatile int * press_count = (volatile int *) dev_id;
// Disable_irq (irq );
Int key = 0;
Switch (irq ){
Case 52:
Key = 0;
Break;
Case 55:
Key = 1;
Break;
Case 57:
Key = 2;
Break;
Case 58:
Key = 3;
Break;
Default: break;
}
Key_timers [key]. data = key;
Mod_timer (& key_timers [key], jiffies + KEY_DELAY );
Printk (KERN_EMERG "irq success ");
Return IRQ_HANDLED;
}
Static void buttons_timer (unsigned long arg) // The timer interrupt processing function, deshake implementation
{
Int key = arg;
Int condition;
Int nf;
Condition = s3c2410_gpio_getpin (button_irqs [key]. pin );
If (! Condition)
{
While (! S3c2410_gpio_getpin (button_irqs [key]. pin ));
Key_timers [key]. expires = jiffies + KEY_DELAY;
Add_timer (& key_timers [key]);
Ide.pdf = 1;
Printk (KERN_EMERG "lower is appear ");
} Else {
If (! Ide.pdf)
Return;
Press_cnt [key] + = 1;
Nf = press_cnt [key] % 2;
S3c2410_gpio_setpin (led_table [key], nf );
Pressed = 1;
Wake_up_interruptible (& r_wait );
Ide.pdf = 0;
Printk (KERN_EMERG "up is appear % d", nf );
// Enable_irq (button_irqs [key]. irq );
}
// Printk (KERN_EMERG "success of interruptible ");
}
Static int led_buttons_open (struct inode * inode, struct file * filp)
{
Int I;
Int err;
For (I = 0; I <sizeof (button_irqs)/sizeof (button_irqs [0]); I ++ ){
Err = request_irq (button_irqs [I]. irq, buttons_interrupt,
Button_irqs [I]. flags, button_irqs [I]. name, (void *) & press_cnt [I]); // request interruption
If (err)
Break;
/* Init_timer (& key_timers [I]);
Key_timers [I]. data = I;
Key_timers [I]. function = buttons_timer;
*/
Setup_timer (& key_timers [I], buttons_timer, I); initialize the timer
}
// Key_timers [0]. expires = jiffies + 3 * HZ;
// Add_timer (& key_timers [0]);
If (err ){
I --;
For (; I> = 0; I --)
Free_irq (button_irqs [I]. irq, (void *) press_cnt [I]);
Return-EBUSY;
}
Return 0;
}
Static ssize_t led_buttons_read (struct file * filp, char _ user * buf, size_t count, loff_t * ppos)
{
Unsigned long err;
Wait_event_interruptible (r_wait, pressed );
Pressed = 0;
Err = copy_to_user (buf, (const void *) press_cnt, sizeof (press_cnt ));
Memset (void *) press_cnt, 0, sizeof (press_cnt ));
Return err? -EFAULT: 0;
}
Static int led_buttons_close (struct inode * inode, struct file * filp)
{
Int I;
For (I = 0; I <sizeof (button_irqs)/sizeof (button_irqs [0]); I ++ ){
Free_irq (button_irqs [I]. irq, (void *) & press_cnt [I]); // release the interrupt number
Del_timer (& key_timers [I]);
}
Return 0;
}
Static int leds_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, unsigned long arg)
{
Switch (cmd)
{
Case 0:
If (arg> 4 ){
Return-EINVAL;
}
Down (& dev. sem );
S3c2410_gpio_setpin (led_table [arg], 0 );
Up (& dev. sem );
Return 0;
Case 1:
If (arg> 4 ){
Return-EINVAL;
}
Down (& dev. sem );
S3c2410_gpio_setpin (led_table [arg], 1 );
Up (& dev. sem );
Return 0;
Default:
Return-EINVAL;
}
}
Struct file_operations cdev_fops = {
. Owner = THIS_MODULE,
. Ioctl = leds_ioctl,
. Open = led_buttons_open,
. Read = led_buttons_read,
. Release = led_buttons_close,
};
Static void leds_setup (struct leds_cdev * dev, int index)
{
Int err, devno = MKDEV (leds_major, index );
Cdev_init (& dev-> cdev, & cdev_fops );
Dev-> cdev. owner = THIS_MODULE;
Dev-> cdev. ops = & cdev_fops;
Err = cdev_add (& dev-> cdev, devno, 1 );
If (err)
Printk (KERN_NOTICE "Error % d adding LED % d \ n", err, index );
}
Static int _ init dev_init (void) // module initialization and Registration
{
Int result;
Int I;
// Struct class * my_class;
Dev_t devno = MKDEV (leds_major, 0 );
For (I = 0; I <4; I ++ ){
S3c2410_gpio_cfgpin (led_table [I], led_pai_table [I]);
S3c2410_gpio_setpin (led_table [I], 0 );
}
If (leds_major)
Result = register_chrdev_region (devno, 1, "leds ");
Else {
Result = alloc_chrdev_region (& devno, 0, 1, "leds ");
Leds_major = devno;
}
If (result <0)
Return result;
Leds_setup (& dev, 0 );
Sema_init (& dev. sem, 1 );
/* My_class = class_create (THIS_MODULE, LED_NAME );
If (IS_ERR (my_class ))
{
Printk ("Err: failed in creating class. \ n ");
Return-1;
}
Device_create (my_class, NULL, MKDEV (leds_major, 0), LED_NAME, 0 );
*/
Return 0;
}
Void _ exit dev_exit (void)
{
Cdev_del (& dev. cdev );
Unregister_chrdev_region (MKDEV (leds_major, 0), 1 );
}
Module_init (dev_init );
Module_exit (dev_exit );
MODULE_LICENSE ("GPL ");
MODULE_AUTHOR ("emperor ");
MODULE_DESCRIPTION ("led module ");
Independent Analysis
Pass the test
If there is a BUG, let's look at it and learn from each other through mutual improvement.