linux驱动摸索 --驱动框架初始化(结合韦东山视频教程)
一.驱动框架
初始化:insmod 加载
1.确定主设备号:
分为静态和动态分配,其中LED_GPIO_SIZE 表示支持的次设备号数目,一般默认为1. 相关实现代码如下:
- int result;
- dev_t dev;
- /*分配主设备号*/
- if (scull_major) /*静态分配一个主设备号*/
- {
- dev = MKDEV(scull_major,0);
- result = register_chrdev_region(dev,LED_GPIO_SIZE,DEVICE_NAME);
- }
- else /*动态分配一个主设备号*/
- {
- result = alloc_chrdev_region(&dev,0,LED_GPIO_SIZE,DEVICE_NAME);
- scull_major = MAJOR(dev);
- }
- if(result <0)
- {
- printk("LED:can not get major:%d\n",scull_major);
- return result;
- }
2.构造 file_operations 结构:结构成员对应相应的处理函数:
- static struct file_operations mini2440_leds_fops = {
- .owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
- .open = mini2440_leds_open,
- .write = mini2440_leds_write,
- };
3.将相关操作告诉内核:
内核用cdev结构来表示字符设备,cev_init()将文件操作和cdev关联。cdev_add()将之前生成的主次设备号和cdev连接在一起,
- led_class = class_create(THIS_MODULE,DEVICE_NAME);
- cdev_init(&led_gpio_cdev, &mini2440_leds_fops);
- result = cdev_add(&led_gpio_cdev, dev, 1);
- if(result <0)
- {
- printk("LED:cdev_add error\n");
- return result;
- }
- device_create(led_class, NULL, MKDEV(scull_major, 0), NULL, "led0");
卸载驱动 rmmod 卸载 代码实现如下:
- dev_t dev_id = MKDEV(scull_major, 0);
- /*卸载主设备号*/
- unregister_chrdev_region(dev_id, LED_GPIO_SIZE);
- device_destroy(led_class,MKDEV(scull_major, 0));
- cdev_del(&led_gpio_cdev);
- class_destroy(led_class);
最后附上一个较为完整的驱动框架,其中创建了主设备号和次设备号,驱动代码如下:
- #include <linux/module.h>
- #include <linux/kernel.h>
- #include <linux/fs.h>
- #include <linux/init.h>
- #include <linux/delay.h>
- #include <asm/uaccess.h>
- #include <asm/irq.h>
- #include <mach/io.h>
- #include <mach/regs-gpio.h>
- #include <mach/hardware.h>
- #include <linux/device.h>
- #include <linux/cdev.h>
- #define DEVICE_NAME "led_1"
- #define LED_GPIO_SIZE 4
- static int scull_major = 0;
- static struct class *led_class;
- static struct cdev led_gpio_cdev[LED_GPIO_SIZE];
- static int mini2440_leds_open(struct inode *inode, struct file *file)
- {
- int minor = MINOR(inode->i_rdev); //MINOR(inode->i_cdev);
- printk("/dev/led%d has opened\n",minor);
- return 0;
- }
- static ssize_t mini2440_leds_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
- {
- char val;
- int minor = MINOR(filp->f_dentry->d_inode->i_rdev);
- copy_from_user(&val, buf, 1);
- printk("/dev/led%d write the val = %d\n",minor,val);
- return 0;
- }
- static struct file_operations mini2440_leds_fops = {
- .owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
- .open = mini2440_leds_open,
- .write = mini2440_leds_write,
- };
- /*
- * 执行insmod命令时就会调用这个函数
- */
- static int mini2440_leds_init(void)
- {
- int result,i;
- dev_t dev;
- /*分配主设备号*/
- if (scull_major) /*静态分配一个主设备号*/
- {
- dev = MKDEV(scull_major,0);
- result = register_chrdev_region(dev,LED_GPIO_SIZE,DEVICE_NAME);
- }
- else /*动态分配一个主设备号*/
- {
- result = alloc_chrdev_region(&dev,0,LED_GPIO_SIZE,DEVICE_NAME);
- scull_major = MAJOR(dev);
- }
- if(result <0)
- {
- printk("LED:can not get major:%d\n",scull_major);
- return result;
- }
- led_class = class_create(THIS_MODULE,DEVICE_NAME);
- if (IS_ERR(led_class)) {
- return PTR_ERR(led_class);
- }
- for (i=0; i<LED_GPIO_SIZE;i++)
- {
- cdev_init(&led_gpio_cdev[i], &mini2440_leds_fops);
- result = cdev_add(&led_gpio_cdev[i], (dev+i), 1);
- if(result <0)
- {
- printk("LED:cdev_add error\n");
- return result;
- }
- device_create(led_class, NULL, MKDEV(scull_major, i), NULL, "led%d",i);
- }
- return 0;
- }
- /*
- * 执行rmmod命令时就会调用这个函数
- */
- static void mini2440_leds_exit(void)
- {
- int i;
- dev_t dev_id = MKDEV(scull_major, 0);
- /*卸载主设备号*/
- unregister_chrdev_region(dev_id, LED_GPIO_SIZE);
- for(i=0;i<LED_GPIO_SIZE;i++)
- {
- device_destroy(led_class,MKDEV(scull_major, i));
- cdev_del(&led_gpio_cdev[i]);
- }
- class_destroy(led_class);
- }
- /* 这两行指定驱动程序的初始化函数和卸载函数 */
- module_init(mini2440_leds_init);
- module_exit(mini2440_leds_exit);
- /* 描述驱动程序的一些信息,不是必须的 */
- MODULE_LICENSE("GPL");
linux 测试代码:
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <stdio.h>
- /*
- * ledtest <dev> <on|off>
- */
- void print_usage(char *file)
- {
- printf("Usage:\n");
- printf("%s <dev> <on|off>\n",file);
- printf("eg. \n");
- printf("%s /dev/led0 a\n", file);
- printf("%s /dev/led1 b\n", file);
- printf("%s /dev/led2 c\n", file);
- printf("%s /dev/led3 d\n", file);
- }
- int main(int argc, char **argv)
- {
- int fd;
- char* filename;
- char val;
- if (argc != 3)
- {
- print_usage(argv[0]);
- return 0;
- }
- filename = argv[1];
- fd = open(filename, O_RDWR);
- if (fd < 0)
- {
- printf("error, can't open %s\n", filename);
- return 0;
- }
- if (!strcmp("a", argv[2]))
- {
- val = 10;
- write(fd, &val, 1);
- }
- else if (!strcmp("b", argv[2]))
- {
- val = 11;
- write(fd, &val, 1);
- }
- else if (!strcmp("c", argv[2]))
- {
- val = 12;
- write(fd, &val, 1);
- }
- else if (!strcmp("d", argv[2]))
- {
- val = 13;
- write(fd, &val, 1);
- }
- return 0;
- }
linux驱动摸索 --驱动框架初始化(结合韦东山视频教程)的更多相关文章
- 【linux】驱动-5-驱动框架分层分离&实战
目录 前言 5. 分离分层 5.1 回顾-设备驱动实现 5.2 分离分层 5.3 设备 5.4 驱动 5.5 系统,模块 5.6 Makefile 参考: 前言 5. 分离分层 本章节记录实现LED驱 ...
- Linux下USB驱动框架分析【转】
转自:http://blog.csdn.net/brucexu1978/article/details/17583407 版权声明:本文为博主原创文章,未经博主允许不得转载. http://www.c ...
- linux块设备驱动---概念与框架(转)
基本概念 块设备(blockdevice) --- 是一种具有一定结构的随机存取设备,对这种设备的读写是按块进行的,他使用缓冲区来存放暂时的数据,待条件成熟后,从缓存一次性写入设备或者从设备一次性 ...
- Linux内核USB驱动【转】
本文转载自:http://www.360doc.com/content/12/0321/14/8363527_196286673.shtml 注意,该文件是2.4的内核的驱动源文件,并不保证在2.6内 ...
- 深入理解Linux字符设备驱动
文章从上层应用访问字符设备驱动开始,一步步地深入分析Linux字符设备的软件层次.组成框架和交互.如何编写驱动.设备文件的创建和mdev原理,对Linux字符设备驱动有全面的讲解.本文整合之前发表的& ...
- Linux块设备驱动(一) _驱动模型
块设备是Linux三大设备之一,其驱动模型主要针对磁盘,Flash等存储类设备,本文以3.14为蓝本,探讨内核中的块设备驱动模型 框架 下图是Linux中的块设备模型示意图,应用层程序有两种方式访问一 ...
- linux usb总线驱动(一)
目录 linux usb总线驱动框架 USB 介绍 传输类型 控制器接口 2440接口 基本流程 alloc_dev choose_address hub_port_init usb_get_devi ...
- Linux网络设备驱动 _驱动模型
Linux素来以其强大的网络功能著名,同时, 网络设备也作为三大设备之一, 成为Linux驱动学习中必不可少的设备类型, 此外, 由于历史原因, Linux并没有强制对网络设备贯彻其"一切皆 ...
- EDK II之USB总线驱动的实现框架
本文简单介绍一下UEFI中USB驱动的实现框架: 下图是USBD向上层驱动提供的接口: 1.从图中我们可以看出,USBDI的实现主要通过调用HCDI实现 和 访问USB_INTERFACE结构体(该结 ...
随机推荐
- bzoj 2753 最小生成树变形
我们根据高度建图,将无向边转化为有向边 首先对于第一问,直接一个bfs搞定,得到ans1 然后第二问,我们就相当于要求找到一颗最小生成树, 满足相对来说深度小的高度大,也就是要以高度为优先级 假设现在 ...
- 爆破phpmyadmin小脚本
#!usr/bin/env python #encoding: utf-8 #by i3ekr import requests headers = {'Content-Type':'applicati ...
- 逐步实现python版wc命令
Python 如何处理管道输入输出 sys.stdin 等于打开了一个文件对象,所有输入的文件都会写入到标准输入文件中(键盘) sys.stdout 等于打来了一个文件对象,使用.write()把信息 ...
- 【bzoj1086】王室联邦
我以为树分块什么的必有高论,结果居然是个暴力…… 方法也很简单,我看下每个节点dfs的时候是否已经大于k个,大于的话我就新开一块. 注意dfs的时候当前节点不能放进子树的块中. #include< ...
- 1.hadoop环境搭建以及配置
提前说明一下:由于环境的配置搞得我很头疼,所以记录下来.并不是零基础,像hadoop的由来.发展史.结构.各个组件,这里都没有介绍,只是为了自己能够在忘了的时候回忆起来,所以记录下来 如何在linux ...
- win 7 浏览器被篡改小插曲
今天下班回家,打开台式机发现IE,火狐都被篡改了.作为运维都会有点强迫症.这是个桌面系统,实在是没兴趣捣鼓.但是还是没办法,经常要用.等我下次有空了,直接换linux好了. 于是开始排查问题吧: 1. ...
- Java中的标记接口(zz)
1.什么是标记接口? Java中把没有定义任何方法和常量的接口称之为标记接口,我们经常使用的比较多的是“”Serializable“”,这个接口也是没有定义人任何方法和常量的. 2.标记接口的作用? ...
- AC日记——Rmq Problem bzoj 3339
3339 思路: 恶心: 代码: #include <cstdio> #include <cstring> #include <iostream> #include ...
- Jquery学习之路(三) 实现弹出层插件
弹出层的应用还是比较多的,登陆,一些同页面的操作,别人的总归是别人的,自己的才是自己的,所以一直以来想写个弹出层插件.不多废话,直接开始吧! 不想看可以在这里直接下载源码xsPop.zip 1:遮罩层 ...
- vi相关内容
vi显示行号: 第一种是,手动显示:在vim命令行模式下输入 :set nu 取消显示:在vim命令行模式下输入: set nonu 第二种是,永久自动显示:我们修改一个配置文件. 我们输入命令:vi ...