加入内核源码树外

① 建立两个文件scull.c,scull.h,以及Makefile文件

Makefile文件

② 用make进行编译,生成scull.ko驱动程序模块

③ 把scull.ko模块加载到内核,并且查看scull.ko驱动

④ 查看当前设备使用的主设备号,主设备号为260

⑤ 首先应该在/dev/目录下创建与该驱动程序相对应的文件节点,查看创建好的驱动程序节点文件并修改scull的权限。

⑥ 编写test.c程序,来对驱动程序进行测试。编译并执行该程序

移除驱动模块

加入内核源码树里面

① 把驱动程序(模块程序)拷贝到内核源码树根目录下/drivers/char下

② 编译配置文件Kconfig,加入驱动选项,使之在make menuconfig的时候出现改模块选项

③ 在内核根目录下执行make menuconfig

④ 没有安装curses库,安装。

⑤ 在内核根目录下执行make menuconfig,找到驱动模块,设置启动为M

⑥ 在模块文件所在目录的Makefile中加入要编译的驱动模块文件

⑦  在源代码根目录linux下,执行make bzImage后执行make modules

⑧  在char目录下查看得知device1.ko已经存在

⑨  用lsmod指令安装模块文件,再对驱动程序进行测试。编译并执行该程序

代码:

 #ifndef _MEMDEV_H_
#define _MEMDEV_H_ #ifndef MEMDEV_MAJOR
#define MEMDEV_MAJOR 260 /*预设的mem的主设备号*/
#endif #ifndef MEMDEV_NR_DEVS
#define MEMDEV_NR_DEVS 2 /*设备数*/
#endif #ifndef MEMDEV_SIZE
#define MEMDEV_SIZE 4096
#endif /*mem设备描述结构体*/
struct mem_dev
{
char *data;
unsigned long size;
}; #endif /* _MEMDEV_H_ */

scull.h

 #include <linux/module.h>
