linux kernel module 实例

先了解一下概念:

Linux内核同步机制API函数:宏:spin_lock_init ( )

宏定义:

      在内核源码中的位置:Linux-2.6.30/include/linux/spinlock.h

宏定义格式:# define spin_lock_init(lock)                             \
              do { *(lock) = SPIN_LOCK_UNLOCKED; } while (0) 

宏功能描述:

       宏spin_lock_init( ):初始化自旋锁lock,其实是将自旋锁指针lock 指向SPIN_LOCK_UNLOCKED宏,该宏的定义在内核文件linux-2.6.30/include/linux/spinlock_types.h中,它表示自旋锁的状态为未加锁。 

何谓自旋锁?它是为实现保护共享资源而提出一种锁机制。其实,自旋锁与互斥锁比较类似,它们都是为了解决对某项资源的互斥使用。无论是互斥锁,还是自旋锁,在任何时刻,最多只能有一个保持者,也就说,在任何时刻最多只能有一个执行单元获得锁。但是两者在调度机制上略有不同。对于互斥锁,如果资源已经被占用,资源申请者只能进入睡眠状态。但是自旋锁不会引起调用者睡眠,如果自旋锁已经被别的执行单元保持,调用者就一直循环在那里看是否该自旋锁的保持者已经释放了锁,"自旋"一词就是因此而得名。


本案例为系统内所有子卡的公共数据,均为静态数据,包含子卡的ID、基本信息、连接信息以及与外面不同类型板卡相连是的不同setting.我们把每一类卡的这些信息,全部放在一个struct里,叫做card_info_t . 

const card_info_t  *card_info_A;
const card_info_t  *card_info_B;


系统内所有的卡做成一个list:

const card_info_t  **card_info_list;


这样就把所有卡的信息全部放到list里面了,从功能角度,先把客户需求完完全全处理好。

接下来,我们把用户的数据与kernel module 的结构联系起来,用一个全局的结构体:

typedef struct 
kernel_glb_ {
 int major;spinlock_t spinlock;
	const card_info_t  **card_info_list;
	const card_info_t  *card_info;
} kernel_glb_t;
static kernel_glb_t  global;
kernel_glb_t *  gbl = &global;

其中的spinlock自旋锁是kernel用来控制资源使用的;major是用来获取kernel module的符号设备的设备号的;


接下来我们还需要定义符号文件的操作API,在linux kernel里,定义了一个file_operations的结构体,用来处理字符设备的操作API,诸如:read/write/lock/unlock/ioctl等;这个里面的任何一个API,我们都可以自行写好,然后挂接到相应的指针上即可。

由于此系统数据比较多,不同类型子卡的数据又有很多种类,我们获取的内容组合也多,不是简单地读写文件,所以我们用out-of-band的ioctl来操作,通过传不同的命令码来实现获取不同的数据;现在ioctl已经不怎么用了,我们用unlocked_ioctl,具体他们之间是什么区别,可以参考一下回答:

ioctl() is one of the remaining parts of the kernel which runs under the Big Kernel Lock (BKL). In the past, the usage of the BKL has made it possible for long-running ioctl()methods to create long latencies for unrelated processes.

Follows an explanation of the patch that introduced unlocked_ioctl and compat_ioctl into 2.6.11. The removal of the ioctl field happened a lot later, in 2.6.36.

Explanation: When ioctl was executed, it took the Big Kernel Lock (BKL), so nothing else could execute at the same time. This is very bad on a multiprocessor machine, so there was a big effort to get rid of the BKL. First, unlocked_ioctl was introduced. It lets each driver writer choose what lock to use instead. This can be difficult, so there was a period of transition during which old drivers still worked (using ioctl) but new drivers could use the improved interface (unlocked_ioctl). Eventually all drivers were converted and ioctl could be removed.

compat_ioctl is actually unrelated, even though it was added at the same time. Its purpose is to allow 32-bit userland programs to make ioctl calls on a 64-bit kernel. The meaning of the last argument to ioctl depends on the driver, so there is no way to do a driver-independent conversion.


这里我们把挂在unlocked_ioctl的API叫做:card_data_ioctl;

long
card_data_ioctl (struct file *filep, unsigned int cmd, unsigned long params)
{
       //用户空间拷贝数据到内核空间这里,这里用户的params和内核的P都是data_ioctl_t的类型,这个类型根据实际需求自己定义即可;
	if (copy_from_user(&p, (void *) params, sizeof(data_ioctl_t)))
	switch(cmd) {
		case  GET_CARD_ID: 
			get_card_id(p); break;
		case  GET_CARD_DATA: 
			get_card_DATA(p); break;

	};
    if (copy_to_user((void *) params, &p, sizeof(data_ioctl_t)));最后把数据给用户空间;
}


那么我们需要的 file_operations,就是这样定义的:


static struct file_operations fops = {
    owner               : THIS_MODULE,
    unlocked_ioctl      : card_data_ioctl,
};


最后我们在init函数里,就可以注册这个设备了,在linux里,注册的函数是这个:


int register_chrdev (	unsigned int  	major,
			const char *  	name,
			const struct file_operations *  	fops
);

int
data_init_module (void)
{ 
    spin_lock_init(&gbl->spinlock);
    if ((gbl->major = register_chrdev(gbl->major, KLM_NAME, &fops)) < 0) {
        return (gbl->major);
    }
    return (0);
}

int
data_cleanup_module(void)
{
    unregister_chrdev(gbl->major, KLM_NAME);
}


moudle_init(data_init_moudle);
module_exit(data_cleanup_moudle);

如何用这个kernel module:

用的方法就很简单了,直接调用到card_data_ioctl即可。一下就是一个例子:

if ((gbl->fd = open(KLM_NAME, O_RDWR)) == -1){}
if ((rc_ = ioctl(gbl->fd, GET_CARD_DATA, params_p_)) != 0) {}






版权声明:本文为luokingfly原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。