/1. 声明一个 led 字符设备结构体 static struct cdev led_cdev; //2.1 声明一个设备号 static dev_t led_num; //声明一个 myled 的类指针 static struct class * led_class; //声明一个 led 的设备指针 static struct device *led_device; //4.定义一个文件操作集 int led_open(struct inode * inode, struct file *file) { printk(KERN_INFO"led_open\n"); return 0; } //ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); ssize_t led_write(struct file * file, const char __user * buff, size_t len, loff_t * offset) { int rt; char kbuf[64]={0}; if(buff==NULL) return -EINVAL; if(len > sizeof kbuf) len=sizeof kbuf; //注释:unsigned long copy_from_user(void *to, const void __user *from, unsigned long n) rt=copy_from_user(kbuf,buff,len); len=len-rt; printk("copy from user buf is %s,len=%d\n",buff,len); return len; } //注释:ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); ssize_t led_read(struct file *file, char __user * buff, size_t len, loff_t * offset) { int rt; char kbuff[64]="I'm kernel data"; if(buff==NULL) return -EINVAL; if(len > sizeof kbuff) len=sizeof kbuff; rt=copy_to_user(buff, kbuff, strlen(kbuff)); len=strlen(kbuff)-rt; printk("len=%d\n",len); return len; } int led_close(struct inode * inode, struct file *file) { printk("led_close\n"); return 0; } struct file_operations led_fops={ .owner = THIS_MODULE, .open = led_open, .write = led_write, .read = led_read, .release = led_close }; static int __init kernel_init(void) { int re; //2.2 构建一个设备号,主设备号为 240,次设备号为 0 led_num=MKDEV(240,0); /3. 注册是设备号 re=register_chrdev_region(led_num, 1, "myled"); if(re<0) { printk("register_chrdev_region error\n"); goto err_register_chrdev_region; } cdev_init(&led_cdev,&led_fops); re=cdev_add(&led_cdev, led_num, 1); if(re<0) { printk("cdev_add failed\n"); goto err_cdev_add; } //创建 myled 的设备类/sys/class 目录中找到 led_class=class_create(THIS_MODULE,"myled"); if(IS_ERR(led_class)) { printk(KERN_INFO"class create error\n"); re=PTR_ERR(led_class); goto err_class_create; } //创建设备类成功创建 myled 的设备信息 led_device=device_create(led_class,NULL,led_num,NULL,"myled"); if (IS_ERR(led_device)) { re = PTR_ERR(led_device); printk("device_create leds device fail\n"); goto err_device_create; } printk(KERN_INFO"mylded_drv\n"); return 0; err_device_create: class_destroy(led_class); err_class_create: cdev_del(&led_cdev); err_cdev_add: unregister_chrdev_region(led_num, 1); return re; err_register_chrdev_region: return re; } static void __exit kernel_exit(void) { device_destroy(led_class,led_num); class_destroy(led_class); cdev_del(&led_cdev); unregister_chrdev_region(led_num, 1); printk("exit myled_drv\n"); } module_init(kernel_init); module_exit(kernel_exit); MODULE_AUTHOR("wangna wangna@blackfin.uclinux.org 1351234556"); MODULE_DESCRIPTION("kernel module test"); MODULE_LICENSE("GPL");为以上代码增加注释
时间: 2024-03-30 21:34:34 浏览: 21
/*
* 该模块实现了一个 led 字符设备,在 /dev 目录下创建 myled 设备文件。
* 本模块实现了文件操作集中的 open、write、read 和 close 函数。
* 使用 register_chrdev_region 函数注册了设备号,使用 cdev_add 函数将设备添加到系统中。
* 使用 class_create 函数创建了 myled 的设备类,使用 device_create 函数创建了 myled 的设备信息。
* 最后使用 module_init 和 module_exit 宏定义了 init 和 exit 函数,并且指定了模块的作者、描述和许可证。
*/
相关问题
上述的代码中,为什么要这样 static struct cdev c_dev;
这是因为在 Linux 内核中,cdev 结构体是用来表示字符设备的,而 static 关键字则表示该结构体只能在当前文件中使用,不能被其他文件访问。因此,这样定义可以确保 c_dev 变量只能在当前文件中使用,避免了其他文件对该变量的误操作。
container_of(cdev, struct cpld_led, cdev);是什么操作
### 回答1:
container_of(cdev, struct cpld_led, cdev) 是一个在 C 语言中使用的宏。它的作用是根据结构体成员的地址推算出结构体的首地址,进而实现从一个结构体成员的指针获取到整个结构体的指针。
这个宏接受三个参数:第一个参数是结构体成员的指针,第二个参数是结构体类型,第三个参数是结构体成员的名称。在这个宏的实现中,通过计算结构体成员在整个结构体中的偏移量,从而推算出结构体的首地址。
在这个具体的代码中,container_of(cdev, struct cpld_led, cdev) 的作用是从一个字符设备结构体的指针 cdev 推算出包含这个字符设备结构体的 cpld_led 结构体的指针。
### 回答2:
container_of(cdev, struct cpld_led, cdev) 是一个宏,用于从给定的 cdev 指针找到包含它的结构体 cpld_led 的指针。
在 Linux 内核中,cdev 代表一个字符设备,而 container_of 宏允许使用 cdev 的地址来获取包含该字符设备的结构体的地址。
这个宏的定义如下:
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type, member) );})
它的作用是通过 ptr 找到 member 成员的地址,然后用结构体的起始地址减去 member 成员的偏移量来得到整个结构体的起始地址。
在这里,cdev 是给定的 cdev 指针,struct cpld_led 是包含 cdev 的结构体类型,cdev 是 cpld_led 结构体中的一个成员。
通过这个宏,可以根据给定的 cdev 指针获取到包含它的 cpld_led 结构体的指针,进而可以使用这个指针来访问和操作 cpld_led 结构体中的其他成员。
总结起来,container_of(cdev, struct cpld_led, cdev) 的操作是用于从给定的 cdev 指针中获取包含它的 cpld_led 结构体的指针。
### 回答3:
container_of(cdev, struct cpld_led, cdev)是一个宏定义,用于从给定的类型(struct cdev)中获取包含另一个类型(struct cpld_led)成员(struct cdev)的结构体的指针。
具体来说,container_of是一个常用于Linux内核中的宏,它的功能是通过成员的地址来计算出包含该成员的结构体的地址。其中,第一个参数cdev是指向成员(struct cdev)的指针,第二个参数struct cpld_led是包含该成员的结构体类型,第三个参数cdev是结构体类型中的成员名。
在使用container_of宏时,我们可以通过这样的方式来获取包含该成员的结构体的指针:
struct cpld_led *led = container_of(cdev, struct cpld_led, cdev);
其中,led就指向了包含cdev成员的struct cpld_led结构体的指针。
使用container_of宏可以方便地从一个成员的指针获取到包含该成员的结构体的指针,这在内核开发中非常常见。这个宏的实现原理是通过将成员的地址减去成员在结构体中的偏移量,从而获得结构体的起始地址。