// 如果问题可以联系我 luther.ge@163.com
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#define log_printf(msg...) printk(KERN_ERR "===luther:=== "msg)
struct gliethttp_card_t {
int irq;
struct class *dchars_class;
struct device *dchars_classdev;
struct cdev cdev;
dev_t devt;
};
static struct gliethttp_card_t *gcard;
static int gcard_open(struct inode *inode, struct file *file)
{
log_printf("gcard_open\n");
return 0;
}
static int gcard_release(struct inode *inode, struct file *file)
{
log_printf("gcard_release\n");
return 0;
}
static const struct file_operations gcard_fops = {
.owner = THIS_MODULE,
.open = gcard_open,
.release = gcard_release,
};
static int __init dchars_init(void)
{
int retval;
gcard = kzalloc(sizeof(*gcard), GFP_KERNEL);
if (gcard == NULL) {
retval = -ENOMEM;
goto out;
}
gcard->dchars_class = class_create(THIS_MODULE, "dchars");
if (IS_ERR(gcard->dchars_class)) {
log_printf("Unable to register dchars class\n");
retval = PTR_ERR(gcard->dchars_class);
gcard->dchars_class = NULL;
goto error_class;
}
/* devices of this class shadow the major:minor of their parent
* device, so clear ->dev_kobj to prevent adding duplicate entries
* to /sys/dev
*/
gcard->dchars_class->dev_kobj = NULL;
retval = alloc_chrdev_region(&gcard->devt, 0, 1, "dchars"); // 申请minor=0开始的1个空间,
// devt存放起始数值[luther.gliethttp]
if (retval) {
log_printf("Failed to alloc_chrdev_region\n");
goto error_chrdev;
}
cdev_init(&gcard->cdev, &gcard_fops);
retval = cdev_add(&gcard->cdev, gcard->devt, 1); // 从devt开始注册1个字符设备空间[luther.gliethttp]
if (retval) {
log_printf("Failed to cdev_add\n");
goto error_cdev;
}
gcard->dchars_classdev = device_create(gcard->dchars_class, NULL,
gcard->devt, NULL, "dchars"); // 参考自usb_classdev_add
if (IS_ERR(gcard->dchars_classdev)) {
log_printf("Failed to device_create\n");
retval = PTR_ERR(gcard->dchars_classdev);
gcard->dchars_classdev = NULL;
goto error_device;
}
out:
return retval;
error_device:
cdev_del(&gcard->cdev);
error_cdev:
unregister_chrdev_region(gcard->devt, 1);
error_chrdev:
class_destroy(gcard->dchars_class);
error_class:
kfree(gcard);
goto out;
}
static void __exit dchars_cleanup(void)
{
//if (gcard->dchars_classdev)
device_unregister(gcard->dchars_classdev);
cdev_del(&gcard->cdev);
unregister_chrdev_region(gcard->devt, 1);
class_destroy(gcard->dchars_class);
kfree(gcard);
}
module_init(dchars_init);
module_exit(dchars_cleanup);
MODULE_LICENSE("GPL");
/*
================================
可以使用modinfo查看ko依赖模块
luther@gliethttp:/vobs/tmp$ modinfo dchars.ko
filename: dchars.ko
license: GPL
srcversion: A29A046B3F84ECA76BB2967
depends:
vermagic: 2.6.27-7-generic SMP mod_unload modversions 586
================================
// 用来测试驱动test_dchars.c
#include
#include
int main(void)
{
int retval;
retval = open("/dev/dchars", O_WRONLY);
printf("%d\n", retval);
for (;;) {
sleep(1);
fprintf(stderr, ".");
}
}
luther@gliethttp:/vobs/tmp$ sudo ./a.out
3
.....Terminated
当然可以配置udev脚本,让/dev/dchars字符设备节点的自动修改执行权限
luther@gliethttp:~$ sudo vim /etc/udev/rules.d/40-basic-permissions.rules
# 在文件结尾追加如下一条rules规则[luther.gliethttp]
KERNEL=="dchars", MODE="0666"
================================
Makefile文件:
obj-m :=dchars.o
CURRENT_PATH := $(shell pwd)
LINUX_KERNEL_PATH := /lib/modules/`uname -r`/build
all:
make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules
clean:
rm -rf .*.cmd *.o *.mod.c *.ko .tmp_versions Module.symvers modules.order Module.markers .Makefile.swp
*/
|