Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1084058
  • 博文数量: 646
  • 博客积分: 288
  • 博客等级: 二等列兵
  • 技术积分: 5375
  • 用 户 组: 普通用户
  • 注册时间: 2010-07-08 14:33
个人简介

为了技术,我不会停下学习的脚步,我相信我还能走二十年。

文章分类

全部博文(646)

文章存档

2014年(8)

2013年(134)

2012年(504)

分类:

2012-06-13 12:54:25

原文地址:IO内存 作者:三点水兽

注:在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");
阅读(401) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~