平台总线式驱动开发——基本框架

1. 总线、设备和驱动

硬编码式的驱动开发带来的问题:

  1. 垃圾代码太多
  2. 结构不清晰
  3. 一些统一设备功能难以支持
  4. 开发效率低下

1.1 初期解决思路:设备与驱动分离

在这里插入图片描述
struct device来表示一个具体设备,主要提供具体设备相关的资源(如寄存器地址、GPIO、中断等)
struct device_driver来表示一个设备驱动,一个驱动可以支持多个操作逻辑相同的设备

由此产生的问题————怎样将两者进行关联(匹配)?
硬件上同一总线上的设备遵循一致的时序通信,在其基础上增加管理设备和驱动的软件功能,于是引入总线(BUS),各种总线的核心框架有内核来实现,通信时序一般由SOC供应商支持;
内核中用struct bus_type 来表示一种总线,总线可以是实际存在的总线,也可以是虚拟总线:

  1. 实际总线:提供时序通信方式 + 管理设备和驱动
  2. 虚拟总线:仅用来管理设备和驱动(最核心的功能就是完成设备和驱动的匹配)

理解方式:
设备:提供硬件资源——男
驱动:提供驱动代码——女
总线:匹配设备和驱动——婚介所:提供沟通机制,完成拉郎配

1.2 升级思路:根据设备树,在系统启动时自动产生每个节点对应的设备

初期方案,各种device需要编码方式注册进内核中的设备管理结构中,为了进一步减少这样的编码,引入设备树

1.2.3 基本数据类型

  1. struct device
struct device 
{
	struct bus_type	*bus;	//总线类型
	dev_t			devt;	//设备号
	struct device_driver *driver;	//设备驱动
    struct device_node  *of_node;//设备树中的节点,重要
	void	(*release)(struct device *dev);//删除设备,重要
    //.......
}
  1. struct device_driver
struct device_driver 
{
	const char		*name;	//驱动名称,匹配device用,重要
	struct bus_type	*bus;    //总线类型
	struct module		*owner;	//模块THIS_MODULE 
	const struct of_device_id	*of_match_table;//用于设备树匹配 of_match_ptr(某struct of_device_id对象地址) 重要
    //......
};

struct of_device_id
{
	char name[32];//设备名
	char type[32];//设备类型
	char compatible[128]; //用于device和driver的match,重点
};
//用到结构体数组,一般不指定大小,初始化时最后加{}表示数组结束

2. 平台总线基础框架

2.1 platform总线驱动

platform是一种虚拟总线,主要用来管理那些不需要时序通信的设备
基本结构图:
在这里插入图片描述

2.2 核心数据类型之platform_device

struct platform_device 
{
    const char    *name;    //匹配用的名字
    int        id;//设备id,用于在该总线上同名的设备进行编号,如果只有一个设备,则为-1
    struct device    dev;   //设备模块必须包含该结构体
    struct resource    *resource;//资源结构体 指向资源数组
    u32        num_resources;//资源的数量 资源数组的元素个数
    const struct platform_device_id    *id_entry;//设备八字
};
struct platform_device_id
{
	char name[20];//匹配用名称
	kernel_ulong_t driver_data;//需要向驱动传输的其它数据
};
struct resource 
{
	resource_size_t start;  //资源起始位置   
	resource_size_t end;   //资源结束位置
	const char *name;      
	unsigned long flags;   //区分资源是什么类型的
};
 
#define IORESOURCE_MEM        0x00000200
#define IORESOURCE_IRQ        0x00000400 
/*
flags 指资源类型,我们常用的是 IORESOURCE_MEM、IORESOURCE_IRQ  这两种。start 和 end 的含义会随着 flags而变更,如

a -- flags为IORESOURCE_MEM 时,start 、end 分别表示该platform_device占据的内存的开始地址和结束值;注意不同MEM的地址值不能重叠

b -- flags为 IORESOURCE_IRQ   时,start 、end 分别表示该platform_device使用的中断号的开始地址和结束值
*/
/**
 *注册:把指定设备添加到内核中平台总线的设备列表,等待匹配,匹配成功则回调驱动中probe;
 */
