【驱动】第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);