【驱动】第10课、字符设备驱动另一种写法之学习笔记

主   机:VMWare--Ubuntu-16.04.2-x64-100ask

开发板:Mini2440--256M NandFlash,   2M NorFlash,   64M SDRAM,   LCD-TD35;
    bootlorder:u-boot1.16,        Kernel:2.6.22.6;
编译器:arm-linux-gcc-3.4.5


 

1、新字符设备驱动思想:把register_chrdev(主,name,&fops);拆分成三部分:
register_chrdev_region(devid, HELLO_CNT, "hello"); 或 alloc_chrdev_region(&devid, 0, HELLO_CNT, "hello");
cdev_init(&hello_cdev, &hello_fops);
cdev_add(&hello_cdev, devid, HELLO_CNT);
举例:
if(major)
{
devid = MKDEV(major, 0);
err = register_chrdev_region(devid, HELLO_CNT, "hello");
}
else
{
err = alloc_chrdev_region(&devid, 0, HELLO_CNT, "hello");
major = MAJOR(devid);
}
if(err < 0)
{
printk(KERN_ERR "hello chrdev_region err: %d\n", err);
return -ENOMEM;
}
cdev_init(&hello_cdev, &hello_fops);
err = cdev_add(&hello_cdev, devid, HELLO_CNT);


2、RTC时间设置:
date 011816322019.05
测试RTC:
1. 修改arch\arm\plat-s3c24xx\common-smdk.c
static struct platform_device __initdata *smdk_devs[] = {
&s3c_device_nand,
&smdk_led4,
&smdk_led5,
&smdk_led6,
&smdk_led7,
改为(在数组smdk_devs里加上s3c_device_rtc):
static struct platform_device __initdata *smdk_devs[] = {
&s3c_device_nand,
&smdk_led4,
&smdk_led5,
&smdk_led6,
&smdk_led7,
&s3c_device_rtc,

2. make uImage, 使用新内核启动
# ls /dev/rtc* -l
# date /* 显示系统时间 */
# date 011816322019.05     /* 设置系统时间 date [MMDDhhmm[[CC]YY][.ss]] ,月日时分年.秒*/

               /* 上面只是设置了软件系统里的时间,还需写入RTC模块芯片,方可不掉电丢失 */
# hwclock -w          /* 把系统时间写入RTC模块芯片 */
3. 断电,重启,执行date。

演例:
使用新内核启动后,RTC系统时间设置如下:
# ls /dev/rtc* -l
crw-rw---- 1 0 0 254, 0 Apr 2 22:03 /dev/rtc0
# date
Sun Apr 2 22:04:05 UTC 2006
# date --help
Usage: date [OPTION]... [MMDDhhmm[[CC]YY][.ss]] [+FORMAT]
# date 011816322019.05
Fri Jan 18 16:32:05 UTC 2019
# date
Fri Jan 18 16:32:18 UTC 2019
# hwclock -w
# date
Fri Jan 18 16:35:52 UTC 2019


 

【课堂笔记】

drivers\rtc\rtc-s3c.c

s3c_rtc_init
  platform_driver_register
    s3c_rtc_probe
      rtc_device_register("s3c", &pdev->dev, &s3c_rtcops, THIS_MODULE)
        rtc_dev_prepare
          cdev_init(&rtc->char_dev, &rtc_dev_fops);
        rtc_dev_add_device
          cdev_add


app: open("/dev/rtc0");
-------------------------------------------
kernel: sys_open
  rtc_dev_fops.open
    rtc_dev_open
      // 根据次设备号找到以前用"rtc_device_register"注册的rtc_device
      struct rtc_device *rtc = container_of(inode->i_cdev,struct rtc_device, char_dev);
      const struct rtc_class_ops *ops = rtc->ops;
      err = ops->open ? ops->open(rtc->dev.parent) : 0;
s3c_rtc_open
app: ioctl(fd, RTC_RD_TIME,...)
-------------------------------------------
kernel: sys_ioctl
  rtc_dev_fops.ioctl
    rtc_dev_ioctl
      struct rtc_device *rtc = file->private_data;
      rtc_read_time(rtc, &tm);
        err = rtc->ops->read_time(rtc->dev.parent, tm);
        s3c_rtc_gettime

 


 

【源码】

hello.c

