Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2634021
  • 博文数量: 333
  • 博客积分: 4817
  • 博客等级: 上校
  • 技术积分: 4413
  • 用 户 组: 普通用户
  • 注册时间: 2011-02-28 10:51
文章分类

全部博文(333)

文章存档

2017年(20)

2016年(57)

2015年(27)

2014年(20)

2013年(21)

2012年(164)

2011年(24)

分类: LINUX

2012-02-25 09:42:59

注:在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_port.h"        /* local definitions */

/*
 * Our parameters which can be set at load time.
 */
int IO_port_major =   0;
int IO_port_minor =   0;

unsigned int gpjcon_old =0;
unsigned int gpjdat_old =0;
unsigned int gpjup_old  =0;

module_param(IO_port_major, int, S_IRUGO);
module_param(IO_port_minor, int, S_IRUGO);



struct IO_port_dev *IO_port_devices;    /* allocated in scull_init_module */
static atomic_t IO_port_available = ATOMIC_INIT(1);
static spinlock_t IO_port_lock = SPIN_LOCK_UNLOCKED;
static DECLARE_WAIT_QUEUE_HEAD(IO_port_wait);
struct resource *IO_port_resource;
struct class *myclass;

/*
 * Open and close
 */

int IO_port_open(struct inode *inode, struct file *filp)
{
    struct IO_port_dev *dev; /* device information */

    spin_lock(&IO_port_lock);

    while (! atomic_dec_and_test (&IO_port_available)) {
        atomic_inc(&IO_port_available);
        spin_unlock(&IO_port_lock);
        if (filp->f_flags & O_NONBLOCK) return -EAGAIN;
        if (wait_event_interruptible (IO_port_wait, atomic_read (&IO_port_available)))
            return -ERESTARTSYS; /* tell the fs layer to handle it */
       
        spin_lock(&IO_port_lock);
    }

    spin_unlock(&IO_port_lock);

    dev = container_of(inode->i_cdev, struct IO_port_dev, cdev);

    /* now trim to 0 the length of the device if open was write-only */
    gpjcon_old = (unsigned int) inl((unsigned long)S3C2410_GPBCON);
    gpjdat_old = (unsigned int) inl((unsigned long)S3C2410_GPBDAT);
    gpjup_old = (unsigned int) inl((unsigned long)S3C2410_GPBUP);
   
    mb();

    outl(0x01555555,(unsigned long)S3C2410_GPBCON);
//    printk( "IO_port con : %x\n", inl(S3C2440_GPJCON));
    outl(0x1fff,(unsigned long)S3C2410_GPBUP);
//    printk( "IO_port up : %x\n", inl(S3C2440_GPJUP));
    mb();

//    outl(0x0,(unsigned long)S3C2410_GPBDAT);
    filp->private_data = dev; /* for other methods */

    return nonseekable_open(inode, filp);          /* success */
}

int IO_port_release(struct inode *inode, struct file *filp)
{
    outl(gpjcon_old,(unsigned long)S3C2410_GPBCON);
    outl(gpjup_old,(unsigned long)S3C2410_GPBUP);
    outl(gpjdat_old,(unsigned long)S3C2410_GPBDAT);
    atomic_inc(&IO_port_available); /* release the device */
    wake_up_interruptible_sync(&IO_port_wait); /* awake other uid's */

    return 0;
}

/*
 * The ioctl() implementation
 */

int IO_port_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_PORT_MAGIC) return -ENOTTY;
    if (_IOC_NR(cmd) > IO_PORT_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_PORT_0:
    outl(0x1de,(unsigned long)S3C2410_GPBDAT);
    break;
       
      case IO_PORT_1: /* Set: arg points to the value */
    outl(0x1be,(unsigned long)S3C2410_GPBDAT);
    break;

      case IO_PORT_2: /* Tell: arg is the value */
    outl(0x17e,(unsigned long)S3C2410_GPBDAT);
    break;

      case IO_PORT_3: /* Get: arg is pointer to result */
    outl(0xfe,(unsigned long)S3C2410_GPBDAT);
    break;

    case IO_PORT_STATUS: /* eXchange: use arg as pointer */
    current_status = (unsigned int) inl((unsigned long)S3C2410_GPBDAT);
    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_port_fops = {
    .owner =    THIS_MODULE,
    .ioctl =    IO_port_ioctl,
    .open =     IO_port_open,
    .release =  IO_port_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_port_cleanup_module(void)
{
    dev_t devno = MKDEV(IO_port_major, IO_port_minor);

    if (IO_port_resource!=NULL) release_region((unsigned long)S3C2410_GPBCON, 0x0c);

    /* Get rid of our char dev entries */
    if (IO_port_devices) {
        cdev_del(&IO_port_devices->cdev);
        kfree(IO_port_devices);
    }

    device_destroy(myclass, MKDEV(IO_port_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_port_setup_cdev(struct IO_port_dev *dev)
{
    int err, devno = MKDEV(IO_port_major, IO_port_minor);
   
    cdev_init(&dev->cdev, &IO_port_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_port", err);
}


int IO_port_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_port_major) {
        dev = MKDEV(IO_port_major, IO_port_minor);
        result = register_chrdev_region(dev, 1, "IO_port");
    } else {
        result = alloc_chrdev_region(&dev, IO_port_minor, 1,
                "IO_port");
        IO_port_major = MAJOR(dev);
    }
    if (result < 0) {
        printk(KERN_WARNING "IO_port: can't get major %d\n", IO_port_major);
        return result;
    }

        /*
     * allocate the devices -- we can't have them static, as the number
     * can be specified at load time
     */
    IO_port_devices = kmalloc(sizeof(struct IO_port_dev), GFP_KERNEL);
    if (!IO_port_devices) {
        result = -ENOMEM;
        goto fail;  /* Make this more graceful */
    }
    memset(IO_port_devices, 0, sizeof(struct IO_port_dev));

        /* Initialize each device. */
        init_MUTEX(&IO_port_devices->sem);
         IO_port_setup_cdev(IO_port_devices);
    if ((IO_port_resource=request_region((unsigned long)S3C2410_GPBCON, 0x0c,"IO_port"))==NULL)
        goto fail;

    printk("S3C2410_GPBCON= %lx\n",(unsigned long)S3C2410_GPBCON);

    myclass = class_create(THIS_MODULE,"test_IO_port");
    device_create(myclass, NULL, MKDEV(IO_port_major,0), NULL, "IO_Port");

    return 0; /* succeed */

  fail:
    IO_port_cleanup_module();
    return result;
}

module_init(IO_port_init_module);
module_exit(IO_port_cleanup_module);

MODULE_AUTHOR("Tekkaman Ninja");
MODULE_LICENSE("Dual BSD/GPL");

阅读(1300) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~