linux系统下驱动的插入

linux的驱动插入一定会进过linux内核,为了保证安全性linux内核会直接阻拦应用层直接访问驱动层(也就是在安装linux系统后,裸机的驱动插入方法就无效了),此时需要按照linux系统的插入方法来做,本文为字符设备驱动框架流程:

在这之前先要明白linux内核下的模块怎么摆放的:

 让我们从最底下向上出发

1在内核层向linux内核申请插入驱动模块

        1)申请设备号(用于代表模块)

           


int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,const char *name)



dev :alloc_chrdev_region函数向内核申请下来的设备号

baseminor :次设备号的起始

count: 申请次设备号的个数

name :执行 cat /proc/devices显示的名称,,表示自己的注释

        例如:dev_t devnum;

                  alloc_chrdev_region(&devnum, 0, 1, "myfifo");

                   printk("%d %d\n", MAJOR(devnum), MINOR(devnum) );

        2)创建一个模块结点(你写的模块)

                    

           //功能
  struct file_operations myops = {
	.open = adc_init,
	.read = adc_read,
	.unlocked_ioctl = adc_ctl,
	.release = adc_release
};

    struct cdev *mycdev;                //创建一个设备节点
    mycdev = cdev_alloc();              //去申请这个节点空间
	cdev_init(mycdev, &myops);          //将节点与你想要的功能放在一起
    

       上文中的功能放到最下面了

         例如:mycdev = cdev_alloc();
                   cdev_init(mycdev, &myops);

        3)绑定模块号与设备节点

         


int cdev_add(struct cdev *dev, dev_t num, unsigned int count);

这里, dev 是 cdev 结构, num 是这个设备响应的第一个设备号, count 是应当关联到设备的设备号的数目. 常常 count 是 1, 但是有多个设备号对应于一个特定的设备的情形. 例如, 设想 SCSI 磁带驱动, 它允许用户空间来选择操作模式(例如密度), 通过安排多个次编号给每一个物理设备.

           cdev_add(MYADC.mycdev, MYADC.devnum, 1); 

        4)完成,打印插入成功的提示信息

        例如:printk("module install-axxxxxxxxxxxxxxxx--------------------------\n");

这样就完成了一个linux中驱动的初始化

具体函数的设置

linux只会给应用层留系统调用接口来直接控制内核,

例如:open,read,write,unlocked——ioctl,release,close,等

通过设置这些方法就可以实现自己想要的系统调用。

具体功能的设置,方法如下

//在相应的系统调用应该进行的函数
struct file_operations myops = {
	.open = adc_init,              
	.read = adc_read,
	.unlocked_ioctl = adc_ctl,
	.release = adc_release
};

下面来看一个实际adc模块代码 

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/version.h>
#include <asm/io.h>
#include <asm/ioctl.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/uaccess.h>

MODULE_AUTHOR("xxx");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("for module test");

#define SETBIT  _IO('A', 0)

struct myadc{
	struct cdev *mycdev;
	dev_t devnum;
	int *ADCCON;
	int *ADCMUX;
	int *ADCDAT;
}MYADC;

//void adc_init(void)
int adc_init(struct inode *i, struct file *f)
{
	MYADC.ADCCON = ioremap(0x126c0000, 4);
	MYADC.ADCDAT = ioremap(0x126c000c, 4);
	MYADC.ADCMUX = ioremap(0x126c001c, 4);

	//*MYADC.ADCCON = (*MYADC.ADCCON&~(0xff<<6)) | (200<<6);
	iowrite32((ioread32(MYADC.ADCCON)&~(0xff<<6)) | (200<<6) ,MYADC.ADCCON);

	//*MYADC.ADCCON |= 1<<14;
	iowrite32(ioread32(MYADC.ADCCON)|(1<<14), MYADC.ADCCON);

	//*MYADC.ADCCON &= ~(1<<2);
	iowrite32((ioread32(MYADC.ADCCON)&~(1<<2)) ,MYADC.ADCCON);

	//*MYADC.ADCMUX = 3;
	iowrite32(3, MYADC.ADCMUX);
	
	return 0;
}

void adc_set(int count)
{
	
}

//void adc_release()
int adc_release(struct inode *i, struct file *f)
{

	iounmap(MYADC.ADCCON);
	iounmap(MYADC.ADCDAT);
	iounmap(MYADC.ADCMUX);

	return 0;
}

ssize_t adc_read(struct file *f, char __user *dataptr, size_t size, loff_t *offset)
{
	int data;
	//*MYADC.ADCCON |= 1;//start 
	iowrite32(ioread32(MYADC.ADCCON)|1, MYADC.ADCCON);
	while(!(ioread32(MYADC.ADCCON) & (1<<15)));//procee
	data = ioread32(MYADC.ADCDAT)&0xfff;
	//printk("xxxxxxxxxx: %d\n", data);
	if(copy_to_user(dataptr, &data, sizeof(data))){}

	return sizeof(data);
}

//void adc_ctl()
long adc_ctl(struct file *f, unsigned int cmd, unsigned long arg)
{
	switch(cmd)
	{

	}
	return 0;
}

struct file_operations myops = {
	.open = adc_init,
	.read = adc_read,
	.unlocked_ioctl = adc_ctl,
	.release = adc_release
};

static int mymodule_init(void)
{

	//1. request dev num
	alloc_chrdev_region(&MYADC.devnum, 0, 1, "xxxxxxxxxxxxxxxadcllllllllllllllll");
	printk("%d %d\n", MAJOR(MYADC.devnum), MINOR(MYADC.devnum) );	

	//2. create cdev struct
	MYADC.mycdev = cdev_alloc();
	cdev_init(MYADC.mycdev, &myops); 

	//3. insert my cdev into kernel
	cdev_add(MYADC.mycdev, MYADC.devnum, 1); 


	//adc_init();
	printk("module install-axxxxxxxxxxxxxxxx--------------------------\n");
	return 0;
}

static void mymodule_exit(void)
{
	//adc_off();
	//1. remove my cdev from kernel
	cdev_del(MYADC.mycdev);
	//2. free cdev struct
	//kfree(mycdev);
	//3. free dev num
	unregister_chrdev_region(MYADC.devnum, 1); 

	printk("module release--------------------------------\n");
}

module_init(mymodule_init);
module_exit(mymodule_exit);

            

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值