int platform_device_register(struct platform_device *);
/**
 *注销:把指定设备从设备列表中删除,如果驱动已匹配则回调驱动方法和设备信息中的release;
 */
void platform_device_unregister(struct platform_device *);
struct resource *platform_get_resource(struct platform_device *dev,unsigned int type, unsigned int num);
/*
	功能:获取设备资源
	参数:dev:平台驱动
		type:获取的资源类型
		num:对应类型资源的序号(如第0个MEM、第2个IRQ等,不是数组下标)
	返回值:成功:资源结构体首地址,失败:NULL
*/

2.3 核心数据类型之platform_driver

struct platform_driver 
{
    int (*probe)(struct platform_device *);//设备和驱动匹配成功之后调用该函数
    int (*remove)(struct platform_device *);//设备卸载了调用该函数
    
    void (*shutdown)(struct platform_device *);
    int (*suspend)(struct platform_device *, pm_message_t state);
    int (*resume)(struct platform_device *);
    struct device_driver driver;//内核里所有的驱动必须包含该结构体
    const struct platform_device_id *id_table;  //能够支持的设备八字数组,用到结构体数组,一般不指定大小,初始化时最后加{}表示数组结束
};
int platform_driver_register(struct platform_driver*pdrv);
/*
	功能:注册平台设备驱动
	参数:pdrv:平台设备驱动结构体
	返回值:成功:0
	失败:错误码
*/
void platform_driver_unregister(struct platform_driver*pdrv);

3. platform的三种匹配方式

在这里插入图片描述
3.1 名称匹配:一个驱动只对应一个设备 ----- 优先级最低

3.2 id匹配(可想象成八字匹配):一个驱动可以对应多个设备 ------优先级次低

​ device模块中,id的name成员必须与struct platform_device中的name成员内容一致

​ 因此device模块中,struct platform_device中的name成员必须指定

​ driver模块中,struct platform_driver成员driver的name成员必须指定,但与device模块中name可以不相同

3.3 设备树匹配:内核启动时根据设备树自动产生的设备 ------ 优先级最高

使用compatible属性进行匹配,注意设备树中compatible属性值不要包含空白字符

​ id_table可不设置,但struct platform_driver成员driver的name成员必须设置

3.1 名称匹配基础框架

/*platform device框架*/
#include <linux/module.h> 
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>

//定义资源数组

static void device_release(struct device *dev)
{
	printk("platform: device release\n");
}

struct platform_device test_device = {
	.id = -1,
	.name = "test_device",//必须初始化
	.dev.release = device_release, 
};

static int __init platform_device_init(void)
{
	platform_device_register(&test_device);
	return 0;
}

static void __exit platform_device_exit(void)
{
	platform_device_unregister(&test_device);
}

module_init(platform_device_init);
module_exit(platform_device_exit);
MODULE_LICENSE("Dual BSD/GPL");
/*platform driver框架*/
#include <linux/module.h> 
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>

static int driver_probe(struct platform_device *dev)
{
	printk("platform: match ok!\n");
	return 0;
}

static int driver_remove(struct platform_device *dev)
{
	printk("platform: driver remove\n");
	return 0;
}

struct platform_driver test_driver = {
	.probe = driver_probe,
	.remove = driver_remove,
	.driver = {
		.name = "test_device", //必须初始化
	},
};

static int __init platform_driver_init(void)
{
	platform_driver_register(&test_driver);
	return 0;
}

static void __exit platform_driver_exit(void)
{
	platform_driver_unregister(&test_driver);
}

module_init(platform_driver_init);
module_exit(platform_driver_exit);
MODULE_LICENSE("Dual BSD/GPL");

设备中增加资源,驱动中访问资源

3.2 ID匹配基础框架

id匹配(可想象成八字匹配):一个驱动可以对应多个设备 ------优先级次低

