S5pv210 (tq210) Study Notes-key driver

Source: Internet
Author: User

After the previous configuration, s5pv210 can be successfully developed to enter the Linux console. With this environment, you can start to learn how to write and test the Linux driver. Learn about Linux Device Drivers, usually starting with character device drivers. Since Linux driver development has a relatively systematic architecture, it is difficult for me to elaborate on its development ideas in an article. For the sake of simplicity, starting from this article, the self-written driver will directly attach the code to make a statement of the deep feelings in the development process.

The first driver I wrote was led, but it didn't feel necessary to issue it. s5pv210 (tq210) key driver source code is for reference only:

 

#include <linux/types.h>#include <linux/module.h>#include <linux/cdev.h>#include <linux/fs.h>#include <linux/device.h>#include <linux/gpio.h>#include <linux/irq.h>#include <linux/interrupt.h>#include <linux/sched.h> #include <linux/wait.h>#include <linux/uaccess.h>static dev_t devno;static struct cdev cdev;static struct class* buttons_class;static struct device* buttons_device;static wait_queue_head_t button_waitq;static volatile int pressed = 0;static unsigned char key_val;struct key_desc{unsigned int  pin;unsigned char value;};static struct key_desc key_descs[8] = {[0] = {.pin = S5PV210_GPH0(0),.value = 0x00,},[1] = {.pin = S5PV210_GPH0(1),.value = 0x01,},[2] = {.pin = S5PV210_GPH0(2),.value = 0x02,},[3] = {.pin = S5PV210_GPH0(3),.value = 0x03,},[4] = {.pin = S5PV210_GPH0(4),.value = 0x04,},[5] = {.pin = S5PV210_GPH0(5),.value = 0x05,},[6] = {.pin = S5PV210_GPH2(6),.value = 0x06,},[7] = {.pin = S5PV210_GPH2(7),.value = 0x07,},};static irqreturn_t buttons_irq(int irq, void *dev_id){volatile struct key_desc *key = (volatile struct key_desc *)dev_id;if(gpio_get_value(key->pin)){key_val = key->value|0x80;}else{key_val = key->value;}pressed = 1;wake_up_interruptible(&button_waitq);return IRQ_RETVAL(IRQ_HANDLED);}static int buttons_open(struct inode *inode, struct file *file){int ret;ret = request_irq(IRQ_EINT(0),   buttons_irq, IRQ_TYPE_EDGE_BOTH, "key1", &key_descs[0]);if(ret)return ret;ret = request_irq(IRQ_EINT(1),   buttons_irq, IRQ_TYPE_EDGE_BOTH, "key2", &key_descs[1]);if(ret)return ret; ret = request_irq(IRQ_EINT(2),   buttons_irq, IRQ_TYPE_EDGE_BOTH, "key3", &key_descs[2]);if(ret)return ret; ret = request_irq(IRQ_EINT(3),   buttons_irq, IRQ_TYPE_EDGE_BOTH, "key4", &key_descs[3]);if(ret)return ret;ret = request_irq(IRQ_EINT(4),   buttons_irq, IRQ_TYPE_EDGE_BOTH, "key5", &key_descs[4]);if(ret)return ret;ret = request_irq(IRQ_EINT(5),   buttons_irq, IRQ_TYPE_EDGE_BOTH, "key6", &key_descs[5]);if(ret)return ret;ret = request_irq(IRQ_EINT(22),  buttons_irq, IRQ_TYPE_EDGE_BOTH, "key7", &key_descs[6]);if(ret)return ret;ret = request_irq(IRQ_EINT(23),  buttons_irq, IRQ_TYPE_EDGE_BOTH, "key8", &key_descs[7]);if(ret)return ret;return 0;}static ssize_t buttons_read(struct file * file, char __user *data, size_t count, loff_t *loff){if(count != 1){printk(KERN_ERR "The driver can only give one key value once!\n");return -ENOMEM;}wait_event_interruptible(button_waitq, pressed);pressed = 0;if(copy_to_user(data, &key_val, 1)){printk(KERN_ERR "The driver can not copy the data to user area!\n");return -ENOMEM;}return 0;}static int buttons_close(struct inode *inode, struct file *file){free_irq(IRQ_EINT(0),  &key_descs[0]);free_irq(IRQ_EINT(1),  &key_descs[1]);free_irq(IRQ_EINT(2),  &key_descs[2]);free_irq(IRQ_EINT(3),  &key_descs[3]);free_irq(IRQ_EINT(4),  &key_descs[4]);free_irq(IRQ_EINT(5),  &key_descs[5]);free_irq(IRQ_EINT(22), &key_descs[6]);free_irq(IRQ_EINT(23), &key_descs[7]);return 0;}struct file_operations buttons_ops = {.open    = buttons_open,.read    = buttons_read,.release = buttons_close,};int buttons_init(void){int ret;cdev_init(&cdev, &buttons_ops);cdev.owner = THIS_MODULE;ret = alloc_chrdev_region(&devno, 0, 1, "buttons");if(ret){printk(KERN_ERR "alloc char device region faild!\n");return ret;}ret = cdev_add(&cdev, devno, 1);if(ret){printk(KERN_ERR "add char device faild!\n");goto add_error;}buttons_class = class_create(THIS_MODULE, "buttonsdrv");if(IS_ERR(buttons_class)){printk(KERN_ERR "create class error!\n");goto class_error;}buttons_device = device_create(buttons_class, NULL, devno, NULL, "buttons");if(IS_ERR(buttons_device)){printk(KERN_ERR "create buttons device error!\n");goto device_error;}init_waitqueue_head(&button_waitq);return 0;device_error:class_destroy(buttons_class);class_error:cdev_del(&cdev);add_error:unregister_chrdev_region(devno,1);return -ENODEV;}void buttons_exit(void){device_destroy(buttons_class, devno);class_destroy(buttons_class);cdev_del(&cdev);unregister_chrdev_region(devno, 1);}module_init(buttons_init);module_exit(buttons_exit);MODULE_LICENSE("GPL");

