ok6410 android driver(8)

  In the past, we know how to create and run a simple character device driver on pc, goldfish and ok6410.

  These two essays I will talk about a led device real exists on ok6410.

  

  In this essay, we will compile a led device driver and test it.

  At first, I wanna write some short summary of the different between a character device and a real device.

  (1) Character device :

  We always control character device in bytes, just like we control a normal file.

  Open file with a file handle, then read, write, llseek and put others control to the handle.

  (2) Real device :

  Acturely, we can control a real device like a normal character driver with file streams.

  But we should know more about the ioctl.

  When a real device connects to pc, it register a address for itself automaticly.

  Then the pc malloc some I/O memory for it, and they will communicate via the I/O memory instead of immediately.

  The I/O memory will protect both pc and device from speech mismach.

 

  1、 leds.c

#include <linux/fs.h>

#include <linux/cdev.h>

#include <linux/pci.h>

#include <asm/uaccess.h>

#include <mach/map.h>

#include <mach/regs-gpio.h>

#include <mach/gpio-bank-m.h>



#define DEVICE_NAME "s3c6410_leds"

#define DEVICE_COUNT 1

#define S3C6410_LEDS_MAJOR 0

#define S3C6410_LEDS_MINOR 234

#define PARAM_SIZE 3



static unsigned char mem[4];

static int major = S3C6410_LEDS_MAJOR;

static int minor = S3C6410_LEDS_MINOR;

static dev_t leds_number;

static int leds_state = 1;

static char *param[] = {"string1", "string2", "string3"};

static int param_size = PARAM_SIZE;

static struct class *leds_class = NULL;



static long s3c6410_leds_ioctl(struct file *filp, unsigned int cmd,

    unsigned long arg)

{

    switch (cmd) {

        unsigned int tmp;

        case 0:

        case 1:

        if (arg > 4) {

            return -EINVAL;

        }

        tmp = ioread32(S3C64XX_GPMDAT);

        if (cmd == 1) {

            tmp &= (~(1 << arg));

        } else {

            tmp |= (1 << arg);

        }

        iowrite32(tmp, S3C64XX_GPMDAT);

        return 0;

        default :

        return -EINVAL;

    }    

}



static ssize_t s3c6410_leds_write(struct file *filp,

    const char __user *buf,    size_t count, loff_t *ppos)

{

    unsigned tmp = count;

    unsigned long i = 0;

    memset(mem, 0, 4);



    if (count > 4) {

        tmp = 4;    

    }

    if (copy_from_user(mem, buf, tmp)) {

        return -EINVAL;

    } else {

        for (i = 0; i < 4; i++) {

            tmp = ioread32(S3C64XX_GPMDAT);

            if (mem[i] == '1') {

                tmp &= (~(1 << i));

            } else {

                tmp |= (1 << i);

            }

            iowrite32(tmp, S3C64XX_GPMDAT);

        }

        return count;

    }

}



static struct file_operations leds_fops = {

    .owner = THIS_MODULE,

    .unlocked_ioctl = s3c6410_leds_ioctl,

    .write = s3c6410_leds_write,

};

static struct cdev leds_cdev;



static int leds_create_device(void)

{

    int ret = 0;

    int err = 0;



    cdev_init(&leds_cdev, &leds_fops);

    leds_cdev.owner = THIS_MODULE;

    if (major > 0) {

        leds_number = MKDEV(major, minor);

        err = register_chrdev_region(leds_number, DEVICE_COUNT, DEVICE_NAME);

        if (err < 0) {

            printk(KERN_WARNING "register_chardev_region() failed.\n");

            return err;

        }

    } else {

        err = alloc_chrdev_region(&leds_cdev.dev, 10,

                DEVICE_COUNT, DEVICE_NAME);

        if (err < 0) {

            printk(KERN_WARNING "register_chardev_region failed.\n");

            return err;

        }

        major = MAJOR(leds_cdev.dev);

        minor = MINOR(leds_cdev.dev);

        leds_number = leds_cdev.dev;

    }



    ret = cdev_add(&leds_cdev, leds_number, DEVICE_COUNT);

    leds_class = class_create(THIS_MODULE, DEVICE_NAME)    ;

    device_create(leds_class, NULL, leds_number, NULL, DEVICE_NAME);

    return ret;



}

