1、電路圖
2、Linux-2.6.32.2核心重要標頭檔目錄:
linux-2.6.32.2/arch/arm/mach-s3c2410/include/mach/regs-gpio.h
linux-2.6.32.2/arch/arm/mach-s3c2410/include/mach/gpio-nrs.h
linux-2.6. 32.2/arch/arm/plat-s3c24xx/gpio.c
linux-2.6. 32.2/include/linux/asm-generic/io.h
linux-2.6. 32.2/include/linux/wait.h
連結關係。如:出現asm則連結之後的內容
asm --- linux-2.6.32.2/include/linux/asm-generic
mach --- linux-2.6.32.2/arch/arm/mach-s3c2410/include/mach
plat --- linux-2.6.32.2/arch/arm/plat-s3c24xx/include/plat
linux-2.6.32.2/arch/arm/plat-s3c/include/plat
3、代碼閱讀分析
拿到驅動代碼首先看下面這個兩個宏:
module_init(beep_init); /*模組載入時調用beep_init函數進行載入*/
module_exit(beep_cleanup); /*模組卸載時調用beep_cleanup函數進行清除*/
4.原始碼beep_drv.c分析:
#include <linux/errno.h> /*公用的頭文*/#include <linux/kernel.h>#include <linux/module.h>#include <linux/slab.h>#include <linux/input.h>#include <linux/init.h>#include <linux/serio.h>#include <linux/delay.h>#include <linux/clk.h>#include <linux/miscdevice.h>#include <linux/gpio.h>#include <asm/io.h> //平台相關的檔案#include <asm/irq.h> /*出現asm 則它會串連到 linux-2.6.32.2/include/linux/asm-generic*/#include <asm/uaccess.h>#include <mach/regs-clock.h>#include <plat/regs-timer.h> #include <mach/regs-gpio.h>//這個檔案在inux-2.6.32.2/arch/arm/mach-s3c2410/include/mach/regs-gpio.h中// /opt/linux-2.6.34/arch/arm/mach-s3c2410/include/mach/regs-gpio.h#include <linux/cdev.h>static int beep_major = 0;/*全域主裝置號*/module_param(beep_major, int, 0);/*傳遞參數這裡沒有到*/MODULE_AUTHOR("Hanson He"); /*聲明作者*/MODULE_LICENSE("Dual BSD/GPL");/*指定使用什麼協議的*/#define BEEP_MAGIC 'k'#define BEEP_START_CMD _IO (BEEP_MAGIC, 1)#define BEEP_STOP_CMD _IO (BEEP_MAGIC, 2)/* _IO(type,nr)用於構造無參數的命令編號;*//* * Open the device; in fact, there's nothing to do here. */int beep_open (struct inode *inode, struct file *filp)/*沒用到,但必需保持完整性*/{return 0;}ssize_t beep_read(struct file *file, char __user *buff, size_t count, loff_t *offp){return 0;}ssize_t beep_write(struct file *file, const char __user *buff, size_t count, loff_t *offp){return 0;}void beep_stop( void ){//add your src HERE!!!//set GPB0 as outputs3c2410_gpio_cfgpin(S3C2410_GPB(0), S3C2410_GPIO_OUTPUT);s3c2410_gpio_setpin(S3C2410_GPB(0),0);}void beep_start( void ){//add your src HERE!!!//set GPB0 as outputs3c2410_gpio_pullup(S3C2410_GPB(0),1);/*上拉電阻*/s3c2410_gpio_cfgpin(S3C2410_GPB(0), S3C2410_GPIO_OUTPUT);/*配置*/s3c2410_gpio_setpin(S3C2410_GPB(0),1);/*置位*/}static int beep_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){//add your src HERE!!!switch ( cmd ) {case BEEP_START_CMD: {beep_start(); break;}case BEEP_STOP_CMD: {beep_stop(); break;}default: {break;}}return 0;}static int beep_release(struct inode *node, struct file *file){return 0;}/* * Set up the cdev structure for a device. */static void beep_setup_cdev(struct cdev *dev, int minor,struct file_operations *fops){int err, devno = MKDEV(beep_major, minor);/*由主次裝置號產生裝置號*/ cdev_init(dev, fops); /* 初始化cdev*/dev->owner = THIS_MODULE;dev->ops = fops;err = cdev_add (dev, devno, 1);/* 註冊裝置*//* Fail gracefully if need be */if (err)printk (KERN_NOTICE "Error %d adding beep%d", err, minor);}/* * Our various sub-devices. *//* Device 0 uses remap_pfn_range */static struct file_operationKERNELDIR ?=/home/student/linux-2.6.32.2all: beep_test beep_test : beep_test.c#arm-linux-gcc -I$(KERNELDIR) -s -Wl,-warn-common --static -o $@ $^arm-linux-gcc -I$(KERNELDIR) -o $@ $^clean :rm beep_tests beep_remap_ops = { ?*file_operations的對象beep_remap_ops,並對其賦值*/.owner = THIS_MODULE, /*指向模組本身*/.open = beep_open, /*把open和beep_open函數關聯起來,註冊*/.release = beep_release,.read = beep_read,.write = beep_write,.ioctl = beep_ioctl,};/* * There's no need for us to maintain any * special housekeeping info, so we just deal with raw cdevs. */static struct cdev BeepDevs;/* * Module housekeeping. */static int beep_init(void)/*模組載入時調用beep_init函數進行載入*/{int result;dev_t dev = MKDEV(beep_major, 0);char dev_name[]="beep";/* Figure out our device number. */if (beep_major)/*裝置號的分配*/result = register_chrdev_region(dev, 1, dev_name); /*手工 分配*/else {result = alloc_chrdev_region(&dev, 0, 1, dev_name);/*系統分配一個裝置號0:第一個次裝置號,1:一個裝置*/beep_major = MAJOR(dev);/*取得主裝置號*/}if (result < 0) {printk(KERN_WARNING "beep: unable to get major %d\n", beep_major);return result;}if (beep_major == 0)beep_major = result;/* Now set up cdev. */beep_setup_cdev(&BeepDevs, 0, &beep_remap_ops);printk("beep device installed, with major %d\n", beep_major);printk("The device name is: %s\n", dev_name);return 0;}static void beep_cleanup(void)/*模組卸載時調用beep_cleanup函數進行清除*/{cdev_del(&BeepDevs);/*登出裝置*/unregister_chrdev_region(MKDEV(beep_major, 0), 1);/*釋放佔用的裝置號*/printk("beep device uninstalled\n");}module_init(beep_init); /*模組載入時調用beep_init函數進行載入*/module_exit(beep_cleanup); /*模組卸載時調用beep_cleanup函數進行清除*/EXPORT_SYMBOL(beep_major);/*????*/相應的Makefile檔案(參考)ifeq ($(KERNELRELEASE),)#KERNELDIR ?= /your/target/source/directory/KERNELDIR ?=/home/lwb/linux-2.6.32.2PWD := $(shell pwd)modules:$(MAKE) -C $(KERNELDIR) M=$(PWD) modulesmodules_install:$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_installclean:rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions.PHONY: modules modules_install cleanelse obj-m := beep_drv.oendif
5、 應該編譯驅動、下載到板子上、註冊。
6、 建立裝置節點
$mknod /dev/node_name c
major minor //char dev_name[]="beep";這裡node_name為beep
7、 測試程式碼
#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <fcntl.h>#include <linux/ioctl.h>#define BEEP_MAGIC 'k' /*宏是跟驅動裡一樣的*/#define BEEP_START_CMD _IO (BEEP_MAGIC, 1)#define BEEP_STOP_CMD _IO (BEEP_MAGIC, 2)int main(){ int i = 0; int dev_fd; dev_fd = open("/dev/beep",O_RDWR | O_NONBLOCK);/*開啟裝置檔案可讀可寫、非阻塞*/ if ( dev_fd == -1 ) { printf("Cann't open file /dev/beep\n"); exit(1); } printf("Start beep\n"); ioctl (dev_fd, BEEP_START_CMD,0); getchar(); ioctl (dev_fd, BEEP_STOP_CMD,0); printf("Stop beep and Close device\n"); close(dev_fd); /*關閉裝置檔案*/ return 0;}
相應的Makefile檔案KERNELDIR ?=/home/lwb/linux-2.6.32.2all: beep_test beep_test : beep_test.c#arm-linux-gcc -I$(KERNELDIR) -s -Wl,-warn-common --static -o $@ $^arm-linux-gcc -I$(KERNELDIR) -o $@ $^clean :rm beep_test
8、 編寫Makefile
KERNELKDIR?=/opt/linux-2.6.32.2/include
all:test
test:test.c
arm-linux-gcc–I $(KERNELDIR) –o S@ S^ //–I
$(KERNELDIR)表包含標頭檔
clean:
rm –rf test
9、舉例:編寫BEEP測試程式
9.1編寫BEEP測試程式beep_drv.c,編譯產生beep_drv.ko
9.2上電開發板,運行uImage核心
9.3下載模組檔案到開發板
9.4動態載入模組檔案insmod
beep_drv.ko
9.5查看BEEP驅動系統自動分配的主裝置號cat
/proc/devices |grep beep
9.6製作BEEP對應的裝置檔案節點
mknod /dev/beep c major 0
9.7將編譯產生的beep_test,下載到開發板,測試BEEP驅動