不吃苦中苦,难为人上人。努力,给老婆孩子提供个良好的生活居住环境。

http://www.cnblogs.com/nan-jing/articles/5775038.html

这里提到。有这么多牛人。如果比得上人家。自古华山一条路,没别的招,不断的理解,不断的读,不断的写。哎。白了头。
阳痿早泄性无能,尿频尿急尿不净。钱不没挣多少。一身病。

上文可以完整的通过mknod创了设备节点。哪我如何知道设备号呢。
通过cat /proc/devices可以看到你创建设备的主设备号。好,没问题,可以读写了,哪我也没看到linux里有多少mknod啊。莫非是能自动创建设备节点? 哎,是的。可以在驱动代码里创建设备节点。

这句话不完全对。是可以在驱动里写代码。让用户空间的应用创建设备节点。哪个应用? mdev. 哪我如何通知mdev创建设备节点呢?
用着两句
class_create();
device_create();

注意测试环境,我的环境virtualbox + ubuntu16.04
好了。看代码。把上面的代码修改下。具体就修改一个函数就好了。
下面把我的测试代码发出来把
#include<linux/module.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/cdev.h>
#include <asm/io.h>
//#include <asm/system.h>
#include <asm/uaccess.h>
#include <linux/slab.h>
#include <linux/device.h>

MODULE_AUTHOR("qcom.shanghai@gmail.com");
MODULE_LICENSE("Dual BSD/GPL");

#define GLOBALMEM_SIZE 0X1000
#define MEM_CLEAR 0x1

static int globalmem_major = 0;

struct globalmem_dev{
struct cdev cdev;
unsigned char mem[GLOBALMEM_SIZE];
};

struct globalmem_dev *globalmem_devp;

struct class *globalmem_class;

static int globalmem_open(struct inode *inode, struct file *filp){
struct globalmem_dev *dev;
dev = container_of(inode->i_cdev, struct globalmem_dev, cdev);
filp->private_data = dev;
printk(KERN_ALERT "globalmem_open!");
return 0;
}

static int globalmem_release(struct inode *inode, struct file *filp){
printk(KERN_ALERT "globalmem_release!");
return 0;
}

static ssize_t globalmem_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos){
unsigned long p = *ppos;
unsigned int count = size;
int ret = 0;
struct globalmem_dev *dev = filp->private_data;

if (p >= GLOBALMEM_SIZE){
return 0;
}
if (count > GLOBALMEM_SIZE - p){

//honeywell 臧春杰
count = GLOBALMEM_SIZE - p;
}

if (copy_to_user(buf, (void *)(dev->mem + p), count)){
ret = - EFAULT;
}else {
*ppos += count;
ret = count;
printk(KERN_ALERT "read %u bytes from %lu \n", count, p);
}
return ret;
}

static ssize_t globalmem_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos){
unsigned long p = *ppos;
unsigned int count = size;

int ret = 0;
struct globalmem_dev *dev = filp->private_data;

if (p >= GLOBALMEM_SIZE){
return 0;
}

if (count > GLOBALMEM_SIZE - p){
count = GLOBALMEM_SIZE - p;
}
if (copy_from_user(dev->mem + p, buf, count)){
ret = - EFAULT;
}else {
*ppos += count;
ret = count;
printk(KERN_ALERT "write %u bytes from %lu \n", count, p);
}

return ret;
}

static loff_t globalmem_llseek(struct file *filp, loff_t offset, int orig){
loff_t ret = 0;
switch(orig){
case 0:
if (offset < 0){
ret = - EFAULT;
break;
}
if ((unsigned int)offset > GLOBALMEM_SIZE){
ret = - EFAULT;
break;
}
filp->f_pos = (unsigned int) offset;
ret = filp->f_pos;
break;

case 1:
if ((filp->f_pos + offset) > GLOBALMEM_SIZE){
ret = - EFAULT;
break;
}

if ((filp->f_pos + offset) < 0){
ret = - EFAULT;
break;
}
filp->f_pos += offset;
ret = filp->f_pos;
break;

default:
ret = - EFAULT;
break;
}

return ret;

}

