LINUX驱动入门(一)

前言:linux

本文将结合简单的驱动代码,讲述编写LINUX下驱动代码流程。所使用的平台是Ubantu14.。shell

本文讲述流程是:先放代码,编译生成驱动,安装卸载驱动。这个流程走完后再讲解驱动代码。bash

驱动测试代码(test.c):app

#include <asm/siginfo.h>
#include <linux/rcupdate.h>
#include <linux/version.h>
#include <linux/slab.h>
#include <linux/kobject.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/jiffies.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/uaccess.h>
#include <linux/sched.h>
#include <linux/device.h>

/* 该驱动支持PCIE设备数量 */
#define CM_PCIE_MAX_MINORS (3)

/* 该驱动的名称 */
#define CM_PCIE_DRIVER_NAME "cm_cpie"

/* 配置信息 */
#define CM_ALTERA_ARRIA10_PCI_ID (0xe003)
#define CM_ALTERA_ARRIA10_PCI_VID (0x1172)

/* 逻辑类指针 */
static struct class *g_cmpcie_class = NULL;

/* 主设备号 */
static int g_cmpcie_major = 0;

/* 设备标记位 */
static unsigned char g_cmpcie_devices[CM_PCIE_MAX_MINORS];

/* 设备配置信息 */
static struct pci_device_id cmpcie_ids[] = {
	{ PCI_DEVICE(CM_ALTERA_ARRIA10_PCI_VID, CM_ALTERA_ARRIA10_PCI_ID) },
	{ 0 }
};

/* PCI-E设备插入内核时调用的函数 */
static int probe(struct pci_dev *dev, const struct pci_device_id *id)
{
	printk("@INFO hava a pcie driver inster\n");
	return 0;
}

/* PCI-E设备拔出内核调用的函数 */
static void remove(struct pci_dev *dev)
{
	printk("@INFO hava a pcie driver remove\n");
}

/* PCI-E驱动实例 */
static struct pci_driver g_cmpcie_driver = {
	.name = CM_PCIE_DRIVER_NAME,  //驱动程序名称
	.id_table = cmpcie_ids, //配置信息
	.probe = probe,  //PCI-E设备插入内核时调用的函数
	.remove = remove, //PCI-E设备拔出内核时调用的函数
};

/* 驱动初始化函数 */
static int pcie_driver_init(void)
{
	int i = 0, ret = 0;
	dev_t dev;
	printk("@INFO driver init\n");
	
	/* 初始化设备标记位 */
	for(i = 0; i < CM_PCIE_MAX_MINORS; i++)
	{
		g_cmpcie_devices[i] = 0;
	}

	/* 申请设备号 */
	ret = alloc_chrdev_region(&dev, 0, CM_PCIE_MAX_MINORS, CM_PCIE_DRIVER_NAME);
	if(ret)
	{
		printk("apply for dev fail\n");
	}
	else
	{
		printk("apply for dev success @dev %d\n", dev);
	}
	g_cmpcie_major = MAJOR(dev);
	
	/* 申请逻辑类指针 */
	g_cmpcie_class = class_create(THIS_MODULE, CM_PCIE_DRIVER_NAME);
	if( IS_ERR(g_cmpcie_class) )
	{
		printk("apply for class fail\n");
	}
	else
	{
		printk("apply for class success\n");
	}

	/* 在PCI-E总线上申请驱动 */
	ret = pci_register_driver(&g_cmpcie_driver);
	if(ret)
	{
		printk("apply for driver fail");
	}
	else
	{
		printk("apply for driver success");
	}

	return 0;
}

/* 驱动销毁函数 */
static void pcie_driver_exit(void)
{
	printk("driver exit");

	/* 释放驱动 */
	pci_unregister_driver(&g_cmpcie_driver);

	/* 释放指针 */
	class_destroy(g_cmpcie_class);

	/* 释放设备号 */
	unregister_chrdev_region(MKDEV(g_cmpcie_major, 0), CM_PCIE_MAX_MINORS);
}

module_init(pcie_driver_init);
module_exit(pcie_driver_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Wang jianbin");
MODULE_DESCRIPTION("This is a driver for PCIE");

同一目录下的Makefile文件函数

#you want produce module name
obj-m := modules.o

#module needed object file name
modules-objs := test.o

#environment needed to complie the module 
KDIR := /lib/modules/`uname -r`/build

#loalce path
PWD := $(shell pwd)

#M is source file path
all:
	make -C $(KDIR) M=$(PWD) modules

clean:
	rm  *.o *.ko *.order *.symvers *.mod.c

运行  make all测试

如图modules.ko即是驱动程序   ui

安装驱动命令:insmod modules.ko 指针

查看驱动信息命令:modinfo modules.kocode

分析驱动依赖性名:depend modules.koblog

卸载驱动命令:rmmod modules

查看内核输出信息:dmesg

查看全部驱动命令:lsmod

查看设备号命令 : cat /pro/devices