手上有一个android开发平台,于是想在底层加个自己的硬件模块然后通过Android的HAL方式向上封装出底层驱动供JAVA APP调用。既然是刚上手,那就用led灯来做为先导开发走走流程吧,至少得把从内核到应用层的流程走通才行。
从底层到上层一共分成四个阶段。
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文件
接下来,就要修改kernel/driver下的MakeFile和Kconfig文件了,在分别其中添加一句
MakeFile文件
Kconfig文件
- source "drivers/swt/Kconfig"
保存所有之后,执行make
编译成功后,就可以在swt/led目录下看到swtled.o文件了,这时候编译出来的img已经包含了swtled驱动了
阅读(7903) | 评论(0) | 转发(1) |