驱动,设备和总线分块编程方式

/*
 * (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");

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值