字符驱动小例子解析

1.
 MODULE_LICENSE ("GPL");
int hello_major = 250;
int hello_minor = 0;
int number_of_devices = 1;
char data[50]="foobar not equal to barfoo";
struct cdev cdev;
dev_t dev = 0;
 
static int hello_open (struct inode *inode, struct file *file)
{
  printk (KERN_INFO "Hey! device opened\n");
  return 0;
}
static int hello_release (struct inode *inode, struct file *file)
{
  printk (KERN_INFO "Hmmm... device closed\n");
  return 0;
}
ssize_t hello_read (struct file *filp, char *buff, size_t count, loff_t *offp)
{
  ssize_t result = 0;
  if (copy_to_user (buff, data, sizeof(data)-1))             // copy_to_user将数据返回给用户
    result = -EFAULT;
  else
    printk (KERN_INFO "wrote %d bytes\n", count);
   return result;
}
ssize_t hello_write (struct file *filp, const char  *buf, size_t count, loff_t *f_pos)
{
  ssize_t ret = 0;
  printk (KERN_INFO "Writing %d bytes\n", count);
  if (count>127) return -ENOMEM;
  if (count<0) return -EINVAL;
  if (copy_from_user (data, buf, count)) {             //  copy_from_user将用户数据读到本地buffer
    ret = -EFAULT;
  }
  else {
    data[127]='\0';
    printk (KERN_INFO"Received: %s\n", data);
    ret = count;
  }
  return ret;
}

struct file_operations hello_fops = {           //文件操作
  .owner = THIS_MODULE,
  .open  = hello_open,
  .release = hello_release,
  .read  = hello_read,
  .write = hello_write
};
 
static int __init hello_2_init (void)
{
  int result;
 
  dev = MKDEV (hello_major, hello_minor);           //拼装设备号,高12位为主设备号,低20位为从设备号。include/linux/kdev_t.h中定义的宏MKDEV。
  result = register_chrdev_region (dev, number_of_devices, "hello");// fs/char_dev.c中定义的函数,注册一个范围内的设备号,成功返回0。
  if (result<0) {
    printk (KERN_WARNING "hello: can't get major number %d\n", hello_major);
    return result;
  }
 
  /* dynamic allocation */
  cdev = cdev_alloc();      // fs/char_dev.c中定义的函数,分配一个cdev结构体
  cdev_init (cdev, &hello_fops); // fs/char_dev.c中定义的函数,关联cdev结构体和file_operations(在linux/fs.h中定义的结构体,里面为文件的常用操作定义)。
  cdev->owner = THIS_MODULE;
//  cdev->ops = &hello_fops;
  result = cdev_add (cdev, dev, 1);  // fs/char_dev.c中定义的函数,关联cdev结构体和dev(设备号)。
  if (result)
    printk (KERN_INFO "Error %d adding char_device", result);
 
  printk (KERN_INFO "Char device registered ...\n");
  return 0;
}
 
static void __exit hello_2_exit (void)
{
  dev_t devno = MKDEV (hello_major, hello_minor);
 
  if (cdev)
    cdev_del (cdev);     // fs/char_dev.c中定义的函数,取消cdev结构体和dev(设备号)的关联
 
  unregister_chrdev_region (devno, number_of_devices); // fs/char_dev.c中定义的函数,释放cdev结构体的空间和dev设备号
 
  printk (KERN_INFO "char device cleaned up :)\n");
}
 
module_init (hello_2_init);
module_exit (hello_2_exit);         //宏module_init和module_exit都被定义在linux源码的include/linux/init.h中,是为init_module和cleanup_module起别名用的(在静态编译时防止重复定义init_module和cleanup_module)。
2. 
 
 
 
当open一个设备节点时,inode中德i_cdev会指向找到的cdev,同时file中的f_op获得已经注册的驱动的file_operations。
cdev---dev (如:250,0)                                                                                             
        ---ops(mypos)---open,read,write等。<---------------------->  file---f_op
 
3.
用户调用read等系统调用时,系统首先调用sys_read(SYSCALL_DEFINE3),再调用vfs_read,再调用初始化完成的结构体file中的file_operations中的read函数,即为调用了hello_read函数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值