注意事项:

  1. device模块中,id的name成员必须与struct platform_device中的name成员内容一致,因此device模块中,struct platform_device中的name成员必须指定
  2. driver模块中,struct platform_driver成员driver的name成员必须指定,但与device模块中name可以不相同
/*platform device框架*/
#include <linux/module.h> 
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>

//定义资源数组

static void device_release(struct device *dev)
{
	printk("platform: device release\n");
}

struct platform_device_id test_id = {
    .name = "test_device",
};

struct platform_device test_device = {
	.name = "test_device",//必须初始化
	.dev.release = device_release, 
    .id_entry = &test_id,
};

static int __init platform_device_init(void)
{
	platform_device_register(&test_device);
	return 0;
}

static void __exit platform_device_exit(void)
{
	platform_device_unregister(&test_device);
}

module_init(platform_device_init);
module_exit(platform_device_exit);
MODULE_LICENSE("Dual BSD/GPL");
/*platform driver框架*/
#include <linux/module.h> 
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>

static int driver_probe(struct platform_device *dev)
{
	printk("platform: match ok!\n");
	return 0;
}

static int driver_remove(struct platform_device *dev)
{
	printk("platform: driver remove\n");
	return 0;
}

struct platform_device_id testdrv_ids[] = 
{
	[0] = {.name = "test_device"},
    [1] = {.name = "abcxyz"},
    [2] = {}, //means ending
};

struct platform_driver test_driver = {
	.probe = driver_probe,
	.remove = driver_remove,
	.driver = {
		.name = "xxxxx", //必须初始化
	},
    .id_table = testdrv_ids,
};

static int __init platform_driver_init(void)
{
	platform_driver_register(&test_driver);
	return 0;
}

static void __exit platform_driver_exit(void)
{
	platform_driver_unregister(&test_driver);
}

module_init(platform_driver_init);
module_exit(platform_driver_exit);
MODULE_LICENSE("Dual BSD/GPL");

用到结构体数组,一般不指定大小,初始化时最后加{}表示数组结束

设备中增加资源,驱动中访问资源

3.3 设备树匹配基础框架

设备树匹配:内核启动时根据设备树自动产生的设备 ------ 优先级最高

注意事项:

  1. 无需编写device模块,只需编写driver模块
  2. 使用compatible属性进行匹配,注意设备树中compatible属性值不要包含空白字符
  3. id_table可不设置,但struct platform_driver成员driver的name成员必须设置
/*platform driver框架*/
#include <linux/module.h> 
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>

static int driver_probe(struct platform_device *dev)
{
	printk("platform: match ok!\n");
	return 0;
}

static int driver_remove(struct platform_device *dev)
{
	printk("platform: driver remove\n");
	return 0;
}

struct platform_device_id testdrv_ids[] = 
{
	[0] = {.name = "test_device"},
    [1] = {.name = "abcxyz"},
    [2] = {}, //means ending
};

struct of_device_id test_of_ids[] = 
{
	[0] = {.compatible = "xyz,abc"},
    [1] = {.compatible = "qwe,opq"},
    [2] = {},
};

struct platform_driver test_driver = {
	.probe = driver_probe,
	.remove = driver_remove,
	.driver = {
		.name = "xxxxx", //必须初始化
        .of_match_table = test_of_ids,
	},
};

static int __init platform_driver_init(void)
{
	platform_driver_register(&test_driver);
	return 0;
}

static void __exit platform_driver_exit(void)
{
	platform_driver_unregister(&test_driver);
}

module_init(platform_driver_init);
module_exit(platform_driver_exit);
MODULE_LICENSE("Dual BSD/GPL");

4.(名称匹配)led代码实践

平台驱动框架

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/io.h>
#include <linux/device.h>
#include <asm/uaccess.h>
#include <asm/atomic.h>
#include "leddrv.h"

int major = 11;
int minor = 0;
int leddrv_num = 1;

struct leddrv_dev
{
	struct cdev mydev;
	volatile unsigned long *pled2_con;
	volatile unsigned long *pled2_dat;

	volatile unsigned long *pled3_con;
	volatile unsigned long *pled3_dat;

