/*_my*/ is added at the end
/*Button driver*/
/*Key resources used by mini2440*/
/******************************************************/
/* Key Corresponding IO Register Corresponding Interrupt Pin*/
/* K1 GPG0 EINT8 */
/* K2 GPG3 EINT11 */
/* K3 GPG5 EINT13 */
/* K4 GPG6 EINT14 */
/* K5 GPG7 EINT15 */
/* K6 GPG11 EINT19 */
/******************************************************/
/*We need to figure out who is the input*/
/*Here, the button controls the corresponding interrupt pin, thereby controlling the corresponding IO register*/
/*It is equivalent to information input from the outside*/
/*What we need to do is to take corresponding response actions based on the corresponding input information*/
/*This achieves the purpose of interrupt response*/
/*The core is to detect*/
/*So, how to detect?*/
/*What to detect?*/
/*How do you know what resources a device actually uses?*/
/*This is a very important question*/
/*I think you should look at the specific circuit schematic*/
/*Only by looking at the diagram can you understand the specific circuit connection*/
/*Thus, you can know the hardware resources required by the device*/
/*The manufacturer's schematics are usually more detailed*/
/*Referenced header file*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
/*define macro*/
#define BUTTON_MAJOR 221 /*Main device number, originally 232, I changed it to 221*/
#define DEVICE_NAME "buttons_my" /*Device name, originally it was buttons, I added _my*/
/*Define the description structure of button interrupt*/
/*It integrates the information of button interrupt*/
/*What do the various members mean?*/
struct button_irq_desc
{
int irq; /*interrupt number*/
/*interrupt number uniquely represents an interrupt*/
int pin; /*Interrupt control register*/
/*The value of this register is set by the interrupt pin*/
/*We want to read the control information from this register*/
int pin_setting; /*Interrupt pin*/
/*The level of this pin is controlled by the button*/
/*Thus, we finally control the value of the register by the button*/
int number; /*number*/
char *name; /*name*/
};
/*Specify the information of 6 buttons*/
static struct button_irq_desc button_irqs [] =
{
{{IRQ_EINT8,S3C2410_GPG0,S3C2410_GPG0_EINT8,0,"KEY1"}, /*K1*/
{IRQ_EINT11,S3C2410_GPG3,S3C2410_GPG3_EINT11,1,"KEY2"}, /*K2*/
{IRQ_EINT13,S3C2410_GPG5 ,S3C2410_GPG5_EINT13,2,"KEY3"}, /*K3*/
{IRQ_EINT14,S3C2410_GPG6,S3C2410_GPG6_EINT14,3,"KEY4"}, /*K4*/
{IRQ_EINT15,S3C2410_GPG7,S3C2410_GPG7_EINT15,4,"KEY5"}, /*K5*/
{IRQ_EINT19,S3C2410_GPG11,S3C2410_GPG11_EINT19,5,"KEY6"}, /*K6*/
}
/*In this way, resources are organized*/
/*In fact, here we not only organize hardware resources*/
/*We also incorporate certain software resources*/
/*Like interrupt numbers*/
/*key_values array*/
/*Stores the value of each key in the event of an interrupt*/
/*What does volatile mean?*/
/*This array is where we store the results of key operations, so it is very important*/
static volatile int key_values [] = {0,0,0,0,0,0};
/*What does the macro DECLARE_WAIT_QUEUE_HEAD() do?*/
/*This macro should create a waiting queue*/
/*The waiting queue is an important method of process scheduling*/
/*The waiting queue is also very interesting. button_waitq represents the queue for key waiting*/
/*That is to say, once a key is pressed, the process in its waiting queue will be activated to perform corresponding processing*/
/*Therefore, the key waiting queue, or the waiting queue set by the interrupt,*/
/*is a very important resource in interrupt processing, which greatly expands the ability of interrupt processing*/
static DECLARE_WAIT_QUEUE_HEAD(button_waitq); /*What is button_waitq?*/
/*Should be the name of the waiting queue*/
/*A flag indicating whether there is data in the key_values array, 0 means no data is readable, 1 means there is data to read*/
static volatile int ev_press = 0; /*Initial value is 0*/
/*Declaration of interrupt service routine buttons_interrupt()*/
/*When an interrupt is detected, the interrupt service routine will be executed*/
/*So how to detect an interrupt?*/
/*And when an interrupt occurs, how to know what kind of interrupt occurred?*/
/*There are many kinds of interrupts, which interrupt should the interrupt service routine serve?*/
/*Obviously, the interrupt number and the interrupt service routine should be linked to form a whole*/
/*This work can be done in the open function*/
/*Parameter irq---interrupt number*/
/*The interrupt service program should correspond to the interrupt number one by one*/
/*When an interrupt corresponding to a certain interrupt number occurs, the service program corresponding to the interrupt number will be called*/
/*Then, detecting the occurrence of the interrupt becomes a prerequisite*/
/*Parameter dev_id --- which button is it*/
static irqreturn_t buttons_interrupt(int irq,void *dev_id);
/*mini2440_buttons_open() function declaration*/
/*Specific function called by driver function open*/
/*The open function implements hardware initialization*/
/*and software initialization*/
/*Create a good environment for the operation of our keyboard device*/
static int mini2440_buttons_open(struct inode *inode,struct file *file);
/*Declaration of mini2440_buttons_close() function*/
/*Specific function called by release*/
/*Disassembly of device software environment*/
/*Specifically, the release of interrupts*/
/*Because interrupt resources are also valuable system resources, they must be released when not in use*/
static int mini2440_buttons_close(struct inode *inode,struct file *file);
/*Declaration of mini2440_buttons_read() function*/
/*Specific function called
by read*/ /*It reads the result of keyboard input*/
/*Essentially, it reads the value of key_values array*/
/*It completes the core function of keyboard as input device*/
/*Whether the array is readable or not should be judged according to the flag bit ev_press*/
/*If the array is readable, read the data into user buffer*/
/*If the array is not readable, the process enters the waiting queue and waits until the array is readable*/
/*The waiting queue mechanism is commonly used in interrupt management*/
/*Because some processes often need to wait for a certain event to occur*/
static int mini2440_buttons_read(struct file *filp,char __user *buff,size_t count,loff_t *offp);
/*Note that __user refers to the user space*/
/*The input result of the keyboard should be read into the user space*/
/*mini2440_buttons_poll() function declaration*/
/*The specific function called by poll*/
/*poll is essentially the calling function of select*/
/*If there is key data, select will return immediately*/
/*If there is no key data, wait*/
/*Essentially, this is the mechanism for the keyboard to wait for input*/
static unsigned int mini2440_buttons_poll(struct file *file,struct poll_table_struct *wait);
/*file_operations structure*/
/*Driver function settings*/
/*Set the previous driver functions separately*/
static struct file_operations mini2440_buttons_fops =
{
.owner = THIS_MODULE,
.open = mini2440_buttons_open, /*open()*/
.release = mini2440_buttons_close, /*release()*/
.read = mini2440_buttons_read, /*read()*/
.poll = mini2440_buttons_poll /*poll()*/
};
/*mini2440_buttons_init() function declaration*/
/*Specific function called by module_init*/
/*Initialization function when module is created*/
/*Main work is to register and create devices*/
/*Specific hardware initialization work can be omitted*/
/*Leave it to the function in fops*/
static int __init mini2440_buttons_init(void);
/*mini2440_buttons_exit() function declaration*/
/*Cleanup work when module is uninstalled*/
/*Mainly device uninstallation*/
static void __exit mini2440_buttons_exit(void);
/*Entry point when creating the module*/
module_init(mini2440_buttons_init);
/*Entry point when module is unloaded*/
module_exit(mini2440_buttons_exit);
/*Some information about the driver*/
MODULE_AUTHOR("http://www.arm9.net"); /*driver author*/
MODULE_DESCRIPTION("S3C2410/S3C2440 BUTTON Driver"); /*Description information*/
MODULE_LICENSE("GPL"); /*Agreement to be followed*/
/************************************************************************/
/*************************The following is the implementation of the previously declared function***********************/
/************************************************************************/
/************************mini2440_buttons_init()************************/
static int __init mini2440_buttons_init(void)
{
int ret; /*Return value of device registration*/
/*Register device driver*/
/*Device number, device name, and driver function*/
ret = register_chrdev(BUTTON_MAJOR,DEVICE_NAME,&mini2440_buttons_fops);
/*Handling registration failure*/
if(ret < 0)
{
printk(DEVICE_NAME " can't register major number\n");
return ret;
}
/*Create device*/
/*devfs_mk_cdev() function is the kernel mode device creation function*/
/*mknod is the user mode device creation function*/
devfs_mk_cdev(MKDEV(BUTTON_MAJOR,0),S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP,DEVICE_NAME);
printk(DEVICE_NAME " initialized\n");
return 0;
}
/******************mini2440_buttons_exit()****************************** /
static void __exit mini2440_buttons_exit(void)
{
/*Remove device*/
devfs_remove(DEVICE_NAME);
/*Cancel the device driver*/
unregister_chrdev(BUTTON_MAJOR,DEVICE_NAME);
}
/**********************mini2440_buttons_open()****************************** */
static int mini2440_buttons_open(struct inode *inode,struct file *file)
{
int i; /*loop variable, because there are 6 buttons*/
int err; /*Return value of interrupt registration function*/
/*Process each button separately, using a for loop*/
/*Specifically, it is necessary to connect the register and the corresponding pin*/
/*Connect the interrupt number and the corresponding interrupt service routine*/
/*This step is similar to the driver registration mentioned above*/
/*We can successfully call it interrupt registration*/
for(i = 0;i < sizeof(button_irqs)/sizeof(button_irqs[0]);i++)
{
/*Connection between register and interrupt pin*/
s3c2410_gpio_cfgpin(button_irqs[i].pin,button_irqs[i].pin_setting);
/*Interrupt registration*/
/*request_irq() function*/
/*Pay attention to its input parameters*/
/*&button_irqs[i] is the resource enjoyed by the interrupt*/
/*Will be passed to buttons_interrupt for processing*/
err = request_irq(button_irqs[i].irq,buttons_interrupt,NULL,button_irqs[i].name,(void *)&button_irqs[i]);
/*Setting the interrupt type*/
/*set_irq_type() function*/
/*What kind of interrupt does the IRQT_BOTHEDGE interrupt type represent?*/
/*There are several very important questions*/
/*After the interrupt is registered and its interrupt type is set, when an interrupt occurs,*/
/*when a button is pressed, can the system automatically detect that an interrupt has occurred?*/
/*After detecting that an interrupt has occurred, can it automatically identify which interrupt number it is?*/
/*If it knows which interrupt number it is, can it automatically call its interrupt service program?*/
/*The answers to these questions are enough to form the core of the interrupt handling mechanism of the Linux system*/
set_irq_type(button_irqs[i].irq,IRQT_BOTHEDGE);
/*Handling registration failure*/
if(err)
break; /*jump out of the loop*/
}
/*If a button interrupt registration fails*/
/*then the previously successfully registered interrupt needs to be dismantled*/
if(err)
{
i--; /*Return to the previous button processing*/
for(;i >=0; i--) /*Dismantle accordingly*/
{
/*Make the interrupt ineffective*/
disable_irq(button_irqs[i].irq);
/*Release interrupt resources*/
free_irq(button_irqs[i].irq,(void *)&button_irqs[i]);
}
return -EBUSY; /*The final return value if the interrupt registration is unsuccessful*/
}
return 0; /*Normal return*/
}
/**************************buttons_interrupt()*****************************/
/*This interrupt service routine sets the value of the key_values array every time it is interrupted*/
/*and sets the value of the array readable flag ev_press*/
/*and wakes up the process in the waiting queue*/
/*This is what interrupt processing often does*/
/*Here, the process that often waits in the waiting queue button_waitq is the array reading process*/
/*That is to say, the reading process has been waiting for key input when no data is read*/
/*The reading process is waiting, which does not mean that all processes are waiting. Other processes should do what they should do*/
static irqreturn_t buttons_interrupt(int irq,void *dev_id)
{
/*button_irq_desc structure variable*/
/*Process the incoming resources*/
struct button_irq_desc *button_irqs = (struct button_irq_desc *)dev_id;
/*Get the value of the register*/
/*This step is crucial*/
/*s3c2410_gpio_getpin() function directly gets the value of the register*/
/*Please note that pressing a button will cause two interrupts*/
/*Pressing is an interrupt, releasing is another interrupt*/
int up = s3c2410_gpio_getpin(button_irqs->pin);
/*Through the circuit schematic, we can know that when the button is not pressed, the interrupt pin should be at a high level*/
/*So the value of the register should be 1*/
/*It is also meaningful to take the variable up, indicating that the default state is the pop-up state*/
/*When the button is pressed, the value of the register should be 0*/
/*The following is to process the value of up*/
/*That is, to store the data in the key_values array after a certain transformation*/
if(up) /*If it is in the pop-up state*/
/*Then a large value must be stored in the corresponding position of the key_values array*/
/*At the same time, it is necessary to be able to identify which button it is from the value*/
key_values[button_irqs->number] = (button_irqs->number + 1) + 0x80;
/*For example, when the K1 key is turned on, key_values[0] is set to (0+1)+0x80, which is 129*/
else /*If the key is closed*/
/*Then store a very small number in the corresponding position of the key_values array*/
/*At the same time, be able to identify which key it is from the value*/
key_values[button_irqs->number] = (button_irqs->number + 1);
/*For example, if the K1 key is closed, key_values[0] is set to (0+1), which is 1*/
/*Set the array readable flag*/
ev_press = 1; /*Indicates that the array is readable*/
/*Wake up the dormant process?*/
/*The button_waitq queue stores the corresponding processing process*/
/*Such as the process of reading the value of the array*/
/*Pay attention to the usage of wake_up_interruptible() and other functions*/
wake_up_interruptible(&button_waitq);
/*return*/
return IRQ_RETVAL(IRQ_HANDLED); /*?*/
}
/************************mini2440_buttons_close()************************ *****/
static int mini2440_buttons_close(struct inode *inode,struct file *file)
{
int i; /*loop variable, need to operate several buttons*/
/*for loop, release interrupts for each key in turn*/
for(i = 0;i < sizeof(button_irqs)/sizeof(button_irqs[0]);i++)
{
/*Disable interrupt*/
disable_irq(button_irqs[i].irq);
/*Release resources*/
free_irq(button_irqs[i].irq,(void *)&button_irqs[i]);
}
/*return*/
return 0;
}
/************************mini2440_buttons_read()************************ ***/
/*Note that the read function only reads the interrupt value once, not continuously*/
/*To read continuously, you need to make a loop and keep calling the read function, but that is not what the driver should do*/
static int mini2440_buttons_read(struct file *filp,char __user *buff,size_t count,loff_t *offp)
{
unsigned long err; /*return value of copy_to_user() function*/
/*If there is no value in the key_values array, the process will sleep*/
/*Until an interrupt comes, the interrupt service routine will wake up the sleeping process to continue reading the value*/
/*Whether there is a value in the key_values array is determined by the ev_press flag*/
/*If there is a value, it is 1, if there is no value, it is 0*/
/*The process waiting queue mechanism is a method of process scheduling*/
if(!ev_press) /*flag is 0, that is, no data*/
{
if(filp->f_flags & O_NONBLOCK) /*??*/
return -EAGAIN;
else /*Process sleeps and is put into button_waitq waiting queue*/
/*Here, the ev_press flag is set to the flag of the sleeping process?*/
/*This is to facilitate the use of poll_wait function*/
/*That is, it is beneficial to select function*/
wait_event_interruptible(button_waitq,ev_press);
/*In the interrupt handling function, this process will be awakened*/
/*Before awakening, ev_press has been set to 1*/
/*The execution point after awakening starts here*/
}
/*The following is the processing situation when the flag bit is 1, that is, there is data to read*/
/*Then start reading data from user space*/
err = copy_to_user(buff,(const void *)key_values,min(sizeof(key_values),count));
/*Use of copy_to_user() function*/
/* Clear the key_values array */
memset((void *)key_values,0,sizeof(key_values));
/*Mark position 0*/
/*Indicates that it has been read*/
ev_press = 0;
/*Handling of err*/
if(err) /*read error*/
return -EFAULT;
else /*read correctly*/
/*return the number of bytes read*/
return min(sizeof(key_values),count);
}
/************************mini2440_buttons_poll()********************** */
static unsigned int mini2440_buttons_poll(struct file *file,struct poll_table_struct *wait)
{
unsigned int mask = 0; /* */
/*poll_wait() function*/
/*will monitor the processes in the process queue button_waitq*/
/*For example, if the flag ev_press of the process where mini2440_button_read is located is set to 1*/
/*then it will not wait any more*/
/*This is essentially the operating mechanism of the select function*/
poll_wait(file,&button_waitq,wait);
if(ev_press)
mask |= POLLIN | POLLRDNORM; /*??*/
return mask;
}
/*Button test program*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
/*Main function entry*/
int main(void)
{
int i; /*loop variable used for keyboard output*/
int buttons_fd; /*buttons device number*/
int key_value[4]; /*Values of four keys*/
/*Open the keyboard device file*/
buttons_fd = open("/dev/buttons",0); /*Open in mode 0*/
/* Enable error handling */
if(buttons_fd < 0) /*If an error occurs during opening, a negative value will be returned*/
{
perror("open device buttons"); /*perror function?*/
exit(1); /*return 1*/
}
/*for infinite loop, waiting for user input*/
/*This is a typical program execution method*/
for(;;)
{
fd_set rds; /*fd_set is a type defined in types.h, essentially an int type*/
/*rds is used to store the device number*/
int ret; /*local variable ret defined in for loop*/
FD_ZERO(&rds); /*rds initialization*/
/*Where is FD_ZERO defined?*/
FD_SET(buttons_fd,&rds); /*Assign the buttons device number to rds*/
/*Where is FD_SET defined?*/
/*Use the select system call to check whether data can be read from the /dev/buttons device*/
/*What does the select function do?*/
ret = select(buttons_fd + 1,&rds,NULL,NULL,NULL);
/*Return value ret*/
/*What is the specific meaning of the return value?*/
/*Processing of ret*/
if(ret < 0) /*When ret is less than 0*/
{
perror("select");
exit(1);
}
if(ret == 0) /*When ret is equal to 0*/
{
printf("Timeout.\n");
}
else /*Can read data*/
if(FD_ISSET(buttons_fd,&rds)) /*??*/
{
/*Read the data sent by the keyboard driver*/
/*key_value is consistent with the definition in the keyboard driver*/
int ret = read(buttons_fd,key_value,sizeof(key_value)); /*Note the difference between ret here and the previous ret*/
/*Note the characteristics of keyboard device reading*/
/*Processing of ret*/
if(ret != sizeof(key_value)) /*Not enough received*/
{
if(errno != EAGAIN) /*???*/
perror("read buttons\n");
continue;
}
else /*If received correctly, print to the standard terminal*/
{
for(i = 0;i < 4;i++) /*The loop variable i defined at the beginning*/
printf("K%d %s, key value = 0x%02x\n",i,(key_value[i] & 0x80) ? "released" : key_value[i] ? "pressed down" : "",key_value[i]);
/*Pay attention to the format of this series of outputs*/
}
}
}
/*Close the device*/
close(buttons_fd);
return 0; /*main function returns*/
}
END! !
Previous article:ARM optimization function parameter count
Next article:NAND FLASH ECC verification principle and implementation
Recommended ReadingLatest update time:2024-11-16 22:53
- Popular Resources
- Popular amplifiers
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- Innolux's intelligent steer-by-wire solution makes cars smarter and safer
- 8051 MCU - Parity Check
- How to efficiently balance the sensitivity of tactile sensing interfaces
- What should I do if the servo motor shakes? What causes the servo motor to shake quickly?
- 【Brushless Motor】Analysis of three-phase BLDC motor and sharing of two popular development boards
- Midea Industrial Technology's subsidiaries Clou Electronics and Hekang New Energy jointly appeared at the Munich Battery Energy Storage Exhibition and Solar Energy Exhibition
- Guoxin Sichen | Application of ferroelectric memory PB85RS2MC in power battery management, with a capacity of 2M
- Analysis of common faults of frequency converter
- In a head-on competition with Qualcomm, what kind of cockpit products has Intel come up with?
- Dalian Rongke's all-vanadium liquid flow battery energy storage equipment industrialization project has entered the sprint stage before production
- Allegro MicroSystems Introduces Advanced Magnetic and Inductive Position Sensing Solutions at Electronica 2024
- Car key in the left hand, liveness detection radar in the right hand, UWB is imperative for cars!
- After a decade of rapid development, domestic CIS has entered the market
- Aegis Dagger Battery + Thor EM-i Super Hybrid, Geely New Energy has thrown out two "king bombs"
- A brief discussion on functional safety - fault, error, and failure
- In the smart car 2.0 cycle, these core industry chains are facing major opportunities!
- The United States and Japan are developing new batteries. CATL faces challenges? How should China's new energy battery industry respond?
- Murata launches high-precision 6-axis inertial sensor for automobiles
- Ford patents pre-charge alarm to help save costs and respond to emergencies
- New real-time microcontroller system from Texas Instruments enables smarter processing in automotive and industrial applications
- TRUWB digital receiver performance based on ADC and its FPGA implementation.pdf
- Can the number of pulses of an ultrasonic generator driven by a transformer be accurately controlled?
- The helper2416 development board driver failed to create a device node
- 【Chuanglong TL570x-EVM】Review 01 - Unboxing
- Power Factor Correction
- Ultra-low standby power consumption < 90mW non-auxiliary AC/DC power supply reference design
- 3D Printer Project—STM32F7508-DK Environment Creation (I)
- Looking for the movie download website of "Miracle"!
- mosfet discrete devices
- MSP430 MCU Development Record (21)