#include <linux/types.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/switch_to.h>
#include <asm/uaccess.h>
#include <linux/slab.h> #include "scull.h" static int mem_major = MEMDEV_MAJOR; module_param(mem_major, int, S_IRUGO); struct mem_dev *mem_devp; /*设备结构体指针*/ struct cdev cdev; /*文件打开函数*/
int mem_open(struct inode *inode, struct file *filp)
{
struct mem_dev *dev; /*获取次设备号*/
int num = MINOR(inode->i_rdev); if (num >= MEMDEV_NR_DEVS)
return -ENODEV;
dev = &mem_devp[num]; /*将设备描述结构指针赋值给文件私有数据指针*/
filp->private_data = dev; return ;
} /*文件释放函数*/
int mem_release(struct inode *inode, struct file *filp)
{
return ;
} /*读函数*/
static ssize_t mem_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos)
{
unsigned long p = *ppos;
unsigned int count = size;
int ret = ;
struct mem_dev *dev = filp->private_data; /*获得设备结构体指针*/ /*判断读位置是否有效*/
if (p >= MEMDEV_SIZE)
return ;
if (count > MEMDEV_SIZE - p)
count = MEMDEV_SIZE - p; /*读数据到用户空间*/
if (copy_to_user(buf, (void*)(dev->data + p), count))
{
ret = - EFAULT;
}
else
{
*ppos += count;
ret = count; printk(KERN_INFO "read %d bytes(s) from %d\n", count, p);
} return ret;
} /*写函数*/
static ssize_t mem_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos)
{
unsigned long p = *ppos;
unsigned int count = size;
int ret = ;
struct mem_dev *dev = filp->private_data; /*获得设备结构体指针*/ /*分析和获取有效的写长度*/
if (p >= MEMDEV_SIZE)
return ;
if (count > MEMDEV_SIZE - p)
count = MEMDEV_SIZE - p; /*从用户空间写入数据*/
if (copy_from_user(dev->data + p, buf, count))
ret = - EFAULT;
else
{
*ppos += count;
ret = count; printk(KERN_INFO "written %d bytes(s) from %d\n", count, p);
} return ret;
} /* seek文件定位函数 */
static loff_t mem_llseek(struct file *filp, loff_t offset, int whence)
{
loff_t newpos; switch(whence) {
case : /* SEEK_SET */
newpos = offset;
break; case : /* SEEK_CUR */
newpos = filp->f_pos + offset;
break; case : /* SEEK_END */
newpos = MEMDEV_SIZE - + offset;
break; default: /* can't happen */
return -EINVAL;
}
if ((newpos<) || (newpos>MEMDEV_SIZE))
return -EINVAL; filp->f_pos = newpos;
return newpos; } /*文件操作结构体*/
static const struct file_operations mem_fops =
{
.owner = THIS_MODULE,
.llseek = mem_llseek,
.read = mem_read,
.write = mem_write,
.open = mem_open,
.release = mem_release,
}; /*设备驱动模块加载函数*/
static int memdev_init(void)
{
int result;
int i; dev_t devno = MKDEV(mem_major, ); /* 静态申请设备号*/
if (mem_major)
result = register_chrdev_region(devno, , "memdev");
else /* 动态分配设备号 */
{
result = alloc_chrdev_region(&devno, , , "memdev");
mem_major = MAJOR(devno);
} if (result < )
return result; /*初始化cdev结构*/
cdev_init(&cdev, &mem_fops);
cdev.owner = THIS_MODULE;
cdev.ops = &mem_fops; /* 注册字符设备 */
cdev_add(&cdev, MKDEV(mem_major, ), MEMDEV_NR_DEVS); /* 为设备描述结构分配内存*/
mem_devp = kmalloc(MEMDEV_NR_DEVS * sizeof(struct mem_dev), GFP_KERNEL);
if (!mem_devp) /*申请失败*/
{
result = - ENOMEM;
goto fail_malloc;
}
memset(mem_devp, , sizeof(struct mem_dev)); /*为设备分配内存*/
for (i=; i < MEMDEV_NR_DEVS; i++)
{
mem_devp[i].size = MEMDEV_SIZE;
mem_devp[i].data = kmalloc(MEMDEV_SIZE, GFP_KERNEL);
memset(mem_devp[i].data, , MEMDEV_SIZE);
} return ; fail_malloc:
unregister_chrdev_region(devno, ); return result;
} /*模块卸载函数*/
static void memdev_exit(void)
{
cdev_del(&cdev); /*注销设备*/
kfree(mem_devp); /*释放设备结构体内存*/
unregister_chrdev_region(MKDEV(mem_major, ), ); /*释放设备号*/
} MODULE_AUTHOR("David Xie");
MODULE_LICENSE("GPL"); module_init(memdev_init);
module_exit(memdev_exit);

scull.c

 obj-m +=scull.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) clean

Makefile

 #include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <linux/i2c.h>
#include <linux/fcntl.h> int main()
{
int fd;
char buf[]="this is a test!"; char buf_read[]; if((fd=open("/dev/scull",O_RDWR))==-) printf("open scull WRONG!\n");
else
printf("open scull SUCCESS!\n"); printf("buf is %s\n",buf); write(fd,buf,sizeof(buf)); lseek(fd,,SEEK_SET); read(fd,buf_read,sizeof(buf)); printf("buf_read is %s\n",buf_read); return ;
}

test.c