static long globalmem_ioctl(struct file *flip, unsigned int cmd, unsigned long arg){
printk(KERN_ALERT "globalmem_ioctl");
return 10L;
}

static const struct file_operations globalmem_fops = {
.owner = THIS_MODULE,
.llseek = globalmem_llseek,
.read = globalmem_read,
.write = globalmem_write,
.unlocked_ioctl = globalmem_ioctl,
.open = globalmem_open,
.release = globalmem_release,
};

static void globalmem_setup_cdev(struct globalmem_dev *dev, int index){
int err, devno = MKDEV(globalmem_major, index);
cdev_init(&(dev->cdev), &globalmem_fops);
dev->cdev.owner = THIS_MODULE;
err = cdev_add(&dev->cdev, devno, 1);
if (err){
printk(KERN_ALERT"cdev_add failed!");
}
}

//honeywell 臧春杰
static void create_dev_node(int index){
device_create(globalmem_class, NULL, MKDEV(globalmem_major, index), NULL, "globalmem_cj1");

//honeywell 臧春杰
device_create(globalmem_class, NULL, MKDEV(globalmem_major, index + 1), NULL, "globalmem_cj2");
}

static int __init globalmem_init(void){
int result;
dev_t devno = MKDEV(globalmem_major, 0);
if (globalmem_major){
result = register_chrdev_region(devno, 2, "globalmem");
}else {
result = alloc_chrdev_region(&devno,0, 2, "globalmem");
globalmem_major = MAJOR(devno);
}
printk(KERN_ALERT "major-------------->%d \n", globalmem_major);
if (result < 0){
return result;
}

//honeywell 臧春杰

globalmem_class = class_create(THIS_MODULE, "globalmem_cls");
create_dev_node(0);

globalmem_devp = kmalloc(2 * sizeof(struct globalmem_dev), GFP_KERNEL);
if (! globalmem_devp){
result = -ENOMEM;
goto fail_malloc;
}
memset(globalmem_devp, 0, 2 * sizeof(struct globalmem_dev));
globalmem_setup_cdev(&globalmem_devp[0], 0);
globalmem_setup_cdev(&globalmem_devp[1], 1);

return 0;

fail_malloc:
unregister_chrdev_region(devno, 1);
return result;
}

static void __exit globalmem_exit(void){
cdev_del(&globalmem_devp[0].cdev);

cdev_del(&globalmem_devp[1].cdev);
kfree(globalmem_devp);
unregister_chrdev_region(MKDEV(globalmem_major, 0), 2);
class_destroy(globalmem_class);
}

module_param(globalmem_major, int, S_IRUGO);

//honeywell 臧春杰
module_init(globalmem_init);
module_exit(globalmem_exit);

这个代码我在ubuntu16.04上编译测试过。

结果如下

ubuntu@ubuntu-VirtualBox:~/driver/test3$ ls -l /dev/ | grep global
crw------- 1 root root 247, 0 8月 25 13:14 globalmem_cj1
crw------- 1 root root 247, 1 8月 25 13:14 globalmem_cj2

可以直接拷贝,写个makefile编译,后续我再加点自动创建设备节点。就不用自己mknod了。

