📄 io_mem.c
字号:
/* * 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 <linux/module.h>#include <linux/moduleparam.h>#include <linux/init.h>#include <linux/kernel.h> /* printk() */#include <linux/slab.h> /* kmalloc() */#include <linux/fs.h> /* everything... */#include <linux/errno.h> /* error codes */#include <linux/types.h> /* size_t */#include <linux/proc_fs.h>#include <linux/fcntl.h> /* O_ACCMODE */#include <linux/seq_file.h>#include <linux/cdev.h>#include <linux/sched.h> /* current and everything */#include <asm/system.h> /* cli(), *_flags */#include <asm/uaccess.h> /* copy_*_user */#include <asm/atomic.h>#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;/* * 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(0x560000d0 , 0x0c); // io_addr =(unsigned long) ioport_map(0x560000d0 , 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(0x0,io_addr+4); break; case IO_MEM_1: iowrite32(0x1,io_addr+4); break; case IO_MEM_2: iowrite32(0x2,io_addr+4); break; case IO_MEM_3: iowrite32(0x3,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(0x560000d0, 0x0c); /* Get rid of our char dev entries */ if (IO_mem_devices) { cdev_del(&IO_mem_devices->cdev); kfree(IO_mem_devices); } /* 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(0x560000d0, 0x0c,"IO_mem"))==NULL) goto fail; 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");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -