注:在tekkaman的一段代码做了一些小修改/*
* main.c -- the bare scull char module
*
* Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
* Copyright (C) 2001 O'Reilly & Associates
*
* The source code in this file can be freely used, adapted,
* and redistributed in source or binary form, so long as an
* acknowledgment appears in derived source files. The citation
* should list that the code comes from the book "Linux Device
* Drivers" by Alessandro Rubini and Jonathan Corbet, published
* by O'Reilly & Associates. No warranty is attached;
* we cannot take responsibility for errors or fitness for use.
*
*/
#include
#include
#include
#include /* printk() */
#include /* kmalloc() */
#include /* everything... */
#include /* error codes */
#include /* size_t */
#include
#include /* O_ACCMODE */
#include
#include
#include /* current and everything */
#include
#include /* cli(), *_flags */
#include /* copy_*_user */
#include
#include "IO_mem.h" /* local definitions */
/*
* Our parameters which can be set at load time.
*/
int IO_mem_major = 0;
int IO_mem_minor = 0;
unsigned int gpjcon_old =0;
unsigned int gpjdat_old =0;
unsigned int gpjup_old =0;
unsigned long io_addr;
module_param(IO_mem_major, int, S_IRUGO);
module_param(IO_mem_minor, int, S_IRUGO);
struct IO_mem_dev *IO_mem_devices; /* allocated in scull_init_module */
static atomic_t IO_mem_available = ATOMIC_INIT(1);
static spinlock_t IO_mem_lock = SPIN_LOCK_UNLOCKED;
static DECLARE_WAIT_QUEUE_HEAD(IO_mem_wait);
struct resource *IO_mem_resource;
struct class *myclass;
/*
* Open and close
*/
int IO_mem_open(struct inode *inode, struct file *filp)
{
struct IO_mem_dev *dev; /* device information */
spin_lock(&IO_mem_lock);
while (! atomic_dec_and_test (&IO_mem_available)) {
atomic_inc(&IO_mem_available);
spin_unlock(&IO_mem_lock);
if (filp->f_flags & O_NONBLOCK) return -EAGAIN;
if (wait_event_interruptible (IO_mem_wait, atomic_read (&IO_mem_available)))
return -ERESTARTSYS; /* tell the fs layer to handle it */
spin_lock(&IO_mem_lock);
}
spin_unlock(&IO_mem_lock);
dev = container_of(inode->i_cdev, struct IO_mem_dev, cdev);
io_addr =(unsigned long) ioremap_nocache(0x56000010 , 0x0c);
// io_addr =(unsigned long) ioport_map(0x56000010 , 0x0c); /*WARNING: "ioport_map" undefined! Don't use it*/
printk( "io_addr : %lx\n", io_addr);
/* now trim to 0 the length of the device if open was write-only */
gpjcon_old = ioread32 (io_addr);
gpjdat_old = ioread32 (io_addr+4);
gpjup_old = ioread32 (io_addr+8);
mb();
iowrite32(0x01555555,io_addr);
iowrite32(0x1fff,io_addr+8);
wmb();
iowrite32(0x0,io_addr+4);
filp->private_data = dev; /* for other methods */
return nonseekable_open(inode, filp); /* success */
}
int IO_mem_release(struct inode *inode, struct file *filp)
{
iowrite32((u32) gpjcon_old ,io_addr);
iowrite32((u32) gpjdat_old ,io_addr+4);
iowrite32((u32) gpjup_old ,io_addr+8);
iounmap((void *)io_addr);
// ioport_unmap((void *)io_addr); /*WARNING: "ioport_unmap" undefined! Don't use it*/
atomic_inc(&IO_mem_available); /* release the device */
wake_up_interruptible_sync(&IO_mem_wait); /* awake other uid's */
return 0;
}
/*
* The ioctl() implementation
*/
int IO_mem_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
int err = 0;
int retval = 0;
unsigned int current_status;
/*
* extract the type and number bitfields, and don't decode
* wrong cmds: return ENOTTY (inappropriate ioctl) before access_ok()
*/
if (_IOC_TYPE(cmd) != IO_MEM_MAGIC) return -ENOTTY;
if (_IOC_NR(cmd) > IO_MEM_MAXNR) return -ENOTTY;
/*
* the direction is a bitmask, and VERIFY_WRITE catches R/W
* transfers. `Type' is user-oriented, while
* access_ok is kernel-oriented, so the concept of "read" and
* "write" is reversed
*/
if (_IOC_DIR(cmd) & _IOC_READ)
err = !access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd));
if (err) return -EFAULT;
switch(cmd) {
case IO_MEM_0:
iowrite32(0x1de,io_addr+4);
break;
case IO_MEM_1:
iowrite32(0x1be,io_addr+4);
break;
case IO_MEM_2:
iowrite32(0x17e,io_addr+4);
break;
case IO_MEM_3:
iowrite32(0x0fe,io_addr+4);
break;
case IO_MEM_STATUS:
current_status = ioread32 (io_addr+4);
retval = __put_user(current_status, (unsigned int __user *)arg);
break;
default: /* redundant, as cmd was checked against MAXNR */
return -ENOTTY;
}
return retval;
}
struct file_operations IO_mem_fops = {
.owner = THIS_MODULE,
.ioctl = IO_mem_ioctl,
.open = IO_mem_open,
.release = IO_mem_release,
.llseek = no_llseek,
};
/*
* Finally, the module stuff
*/
/*
* The cleanup function is used to handle initialization failures as well.
* Thefore, it must be careful to work correctly even if some of the items
* have not been initialized
*/
void IO_mem_cleanup_module(void)
{
dev_t devno = MKDEV(IO_mem_major, IO_mem_minor);
if (IO_mem_resource!=NULL) release_mem_region(0x56000010, 0x0c);
/* Get rid of our char dev entries */
if (IO_mem_devices) {
cdev_del(&IO_mem_devices->cdev);
kfree(IO_mem_devices);
}
device_destroy(myclass, MKDEV(IO_mem_major, 0));
class_destroy(myclass);
/* cleanup_module is never called if registering failed */
unregister_chrdev_region(devno, 1);
}
/*
* Set up the char_dev structure for this device.
*/
static void IO_mem_setup_cdev(struct IO_mem_dev *dev)
{
int err, devno = MKDEV(IO_mem_major, IO_mem_minor);
cdev_init(&dev->cdev, &IO_mem_fops);
dev->cdev.owner = THIS_MODULE;
err = cdev_add (&dev->cdev, devno, 1);
/* Fail gracefully if need be */
if (err)
printk(KERN_NOTICE "Error %d adding IO_mem", err);
}
int IO_mem_init_module(void)
{
int result;
dev_t dev = 0;
/*
* Get a range of minor numbers to work with, asking for a dynamic
* major unless directed otherwise at load time.
*/
if (IO_mem_major) {
dev = MKDEV(IO_mem_major, IO_mem_minor);
result = register_chrdev_region(dev, 1, "IO_mem");
} else {
result = alloc_chrdev_region(&dev, IO_mem_minor, 1,
"IO_mem");
IO_mem_major = MAJOR(dev);
}
if (result < 0) {
printk(KERN_WARNING "IO_mem: can't get major %d\n", IO_mem_major);
return result;
}
/*
* allocate the devices -- we can't have them static, as the number
* can be specified at load time
*/
IO_mem_devices = kmalloc(sizeof(struct IO_mem_dev), GFP_KERNEL);
if (!IO_mem_devices) {
result = -ENOMEM;
goto fail; /* Make this more graceful */
}
memset(IO_mem_devices, 0, sizeof(struct IO_mem_dev));
/* Initialize each device. */
init_MUTEX(&IO_mem_devices->sem);
IO_mem_setup_cdev(IO_mem_devices);
if ((IO_mem_resource=request_mem_region(0x56000010, 0x0c,"IO_mem"))==NULL)
goto fail;
// printk("IO_mem_resource is %x\n", (unsigned int)IO_mem_resource);
myclass = class_create(THIS_MODULE,"test_iomem");
device_create(myclass, NULL, MKDEV(IO_mem_major,0), NULL, "IO_mem");
return 0; /* succeed */
fail:
IO_mem_cleanup_module();
return result;
}
module_init(IO_mem_init_module);
module_exit(IO_mem_cleanup_module);
MODULE_AUTHOR("Tekkaman Ninja");
MODULE_LICENSE("Dual BSD/GPL");
阅读(509) | 评论(0) | 转发(0) |