用户空间:
使用ioctl可以用来设置、获取设备的工作属性参数
ioctl(fd,cmd);
ioctl(fd,cmd,&arg);
内核空间:
.unlocked_ioctl = led_ioctl 为成员变量函数指针赋值
实验步骤:
vi led_drv.c
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#define LED_ON 0x10001
#define LED_OFF 0x10002
/*
*./test <on/off> <1/2/3/4>
* */
int main(int argc, char *argv[])
{
int fd = 0;
int cmd = 0;
int index = 0;
if(argc != 3)
{
printf("usage: %s <on/off> <1/2/3/4>\n", argv[0]);
return -1;
}
fd = open("/dev/myleds", O_RDWR);
if(fd < 0)
{
perror("open failed");
return -1;
}
printf("open myleds successed!\n");
if(strcmp(argv[1], "on") == 0)
cmd = 0x10001;
else if(strcmp(argv[1], "off") == 0)
cmd = 0x10002;
else
return -1;
index = strtoul(argv[2], NULL, 0);
if(index>4)
{
printf("usage: %s <on/off> <1/2/3/4>\n", argv[0]);
return -1;
}
ioctl(fd, cmd, &index);
close(fd);
return 0;
}
vi test.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/gpio.h>
#include <mach/platform.h>
#include <linux/uaccess.h>
MODULE_LICENSE("GPL");
#define LED_ON (0x10001)
#define LED_OFF (0x10002)
dev_t dev; //设备号
unsigned int major = 0; //主设备号
unsigned int minor = 5; //次设备号
struct cdev led_cdev;
typedef struct led_desc
{
char *name;//名称
int gpio;//管脚编号
}led_desc_t;
led_desc_t leds[]=
{
{"led1", PAD_GPIO_C+12},
{"led2", PAD_GPIO_C+7},
{"led3", PAD_GPIO_C+11},
{"led4", PAD_GPIO_B+26},
};
int led_open(struct inode *inode, struct file *filp)
{
return 0;
}
int led_release(struct inode *inode, struct file *filp)
{
return 0;
}
ssize_t led_write(struct file *filp, const char __user *buf,
size_t len, loff_t *offset)
{
return len;
}
ssize_t led_read(struct file *filp, char __user *buf,
size_t len, loff_t *offset)
{
return len;
}
long led_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int k_index = 0;
int ret = 0;
/*arg 4字节内存 其中存储了用户空间变量index的地址
*我们需要知道该地址对应的内存中存储的是1/2/3/4
*需要通过读取该内存空间才能知道其中存储的值
* */
ret = copy_from_user(&k_index, (const void __user *)arg, 4);
if(k_index>4)
{
return -EINVAL;
}
if(cmd == LED_ON){
gpio_set_value(leds[k_index-1].gpio, 0);
}else if(cmd == LED_OFF){
gpio_set_value(leds[k_index-1].gpio, 1);
}else{
return -EINVAL;
}
return 0;
}
struct file_operations led_fops =
{
.owner = THIS_MODULE,
.open = led_open,
.release = led_release,
.write = led_write,
.read = led_read,
.unlocked_ioctl = led_ioctl,
};
int __init led_drv_init(void)
{
int i = 0;
if(major)//静态
{
/*注册设备号*/
//dev = major<<20|minor;
dev = MKDEV(major, minor);
register_chrdev_region(dev, 1, "myleds");
}
else //动态
{
alloc_chrdev_region(&dev, minor, 1, "myleds");
printk("<2>" "major=%d minor=%d\n", MAJOR(dev), MINOR(dev));
}
/*初始化cdev变量*/
cdev_init(&led_cdev, &led_fops);
/*注册cdev变量*/
cdev_add(&led_cdev, dev, 1);
for(; i<ARRAY_SIZE(leds); i++)
{
/*申请GPIO管脚*/
gpio_request(leds[i].gpio, leds[i].name);
/*设置为输出模式*/
gpio_direction_output(leds[i].gpio, 1);
}
return 0;
}
void __exit led_drv_exit(void)
{
int i = 0;
for(; i<ARRAY_SIZE(leds); i++)
{
/*释放GPIO管脚*/
gpio_free(leds[i].gpio);
}
/*注销cdev变量*/
cdev_del(&led_cdev);
/*注销设备号*/
unregister_chrdev_region(dev, 1);
}
module_init(led_drv_init);
module_exit(led_drv_exit);
make
arm-cortex_a9-linux-gnueabi-gcc test.c
cp led_drv.ko ../../rootfs/
cp a.out ../../rootfs/
开发板执行
rmmod led_drv
nsmod led_drv.ko
mknod /dev/myleds c 243 5
./test on 1
./test off 1