接触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)