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[];
static int major = S3C6410_LEDS_MAJOR;
static int minor = S3C6410_LEDS_MINOR;
static dev_t leds_number;
static int leds_state = ;
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 :
case :
if (arg > ) {
return -EINVAL;
}
tmp = ioread32(S3C64XX_GPMDAT);
if (cmd == ) {
tmp &= (~( << arg));
} else {
tmp |= ( << arg);
}
iowrite32(tmp, S3C64XX_GPMDAT);
return ;
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 = ;
memset(mem, , ); if (count > ) {
tmp = ;
}
if (copy_from_user(mem, buf, tmp)) {
return -EINVAL;
} else {
for (i = ; i < ; i++) {
tmp = ioread32(S3C64XX_GPMDAT);
if (mem[i] == '') {
tmp &= (~( << i));
} else {
tmp |= ( << 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 = ;
int err = ; cdev_init(&leds_cdev, &leds_fops);
leds_cdev.owner = THIS_MODULE;
if (major > ) {
leds_number = MKDEV(major, minor);
err = register_chrdev_region(leds_number, DEVICE_COUNT, DEVICE_NAME);
if (err < ) {
printk(KERN_WARNING "register_chardev_region() failed.\n");
return err;
}
} else {
err = alloc_chrdev_region(&leds_cdev.dev, ,
DEVICE_COUNT, DEVICE_NAME);
if (err < ) {
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 = ;
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[]);
printk("param1\t%s\n", param[]);
printk("param2\t%s\n", param[]); 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

  

上一篇:查看软件安装的位置 Ubuntu


下一篇:Java工具类—包装类