分类: LINUX
2010-10-29 19:30:47
Linux Platform Device and Driver
http://blog.chinaunix.net/u2/60011/showart.php?id=1018502
http://blog.csdn.net/lanmanck/archive/2009/08/17/4455692.aspx
写的很精彩,尚观还是有两下子呵呵
原文地址:
(尚观-linux开发小组成员)
1.你的驱动只能挂一个设备.
2.无法用udev生成,因为没有class.(register_chrdev已经过时了).
3.如果你想单独写一驱动包括子系统层.
#include "hello.h"
#define HELLO_MAX_DEVS 6
static dev_t hello_base_id;
static int cur_dev_num = 0;
static struct class* hello_class;
typedef struct hello_dev {
struct cdev chrdev;
int dev_idx;
u8* dma_buf;
size_t cur_size;
}hello_dev_t;
static hello_dev_t* hi_dev[HELLO_MAX_DEVS];
static int __devinit hello_probe(struct platform_device *pdev);
static int __devexit hello_remove(struct platform_device *pdev);
static int hello_open(struct inode *inode, struct file *filp);
static int hello_close(struct inode *inode, struct file *filp);
static ssize_t hello_read(struct file *filp, char *buff, size_t count, loff_t *offp);
static ssize_t hello_write(struct file *filp, const char *buff, size_t count, loff_t *offp);
static int hello_open(struct inode *inode, struct file *filp)
{
hello_dev_t* hdev;
int idx;
idx = iminor(inode) - MINOR(hello_base_id);
hdev = hi_dev[idx];
sprintf(hdev->dma_buf, "hello%d from kernel!", idx);
hdev->cur_size = strlen(hdev->dma_buf);
filp->private_data = hdev;
return 0;
}
static int hello_close(struct inode *inode, struct file *filp)
{
hello_dev_t* hdev;
int idx;
idx = iminor(inode) - MINOR(hello_base_id);
hdev = hi_dev[idx];
filp->private_data = NULL;
printk("bye %d\n", hdev->dev_idx);
return 0;
}
static ssize_t hello_read(struct file *filp, char *buff, size_t count, loff_t *offp)
{
int ret;
size_t len;
hello_dev_t *hdev = filp->private_data;
len = (count > hdev->cur_size) ? hdev->cur_size : count;
ret = copy_to_user(buff, hdev->dma_buf, len);
return len;
}
static ssize_t hello_write(struct file *filp, const char *buff, size_t count, loff_t *offp)
{
int ret;
size_t len;
hello_dev_t *hdev = filp->private_data;
len = (count < MEM_LEN) ? count : MEM_LEN;
ret = copy_from_user(hdev->dma_buf, buff, len);
hdev->cur_size = len;
return len;
}
static struct platform_driver hello_driver = {
.probe = hello_probe,
.remove = hello_remove,
.driver = {
.name = HELLO_DEV_NAME,
.owner = THIS_MODULE,
},
};
static struct file_operations hello_fops = {
.owner = THIS_MODULE,
.open = hello_open,
.release = hello_close,
.read = hello_read,
.write = hello_write,
};
static int __devinit hello_probe(struct platform_device *pdev)
{
int ret;
dev_t dev_id;
struct class_device* cls_dev;
hello_dev_t *hdev;
printk("device %s-%d detected!\n", pdev->name, pdev->id);
hi_dev[cur_dev_num] = hdev = kzalloc(sizeof(hello_dev_t), GFP_KERNEL);
hdev->dma_buf = kmalloc(MEM_LEN, GFP_KERNEL);
hdev->dev_idx = cur_dev_num++;
dev_id = MKDEV(MAJOR(hello_base_id), MINOR(hello_base_id) + hdev->dev_idx);
pdev->dev.devt = dev_id;
cdev_init(&hdev->chrdev, &hello_fops);
hdev->chrdev.owner = THIS_MODULE;
ret = cdev_add(&hdev->chrdev, dev_id, 1);
if (ret)
{
printk("fail to register driver for " HELLO_DEV_NAME "%d!\n", pdev->id);
return ret;
}
platform_set_drvdata(pdev, hdev);
cls_dev = class_device_create(hello_class,
NULL,
dev_id,
&pdev->dev,
HELLO_DEV_NAME "%d", hdev->dev_idx
);
if (IS_ERR(cls_dev))
return PTR_ERR(cls_dev);
printk("driver for "HELLO_DEV_NAME".%d (%d,%d) registered\n", hdev->dev_idx, MAJOR(dev_id), MINOR(dev_id));
return ret;
}
static int __devexit hello_remove(struct platform_device *pdev)
{
hello_dev_t* hdev;
class_device_destroy(hello_class, pdev->dev.devt);
hdev = platform_get_drvdata(pdev);
if (hdev) cdev_del(&hdev->chrdev);
kfree(hdev->dma_buf);
kfree(hdev);
platform_set_drvdata(pdev, NULL);
pdev->dev.devt = 0;
cur_dev_num--;
printk(HELLO_DEV_NAME "%d removed!\n", pdev->id);
return 0;
}
static int __init hello_init(void)
{
int ret;
cur_dev_num = 0;
ret = alloc_chrdev_region(&hello_base_id,
10,
HELLO_MAX_DEVS,
HELLO_DEV_NAME
);
if (ret)
return ret;
hello_class = class_create(THIS_MODULE, HELLO_DEV_NAME);
if (IS_ERR(hello_class))
return PTR_ERR(hello_class);
ret = platform_driver_register(&hello_driver);
return ret;
}
static void __exit hello_exit(void)
{
platform_driver_unregister(&hello_driver);
class_destroy(hello_class);
unregister_chrdev_region(hello_base_id, HELLO_MAX_DEVS);
printk("unregister driver " HELLO_DEV_NAME "\n");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");