前半部分是调试问题分析,后半部分是驱动详解。
前台代码:接收用户输入的命令,并把命令发到后台。
-
struct icfs_cmd_func_t
-
{
-
char cmd[32];
-
int (*call_back_t)(int argc, char **agrv);
-
char help[128];
-
};
-
......
-
-
struct icfs_cmd_func_t g_stat_cmds[ICFS_CMD_COUNT] =
-
{
-
{"-h", icfs_cmd_help, "help", },
-
{"-v", icfs_cmd_showversion, "show version", },
-
{"-stat_start", icfs_cmd_stat_start, "stat_start", },
-
{"-stat_stop", icfs_cmd_stat_stop, "stat_stop", },
-
};
-
-
void usage()
-
{
-
//提示信息
-
}
-
-
int icfs_cmd_help(int argc, char **agrv)
-
{
-
int i = 0;
-
-
for(i=0; i<ICFS_CMD_COUNT; i++)
-
{
-
printf("%s %s\n", g_stat_cmds[i].cmd, g_stat_cmds[i].help);
-
}
-
-
return 0;
-
}
-
-
int icfs_cmd_showversion(int argc, char **agrv)
-
{
-
int iFd = 0;
-
char acBuf[STATISTICS_BUF_SIZE];
-
-
iFd = open("/dev/icfs_debug_dev", O_RDONLY);
-
if(iFd < 0)
-
{
-
printf("open df error!\n");
-
return -1;
-
}
-
-
ioctl(iFd, STATISTIC_CMD_VERSION, acBuf);
-
close(iFd);
-
-
return 0;
-
}
-
......
-
int icfs_cmd_dispatch(int argc, char **argv)
-
{
-
int i;
-
-
for (i=0; i<ICFS_CMD_COUNT; i++)
-
{
-
if (!strcmp(argv[1], g_stat_cmds[i].cmd))
-
{
-
g_stat_cmds[i].call_back_t(argc, argv);
-
}
-
}
-
-
return 0;
-
}
-
-
int main(int argc, char *argv[])
-
{
-
int ret;
-
-
if(argc < 2){
-
usage();
-
return -1;
-
}
-
-
ret = icfs_cmd_dispatch(argc, argv);
-
-
return 0;
-
}
驱动程序:
在register_chrdev注册设备的时候使用的设备号要和MKDEV(MAJOR_NUM, 0)使用的主设备号保持一致,否则会提示权限不够(这种权限提示也会出现在用户没有root权限的时候)。
对于代码中红色加粗有下划线的函数一开始我用的是class_device_create和class_device_unregister,加上头文件#include 依然提示函数不存在,后来查找资料发现版本不一样,函数名也发生了变化,改成如下代码就没有问题了。
-
#define ICFS_DEBUG_DEV "ICFS_DEBUG_DEV"
-
-
#define STATISTICS_BUF_SIZE 256
-
-
#define MAJOR_NUM 200 //主设备号
-
-
static struct class *pstICFSDebugDrv_class;
-
static struct device *pstICFSSDebugDrv_class_dev;
-
-
volatile unsigned long *gpfcon = NULL;
-
volatile unsigned long *gpfdat = NULL;
-
-
extern char *icfs_kernel_version;
-
extern int icfs_stat_start(void);
-
extern int icfs_stat_stop(void);
-
-
-
#if ICFS_KERN_VERSION <=2006032000
-
int icfs_debug_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-
#else
-
long icfs_debug_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-
#endif
-
{
-
char buf[STATISTICS_BUF_SIZE];
-
unsigned long ret;
-
-
printk(KERN_ALERT" icfs_debug_ioctl arg %lu\n", arg);
-
-
ret = copy_from_user(buf, (struct ioctl_data *)arg, 100);
-
switch (cmd)
-
{
-
.....
-
case 2:
-
if(NULL != icfs_kernel_version)
-
{
-
printk(KERN_ALERT"version: %s\n", icfs_kernel_version);
-
}
-
.....
-
default:
-
printk(KERN_ALERT"icfs_debug_ioctl default: \n");
-
}
-
-
return 0;
-
}
-
-
struct file_operations icfs_debug_fops = {
-
#if ICFS_KERN_VERSION <=2006032000
-
.ioctl = icfs_debug_ioctl,
-
#else
-
.unlocked_ioctl = icfs_debug_ioctl,
-
#endif
-
};
-
-
int icfs_cmd_init(void)
-
{
-
int ret;
-
-
ret = register_chrdev(MAJOR_NUM,ICFS_DEBUG_DEV, &icfs_debug_fops);
-
if(ret)
-
{
-
printk(KERN_ALERT"icfs_debug_dev register failure\n");
-
return ret;
-
}
-
else
-
{
-
pstICFSDebugDrv_class = class_create(THIS_MODULE, ICFS_DEBUG_DEV);
-
-
pstICFSSDebugDrv_class_dev = device_create(pstICFSDebugDrv_class,
-
NULL,
-
MKDEV(MAJOR_NUM, 0),
-
NULL,
-
"icfs_debug_dev");
-
-
printk(KERN_ALERT"icfs_debug_dev register success!\n");
-
}
-
return 0;
-
}
-
-
void icfs_cmd_exit(void)
-
{
-
unregister_chrdev(MAJOR_NUM, ICFS_DEBUG_DEV);
-
device_unregister(pstICFSSDebugDrv_class_dev);
-
class_destroy(pstICFSDebugDrv_class);
-
-
return;
-
}
module_init(icfs_cmd_init);
module_exit(icfs_cmd_exit);
字符设备驱动程序框架:
1、写出open、write函数
2、告诉内核
1)定义一个struct file_operations结构并填充好
static struct file_operations first_drv_fops = {
.owner = THIS_MODULE,
.open = first_drv_open,
.write = first_drv_write,
};
2)把struct file_operations结构体告诉内核
major = register_chrdev(0, "first_drv", &first_drv_fops); //注册, 告诉内核
相关参数:第一个,设备号,0自动分配主设备号,否则为主设备号0-255(一般填0)
第二个:设备名
第三个:struct file_operations结构体
3)register_chrdev由谁调用(入口函数调用)
static int first_drv_init(void)
4)入口函数须使用内核宏来修饰
module_init(first_drv_init);
module_init会定义一个结构体,这个结构体里面有一个函数指针指向first_drv_init这个函数,当我们加载或安装一个驱动时,内核会自动找到这个结构体,然后调用里面的函数指针,这个函数指针指向first_drv_init这个函数,first_drv_init这个函数就是把structfile_operations结构体告诉内核
5)有入口函数就有出口函数
module_exit(first_drv_exit);
最后加上遵循的协议
MODULE_LICENSE("GPL");
3.
class_create是创建设备类型,device_create是在/dev目录下创建设备节点。
class_create第一个参数是制定此类型设备的所有者是哪个模块,第二个参数是类型名字。
device_create第一个参数是设备所属的类,
第二个参数是这个设备的父设备(没有的就填NULL)
第三个参数是设备号
第四个参数是a pointer to a struct device that is assiociated with this class device.
第五个参数是设备名
注意,在2.6较早的内核版本中,device_create(…)函数名称不同,是class_device_create(…),所以在新的内核中编译以前的模块程序有时会报错,就是因为函数名称不同。
4.module_exit()时要先释放设备号,再释放设备,最后释放设备类型。
阅读(903) | 评论(0) | 转发(0) |