/*
* (C) Copyright 2014
* Kevin Jiang, Farsight, <coreteker@gmail.com>.
*
* 说明:演示平台驱动。
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/platform_device.h>
#include "ioctl.h"
#define FSDEV_MAJOR 250
#define FSDEV_MINOR 0
#define FSDEV_NR 1
#define FSDEV_NAME "fsdev"
struct fsdev {
struct cdev cdev;
struct resource *ledres;
void __iomem *ledcon;
void __iomem *leddat;
};
static struct fsdev fsdev;
static int fsplt_open(struct inode *inode, struct file *filp)
{
return 0;
}
static int fsplt_close(struct inode *inode, struct file *filp)
{
iowrite32(0x0, fsdev.leddat);
return 0;
}
static int fsplt_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
{
int ret = 0;
if (_IOC_TYPE(cmd) != FS_IOC_MAGIC)
return -ENOTTY;
if (_IOC_NR(cmd) > FS_IOC_MAXNR)
return -ENOTTY;
if (_IOC_DIR(cmd) & _IOC_READ)
ret = !access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd));
else if (_IOC_DIR(cmd) & _IOC_WRITE)
ret = !access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd));
if (ret)
return -EFAULT;
switch (cmd) {
case FS_IOC_LED_ON:
iowrite32(ioread32(fsdev.leddat) | (1 << (*(unsigned int *)arg & 0x03)), fsdev.leddat);
break;
case FS_IOC_LED_OFF:
iowrite32(ioread32(fsdev.leddat) & ~(1 << (*(unsigned int *)arg & 0x03)), fsdev.leddat);
break;
}
return 0;
}
static struct file_operations fsfops = {
.owner = THIS_MODULE,
.open = fsplt_open,
.release = fsplt_close,
.ioctl = fsplt_ioctl
};
static int fsplt_probe(struct platform_device *pdev)
{
int ret;
dev_t devno;
struct resource *ledreq;
devno = MKDEV(FSDEV_MAJOR, FSDEV_MINOR);
ret = register_chrdev_region(devno, FSDEV_NR, FSDEV_NAME);
if (ret) {
printk(KERN_ERR "fsplt: register chrdev region failed\n");
goto reg_err;
}
memset(&fsdev, 0, sizeof(struct fsdev));
cdev_init(&fsdev.cdev, &fsfops);
fsdev.cdev.owner = THIS_MODULE;
ret = cdev_add(&fsdev.cdev, devno, FSDEV_NR);
if (ret) {
printk(KERN_ERR "fsplt: cdev add failed");
goto add_err;
}
fsdev.ledres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
ledreq = request_mem_region(fsdev.ledres->start, resource_size(fsdev.ledres), "GPG3");
if (ledreq == NULL) {
printk(KERN_ERR "fsplt: request memery region failed\n");
ret = -EBUSY;
goto req_err;
}
fsdev.ledcon = ioremap(fsdev.ledres->start, 4);
if (fsdev.ledcon == NULL) {
printk(KERN_ERR "fsplt: ioremap failure\n");
ret = -EFAULT;
goto map_con_err;
}
fsdev.leddat = ioremap(fsdev.ledres->start + 4, 4);
if (fsdev.leddat == NULL) {
printk(KERN_ERR "fsplt: ioremap failure\n");
ret = -EFAULT;
goto map_dat_err;
}
iowrite32(0x1111, fsdev.ledcon);
iowrite32(0x0, fsdev.leddat);
return 0;
map_dat_err:
iounmap(fsdev.ledcon);
map_con_err:
release_mem_region(fsdev.ledres->start, resource_size(fsdev.ledres));
req_err:
cdev_del(&fsdev.cdev);
add_err:
unregister_chrdev_region(devno, FSDEV_NR);
reg_err:
return ret;
}
static int fsplt_remove(struct platform_device *pdev)
{
dev_t devno;
devno = MKDEV(FSDEV_MAJOR, FSDEV_MINOR);
iounmap(fsdev.ledcon);
iounmap(fsdev.leddat);
release_mem_region(fsdev.ledres->start, resource_size(fsdev.ledres));
cdev_del(&fsdev.cdev);
unregister_chrdev_region(devno, FSDEV_NR);
return 0;
}
static struct platform_driver fsplt_drv = {
.probe = fsplt_probe,
.remove = fsplt_remove,
.driver = {
.owner = THIS_MODULE,
.name = "fsled",
},
};
static int __init fsplt_init(void)
{
return platform_driver_register(&fsplt_drv);
}
static void __exit fsplt_exit(void)
{
platform_driver_unregister(&fsplt_drv);
}
module_init(fsplt_init);
module_exit(fsplt_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Kevin Jiang <coreteker@gmail.com>");
MODULE_DESCRIPTION("This is an example for GPIO programming");
驱动,设备和总线分块编程方式
最新推荐文章于 2024-10-02 14:03:05 发布