static void leds_init_gpm(int leds_default)

{

    int tmp = 0;

    tmp = ioread32(S3C64XX_GPMCON);

    tmp &= (~0xFFFF);

    tmp |= 0x1111;

    iowrite32(tmp, S3C64XX_GPMCON);



    tmp = ioread32(S3C64XX_GPMPUD);

    tmp &= (~0xFF);

    tmp |= 0xAA;

    iowrite32(tmp, S3C64XX_GPMPUD);



    tmp = ioread32(S3C64XX_GPMDAT);

    tmp &= (~0xF);

    tmp |= leds_default;

    iowrite32(tmp, S3C64XX_GPMDAT);

}



static int leds_init(void)

{

    int ret;

    ret = leds_create_device();

    leds_init_gpm(~leds_state);

    printk(DEVICE_NAME "\tinitialized.\n");



    printk("param0\t%s\n", param[0]);

    printk("param1\t%s\n", param[1]);

    printk("param2\t%s\n", param[2]);

    

    return ret;

}



static void leds_destroy_device(void)

{

    device_destroy(leds_class, leds_number);

    if (leds_class) {

        unregister_chrdev_region(leds_number, DEVICE_COUNT);

        return;

    }

}

static void leds_exit(void)

{

    leds_destroy_device();

    printk(DEVICE_NAME"\texit.\n");

}



module_init(leds_init);

module_exit(leds_exit);



module_param(leds_state, int, S_IRUGO | S_IWUSR);

module_param_array(param, charp, &param_size, S_IRUGO | S_IWUSR);



MODULE_LICENSE("GPL");

  Then follow the steps we analysis in wordcount device (character device).

  2、init and exit entrance functions

  (1) init function :

// init entrance function

module_init(leds_init);

// 

static int leds_init(void)

{

    ...

        // create device like normal character device

    ret = leds_create_device();

        // init the device by its I/O memory

    leds_init_gpm(~leds_state);

    ...

}

  (2) exit function :

// exit entrance function

module_exit(leds_exit);

//

static void leds_exit(void)

{

        // destroy and unregister the device

    leds_destroy_device();

    printk(DEVICE_NAME"\texit.\n");

}

  3、the device mechanism supported by the device driver

// file control mechanism

static struct file_operations leds_fops = {

    .owner = THIS_MODULE,

    .unlocked_ioctl = s3c6410_leds_ioctl,

    .write = s3c6410_leds_write,

};

// device defination

static struct cdev leds_cdev;

  4、the callback operation functions

static struct file_operations leds_fops = {

    .owner = THIS_MODULE,

    .unlocked_ioctl = s3c6410_leds_ioctl,

    .write = s3c6410_leds_write,

};

//

static long s3c6410_leds_ioctl(struct file *filp, unsigned int cmd,

    unsigned long arg)

...

//

static ssize_t s3c6410_leds_write(struct file *filp,

    const char __user *buf,    size_t count, loff_t *ppos)

...

  I don't want to talk much about file_operations, you can check it in /kernel_dir/include/linux/fs.h and 《LDD》.

 

  TIPS-1 :

If you want to test the device, you could use echo.

But don't try to use a shell scripts to control it. because the shell in android and pc is working not like the original shell.

Ok, if you turely want to got a test in shell scripts, try this in you pc :

// choose no

$ sudo dpkg-reconfigure dash

  TIPS-2 :

Our device is /dev/s3c6410_leds instead of /dev/leds

 

 

  

你可能感兴趣的:(android)