	volatile unsigned long *pled4_con;
	volatile unsigned long *pled4_dat;

	volatile unsigned long *pled5_con;
	volatile unsigned long *pled5_dat;
	
	struct class *pcls;
	struct device *pdev;
};

struct leddrv_dev *pgmydev;

int leddrv_open(struct inode *pnode,struct file *pfile);
int leddrv_close(struct inode *pnode,struct file *pfile);
long leddrv_ioctl(struct file *pfile,unsigned int cmd,unsigned long arg);
void ioremap_ledreg(struct leddrv_dev *pmydev,struct platform_device *p_pltdev);
void set_out_ledreg(struct leddrv_dev *pmydev);
void iounmap_ledreg(struct leddrv_dev *pmydev);
void led_on(struct leddrv_dev *pmydev,int ledno);
void led_off(struct leddrv_dev *pmydev,int ledno);

struct file_operations myops = {
	.owner = THIS_MODULE,
	.open = leddrv_open,
	.release = leddrv_close,
	.unlocked_ioctl = leddrv_ioctl,
};

int fs4412leds_driver_probe(struct platform_device *p_pltdev)
{
	int ret = 0;
	dev_t devno = MKDEV(major,minor);
	
	ret = register_chrdev_region(devno,leddrv_num,"leddrv");
	if(ret){
		ret = alloc_chrdev_region(&devno,minor,leddrv_num,"leddrv");
		if(ret){
			printk("get devno failed\n");
			return -1;
		}
		major = MAJOR(devno);
	}
	
	pgmydev = (struct leddrv_dev *)kmalloc(sizeof(struct leddrv_dev),GFP_KERNEL);
	if(NULL == pgmydev){
		unregister_chrdev_region(devno,leddrv_num);
		printk("kmalloc failed\n");
		return -1;
	}
	memset(pgmydev,0,sizeof(struct leddrv_dev));
	cdev_init(&pgmydev->mydev,&myops);

	pgmydev->mydev.owner = THIS_MODULE;
	cdev_add(&pgmydev->mydev,devno,leddrv_num);
	
	/*ioremap*/
	ioremap_ledreg(pgmydev,p_pltdev);
	/*con_register set output*/
	set_out_ledreg(pgmydev);

	pgmydev->pcls = class_create(THIS_MODULE,"myled");
	if(IS_ERR(pgmydev->pcls)){
		printk("class_create failed\n");
		cdev_del(&pgmydev->mydev);
		unregister_chrdev_region(devno,leddrv_num);
		kfree(pgmydev);
		pgmydev = NULL;
		return -1;
	}
	pgmydev->pdev = device_create(pgmydev->pcls,NULL,devno,NULL,"leddrv");
	if(NULL == pgmydev->pdev){
		printk("class_create failed\n");
		class_destroy(pgmydev->pcls);
		cdev_del(&pgmydev->mydev);
		unregister_chrdev_region(devno,leddrv_num);
		kfree(pgmydev);
		pgmydev = NULL;
		return -1;
	}

	return 0;
}

int fs4412leds_driver_remove(struct platform_device *p_pltdev)
{
	dev_t devno = MKDEV(major,minor);
	/*iounmap*/

	iounmap_ledreg(pgmydev);
	class_destroy(pgmydev->pcls);
	device_destroy(pgmydev->pcls,devno);

	cdev_del(&pgmydev->mydev);
	unregister_chrdev_region(devno,leddrv_num);
	kfree(pgmydev);
	pgmydev = NULL;
	return 0;
}


struct platform_driver fs4412leds_driver = 
{
	.driver.name = "fs4412leds",
	.probe = fs4412leds_driver_probe,
	.remove = fs4412leds_driver_remove,
};

int  __init fs4412leds_driver_init(void)
{
	platform_driver_register(&fs4412leds_driver);
	return 0;
}

void __exit fs4412leds_driver_exit(void)
{
	platform_driver_unregister(&fs4412leds_driver);
}


