在上一篇中我们已经了解了字符设备驱动的原理,也了解了应用层调用内核函数的机制,但是我们每次操作设备,都必须首先通过mknod命令创建一个设备文件名,比如说我们要打开u盘,硬盘等这些设备,难道我们还要自己创建,就如同刘老师常说的一句话,这也太山寨了吧,所以我们今天我们来点比较专业的,让函数帮我们自动创建;

  在Linux 下,设备和驱动通常都需要挂接在一种总线上,总线有PCI、USB、I2C、SPI 等等,总线是处理器和设备之间的通道,在设备模型中,所有的设备都通过总线相连,一总线来管理设备和驱动函数;

  因此我们先了解一下sys下的目录

  block:用于管理块设备,系统中的每一个块设备会在该目录下对应一个子目录;

  bus:用于管理总线,没注册一条总线,在该目录下有一个对应的子目录,其中,每个总线子目录下会有两个子目录:devices和drivers。

  devices包含里系统中所有属于该总线的的设备。

  drivers包含里系统中所有属于该总线的的驱动。

  class:将系统中的设备按功能分类。

  devices:该目录提供了系统中设备拓扑结构图。

  dev:该目录已注册的设备节点的视图。

  kernel:内核中的相关参数。

  module:内核中的模块信息。

  fireware:内核中的固件信息。

  Fs:描述内核中的文件系统。

  下面的代码是我们在sys/class中创建一个名为dog的类,然后在创建一个设备(wangcai);

 #include <linux/init.h>
#include <linux/module.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/err.h> MODULE_LICENSE("GPL");
MODULE_AUTHOR("bunfly"); struct class *dog;
struct device *wangcai; int bunfly_init()
{
dog = class_create(THIS_MODULE, "dog");//创建一个dog类
if(IS_ERR(dog)) {
PTR_ERR(dog);
return ;
} wangcai = device_create(dog, NULL, MKDEV(, ), NULL, "wangcai%d", );//创建一个名为旺财的设备
if(IS_ERR(wangcai)) {
PTR_ERR(wangcai);
return ;
} return ;
} int bunfly_exit()
{
printk("this is bunfly_exit\n"); return ;
} module_init(bunfly_init);
module_exit(bunfly_exit);

  在实际的工作中我们一般都不需要创建类,设备等,linux系统都为常见的设备分好了类,而设备厂商都已经提供了,我们做的就是来驱动这些设备;在sys/class类中我们经常用的就是misc(杂项类)

  杂项设备也是在嵌入式系统中用得比较多的一种设备驱动,其定义如下:

  struct device;  

 struct miscdevice  {
int minor; //次设备号
const char *name; //设备名
const struct file_operations *fops;//文件操作
struct list_head list; //形成链表
struct device *parent;
struct device *this_device;
const char *nodename;
mode_t mode;
}; extern int misc_register(struct miscdevice * misc); //混杂设备注册
extern int misc_deregister(struct miscdevice *misc); //混杂设备注销 #define MODULE_ALIAS_MISCDEV(minor) \
MODULE_ALIAS("char-major-" __stringify(MISC_MAJOR) \
"-" __stringify(minor))
#endif

  下面代码是在misc下注册一个名为bunfly_led的设备;插入模块后,在/dev下生成一个名为bunfly_led的设备名

  

 #include <linux/init.h>
#include <linux/module.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/miscdevice.h> MODULE_LICENSE("GPL");
MODULE_AUTHOR("bunfly"); struct file_operations fops;//方法
struct miscdevice led; int bunfly_init()
{
led.name = "bunfly_led";//设备名
led.fops = &fops;//关联方法
misc_register(&led);//在杂项类中注册led return ;
} int bunfly_exit()
{
printk("this is bunfly_exit\n");
misc_deregister(&led);//注销 return ;
} module_init(bunfly_init);
module_exit(bunfly_exit);

  下面代码的功能是用ioctl()函数控制led灯,格式:./ioctl /dev/bunfly_led 0 (灯亮)  | 1(灯灭)

 #include <stdio.h>
#include <string.h>
#include <fcntl.h> //输入 ./ioctl /dev/bunly_led 1(灯灭) : 0(灯亮)
int main(int argc, char *argv[])
{
if(argc != ) {
printf("using %s <devname> 1:0\n", argv[]);
return ;
} int fd = ;
fd = open(argv[], O_RDWR);
if(fd < ) {
perror("open");
return ;
} //argv【2】为字符,需要atoi转换为数字
ioctl(fd, atoi(argv[]));
close(fd);
return ;
}

  内核中:

  

 #include <linux/init.h>
#include <linux/module.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/io.h>
#include <linux/gpio.h> MODULE_LICENSE("GPL");
MODULE_AUTHOR("bunfly"); int bunfly_open(struct inode *n, struct file *fp);
long bunfly_ioctl(struct file *fp, unsigned int num, unsigned long vlaue);
void led_on();
void led_off(); struct file_operations fops;//方法
struct miscdevice led; unsigned long gpio_virt;
unsigned long *gpm4con, *gpm4dat; int bunfly_init()
{
fops.open = bunfly_open;//调用系统函数
fops.unlocked_ioctl = bunfly_ioctl; gpio_virt = ioremap(0x11000000, SZ_4K);//led物理地址到虚拟地址的映射
gpm4con = gpio_virt + 0x02e0;
gpm4dat = gpio_virt + 0x02e4; led.name = "bunfly_led";
led.fops = &fops;
misc_register(&led);//注册杂项类设备led return ;
} int bunfly_exit()
{
printk("this is bunfly_exit\n");
misc_deregister(&led);//注销设备 return ;
} module_init(bunfly_init);
module_exit(bunfly_exit); int bunfly_open(struct inode *n, struct file *fp)
{
printk("this is bunfly_open\n");
return ;
} long bunfly_ioctl(struct file *fp, unsigned int num, unsigned long vlaue)
{
if(num == ) {
led_on();
}
else {
if(num == ) {
led_off();
}
else {
printk("unkonw command %d\n", num);
}
} return ;
} void led_on()
{
*gpm4con &= ~0xffff;
*gpm4con |= 0x1111;
*gpm4dat = 0x0;
} void led_off()
{
*gpm4con &= ~0xffff;
*gpm4con |= 0x1111;
*gpm4dat = 0xf; }

