Chinaunix首页 | 论坛 | 博客
  • 博客访问: 431957
  • 博文数量: 122
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 688
  • 用 户 组: 普通用户
  • 注册时间: 2013-09-04 12:30
文章分类

全部博文(122)

文章存档

2017年(5)

2016年(4)

2015年(56)

2014年(41)

2013年(16)

我的朋友

分类: LINUX

2014-12-10 19:09:34

前半部分是调试问题分析,后半部分是驱动详解。

前台代码:接收用户输入的命令,并把命令发到后台。

点击(此处)折叠或打开

  1. struct icfs_cmd_func_t
  2. {
  3.     char cmd[32];
  4.     int (*call_back_t)(int argc, char **agrv);
  5.     char help[128];
  6. };
  7. ......

  8. struct icfs_cmd_func_t g_stat_cmds[ICFS_CMD_COUNT] =
  9. {
  10.     {"-h",         icfs_cmd_help,          "help",          },
  11.     {"-v",         icfs_cmd_showversion, "show version", },
  12.     {"-stat_start",     icfs_cmd_stat_start, "stat_start", },
  13.     {"-stat_stop",     icfs_cmd_stat_stop,        "stat_stop",         },
  14. };

  15. void usage()
  16. {
  17.     //提示信息
  18. }

  19. int icfs_cmd_help(int argc, char **agrv)
  20. {
  21.     int i = 0;

  22.     for(i=0; i<ICFS_CMD_COUNT; i++)
  23.     {
  24.         printf("%s %s\n", g_stat_cmds[i].cmd, g_stat_cmds[i].help);
  25.     }
  26.     
  27.     return 0;
  28. }

  29. int icfs_cmd_showversion(int argc, char **agrv)
  30. {
  31.     int iFd = 0;
  32.     char acBuf[STATISTICS_BUF_SIZE];

  33.     iFd = open("/dev/icfs_debug_dev", O_RDONLY);
  34.     if(iFd < 0)
  35.     {
  36.           printf("open df error!\n");
  37.           return -1;
  38.     }
  39.     
  40.     ioctl(iFd, STATISTIC_CMD_VERSION, acBuf);
  41.     close(iFd);
  42.     
  43.     return 0;
  44. }
  45. ......
  46. int icfs_cmd_dispatch(int argc, char **argv)
  47. {
  48.     int i;

  49.     for (i=0; i<ICFS_CMD_COUNT; i++)
  50.     {
  51.         if (!strcmp(argv[1], g_stat_cmds[i].cmd))
  52.         {
  53.             g_stat_cmds[i].call_back_t(argc, argv);
  54.         }
  55.     }

  56.     return 0;
  57. }

  58. int main(int argc, char *argv[])
  59. {
  60.   int ret;

  61.   if(argc < 2){
  62.     usage();
  63.     return -1;
  64.   }

  65.   ret = icfs_cmd_dispatch(argc, argv);
  66.   
  67.   return 0;
  68. }
驱动程序:
register_chrdev注册设备的时候使用的设备号要和MKDEV(MAJOR_NUM, 0)使用的主设备号保持一致,否则会提示权限不够(这种权限提示也会出现在用户没有root权限的时候)。
对于代码中红色加粗有下划线的函数一开始我用的是class_device_create和class_device_unregister,加上头文件#include 依然提示函数不存在,后来查找资料发现版本不一样,函数名也发生了变化,改成如下代码就没有问题了。

点击(此处)折叠或打开

  1. #define ICFS_DEBUG_DEV             "ICFS_DEBUG_DEV"

  2. #define STATISTICS_BUF_SIZE     256

  3. #define MAJOR_NUM 200 //主设备号

  4. static struct class *pstICFSDebugDrv_class;
  5. static struct device *pstICFSSDebugDrv_class_dev;

  6. volatile unsigned long *gpfcon = NULL;
  7. volatile unsigned long *gpfdat = NULL;

  8. extern char *icfs_kernel_version;
  9. extern int icfs_stat_start(void);
  10. extern int icfs_stat_stop(void);


  11. #if ICFS_KERN_VERSION <=2006032000
  12. int icfs_debug_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
  13. #else
  14. long icfs_debug_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
  15. #endif
  16. {
  17.     char buf[STATISTICS_BUF_SIZE];
  18.     unsigned long ret;
  19.     
  20.     printk(KERN_ALERT" icfs_debug_ioctl arg %lu\n", arg);
  21.     
  22.     ret = copy_from_user(buf, (struct ioctl_data *)arg, 100);
  23.     switch (cmd)
  24.     {
  25.         .....
  26.         case 2:
  27.             if(NULL != icfs_kernel_version)
  28.             {
  29.                 printk(KERN_ALERT"version: %s\n", icfs_kernel_version);
  30.             }
  31.         .....
  32.         default:
  33.             printk(KERN_ALERT"icfs_debug_ioctl default: \n");
  34.     }
  35.     
  36.     return 0;
  37. }

  38. struct file_operations icfs_debug_fops = {
  39. #if ICFS_KERN_VERSION <=2006032000
  40.   .ioctl = icfs_debug_ioctl,
  41. #else
  42.   .unlocked_ioctl = icfs_debug_ioctl,
  43. #endif
  44. };

  45. int icfs_cmd_init(void)
  46. {
  47.     int ret;
  48.     
  49.     ret = register_chrdev(MAJOR_NUM,ICFS_DEBUG_DEV, &icfs_debug_fops);
  50.     if(ret)
  51.     {
  52.         printk(KERN_ALERT"icfs_debug_dev register failure\n");
  53.         return ret;
  54.     }
  55.     else
  56.     {
  57.      pstICFSDebugDrv_class = class_create(THIS_MODULE, ICFS_DEBUG_DEV);
  58.         
  59.         pstICFSSDebugDrv_class_dev = device_create(pstICFSDebugDrv_class,
  60.              NULL,
  61.              MKDEV(MAJOR_NUM, 0),
  62.              NULL,
  63.              "icfs_debug_dev");

  64.         printk(KERN_ALERT"icfs_debug_dev register success!\n");
  65.     }
  66.     return 0;
  67. }

  68. void icfs_cmd_exit(void)
  69. {
  70.     unregister_chrdev(MAJOR_NUM, ICFS_DEBUG_DEV);
  71.     device_unregister(pstICFSSDebugDrv_class_dev);
  72.     class_destroy(pstICFSDebugDrv_class);

  73.     return;
  74. }
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()
时要先释放设备号,再释放设备,最后释放设备类型。
阅读(890) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~