int leddrv_open(struct inode *pnode,struct file *pfile)
{
	pfile->private_data = (void *)container_of(pnode->i_cdev,struct leddrv_dev,mydev);
	return 0;
}


int leddrv_close(struct inode *pnode,struct file *pfile)
{
	return 0;
}

void led_on(struct leddrv_dev *pmydev,int ledno)
{
	switch(ledno)
	{
		case 2:
			writel(readl(pmydev->pled2_dat) | (0x1 << 7),pmydev->pled2_dat);
			break;
		case 3:
			writel(readl(pmydev->pled3_dat) | (0x1 << 0),pmydev->pled3_dat);
			break;
		case 4:
			writel(readl(pmydev->pled4_dat) | (0x1 << 4),pmydev->pled4_dat);
			break;
		case 5:
			writel(readl(pmydev->pled5_dat) | (0x1 << 5),pmydev->pled5_dat);
			break;
	}
}

void led_off(struct leddrv_dev *pmydev,int ledno)
{
	switch(ledno)
	{
		case 2:
			writel(readl(pmydev->pled2_dat) & (~(0x1 << 7)),pmydev->pled2_dat);
			break;
		case 3:
			writel(readl(pmydev->pled3_dat) & (~(0x1 << 0)),pmydev->pled3_dat);
			break;
		case 4:
			writel(readl(pmydev->pled4_dat) & (~(0x1 << 4)),pmydev->pled4_dat);
			break;
		case 5:
			writel(readl(pmydev->pled5_dat) & (~(0x1 << 5)),pmydev->pled5_dat);
			break;
	}
}

long leddrv_ioctl(struct file *pfile,unsigned int cmd,unsigned long arg)
{
	struct leddrv_dev  *pmydev = (struct leddrv_dev*)pfile->private_data;
	if(arg < 2 || arg > 5)
	{
		return -1;
	}
	switch(cmd){
		case MY_LED_ON:
			led_on(pmydev,arg);
			break;
		case MY_LED_OFF:
			led_off(pmydev,arg);
			break;
		default:
			return -1;
	}
	return 0;
}

void ioremap_ledreg(struct leddrv_dev *pmydev,struct platform_device *p_pltdev)
{
	struct resource *pres = NULL;

	pres = platform_get_resource(p_pltdev,IORESOURCE_MEM,2);
	pmydev->pled2_con = ioremap(pres->start,4);

	pres = platform_get_resource(p_pltdev,IORESOURCE_MEM,3);
	pmydev->pled2_dat = ioremap(pres->start,4);

	pres = platform_get_resource(p_pltdev,IORESOURCE_MEM,0);
	pmydev->pled3_con = ioremap(pres->start,4);

	pres = platform_get_resource(p_pltdev,IORESOURCE_MEM,1);
	pmydev->pled3_dat = ioremap(pres->start,4);

	pres = platform_get_resource(p_pltdev,IORESOURCE_MEM,4);
	pmydev->pled4_con = ioremap(pres->start,4);

	pres = platform_get_resource(p_pltdev,IORESOURCE_MEM,5);
	pmydev->pled4_dat = ioremap(pres->start,4);

	pmydev->pled5_con = pmydev->pled4_con;
	pmydev->pled5_dat = pmydev->pled4_dat;
}
void set_out_ledreg(struct leddrv_dev *pmydev)
{
	writel(((readl(pmydev->pled2_con) & (~(0xf << 28))) | (0x1 << 28)),pmydev->pled2_con);
	writel(((readl(pmydev->pled3_con) & (~(0xf <<  0))) | (0x1 <<  0)),pmydev->pled3_con);
	writel(((readl(pmydev->pled4_con) & (~(0xf << 16))) | (0x1 << 16)),pmydev->pled4_con);
	writel(((readl(pmydev->pled5_con) & (~(0xf << 20))) | (0x1 << 20)),pmydev->pled5_con);

	
	writel(readl(pmydev->pled2_dat) & (~(0x1 << 7)),pmydev->pled2_dat);
	writel(readl(pmydev->pled3_dat) & (~(0x1 << 0)),pmydev->pled3_dat);
	writel(readl(pmydev->pled4_dat) & (~(0x1 << 4)),pmydev->pled4_dat);
	writel(readl(pmydev->pled5_dat) & (~(0x1 << 5)),pmydev->pled5_dat);

}
void iounmap_ledreg(struct leddrv_dev *pmydev)
{
	iounmap(pmydev->pled2_con);
	pmydev->pled2_con = NULL;
	iounmap(pmydev->pled2_dat);
	pmydev->pled2_dat = NULL;

	iounmap(pmydev->pled3_con);
	pmydev->pled3_con = NULL;
	iounmap(pmydev->pled3_dat);
	pmydev->pled3_dat = NULL;

	iounmap(pmydev->pled4_con);
	pmydev->pled4_con = NULL;
	iounmap(pmydev->pled4_dat);
	pmydev->pled4_dat = NULL;

	pmydev->pled5_con = NULL;
	pmydev->pled5_dat = NULL;
}




