MISC驱动
所有的 MISC 设备驱动的主设备号都为 10,不同的设备使用不同的从设备号。 MISC 设备会自动创建 cdev,不需要像手动创建,因此采用 MISC 设备驱动可以简化字符设备驱动的编写。 需要向 Linux 注册一个 miscdevice 设备
1 2 3 4 5 6 7 8 9 10 11
| struct miscdevice { int minor; const char *name; const struct file_operations *fops; struct list_head list; struct device *parent; struct device *this_device; const struct attribute_group **groups; const char *nodename; umode_t mode; };
|
Linux 系统已经预定义了一些 MISC 设备的子设备号,这些预定义的子设备号定义在include/linux/miscdevice.h 文件中,如下所示:
1 2 3 4 5 6 7 8
| 13 #define PSMOUSE_MINOR 1 14 #define MS_BUSMOUSE_MINOR 2 15 #define ATIXL_BUSMOUSE_MINOR 3 16 17 #define ATARIMOUSE_MINOR 5 18 #define SUN_MOUSE_MINOR 6 ...... 52 #define MISC_DYNAMIC_MINOR 255
|
注册和删除设备
1 2
| int misc_register(struct miscdevice * misc) int misc_deregister(struct miscdevice *misc)
|
eg:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
| #include <linux/module.h> #include <linux/kernel.h> #include <linux/gpio.h> #include <linux/fs.h> #include <linux/fcntl.h> #include <linux/errno.h> #include <linux/of_gpio.h> #include <linux/io.h> #include <linux/init.h> #include <linux/types.h> #include <linux/cdev.h> #include <linux/device.h> #include <linux/of.h> #include <linux/of_address.h> #include <linux/platform_device.h> #include <linux/miscdevice.h> #include <asm/mach/map.h> #include <asm/uaccess.h> #include <asm/io.h>
#define misc_beepname "miscbeep" #define beep_minor 144 #define BEEPON 1 #define BEEPOFF 0
struct miscbeep_dev{ dev_t devid; struct cdev cdev; struct class *class; struct device *device; struct device_node *nd; int beep_gpio; }; struct miscbeep_dev miscbeep; static int misc_beep_open(struct inode *inode, struct file *filp) { filp -> private_data = &miscbeep; return 0; }
static ssize_t misc_beep_write(struct file *filp, const char __user *buf, size_t cnt,loff_t *offt ) { int retvalue; unsigned char databuf[1]; unsigned char state; struct miscbeep_dev *dev = filp->private_data; retvalue = copy_from_user(databuf, buf, cnt); if(retvalue < 0) { printk("can't find user's data\r\n"); return -EFAULT; } state = databuf[0]; if(state == BEEPON) { gpio_set_value(dev->beep_gpio, 0); }else if(state == BEEPOFF) { gpio_set_value(dev->beep_gpio, 1); } return 0; }
static struct file_operations misc_beep_fops = { .owner = THIS_MODULE, .open = misc_beep_open, .write = misc_beep_write, };
static struct miscdevice beep_miscdev = { .minor = beep_minor, .name = misc_beepname, .fops = &misc_beep_fops, };
static int miscbeep_probe(struct platform_device *dev) { int ret = 0; printk("beep driver and device have matched\r\n"); miscbeep.nd = of_find_node_by_path("/beep"); if(miscbeep.nd == NULL) { printk("beep node can't find\r\n"); return -EINVAL; } miscbeep.beep_gpio = of_get_named_gpio(miscbeep.nd, "beep-gpio", 0); if(miscbeep.beep_gpio < 0 ) { printk("can't get beep-gpio\r\n"); return -EINVAL; } ret = gpio_direction_output(miscbeep.beep_gpio, 1); if(ret < 0) { printk("misc device register failed!\r\n"); return -EFAULT; } ret = misc_register(&beep_miscdev); if(ret < 0) { printk("misc device register failed\r\n"); return -EFAULT; } return 0; }
static int miscbeep_remove(struct platform_device *dev) { gpio_set_value(miscbeep.beep_gpio, 1); gpio_free(miscbeep.beep_gpio); misc_deregister(&beep_miscdev);
return 0; }
static const struct of_device_id beep_of_match[] = { {.compatible = "atkalpha-beep"}, {} };
static struct platform_driver beep_driver = { .driver = { .name = "imx6ul-beep", .of_match_table = beep_of_match, }, .probe = miscbeep_probe, .remove = miscbeep_remove, };
static int __init miscbeep_init(void) { return platform_driver_register(&beep_driver); } static void __exit miscbeep_exit(void) { platform_driver_unregister(&beep_driver); }
module_init(miscbeep_init); module_exit(miscbeep_exit); MODULE_LICENSE("GPL");
|