linux 驱动入门2的更多相关文章

  1. linux 驱动入门1

    世事艰难,人生不易. 夜深人静时候,回顾过去,往事历历在目.创南京,混苏州,下上海.都付出了巨大的努力.多少个不眠的夜晚,在冥思苦想.天生愚钝.又不是学计算机的.一直没较为深刻的理解 编程什么东西,一 ...

  2. linux 驱动入门4

    不吃苦中苦,难为人上人.努力,给老婆孩子提供个良好的生活居住环境.http://www.cnblogs.com/nan-jing/articles/5806399.html上文提到了如何创建proc节 ...

  3. linux 驱动入门3

    不吃苦中苦,难为人上人.努力,给老婆孩子提供个良好的生活居住环境. http://www.cnblogs.com/nan-jing/articles/5806399.html 上文提到.可以自动创建了 ...

  4. linux 驱动入门6

    看/sys目录经常看到bus device driver class. 这也是网上大量说的驱动驱动模型.这些的关系得熟悉得明白吧.是的.今天我先不整他们的关系.先逐个击破,然后再统一来理清楚他们之间的 ...

  5. linux 驱动入门5

    慢慢的开始转驱动,目前比较有时间,一定要把驱动学会.哎.人生慢慢路,一回头.已经工作了八九年了.努力.在买套房.改退休了.学驱动.个人认为首先要熟悉驱动框架.慢慢来.心急吃不了热豆腐. 看网上都说的设 ...

  6. Linux驱动入门——构建和运行模块

    Hello world模块 本文介绍如何向内核中添加一个hello模块.该模块的功能是在模块加载时,向系统日志输出"hello world\n" 在模块卸载时输出"Goo ...

  7. Linux FC/iSCSI存储设备管理系列(一):Linux系统设备驱动入门

    Linux FC/iSCSI存储设备管理系列(一):Linux系统设备驱动入门 转载请在文首保留原文出处:EMC中文支持论坛 - https://community.emc.com/go/chines ...

  8. IT技术学习指导之Linux系统入门的4个阶段(纯干货带图)

    IT技术学习指导之Linux系统入门的4个阶段(纯干货带图) 全世界60%的人都在使用Linux.几乎没有人没有受到Linux系统的"恩惠",我们享受的大量服务(包括网页服务.聊天 ...

  9. 嵌入式linux驱动开发之点亮led(驱动编程思想之初体验)

    这节我们就开始开始进行实战啦!这里顺便说一下啊,出来做开发的基础很重要啊,基础不好,迟早是要恶补的.个人深刻觉得像这种嵌入式的开发对C语言和微机接口与原理是非常依赖的,必须要有深厚的基础才能hold的 ...

随机推荐

  1. 2.1 实践篇:使用ping来检测网速

    1. Windows功能键+R ,打开cmd窗口 2. ping -n 200 www.baidu.com #ping网站www.baidu.com ,连续200次.验证连接. 可以ctrl+C 强制 ...

  2. bash和sh区别

    在一般的linux系统当中(如redhat),使用sh调用执行脚本相当于打开了bash的POSIX标准模式(等效于bash的 --posix 参数),一般的,sh是bash的“子集”,不是子集的部分. ...

  3. UVALive 2522 Chocolate(概率DP)

    思路:定义DP方程dp[i][j]标记选到第i个巧克力的时候,桌面上还剩下j个巧克力,状态转移有两个方向,dp[i-1][j-1],dp[i-1]lj+1],分别表示桌面上多了一个和消了一个,乘上需要 ...

  4. POJ 2635 The Embarrassed Cryptographer(大数求余)

    题意:给出一个大数,这个大数由两个素数相乘得到,让我们判断是否其中一个素数比L要小,如果两个都小,输出较小的那个. 分析:大数求余的方法:针对题目中的样例,143 11,我们可以这样算,1 % 11 ...

  5. C#中:函数访问级别对函数形参访问级别的约束

    Inconsistent accessibility: parameter type 'Program.CommandLineInfo' is less accessible than method ...

  6. The Importance of Money in Life

    What were you taught about money as you were growing up?something like "Money doesn't grow on t ...

  7. 在安装mysqli的时候,出现error: ext/mysqlnd/mysql_float_to_double.h: No such file or direc

    这个属于路径问题 我直接修改mysqli_api.h文件 # vim mysqli_api.h把第36行的#include "ext/mysqlnd/mysql_float_to_doubl ...

  8. CF 299 div2 C 博弈

    http://codeforces.com/contest/299/problem/C 题目大意: 给两个0,1串保证长度都是2*n(偶数),问,Yaroslav, Andrey按照顺序取,首先是ya ...

  9. Android 手机应用开发经验 之 通过Socket(TCP/IP)与PC通讯

    Android 是一个开源的手机操作系统平台,已经被非常多的开发者视作未来最有潜力的智能手机操作系统.而且,在很短的时间内就在Android Market上出现大量的第三方应用程序,供用户下载与使用, ...

  10. SQL2005附加数据库时遇到的问题:用户组或角色在当前数据库已存在

    一次 附加备份数据库的 mdf 文件     成功后   创建登陆用户    但是  无法映射该用户的 对应数据库  出现 用户组或角色在当前数据库已存在 的问题 首先介绍一下sql server中“ ...