標籤:des io ar os sp div on 2014 art
Linux應用程式層想要操作kernel層的API,比方想操作相關GPIO或寄存器,能夠通過寫一個字元裝置驅動來實現。
1、先在rootfs中的 /dev/ 下產生一個字元裝置。注意主裝置號 和 從裝置號。可用例如以下shell指令碼產生:
if [ ! -e audioIN ];then sudo mknod audioIN c 240 0 fi
產生的裝置為 /dev/audioIN ,主裝置號240,從裝置號0。
2、寫audioINdriver.ko ,audioINdriver.c 基本代碼架構例如以下:代碼中定義了裝置名稱audioIN,裝置號240, 0 ,與之前建立的裝置一致。
/************************************************************************** * audioINdriver.c * * kang_liu <[email protected]> * 2014-07-15\**************************************************************************/#include <asm/uaccess.h>#include <asm/errno.h>#include <linux/types.h>#include <linux/fs.h>#include <linux/init.h>#include <linux/module.h>#include <linux/cdev.h>#include <mach/gpio.h>//#include <mach/at91_rstc.h> /* debug *///#include <mach/at91_pmc.h>//#include <mach/at91_rstc.h>//#include <mach/at91_shdwc.h>#include <mach/irqs.h>//#include "generic.h"//#include "clock.h"#include <mach/w55fa92_reg.h>#include <asm/io.h>#define DEV_MAJOR 240#define DEV_MINOR 0#define NUM_MINORS 1#define DEVICE_NAME "audioIN"#define ERR(fmt, args...) printk(KERN_ALERT __FILE__ ": " fmt, ##args)#define MSG(fmt, args...) printk(KERN_INFO __FILE__ ": " fmt, ##args)#define DBG(fmt, args...) printk(KERN_DEBUG __FILE__ ": " fmt, ##args)static ssize_t user_gpio_read(struct file *fp, char __user *buff, size_t count, loff_t *offp){ char str[32] = {0}; char out[32] = {0}; int n, err;// printk("lk~~~~~~~read buff = %s\n",buff); err = copy_from_user(str, buff, count);// printk("lk~~~~~~~read str = %s\n",str); if (err) return -EFAULT;sprintf(out,"return values");memset(buff, 0, count);err = copy_to_user(buff, out, sizeof(out));if (err) return -EFAULT; return n;}static ssize_t user_gpio_write(struct file *fp, const char __user *buff, size_t count, loff_t *offp){ int err; char tmp[32]; // printk("lk~~~~~~~write buff = %s\n",buff); err = copy_from_user(tmp, buff, count);// printk("lk~~~~~~~write tmp = %s\n",tmp); if (err) return -EFAULT;if('1' == tmp[0]){//LINE INprintk("line in\n");}else if('0' == tmp[0]){//MIC INprintk("mic in\n");} return count;}static ssize_t user_gpio_open(struct inode *inode,struct file *fp) {// printk("open gpio devices\n"); return 0; } static struct file_operations user_gpio_file_ops = { .owner = THIS_MODULE, .write = user_gpio_write, .read = user_gpio_read, .open = user_gpio_open, };static struct cdev *dev;static void __exit user_audioIN_exit(void){printk("exit audioIN\n"); dev_t devno = MKDEV(DEV_MAJOR, DEV_MINOR); unregister_chrdev_region(devno, NUM_MINORS); cdev_del(dev); return;}static int __init user_audioIN_init(void){printk("init audioIN\n"); int err = 0; int i; dev_t devno = MKDEV(DEV_MAJOR, DEV_MINOR); err = register_chrdev_region(devno, NUM_MINORS, DEVICE_NAME); if (err) goto fail_devno; dev = cdev_alloc(); dev->ops = &user_gpio_file_ops; dev->owner = THIS_MODULE; err = cdev_add(dev, devno, NUM_MINORS); if (err) goto fail_cdev; return err;fail_cdev:fail_devno: unregister_chrdev_region(devno, NUM_MINORS);fail_gpio: return err;}module_init(user_audioIN_init);module_exit(user_audioIN_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("kang_liu <[email protected]>");MODULE_DESCRIPTION("Access GSEIO from userspace.");
這裡就能夠調用kernel層的一些API進行底層的操作。
Makefile:產生audioINdriver.ko
# Comment/uncomment the following line to disable/enable debugging#DEBUG = yBUILD_TOOLS_PRE = arm-linux-CC=$(BUILD_TOOLS_PRE)gccLD=$(BUILD_TOOLS_PRE)ld# Add your debugging flag (or not) to CFLAGSifeq ($(DEBUG),y) DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlineselse DEBFLAGS = -O2endifKERNEL_DIR = ../../../linux-2.6.35.4EXTRA_CFLAGS += $(DEBFLAGS)EXTRA_CFLAGS += -I$(LDDINC)EXTRA_CFLAGS +=-I$(KERNEL_DIR)/arch/arm/mach-w55fa92/includeEXTRA_CFLAGS +=-I$(KERNEL_DIR)/arch/armEXTRA_CFLAGS +=-I$(KERNEL_DIR)/arch/arm/includeEXTRA_CFLAGS +=-I$(KERNEL_DIR)/arch/arm/include/linuxifneq ($(KERNELRELEASE),)# call from kernel build systemaudioIN-objs := audioINdriver.oobj-m:= audioINdriver.oelseKERNELDIR ?= $(KERNEL_DIR)#KERNELDIR ?= /lib/modules/$(shell uname -r)/buildPWD := $(shell pwd)modules:$(MAKE) ARCH=arm CROSS_COMPILE=$(BUILD_TOOLS_PRE) -C $(KERNELDIR) M=$(PWD) LDDINC=$(PWD)/../include modulesendifclean:rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions modules.order Module.symversdepend .depend dep:$(CC) $(CFLAGS) -M *.c > .dependifeq (.depend,$(wildcard .depend))include .dependendif
3. 產生好 .ko 以後,就能夠在ARM板上,載入驅動。
insmod audioINdriver.ko
4、載入驅動成功後,就能夠在應用程式層直接操作裝置 /dev/audioIN,來實現相關功能,將一些參數傳到驅動層,運行相關kernel層的代碼。
應用程式層測試程式例如以下:
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <errno.h>#include <fcntl.h>#include <sys/types.h>#include <sys/stat.h>#include <sys/syscall.h>#define BUF_LEN 32int s_audioInFd = 0;int InitAudioInDevice(){s_audioInFd = open("/dev/audioIN",O_RDWR);if (s_audioInFd > 0){return 1;}else{printf("Can't open the GSE IO device\n");return 0;}}void UninitAudioInDevice(){if (s_audioInFd > 0)close(s_audioInFd);}int getAudioIn(){char buffer[BUF_LEN] = {0};if (s_audioInFd > 0){memcpy(&buffer[0], "lk_test", 7);//printf("get buffer = %s\n", buffer);int len = read(s_audioInFd, buffer, 7);//printf("get buffer = %s, len = %d\n", buffer, len);return len;}return -1;}int setAudioIn(int micLine){char buffer[BUF_LEN] = {0};if (s_audioInFd > 0){sprintf(buffer, "%d", micLine);int len = write(s_audioInFd, buffer, sizeof(buffer));if (len > 0)return 1;}return 0;}
當中的read 和 write函數,可從驅動中擷取一些返回值,也可將字串傳到驅動中。
驅動的入口為:
module_init(user_audioIN_init);
module_exit(user_audioIN_exit);
Linux實現字元裝置驅動的基礎步驟