系统之家 - Windows操作系统&装机软件下载网站!

当前位置: 首页  >  教程资讯  >  电脑教程 Linux字符设备驱动编写基本流程

Linux字符设备驱动编写基本流程

时间:2023-06-02 16:16:41 来源: 人气:

   ---简介,  Linux下的MISC简单字符设备驱动虽然使用简单,但却不灵活。,  只能建立主设备号为10的设备文件。字符设备比较容易理解,同时也能够满足大多数简单的硬件设备,字符设备通过文件系          统中的名字来读取。这些名字就是文件系统中的特殊文件或者称为设备文件、文件系统的简单结点,一般位于/dev/目录下          使用ls进行查看会显示以C开头证明这是字符设备文件crw--w---- 1 root tty 4, 0 4月 14 11:05 tty0。第一个数字是主设备                号,第二个数字是次设备号。,  ---分配和释放设备编号,  1)在建立字符设备驱动时首先要获取设备号,为此目的的必要的函数是register_chrdev_region,在linux/fs.h中声明:int                register_chrdev_region(dev_t first, unsigned int count, char *name);first是你想要分配的起始设备编号,first的次编号通            常是0,count是你请求的连续设备编号的总数。count如果太大会溢出到下一个主设备号中。name是设备的名字,他会出          现在/proc/devices 和sysfs中。操作成功返回0,如果失败会返回一个负的错误码。,  2)如果明确知道设备号可用那么上一个方法可行,否则我们可以使用内核动态分配的设备号int alloc_chrdev_region(dev_t            *dev, unsigned int firstminor,unsigned int count, char *name);dev是个只输出的参数,firstminor请求的第一个要用的次            编号,count和name的作用如上1)对于新驱动,最好的方法是进行动态分配,  3)释放设备号,void unregister_chrdev_region(dev_t first unsigned int count);,  ---文件操作file_operations结构体,内部连接了多个设备具体操作函数。该变量内部的函数指针指向驱动程序中的具体操           作,没有对应动作的指针设置为NULL。,  1)fops的第一个成员是struct module *owner 通常都是设置成THIS_MODULE。,  linux/module.h中定义的宏。用来在他的操作还在被使用时阻止模块被卸载。,  2)loff_t (*llseek) (struct file *, loff_t, int);该方法用以改变文件中的当前读/写位置,  返回新位置。,  3)ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);该函数用以从设备文件,  中读取数据,读取成功返回读取的字节数。,  4)ssize_t (*write) (struct file *, const char __user *,size_t , loff_t *);该函数用以向设备,  写入数据,如果成功返回写入的字节数。,  5)int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);ioctl系统调用提供,  发出设备特定命令的方法。,  6)int (*open) (struct inode *, struct file *);设备文件进行的第一个操作,打开设备文件。,  7)int (*release) (struct inode *, struct file *);释放文件结构函数指针。,  一般初始化该结构体如下:,  struct file_operations fops = {,  .owner = THIS_MODULE, .llseek = xxx_llseek, .read = xxx_read, .write = xxx_write,,  .ioctl = xxx_ioctl, .open = xxx_open, .release = xxx_release };,  PS:以上的文件操作函数指针并不是全部,只是介绍了几个常用的操作。,  ---文件结构,  struct file定义在linux/fs.h中,是设备驱动中第二个最重要的数据结构,此处的file和,  用户空间程序中的FILE指针没有关系。前者位于内核空间,后者位于用户控件。,  文件结构代表一个打开的文件。(他不特定给设备驱动;系统中每个打开的文件,  有一个关联的struct file在内核空间)。它由内核在open时创建,并可以传递给文件件,  操作函数,文件关闭之后,内核释放数据结构。,  1)mode_t f_mode。确定文件读写模式,  2)loff_t f_ops。当前读写位置,  3)unsigned int f_flags 。文件标志,O_RDONLY、O_NONBLOCK,,  4)struct file_operations *f_op。关联文件相关操作,  5)void *private_data。open系统调用设置该指针NULL,指向分配的数据。,  6)struct dentry *f_dentry。关联到文件的目录入口dentry结构。,  ---inode结构,  inode结构由内核在内部用来表示文件。它和代表打开文件描述符的文件结构是不,  同的。inode结构包含大量关于文件的信息。作为通用规则,这个结构只有两个成,  员对驱动代码有作用。,  dev_t i_rdev。对于代表设备文件的节点,这个成员包含实际的设备编号。,  struct cdev *i_cdev。内核内部结构,代表字符设备。,  ---字符设备注册,  在内核调用你的设备操作前,你编写分配并注册一个或几个struct cdev.,  struct cdev *my_cdev = cdev_alloc(); my_cdev->ops = &my_fops;,  或者定义成static均可。,  对定义的cdev变量进行初始化,可以使用专门的函数,或者使用如上的方法。,  cdev_init( my_cdev, &my_fops); 其实上边的两行代码就是做了这个函数的工作。,  最后告诉内核该cdev。,  cdev_add(struct cdev *dev, dev_t num, unsigned int count);,  /*上述总结,到此关于设备文件相关的结构数据以及如何注册销毁等操作相关的,  函数基本上都已经介绍完毕。主要的还是要设计具体操作的函数来实现具体的,  逻辑操作*/,  以下代码整理、摘录自《Android深度探索HAL与驱动开发-李宁》LED驱动篇,  #include,  #include,  #include,  #include,  #include,  #include,  #include,  #deifne DEVICE_NAME "s3c6410_leds",  #define DEVICE_COUNT 1,  #define S3C6410_LEDS_MAJOR 0,  #define S3C6410_LEDS_MINOR 234,  #define PARAM_SIZE 3,  static int major = S3C6410_LEDS_MAJOR;,  static int minor = S3C6410_LEDS_MINOR;,  static dev_t dev_number;,  static int leds_state = 1;,  static char *params[] = {"string1","string2","string3"};,  static iint param_size = PARAM_SIZE;,  static struct class *leds_class = NULL;,  static int s3c6410_leds_ioctl (struct file *file, unsigned int cmd, unsigned long arg),  {,  switch (cmd),  {,  unsigned tmp;,  case 0:,  case 1:,  if (arg > 4),  return -EINVAL;,  tmp = ioread32 (S3C64XX_GPMDAT);,  if (cmd == 1),  tmp &= (~(1 << arg));,  else,  tmp |= (1 << arg);,  iowrite32 (tmp, S3C64XX_GPMDAT);,  return 0;,  default : return -EINVAL;,  },  },  static ssize_t s3c6410_leds_write (struct file *file, const char __user *buf, size_t count, loff_t *ppos),  {,  unsigned tmp = count;,  unsigned long i = 0;,  memset(mem, 0, 4);,  if (count > 4),  tmp = 4;,  if (copy_from_user (mem, buf, tmp) ),  return -EFAULT;,  else{,  for( i=0; i<4; i++),  {,  tmp = ioread32(S3C64XX_GPMDAT);,  if (mem[i] == 1),  tmp &= (~(1 << i));,  else,  tmp |= (1 << i);,  iowrite32(tmp, S3C64XX_GPMDAT);,  },  return count;,  },  },  static struct file_operations dev_fops =,  {.owner = THIS_MODULE, .unlocked_ioctl = s3c6410_leds_ioctl, .write = s3c6410_leds_write};,  static struct cdev leds_cdev;,  static int leds_create_device(void),  {,  int ret = 0;,  int err = 0;,  cdev_init (&leds_cdev, &dev_fops);,  leds_cdev.owner = THIS_MODULE;,  if (major > 0),  {,  dev_number = MKDEV(major,minor);,  err = register_chrdev_region(dev_number, DEVICE_COUNT, DEVICE_NAME);,  if (err < 0),  {,  printk(KERN_WANRING "register_chrdev_region errorn");,  return err,  },  },  else{,  err = alloc_chrdev_region(&leds_cdev.dev, 10, DEVICE_COUNT, DEVICE_NAME);,  if(err < 0),  {,  printk (KERN_WARNING "alloc_chrdev_region errorn");,  return err;,  },  major = MAJOR(leds_cdev.dev);,  major = MINOR(leds_cdev.dev);,  dev_number = leds_cdev.dev;,  },  ret = cdev_add(&leds_cdev,dev_number, DEVICE_COUNT);,  leds_class = class_create (THIS_MODULE, DEVICE_NAME);,  device_create (leds_class, NULL, dev_number, NULL, DEVICE_NAME);,  return ret;,  },  static void leds_init_gpm(int leds_default){,  int tmp = 0;,  tmp = ioread32(S3C64XX_GPMCON);,  tmp &= (~0xffff);,  tmp |= 0x1111;,  iowrite32(tmp,S3C64XX_GPMCON);,  tmp = ioread32(S3C64XX_GPMPUD);,  tmp &= (~0XFF);,  tmp |= 0xaa;,  iowrite32(tmp,S3C64XX_GPMPUD);,  tmp = ioread32(S3C64XX_GPMDAT);,  tmp &= (~0xf);,  tmp |= leds_default;,  iowrite32(tmp, S3C64XX_GPMDAT);,  },  static leds_init( void),  {,  int ret;,  ret = leds_create_device();,  leds_init_gpm (~leds_state);,  printk(DEVICE_NAME"tinitializedn");,  return ret;,  },  static void leds_destroy_device(void),  {,  device_destroy(leds_class, dev_number);,  if(leds_class),  class_destroy(leds_class);,  unregister_chrdev_region(dev_number, DEVICE_NAME);,  },  static void leds_exit(void),  {,  leds_destroy_device();,  printk(DEVICE_NAME"texitn");,  },  module_init(leds_init);,  module_exit(leds_exit);,  module_param(leds_state, int, S_IRUGO|S_IWUSR);,  module_param_array(params, charp, ?m_size, S_IRUGO|S_IWUSR);,  MODULE_LICENSE("GPL");,  MODULE_AUTHOR("lining");,

作者

教程资讯

电脑教程排行

系统教程

系统主题