Linux符设备驱动编程的更多相关文章

  1. 介绍linux设备驱动编程

    目前,Linux软件工程师大致可分为两个层次: (1)Linux应用软件工程师(Application Software Engineer):       主要利用C库函数和Linux API进行应用 ...

  2. Linux 视频设备驱动V4L2最常用的控制命令

    http://blog.csdn.net/shaolyh/article/details/6583226 Linux 视频设备驱动V4L2最常用的控制命令使用说明(1.02) 命令 功能 VIDIOC ...

  3. Linux块设备驱动详解

    <机械硬盘> a:磁盘结构 -----传统的机械硬盘一般为3.5英寸硬盘,并由多个圆形蝶片组成,每个蝶片拥有独立的机械臂和磁头,每个堞片的圆形平面被划分了不同的同心圆,每一个同心圆称为一个 ...

  4. Linux字符设备驱动基本结构

    1.Linux字符设备驱动的基本结构 Linux系统下具有三种设备,分别是字符设备.块设备和网络设备,Linux下的字符设备是指只能一个字节一个字节读写的设备,不能随机读取设备内存中某一数据,读取数据 ...

  5. (57)Linux驱动开发之三Linux字符设备驱动

    1.一般情况下,对每一种设备驱动都会定义一个软件模块,这个工程模块包含.h和.c文件,前者定义该设备驱动的数据结构并声明外部函数,后者进行设备驱动的具体实现. 2.典型的无操作系统下的逻辑开发程序是: ...

  6. linux块设备驱动之实例

    1.注册:向内核注册个块设备驱动,其实就是用主设备号告诉内核这个代表块设备驱动 sbull_major  =  register_blkdev(sbull_major, "sbull&quo ...

  7. 深入理解Linux字符设备驱动

    文章从上层应用访问字符设备驱动开始,一步步地深入分析Linux字符设备的软件层次.组成框架和交互.如何编写驱动.设备文件的创建和mdev原理,对Linux字符设备驱动有全面的讲解.本文整合之前发表的& ...

  8. Linux字符设备驱动结构(一)--cdev结构体、设备号相关知识机械【转】

    本文转载自:http://blog.csdn.net/zqixiao_09/article/details/50839042 一.字符设备基础知识 1.设备驱动分类 linux系统将设备分为3类:字符 ...

  9. Smart210学习记录----beep linux字符设备驱动

    今天搞定了beep linux字符设备驱动,心里还是很开心的,哈哈...但在完成的过程中却遇到了一个非常棘手的问题,花费了我大量的时间,,,, 还是把问题描述一下吧,好像这个问题很普遍的,网上许多解决 ...

随机推荐

  1. Flutter Map<String, dynamic> 、List<String> a-z 排序

    字符串从 a-z 排序. Map<String, String> map = XXX, List<String> keys = map.keys.toList(); // ke ...

  2. I2C裸机驱动程序设计

    ① I2C(Inter-Integrated Circuit)总线是由飞利浦公司开发的两线式串行总线,用于连接微控制器及其外围设备 ② I2C总线有两根双向信号线 (1)SDA:Serial Data ...

  3. 2.使用ngx_http_auth_basic_module模块为不带认证的资源添加授权

    1.首先需要生成用户名和密码 使用openssl来生成,生成命令(openssl在安装nginx的时候已经安装) echo "kibana:$(openssl passwd -crypt y ...

  4. openerp学习笔记 对象继承,对象初始化数据

    1.对象继承     _inherit = "product.product" 继承产品对象,给产品对象添加字段或方法,不需要设置 _name._table 等属性     注意: ...

  5. linux(ubuntu-16.1) 下安装 odoo10 新版

    1.虚拟机(VMware)中安装 ubuntu-16.1(网络适配器选择桥接模式). 安装成功后,运行 ubuntu 提示 "CPU已被客户机操作系统禁用" 时,需要修改配置文件解 ...

  6. Word常用定义的变量

    unit U_WordConst;  interface {*******Word窗体状态************} const   wdWindowStateNormal = $00000000;  ...

  7. centos7 配置php-fpm

    1.复制相应的文件cp /usr/local/php7/etc/php-fpm.conf.default /usr/local/php7/etc/php-fpm.confcp /usr/local/p ...

  8. LINUX安装UNZIP

    安装完linux ,发现没有UNZIP,没办法,重新安装. 1.获取unzip源码 sudo wget http://downloads.sourceforge.net/infozip/unzip55 ...

  9. 028-applicationContext.xml配置文件

    版本一 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns:xsi="http: ...

  10. oracle insert两个关联表

    现有一张老师学生表(tb_tea_cou),由于业务需要,需把老师学生表tb_tea_stu拆分成两张表(tb_tea.tb_cou),并把记录insert到这两张子表中(tb_tea.tb_cou为 ...