使用ioctrl编写按键驱动
1 上层:ioctl
2 #include <sys/ioctl.h>
3 int ioctl(int d, int request, ...);
4 驱动:ioctl
5 struct file_operations文件操作集合
6
7 ioctl命令:32bit的数值 通常分为4部分
8 linux-3.5\Documentation\ioctl\ioctl-number.txt
9
10 If you are adding new ioctl's to the kernel, you should use the _IO
11 macros defined in <linux/ioctl.h>:
12
13 _IO an ioctl with no parameters
14 _IOW an ioctl with write parameters (copy_from_user)
15 _IOR an ioctl with read parameters (copy_to_user)
16 _IOWR an ioctl with both write and read parameters.
17
18 _IO 没有任何参数的ioctl指令
19 _IOW 带有写数据参数的ioctl指令
20 _IOR 带有读数据参数的ioctl指令
21 _IOWR 带有读写数据和方向的ioctl指令
22
23 linux/ioctl.h:
24 #define _IOC(dir,type,nr,size) \
25 ((unsigned int) \
26 (((dir) << _IOC_DIRSHIFT) | \
27 ((type) << _IOC_TYPESHIFT) | \
28 ((nr) << _IOC_NRSHIFT) | \
29 ((size) << _IOC_SIZESHIFT)))
30
31 /* used to create numbers */
32 #define _IO(type,nr) _IOC(_IOC_NONE,(type),(nr),0)
33 #define _IOR(type,nr,size) _IOC(_IOC_READ,(type),(nr),sizeof(size))
34 #define _IOW(type,nr,size) _IOC(_IOC_WRITE,(type),(nr),sizeof(size))
35 #define _IOWR(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),sizeof(size))
36
37 /* used to decode them.. */
38 #define _IOC_DIR(nr) (((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK)
39 #define _IOC_TYPE(nr) (((nr) >> _IOC_TYPESHIFT) & _IOC_TYPEMASK)
40 #define _IOC_NR(nr) (((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK)
41 #define _IOC_SIZE(nr) (((nr) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK)
42
43 _IOC(dir,type,nr,size)
44 dir 方向
45 type 类型 幻数/魔数 magic
46 nr 指令编号
47 size 传送数据类型
1 #include <linux/kernel.h>
2 #include <linux/module.h>
3 #include <linux/fs.h>
4 #include <linux/device.h>
5 #include <asm/io.h>
6 #include <asm/uaccess.h>
7 #include <linux/cdev.h>
8 #include <linux/ioctl.h>
9 #include <linux/delay.h>
10
11 #define GPX3CON_PHY_ADDR 0x11000C60
12 #define GPX3DAT_PHY_ADDR 0x11000C64
13 #define GPX3PUD_PHY_ADDR 0x11000C68
14
15 static volatile unsigned long* gpx3con;
16 static volatile unsigned long* gpx3dat;
17 static volatile unsigned long* gpx3pud;
18
19 static dev_t button_dev;
20 static struct class* button_class;
21 static struct cdev* button_cdev;
22
23 static int button_open(struct inode *inod, struct file *fil)
24 {
25 return 0;
26 }
27
28 static int button_release(struct inode *inod, struct file *fil)
29 {
30 printk("button release......\n");
31
32 return 0;
33 }
34
35 static ssize_t button_read(struct file *fil, char __user *buf, size_t count, loff_t * offsets)
36 {
37 unsigned char button_status=0;
38
39 if(!(*gpx3dat & (1<<2)))
40 {
41 mdelay(100);
42 if(!(*gpx3dat & (1<<2)))
43 {
44 printk("button1 press\n");
45 button_status = 1;
46 }
47 }
48 else if(!(*gpx3dat & (1<<3)))
49 {
50 mdelay(100);
51 if(!(*gpx3dat & (1<<3)))
52 {
53 printk("button2 press\n");
54 button_status = 2;
55 }
56 }
57 else if(!(*gpx3dat & (1<<4)))
58 {
59 mdelay(100);
60 if(!(*gpx3dat & (1<<4)))
61 {
62 printk("button3 press\n");
63 button_status = 3;
64 }
65 }
66 else if(!(*gpx3dat & (1<<5)))
67 {
68 mdelay(100);
69 if(!(*gpx3dat & (1<<5)))
70 {
71 printk("button4 press\n");
72 button_status = 4;
73 }
74 }
75 else
76 button_status = 0;
77
78 return copy_to_user(buf, &button_status,1);
79 }
80
81 static struct file_operations button_fops =
82 {
83 .owner = THIS_MODULE,
84 .open = button_open,
85 .release = button_release,
86 .read = button_read,
87 };
88
89 static int __init buttondriver_init(void)
90 {
91 alloc_chrdev_region(&button_dev, 0,1, "buttondriver");
92
93 button_cdev = cdev_alloc();
94
95 button_cdev->count = 1;
96 button_cdev->dev = button_dev;
97 button_cdev->ops = &button_fops;
98 button_cdev->owner = THIS_MODULE;
99
100 cdev_add(button_cdev,button_dev,1);
101
102 button_class = class_create(THIS_MODULE,"button_class");
103 device_create(button_class,NULL,button_dev,NULL,"button");
104
105 gpx3con = ioremap(GPX3CON_PHY_ADDR,12);
106 gpx3dat = gpx3con + 1;
107 gpx3pud = gpx3con + 2;
108
109 *gpx3con &= ~(0xFFFF<<8);
110 *gpx3pud &= ~(0xFF<<4);
111 *gpx3pud |= 0xFF<<4;
112
113 return 0;
114 }
115
116 static void __exit buttondriver_exit(void)
117 {
118 iounmap(gpx3con);
119
120 device_destroy(button_class,button_dev);
121 class_destroy(button_class);
122
123 cdev_del(button_cdev);
124 unregister_chrdev_region(button_dev, 1);
125 }
126
127 module_init(buttondriver_init);
128 module_exit(buttondriver_exit);
129 MODULE_LICENSE("GPL");
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc,char *argv[])
{
int button_fd;
unsigned char button_status;
if(argc !=2)
{
printf("Usage:<%s> </dev/?node>\n",argv[0]);
return -1;
}
button_fd = open(argv[1],O_RDONLY);
while(1)
{
read(button_fd,&button_status,1);
if(button_status!=0)
printf("button %d\n",button_status);
// sleep(1);
}
}
按键控制led 上层测试程序
1 #include <stdio.h>
2 #include <sys/types.h>
3 #include <sys/stat.h>
4 #include <fcntl.h>
5 #include <unistd.h>
6 #include <stdlib.h>
7 #include <sys/ioctl.h>
8 #include <string.h>
9
10 #define LED_MAGIC 'L'
11 #define LED_ALL_ON _IO('L',0x0)
12 #define LED_ALL_OFF _IO('L',0x1)
13 #define LED_NUM_ON _IOW('L',0x2,unsigned char)
14 #define LED_NUM_OFF _IOW('L',0x3,unsigned char)
15
16 int main(int argc,char *argv[])
17 {
18 int led_fd,button_fd;
19 unsigned char button_status;
20
21 if(argc <3)
22 {
23 printf("Usage:<%s> <buttonnode> <lednode>\n",argv[0]);
24 return -1;
25 }
26
27 button_fd = open(argv[1],O_RDONLY);
28 led_fd = open(argv[2],O_WRONLY);
29
30 while(1)
31 {
32 read(button_fd,&button_status,1);
33
34 if(button_status==1)
35 ioctl(led_fd,LED_NUM_ON,0);
36 else if(button_status==2)
37 ioctl(led_fd,LED_NUM_ON,1);
38 else if(button_status==3)
39 ioctl(led_fd,LED_NUM_ON,2);
40 else if(button_status==4)
41 ioctl(led_fd,LED_NUM_ON,3);
42 else
43 ioctl(led_fd,LED_ALL_OFF);
44 // sleep(1);
45 }
46 }
附件led驱动 自己看看修改
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/cdev.h>
#include <linux/ioctl.h>
#define LED_MAGIC 'L'
#define LED_ALL_ON _IO('L',0x0)
#define LED_ALL_OFF _IO('L',0x1)
#define LED1_ON _IO('L',0x2)
#define LED1_OFF _IO('L',0x3)
#define LED2_ON _IO('L',0x4)
#define LED2_OFF _IO('L',0x5)
#define LED3_ON _IO('L',0x6)
#define LED3_OFF _IO('L',0x7)
#define LED4_ON _IO('L',0x8)
#define LED4_OFF _IO('L',0x9)
#define GPM4CON_PHY_ADDR 0x110002E0
#define GPM4DAT_PHY_ADDR 0x110002E4
static volatile unsigned long* gpm4con;
static volatile unsigned long* gpm4dat;
static dev_t led_dev;
static struct class* led_class;
static struct cdev* led_cdev;
static int led_open(struct inode *inod, struct file *fil)
{
return 0;
}
static int led_release(struct inode *inod, struct file *fil)
{
printk("led release......goodbye!!!!\n");
return 0;
}
static ssize_t led_write(struct file *fil, const char __user *buf, size_t count, loff_t *offsets)
{
return 0;
}
static long led_ioctl(struct file *fil, unsigned int cmd, unsigned long arg)
{
switch(cmd)
{
case LED_ALL_ON:
*gpm4dat &= ~(0xF<<0);break;
case LED_ALL_OFF:
*gpm4dat |= 0xF<<0;break;
case LED1_ON:
*gpm4dat &= ~(0x1<<0);break;
case LED1_OFF:
*gpm4dat |= 0x1<<0;break;
case LED2_ON:
*gpm4dat &= ~(0x1<<1);break;
case LED2_OFF:
*gpm4dat |= 0x1<<1;break;
case LED3_ON:
*gpm4dat &= ~(0x1<<2);break;
case LED3_OFF:
*gpm4dat |= 0x1<<2;break;
case LED4_ON:
*gpm4dat &= ~(0x1<<3);break;
case LED4_OFF:
*gpm4dat |= 0x1<<3;break;
default:
printk("cmd is error!!\n");
return -EINVAL;
}
return 0;
}
static struct file_operations led_fops =
{
.owner = THIS_MODULE,
.open = led_open,
.release = led_release,
.write = led_write,
.unlocked_ioctl = led_ioctl,
};
static int __init leddriver_init(void)
{
alloc_chrdev_region(&led_dev, 0,1, "leddriver");
led_cdev = cdev_alloc();
led_cdev->count = 1;
led_cdev->dev = led_dev;
led_cdev->ops = &led_fops;
led_cdev->owner = THIS_MODULE;
cdev_add(led_cdev,led_dev,1);
led_class = class_create(THIS_MODULE,"led_class");
device_create(led_class,NULL,led_dev,NULL,"led");
gpm4con = ioremap(GPM4CON_PHY_ADDR,8);
gpm4dat = gpm4con + 1;
*gpm4con &= ~(0xFFFF<<0);
*gpm4con |= 0x1111<<0;
*gpm4dat |= 0xF<<0;
return 0;
}
static void __exit leddriver_exit(void)
{
iounmap(gpm4con);
device_destroy(led_class,led_dev);
class_destroy(led_class);
cdev_del(led_cdev);
unregister_chrdev_region(led_dev, 1);
}
module_init(leddriver_init);
module_exit(leddriver_exit);
MODULE_LICENSE("GPL");