  1 /*
  2  * 2019-01-17
  3  * 目的: 字符设备驱动的新写法;
  4  */
  5 
  6 #include <linux/device.h>
  7 #include <linux/fs.h>
  8 #include <linux/module.h>
  9 #include <linux/errno.h>
 10 #include <linux/kernel.h>
 11 #include <linux/init.h>
 12 #include <linux/platform_device.h>
 13 #include <asm/uaccess.h>
 14 #include <asm/io.h>
 15 
 16 #include <linux/types.h>
 17 #include <linux/cdev.h>
 18 
 19 #include <linux/nsc_gpio.h>
 20 
 21 #define HELLO_CNT 2        /* hello设备数目 */
 22 MODULE_LICENSE("GPL");
 23 
 24 static struct class *cls;
 25 static struct class_device *hello_class_devs[4];
 26 /* 1.确定主设备号 */
 27 static int major, minor;
 28 
 29 static int hello_open(struct inode *inode, struct file *filp)
 30 {
 31     printk("hello_open:\n");
 32     return 0;
 33 }
 34 
 35 /* 2.构建file_operations结构体 */
 36 static struct file_operations hello_fops = {
 37     .owner = THIS_MODULE,
 38     .open  = hello_open,
 39 };
 40 
 41 static struct cdev hello_cdev;        /* use 1 cdev for all devices */
 42 static int hello_init(void)
 43 {
 44     dev_t devid;
 45     int err;
 46 
 47     /* 3.告诉内核 */
 48     if(major)
 49     {
 50         devid = MKDEV(major, 0);
 51         err = register_chrdev_region(devid, HELLO_CNT, "hello");
 52     }
 53     else
 54     {
 55         err = alloc_chrdev_region(&devid, 0, HELLO_CNT, "hello");
 56         major = MAJOR(devid);
 57     }
 58     if(err < 0)
 59     {
 60         printk(KERN_ERR "hello chrdev_region err: %d\n", err);
 61         return -ENOMEM;
 62     }
 63     cdev_init(&hello_cdev, &hello_fops);
 64     err = cdev_add(&hello_cdev, devid, HELLO_CNT);
 65     if(err < 0)
 66     {
 67         printk(KERN_ERR "Failed to add hello_cdev\n");
 68         goto err_fail1;
 69     }
 70     /* 4.创建类和类下的设备 */
 71     cls = class_create(THIS_MODULE, "hello");
 72     if(!cls)
 73     {
 74         printk(KERN_ERR "Failed to create hello class!\n");
 75         err = -ENOMEM;
 76         goto err_fail2;
 77     }
 78     for(minor = 0; minor < 4; minor++)
 79     {
 80         hello_class_devs[minor] = class_device_create(cls, NULL, MKDEV(major, minor), NULL, "hello%d", minor);
 81         if(!hello_class_devs[minor])
 82         {
 83             printk(KERN_ERR "Failed to create hello%d class device!\n", minor);
 84             minor--;
 85             err = -ENOMEM;
 86             goto err_fail3;
 87         }
 88     }
 89     return 0;
 90  err_fail3:
 91      for(; minor >= 0; minor--)
 92     {
 93         class_device_unregister(hello_class_devs[minor]);
 94         //class_device_destroy(cls, MKDEV(major, minor));
 95     }
 96      class_destroy(cls);
 97  err_fail2:
 98      cdev_del(&hello_cdev);
 99  err_fail1:
100      unregister_chrdev_region(devid, HELLO_CNT);
101      return err;
102 }
103 
104 static void hello_exit(void)
105 {
106     for(minor = 0; minor < 4; minor++)
107     {
108         class_device_unregister(hello_class_devs[minor]);
109         //class_device_destroy(cls, MKDEV(major, minor));
110     }
111      class_destroy(cls);
112      cdev_del(&hello_cdev);
113      unregister_chrdev_region(MKDEV(major, 0), HELLO_CNT);
114 }
115 module_init(hello_init);
116 module_exit(hello_exit);

 

posted @ 2019-01-18 17:00  大秦长剑  阅读(226)  评论(0编辑  收藏  举报