接触Linux 、 Android两年了!学会了好多!但是没有精通的!对自己的实力没有自信!所以最近专心研究Linux的驱动!练习练习!以前看过很多书!但是看过就忘记了!知道个大概!应该包含哪些头文件都不知道!刚开始先抄抄代码、仔细理解理解!一动手才发现!看到的和你用手打出来那差距不是一般的大!打出来和自己写出来那差距更是天上地下!一下代码出自《精通Linux设备驱动程序开发》,在pandaboard开发板上面测试;内核版本是:Kernel 3.0.31;
#include <linux/fs.h> #include <linux/cdev.h> #include <linux/parport.h> #include <asm/uaccess.h> #include <linux/platform_device.h> #define DEVICE_NAME "led" static dev_t dev_number; //Allotted device number static struct class *led_class; //Class to which this device belongs struct cdev led_cdev; //Associated cdev struct pardevice *pdev; //Parallel port device //LED OPEN int led_open(struct inode *inode, struct file *filp) { return 0; } //write to the led ssize_t led_write(struct file *file, const char *buf, size_t count, loff_t *ppos) { char kbuf; if(copy_from_user(&kbuf, buf, 1)) { return -EFAULT; } //Claim the port parport_claim_or_block(pdev); //Write to the device parport_write_data(pdev->port, kbuf); //Release the port parport_release(pdev); return count; } //Release the device int led_release(struct inode *inode, struct file *file) { return 0; } static struct file_operations led_fops = { .owner = THIS_MODULE, .open = led_open, .write = led_write, .release =led_release, }; static int led_preempt(void *handle) { return 1; } //Parport attach method static void led_attach(struct Parport *port) { /* Register the parallel LED device with parport */ pdev = parport_register_device(port, DEVICE_NAME, led_preempt, NULL, NULL, 0, NULL); if(pdev == NULL) { printk("Bad register\n"); } } //Parport detach method static void led_detach(struct parport *port) { printk(".............led_detach................\n"); } //Parport driver operation static struct parport_driver led_driver = { .name = "led", .attach = led_attach, .detach = led_detach, }; int __init led_init(void) { if(alloc_chrdev_region(&dev_number, 0, 1, DEVICE_NAME) < 0) { printk(KERN_DEBUG "Can't register device\n"); return -1; } //Create the led class led_class = class_create(THIS_MODULE, DEVICE_NAME); if(IS_ERR(led_class)){ printk("Bad class create\n"); } //Connect the file operation with the cdev cdev_init(&led_cdev, &led_fops); led_cdev.owner = THIS_MODULE; //Connect the major/minor number to the cdev if(cdev_add(&led_cdev, dev_number, 1)){ printk("Bad cdev add\n"); return 1; } device_create(led_class, NULL, dev_number, NULL, DEVICE_NAME); //Register this driver with parport if(parport_register_driver(&led_driver)) { printk(KERN_ERR "Bad parport Register \n"); return -EIO; } printk("LED Driver Initialized.\n"); return 0; } void __exit led_cleanup(void) { unregister_chrdev_region(dev_number, 1); device_destroy(led_class, dev_number); class_destroy(led_class); return; } module_init(led_init); module_exit(led_cleanup); MODULE_LICENSE("GPL");
Note:
(1)linux内核2.6早期版本的class_device_create()函数在后期的版本中改为了device_create();我用的内核是:kernel 3.0.31;
=> include/linux/device.h
=> struct class {
=> #define class_create(owner, name)
=> extern struct device *device_create(struct class *cls, struct device *parent,
dev_t devt, void *drvdata,
const char *fmt, ...)
__attribute__((format(printf, 5, 6)));
=> include/linux/cdev.h
/* *字符设备驱动程序是由一个cdev结构描述的; */ struct cdev { struct kobject kobj; struct module *owner; /*指向设备驱动程序"文件操作表"的指针*/ const struct file_operations *ops; struct list_head list; dev_t dev; /*设备号*/ unsigned int count; /*设备号的大小*/ }; //把内核字符设备和文件操作绑定在一起 void cdev_init(struct cdev *, const struct file_operations *); //把内核字符设备和设备号绑定在一起 int cdev_add(struct cdev *, dev_t, unsigned);
(2)
测试结果:
(1)
(2)
(3)