|
楼主 |
发表于 2015-6-6 20:45:00
|
显示全部楼层
再转个android 下led的驱动,分4步,这个多少是有点问题
1: 内核硬件驱动层
2: HAL(硬件抽象层)
3: 框架层(framework,包含JNI和实现硬件服务的JAVA接口)
4: JAVA应用层
一,首先是第一层,内核硬件驱动层
在kernel\driver\下新建一个目录swt,在swt下再新建led文件夹,并新建swtled.c swtled.h,通过注册模块方式,实现ioctl,write,read接口。之后通过设备名给上层访问。
swtled.c部分
点击(此处)折叠或打开
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/uaccess.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/miscdevice.h>
#include <linux/watchdog.h>
#include <linux/fs.h>
#include <asm/io.h>
#include <mach/gpio.h>
#include <asm/uaccess.h>
#define LED_ON _IO ('k',1)
#define LED_OFF _IO ('k',2)
struct light_dev
{
struct cdev cdev;
unsigned char value;
};
static struct light_dev *light_devp;
static struct class * light_class = NULL;
int light_major = 250;
#if 0
static ssize_t light_val_show(struct device* dev, struct device_attribute* attr, char* buf)
{
return 0;
}
static ssize_t light_val_store(struct device* dev, struct device_attribute* attr, const char* buf, size_t count)
{
return 0;
}
static DEVICE_ATTR(val, S_IRUGO | S_IWUSR, light_val_show, light_val_store);
#endif
void led_off(int arg)
{
switch(arg)
{
case 1: gpio_set_value(RK29_PIN6_PB3,GPIO_LOW); //GPIO8
break;
case 2: gpio_set_value(RK29_PIN6_PC2,GPIO_LOW); //GPIO10
break;
default:
break;
}
}
void led_on(int arg)
{
switch(arg)
{
case 1: gpio_set_value(RK29_PIN6_PB3,GPIO_HIGH);
break;
case 2: gpio_set_value(RK29_PIN6_PC2,GPIO_HIGH);
break;
default:
break;
}
}
int light_open(struct inode *inode, struct file *filp)
{
struct light_dev *dev;
int ret = 0;
printk(KERN_ALERT"light_open()");
dev = container_of(inode->i_cdev, struct light_dev, cdev);
filp->private_data = dev;
ret = gpio_request(RK29_PIN6_PB3, NULL);
if(ret != 0)
{
gpio_free(RK29_PIN6_PB3);
}
gpio_direction_output(RK29_PIN6_PB3, 0);
ret = gpio_request(RK29_PIN6_PC2, NULL);
if(ret != 0)
{
gpio_free(RK29_PIN6_PC2);
}
gpio_direction_output(RK29_PIN6_PC2, 0);
return 0;
}
int light_release(struct inode *inode, struct file *filp)
{
printk(KERN_ALERT"light_release()");
return 0;
}
ssize_t light_read(struct file *filp, char __user *buf, size_t count, loff_t*f_pos)
{
struct light_dev *dev = filp->private_data;
printk(KERN_ALERT"light_read()");
if (copy_to_user(buf, &(dev->value), 1))
{
return -EFAULT;
}
return 1;
}
ssize_t light_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
{
struct light_dev *dev = filp->private_data;
printk(KERN_ALERT"light_write()");
if (copy_from_user(&(dev->value), buf, 1))
{
return -EFAULT;
}
if (dev->value == 1)
printk(KERN_ALERT"LED on");
else
printk(KERN_ALERT"LED off");
return 1;
}
int light_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
{
struct light_dev *dev = filp->private_data;
printk(KERN_ALERT"light_ioctl(cmd = %d)", cmd);
switch (cmd)
{
case LED_ON:
led_on(arg);
break;
case LED_OFF:
led_off(arg);
break;
default: break;
}
return 0;
}
struct file_operations light_fops =
{
.owner = THIS_MODULE,
.read = light_read,
.write = light_write,
.ioctl = light_ioctl,
.open = light_open,
.release = light_release,
};
static int light_setup_cdev(struct light_dev *dev, int index)
{
int err, devno = MKDEV(light_major, index);
cdev_init(&dev->cdev, &light_fops);
dev->cdev.owner = THIS_MODULE;
dev->cdev.ops = &light_fops;
dev->value = 0;
err = cdev_add(&dev->cdev, devno, 1);
return err;
}
int light_init(void)
{
int result = 0;
struct device * temp = NULL;
dev_t dev = MKDEV(light_major, 0);
printk(KERN_ALERT"light_init()");
if (light_major) {
result = register_chrdev_region(dev, 1, "LED");
}
else {
result = alloc_chrdev_region(&dev, 0, 1, "LED");
light_major = MAJOR(dev);
}
if (result < 0) {
goto failed;
}
light_devp = kmalloc(sizeof(struct light_dev), GFP_KERNEL);
if (!light_devp){
result = -ENOMEM;
goto unregister;
}
memset(light_devp, 0, sizeof(struct light_dev));
result = light_setup_cdev(light_devp, 0);
if(result) {
goto cleanup;
}
light_class = class_create(THIS_MODULE, "led");
if(IS_ERR(light_class)) {
printk(KERN_ALERT"Failed to create light class./n");
goto destroy_cdev;
}
temp = device_create(light_class, NULL, dev, "%s", "swtled");
if(IS_ERR(temp)) {
printk(KERN_ALERT"Failed to create hello device.");
goto destroy_class;
}
#if 0
result = device_create_file(temp, &dev_attr_val);
if(result < 0) {
printk(KERN_ALERT"Failed to create attribute val.");
goto destroy_device;
}
dev_set_drvdata(temp, light_devp);
#endif
return 0;
destroy_device:
device_destroy(light_class, dev);
destroy_class:
class_destroy(light_class);
destroy_cdev:
cdev_del(&(light_devp->cdev));
cleanup:
kfree(light_devp);
unregister:
unregister_chrdev_region(dev, 1);
failed:
printk(KERN_ALERT"light_init failed.");
return result;
}
void light_cleanup(void)
{
printk(KERN_ALERT"light_cleanup()");
if(light_class) {
device_destroy(light_class, MKDEV(light_major, 0));
class_destroy(light_class);
}
if(light_devp) {
cdev_del(&light_devp->cdev);
kfree(light_devp);
}
unregister_chrdev_region(MKDEV(light_major, 0), 1);
}
module_init(light_init);
module_exit(light_cleanup);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("led driver");
MODULE_ALIAS("led module");
led文件夹中Kconfig文件
点击(此处)折叠或打开
config SWT_XXX_LED
bool "swt led"
default n
help
This compiles in support for the led of xxx.
led文件夹中MakeFile文件
点击(此处)折叠或打开
obj-$(CONFIG_SWT_XXX_LED)+=swt_led.o
swtled文件中Kconfig文件
点击(此处)折叠或打开
menu "swtled Drivers"
source "drivers/swt/led/Kconfig"
endmenu
swtled文件夹中MakeFile文件
点击(此处)折叠或打开
obj-y += led/
接下来,就要修改kernel/driver下的MakeFile和Kconfig文件了,在分别其中添加一句
MakeFile文件
点击(此处)折叠或打开
obj-y += swt/
Kconfig文件
点击(此处)折叠或打开
source "drivers/swt/Kconfig"
保存所有之后,执行make
编译成功后,就可以在swt/led目录下看到swtled.o文件了,这时候编译出来的img已经包含了swtled驱动了 |
|