Test code:

#include <stdio.h>#include <fcntl.h>int main(){int fd = open("/dev/buttons", O_RDWR);if(fd < 0){printf("open error");;return 0;}unsigned char key;while(1){read(fd, &key, 1);printf("The key = %x\n", key);}close(fd);}

Compared with the polling key driver, the interrupt key driver can greatly save CPU resources. Therefore, we recommend that you use the interrupt method.

However, this method has a drawback. If the buttons are not received, the program will always block here. Fortunately, the Linux Kernel provides the poll mechanism to set the delay time, if a key message is received during this time, the key value is obtained. Otherwise, the system times out and exits. It is very simple to enable the kernel to support poll. It is only possible to provide poll processing functions for Poll members of file_operations.

 

To enable the kernel to support poll, perform the following steps:

Add a poll header file

Compile the poll processing function:

static unsigned buttons_poll(struct file *file, poll_table *wait){unsigned int mask = 0;poll_wait(file, &button_waitq, wait);if (pressed)mask |= POLLIN | POLLRDNORM;return mask;}

Add the poll handler to file_operations:

 

 

.poll    = buttons_poll,

In this way, the driver supports the poll mechanism. The following is a poll test program:

 

 

#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <stdio.h>#include <poll.h>int main(int argc, char **argv){int fd;unsigned char key_val;int ret;struct pollfd fds[1];fd = open("/dev/buttons", O_RDWR);if (fd < 0){printf("can't open!\n");}fds[0].fd     = fd;fds[0].events = POLLIN;while (1){ret = poll(fds, 1, 5000);if (ret == 0){printf("time out\n");}else{read(fd, &key_val, 1);printf("key_val = 0x%x\n", key_val);}}return 0;}

In this way, the driver is completed. If you find other problems during the preparation and testing phase, leave a message to discuss them.

 

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.