linux设备驱动之字符设备驱动模型(2)的更多相关文章

  1. 【转】深入浅出:Linux设备驱动之字符设备驱动

    深入浅出:Linux设备驱动之字符设备驱动 一.linux系统将设备分为3类:字符设备.块设备.网络设备.使用驱动程序: 字符设备:是指只能一个字节一个字节读写的设备,不能随机读取设备内存中的某一数据 ...

  2. 手把手教Linux驱动3-之字符设备架构详解,有这篇就够了

    一.Linux设备分类 Linux系统为了管理方便,将设备分成三种基本类型: 字符设备 块设备 网络设备 字符设备: 字符(char)设备是个能够像字节流(类似文件)一样被访问的设备,由字符设备驱动程 ...

  3. Linux驱动设计——字符设备驱动(一)

    Linux字符设别驱动结构 cdev结构体 struct cdev { struct kobject kobj; struct module *owner; const struct file_ope ...

  4. Linux 设备驱动之字符设备

    参考转载博客:http://blog.chinaunix.net/uid-26833883-id-4369060.html https://www.cnblogs.com/xiaojiang1025/ ...

  5. linux中c表示字符设备文件符号

    linux中c表示字符设备文件,b表示块设备文件,l表示符号链接文件,r表示可读权限,w表示可写权限.linux文件属性解读:文件类型:-:普通文件 (f)d:目录文件b:块设备文件 (block)c ...

  6. linux设备驱动之字符设备驱动模型(1)

    一:字符设备驱动 在linux下面,应用层看到的一切皆为文件(名字)所有的设备都是文件,都可以调用open,read,write来操作,而在内核中每个中每个设备有唯一的对应一个设备号: APP   ( ...

  7. 深入浅出:Linux设备驱动之字符设备驱

    一.linux系统将设备分为3类:字符设备.块设备.网络设备.使用驱动程序: 字符设备:是指只能一个字节一个字节读写的设备,不能随机读取设备内存中的某一数据,读取数据需要按照先后数据.字符设备是面向流 ...

  8. 【Linux驱动】字符设备驱动

    一.linux系统将设备分为3类:字符设备.块设备.网络设备.使用驱动程序: 1.字符设备:是指只能一个字节一个字节读写的设备,不能随机读取设备内存中的某一数据,读取数据需要按照先后数据.字符设备是面 ...

  9. 蜕变成蝶~Linux设备驱动之字符设备驱动

    一.linux系统将设备分为3类:字符设备.块设备.网络设备.使用驱动程序: 字符设备:是指只能一个字节一个字节读写的设备,不能随机读取设备内存中的某一数据,读取数据需要按照先后数据.字符设备是面向流 ...

随机推荐

  1. 网站开发进阶(二十)JS中window.alert()与alert()的区别

    JS中window.alert()与alert()的区别 前言 alert与window.alert没什么区别,如果有人觉得有区别,那就来解释一下:所有以window.开始的语句,都可以直接把wind ...

  2. Android官方技术文档翻译——开发工具的构建概述

    本文译自Android官方技术文档<Build Overview>,原文地址:http://tools.android.com/build. 因为<Android Lint Chec ...

  3. Dll的编写 在unity中加载

    1. 在VS中新建Dll项目 2.在头文件中对函数进行声明 extern "C" int _declspec(dllexport) testunity(); 3.在源文件中写函数体 ...

  4. 安卓系统底层C语言算法之测试参数是几个long型的算法

    #include <stdio.h> #define BITS_PER_LONG (sizeof(unsigned long) * 8) //求一个数x是几个long的长度 #define ...

  5. C#中使用双缓冲来避免绘制图像过程中闪烁

    自己所做项目中,在显示医学图像的界面中,当鼠标拖动图像时,不断刷新从后台获取新的图像,而整个过程就很诡异,一直闪个不停. 找到的一个可行方法是:在用户控件的构造函数中加入以下代码: SetStyle( ...

  6. JVM学习--(三)配置参数

    JVM配置参数分为三类参数: 1.跟踪参数 2.堆分配参数 3.栈分配参数 这三类参数分别用于跟踪监控JVM状态,分配堆内存以及分配栈内存. 跟踪参数 跟踪参数用于跟踪监控JVM,往往被开发人员用于J ...

  7. Java内存模型_volatile

    volatile变量自身具有下列两点特性: 可见性:锁的happens-before规则保证释放锁和获取锁的两个线程之间的内存可见性.意味着对一个volatile变量的读,总是能看到(任意线程)对这个 ...

  8. plsql developer 使用 oracle instantclient的安装和配置

    本文由ibyedo1贡献 1.下载 oracle instantclient basic package,在 oracle 官网下载就可以,地址如下: http://www.oracle.com/te ...

  9. VMS项目总结

    开发完一个项目后,如果能够很好的对这个项目做个总结,对我们以后的项目开发以及个人技术的积累都会有很大的帮助.最近在外派公司做完一个系统,在此进行一下深入的总结,也希望给读者带来一些个启示. 一.系统介 ...

  10. 比较Fink, macports 跟 homebrew

    http://www.myexception.cn/brew/412107.html 比较Fink, macports 和 homebrew 如果你有Linux/Unix背景,那么在Mac上你一定想安 ...