我的板子上有4個led,對應的gpio口是gpb5,gpb6,gpb8,gpb10
io對映用的是靜態對映的方式,靜態對映的內容再arch/arm/mach-s3c2410/mach-smdk2410.c中,如果每記錯就是這個路徑
linux核心對著個soc支援還是很好的,硬體資源都已標頭檔案的方式寫在原始碼中了,但由於目錄紛繁複雜,建議使用vim+ctag瀏覽**
回頭用空把我對靜態對映的理解也寫下來,現在就先預設對映都已經做好。
還是用了mach/gpio-fns.h中的s3c2410_gpio_cfgpin等配置gpio的函式,比較好用,很省心
先把**貼上來再說
1. 標頭檔案部分,沒什麼好說的,用什麼就include進來
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define led_major249
#define device_name "myled"
2.一些巨集定義
關於s3c2410_gpb(x)這個巨集,這個巨集定義再mach/gpio-nrs.h中,定義如下
#define s3c2410_gpb(_nr) (s3c2410_gpio_b_start + (_nr))
在這個之前有個列舉的結構
enum s3c_gpio_number ;
這裡定義了一組start
再往上看
#define s3c2410_gpio_next(__gpio) \
((__gpio##_start) + (__gpio##_nr) + config_s3c_gpio_space + 0)
在#define中,標準定義了#和##兩種操作。#用來把引數轉換成字串,##則用來連線兩個前後兩個引數,把它們變成乙個字串。
s3c2410_gpio_b_start = s3c2410_gpio_next(s3c2410_gpio_a)
這句話就可一翻譯成
s3c2410_gpio_b_start=s3c2410_gpio_a_start + s3c2410_gpio_a_nr + config_s3c_gpio_space
s3c2410_gpio_a_nr定義為#define s3c2410_gpio_a_nr (32)
config_s3c_gpio_space 定義為 #define config_s3c_gpio_space 0
那麼最終
s3c2410_gpio_a_start=0
s3c2410_gpio_b_start=32
以此類推,這個32實際上就是對應每個gpio口的位址空間,也就是說
gpb0=32,gpb1=33 ...
這些都是偏移量,那基位址在**呢?這就要看s3c2410_gpio_cfgpin函式中的操作了
這個追下去簡直是個無底洞,有興趣的可以試試,這裡就不往下追了,繼續看**,關於gpb0~10的定義就清楚了
//*************************繼續************************************
#define gpb0(s3c2410_gpb(0))
#define gpb5(s3c2410_gpb(5))
#define gpb6(s3c2410_gpb(6))
#define gpb8(s3c2410_gpb(8))
#define gpb10(s3c2410_gpb(10))
//************************這裡定義乙個陣列,儲存每個led對應的gpio口,便於後面呼叫
static unsigned int led_index[5]=;
static int led_major=led_major;
static int led_minor;
//定義led裝置結構體,重點是要包含cdev,這個結構體相當於驅動程式掛接再核心驅動框架的介面,其他的引數都是根據自己需要定義的,比如led_status
struct led_dev
;struct led_dev *led_devp;
//led的開啟函式,驅動模組載入後,mknod相應的節點,open /dev/led就呼叫到了這個函式
//這裡做了幾件事情,首先是根據inode節點獲得裝置號,然後從裝置號中分離出次裝置號
//因為由4個led,他們用同樣的驅動程式,也就是共用4個裝置號,但如果想單獨操作每個led的話,就要根據led0~led3來區別對待
//這個區別的方法就是用次裝置號,這個次裝置號一方面再mknod時指定,最重要的要再後面的模組init模組中建立相應的裝置結構
//這個後面會看到
//得到了次裝置號,就配置對應的gpio口為輸出模式
static int s3c2440_led_open(struct inode *inode,struct file *filp)
//release函式,這裡沒做什麼事
static int s3c2440_led_release(struct inode *inode,struct file *filp)
//ioclt函式,這是乙個很有用的函式,後面對led的操作的應用程式就是呼叫的這個函式操作led的
//通過傳遞的cmd引數,對led進行操作
static int s3c2440_led_ioctl(struct inode *inode,struct file *filp,unsigned int cmd,unsigned long arg)
return 0;
}//函式掛接
static struct file_operations s3c2440_led_ops=
;//設定cdev,這是對字元裝置的通用做法
static void led_setup_cdev(struct led_dev* dev,int index)
}//init模組,模組載入的時候會呼叫這個函式。前面說過,如果要支援多個裝置,也就是多個裝置號,那麼要申請多個裝置號,同時申請多個對應的裝置結構
static int __init s3c2440_led_init(void)
//申請了5個次裝置號,對應要申請5個裝置結構體
memset(led_devp,0,5*sizeof(struct led_dev));
led_setup_cdev(&led_devp[0],0);
led_setup_cdev(&led_devp[1],1);
led_setup_cdev(&led_devp[2],2);
led_setup_cdev(&led_devp[3],3);
led_setup_cdev(&led_devp[4],4);
printk(kern_notice "init module, result=%d\n",result);
return result;
}//解除安裝函式
static void __exit s3c2440_led_exit(void)
module_author("weicz");
module_license("dual bsd/gpl");
module_init(s3c2440_led_init);
module_exit(s3c2440_led_exit);
至此驅動部分**就完成了
下面是乙個測試程式用來測試這段驅動程式,很簡單就不說什麼了
關於編譯,編譯模組制定的選項比較多,每次寫很麻煩,我寫成乙個makefile,,只要在同一目錄下make一下就好
makefilene內容
obj-m :=led.o
kernel_dir := /home/huniu/sources/kernel/linux-2.6.35
pwd :=$(shell pwd)
all:
make -c $(kernel_dir) subdirs=$(pwd) modules
clean:
rm *.o *.ko *.mod.c
.phony:clean
這裡的kernel_dir根據自己的原始碼路徑修改
那個應用程式的編譯比較簡單
如果檔案系統沒有移植glibc庫的話,要靜態編譯才能使用stdio.h的函式,也就是編譯選項中加入-static選項
led的驅動就寫到這裡,後面寫按鍵驅動
Linux裝置驅動之《字元裝置驅動》
linux裝置中最大的特點就是裝置操作猶如檔案操作一般,在應用層看來,硬體裝置只是乙個裝置檔案。應用程式可以像操作檔案一樣對硬體裝置進行操作,如open close read write 等。下面是乙個字元裝置驅動程式的簡單實現test.c 模組分析 1.初始化裝置驅動的結構體 struct fil...
Linux裝置驅動之字元裝置驅動
一 linux裝置的分類 linux系統將裝置分成三種基本型別,每個模組通常實現為其中某一類 字元模組 塊模組或網路模組。這三種型別有 字元裝置 字元裝置是個能夠像位元組流 類似檔案 一樣被訪問的裝置,由字元裝置驅動程式來實現這種特性。字元裝置可以通過檔案系統節點來訪問,比如 dev tty1等。這...
Linux裝置驅動程式學習(1) 字元裝置驅動程式
linux裝置驅動程式學習 1 字元裝置驅動程式 一 分配裝置號 1 對字元裝置的訪問是通過檔案系統內的裝置名稱進行的 dev ttys0 在核心中,include dev t 用來儲存裝置編號 包括主裝置號和次裝置號。由dev t獲得主次裝置號 major dev t dev minor dev ...