MODULE_LICENSE("GPL");

module_init(fs4412leds_driver_init);
module_exit(fs4412leds_driver_exit);

平台设备框架

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>

#define GPX1CON 0x11000c20
#define GPX1DAT 0x11000c24

#define GPX2CON 0x11000c40
#define GPX2DAT 0x11000c44

#define GPF3CON 0x114001e0
#define GPF3DAT 0x114001e4

void fs4412leds_dev_release(struct device *pdev)
{
	printk("fs4412leds_dev_release is called\n");
}

struct resource fs4412leds_dev_res[] = {
	[0] = {.start = GPX1CON,.end = GPX1CON + 3,.name = "GPX1CON",.flags = IORESOURCE_MEM},
	[1] = {.start = GPX1DAT,.end = GPX1DAT + 3,.name = "GPX1DAT",.flags = IORESOURCE_MEM},

	[2] = {.start = GPX2CON,.end = GPX2CON + 3,.name = "GPX2CON",.flags = IORESOURCE_MEM},
	[3] = {.start = GPX2DAT,.end = GPX2DAT + 3,.name = "GPX2DAT",.flags = IORESOURCE_MEM},

	[4] = {.start = GPF3CON,.end = GPF3CON + 3,.name = "GPF3CON",.flags = IORESOURCE_MEM},
	[5] = {.start = GPF3DAT,.end = GPF3DAT + 3,.name = "GPF3DAT",.flags = IORESOURCE_MEM},
};


struct platform_device fs4412leds_device = {
	.name = "fs4412leds",
	.dev.release = fs4412leds_dev_release,
	.resource = fs4412leds_dev_res,
	.num_resources = ARRAY_SIZE(fs4412leds_dev_res),
};



int __init fs4412leds_device_init(void)
{
	platform_device_register(&fs4412leds_device);
	return 0;
}

void __exit fs4412leds_device_exit(void)
{
	platform_device_unregister(&fs4412leds_device);
}

MODULE_LICENSE("GPL");

module_init(fs4412leds_device_init);
module_exit(fs4412leds_device_exit);

5.宏替代(驱动中常用)

