在线问答
直播中

dvd1478

11年用户 586经验值
擅长:可编程逻辑 电源/新能源 MEMS/传感技术 测量仪表 嵌入式技术 制造/封装 模拟技术 连接器 EMC/EMI设计 光电显示 存储技术 EDA/IC设计 处理器/DSP 接口/总线/驱动 控制/MCU RF/无线
私信 关注

【OK210试用体验】字符驱动之LED灯驱动

1、模块的入口函数分析
第一、使用 register_chrdev 注册字符设备,这个函数是内核提供的接口,内核已经帮我们实现了,不用我们操心。(注意了,有些 Linux 发行版本有可能会使用 register_chrdev_region 函数来注册字符设备。)
第二、使用内核提供的 class_create、device_create 函数分别创建类、在类下 创建设备。
第三、申请 GPIO资源
static int __init Sunfire_led_init(void)
{
int i;
int ret;
for(i=0; i
ret = gpio_request(led_gpios, "LED"); //drivers/gpio/gpiolib.c
if (ret) {
printk("%s: request GPIO %d for LED%d failed, ret = %dn", DEVICE_NAME,
led_gpios,i,ret);
return ret;
}
s3c_gpio_cfgpin(led_gpios, S3C_GPIO_OUTPUT);//archarmplat-samsunggpio-config.c
//gpio_direction_output(led_gpios,S5PV210_MP04_X_OUTP);
gpio_set_value(led_gpios, 1);
}
major = register_chrdev(0, "led_drv", &sf210_led_dev_fops);
led_class = class_create(THIS_MODULE, "led_drv");
led_device = device_create(led_class, NULL, MKDEV(major, 0), NULL, DEVICE_NAME);
printk(DEVICE_NAME" driver successfully probedn");
return 0;
}
2、模块的出口函数分析
驱动的出口函数的主要工作一般是注销 XXX、卸载 XXX,等等类似的清除工作,作为模块的出口函数,主要做了以下几件事:
第一、使用内核提供的 unregister_chrdev函数注销字符设备
第二、使用内核提供的 device_unregister、class_destroy 函数分别卸载类下的 设备、卸载类。
第三、释放 GPIO资源
static void __exit Sunfire_led_exit(void)
{
int i;
for (i = 0; i < LED_NUM; i++) {
gpio_free(led_gpios);
}
unregister_chrdev(major,"led_drv");
device_unregister(led_device);
class_destroy(led_class);
printk(DEVICE_NAME" driver successfully exitn");
}
3、结构体
1、file_operations 结构体
static struct file_operations sf210_led_dev_fops = {
.owner = THIS_MODULE,
.write     = sf210_led_write,
.open      = sf210_leds_open,
.release   = sf210_leds_close,
};
static struct class *led_class; //创建led_drv类
static struct device *led_device;//在led_drv类下创建/dev/DEVICE_NAME设备,供应用程序打开设备
int major; //注册字符设备
sf210_led_dev_fops - > major |->led_device
led_class |
4、设备的实际操作函数
static struct file_operations sf210_led_dev_fops = {
.owner = THIS_MODULE,
.write     = sf210_led_write,
.open      = sf210_leds_open,
.release   = sf210_leds_close,
};
关键是sf210_led_write
static ssize_t sf210_led_write(struct file * file, const char __user * buffer, size_t count, loff_t * ppos)
{
int val[2];
//printk(KERN_ALERT ": %d n", count);
if(count>=sizeof(val)){
   copy_from_user(&val, buffer, count);
   gpio_set_value(led_gpios[val[1]],!val[0]);
   printk(DEVICE_NAME": %d %dn", val[1], val[0]);
return 0;
}
return -EINVAL;
}
注意:应用空间和内核空间 的包括指针数据的传递不能单纯用 memcpy 函数,必须使用 copy_from_user
函数或 copy_to_user函数
5、应用函数
int main(int argc, char **argv)
{
int on;
int led_no;
int val[2];
int fd;
if (argc != 3 || sscanf(argv[1], "%d", &led_no) != 1 || sscanf(argv[2],"%d", &on) != 1 ||
    on < 0 || on > 1 || led_no < 1 || led_no > 4)
{
printf("Usage: sunfire_led_test led_num[1..4] 0|1n");
return -1;
}
fd = open("/dev/sfLeds", O_RDWR);
if (fd < 0)
{
printf("Can not open ledsn");
return -1;
}
val[0]=on;
val[1]=(led_no-1);
//ioctl(fd, on, (led_no-1));
write(fd, &val,sizeof(val)/sizeof(char));
close(fd);
return 0;
}
fd = open("/dev/sfLeds", O_RDWR); 注意使用的是O_RDWR
调用的函数
write(fd, &val,sizeof(val)/sizeof(char));
6、实验效果
10.png

回帖(2)

825843374

2015-9-29 13:37:44
感谢楼主的分享,学习学习
举报

dvd1478

2015-10-1 00:19:30
引用: 825843374 发表于 2015-9-29 13:37
感谢楼主的分享,学习学习

谢谢支持!~
举报

更多回帖

×
20
完善资料,
赚取积分