【OK210试用体验】字符驱动之LED灯驱动 - 在线问答 - 电子技术论坛 - 最好最受欢迎电子论坛!

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

dvd1478 ( 楼主 ) 2015-9-28 00:28:18  只看该作者 倒序浏览
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、实验效果


2个回复

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

谢谢支持!~
您需要登录后才可以回帖 登录 | 注册

本版积分规则


关闭

站长推荐上一条 /7 下一条

小黑屋|手机版|Archiver|电子发烧友 ( 湘ICP备2023018690号 )

GMT+8, 2024-11-13 08:34 , Processed in 0.622838 second(s), Total 65, Slave 46 queries .

Powered by 电子发烧友网

© 2015 bbs.elecfans.com

微信扫描
快速回复 返回顶部 返回列表