struct platform_driver xxx = {

};
module_platform_driver(xxx);
//最终展开后就是如下形式:
static int __init xxx_init(void)
{
return platform_driver_register(&xxx);
}
module_init(xxx_init);
static void __exit xxx_init(void)
{
return platform_driver_unregister(&xxx);
}
module_exit(xxx_exit)

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这是书的光盘。共分为两个部分,这是第一部分。 本书由浅入深、循序渐进地介绍了Windows驱动程序的开发方法与调试技巧。本书共分23章,内容涵盖了 Windows操作系统的基本原理、NT驱动程序与WDM驱动程序的构造、驱动程序中的同步异步处理方法、驱 动程序中即插即用功能、驱动程序的各种调试技巧等。同时,还针对流行的PCI驱动程序、USB驱动程序 、虚拟串口驱动程序、摄像头驱动程序、SDIO驱动程序进行了详细的介绍,本书最大的特色在于每一节 的例子都是经过精挑细选的,具有很强的针对性。力求让读者通过亲自动手实验,掌握各类Windows驱动 程序的开发技巧,学习尽可能多的Windows底层知识。   本书适用于中、高级系统程序员,同时也可用做高校计算机专业操作系统实验课的补充教材。 原创经典,威盛一线工程师倾力打造。深入驱动核心,剖析操作系统底层运行机制,通过实例引导,快 速学习编译、安装、调试的方法。   从Windows最基本的两类驱动程序的编译、安装、调试入手讲解,非常容易上手,用实例详细讲解 PCI、USB、虚拟串口、虚拟摄像头、SDIO等驱动程序的开发,归纳了多种调试驱动程序的高级技巧,如 用WinDBG和VMWARE软件对驱动进行源码级调试,深入Windows操作系统的底层和内核,透析Windows驱动 开发的本质。 本书是作者结合教学和科研实践经验编写而成的,不仅详细介绍了Windows内核原理,而且介绍了编程技 巧和应用实例,兼顾了在校研究生和工程技术人员的实际需求,对教学、生产和科研有现实的指导意义 ,是一本值得推荐的专著。              ——中国工程院院士   院士推荐   目前,电子系统设计广泛采用通用操作系统,达到降低系统的设计难度和缩短研发周期。实现操作 系统与硬件快速信息交换是电子系统设计的关键。   通用操作系统硬件驱动程序的开发,编写者不仅需要精通硬件设备、计算机总线,而且需要Windows 操作系统知识以及调试技巧。学习和掌握Windows硬件驱动程序的开发是电子系统设计人员必备的能力。   本书是作者结合教学和科研实践经验编写而成的,不仅详细介绍了Windows内核原理,并且介绍了编 程技巧和应用实例,兼顾了在校研究生和工程技术人员的实际需求,对教学、生产和科研有现实的指导 意义,是一本值得推荐的专著。 第1篇 入门篇 第1章 从两个最简单的驱动谈起 本章向读者呈现两个最简单的Windows驱动程序,一个是NT驱动程序,另一个是WDM驱动程序。 这两个驱动程序没有操作具体的硬件设备,只是在系统里创建了虚拟设备。在随后的章节中,它们会作 为基本驱动程序框架,被本书其他章节的驱动程序开发所复用。笔者将带领读者编写代码、编译、安装 和调试程序。   1.1 DDK的安装   1.2 第一个驱动程序HelloDDK的代码分析    1.2.1 HelloDDK的头文件    1.2.2 HelloDDK的入口函数    1.2.3 创建设备例程    1.2.4 卸载驱动例程    1.2.5 默认派遣例程   1.3 HelloDDK的编译和安装    1.3.1 用DDK环境编译HelloDDK    1.3.2 用VC集成开发环境编译HelloDDK    1.3.3 HelloDDK的安装   1.4 第二个驱动程序HelloWDM的代码分析    1.4.1 HelloWDM的头文件    1.4.2 HelloWDM的入口函数    1.4.3 HelloWDM的AddDevice例程    1.4.4 HelloWDM处理PNP的回调函数    1.4.5 HelloWDM对PNP的默认处理    1.4.6 HelloWDM对IRP_MN_REMOVE_DEVICE的处理    1.4.7 HelloWDM对其他IRP的回调函数    1.4.8 HelloWDM的卸载例程   1.5 HelloWDM的编译和安装    1.5.1 用DDK编译环境编译HelloWDM    1.5.2 HelloWDM的编译过程    1.5.3 安装HelloWDM   1.6 小结  第2章 Windows操作驱动基本概念  驱动程序被操作系统加载在内核模下,它与Windows操作系统内核的其他组件进行密切交互。本章主 要介绍Windows操作系统内核的基本概念,同时还介绍应用程序和驱动程序之间的通信方法。   2.1 Windows操作系统概述    2.1.1 Windows家族    2.1.2 Windows特性    2.1.3 用户模和内核模    

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值