Buttons-atomic operation (atomic) for character Devices)

Source: Internet
Author: User

Buttons_atomic.c

# 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 ");

 

 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.