150 likes | 325 Views
Linux 驅動程式添加實驗. Linux 下字元設備驅動的添加. 在一個字元設備驅動 實現對 GPIO 埠的操作 在模組載入的時候 跑馬燈執行起來 模組卸載的時候 跑馬燈停止 FS2410XP 上的 4 個 LED 由 4 個 I/O 口控制,它們分別是 GPF4~GPF7 當 GPF4~GPF7 輸出低電壓的時候 相應的 LED 指示燈亮. 字元設備程式 gpiodrv.c. #include <linux/config.h> #include <linux/init.h> #include <linux/module.h>
E N D
Linux下字元設備驅動的添加 • 在一個字元設備驅動 • 實現對GPIO埠的操作 • 在模組載入的時候 • 跑馬燈執行起來 • 模組卸載的時候 • 跑馬燈停止 • FS2410XP上的4個LED • 由4個I/O口控制,它們分別是 • GPF4~GPF7 • 當GPF4~GPF7輸出低電壓的時候 • 相應的LED指示燈亮
字元設備程式gpiodrv.c • #include <linux/config.h> • #include <linux/init.h> • #include <linux/module.h> • #include <linux/fs.h> • #include <linux/iobuf.h> • #include <linux/kernel.h> • #include <linux/major.h> • #include <asm/uaccess.h> • #include <asm/hardware.h> • #include <asm/arch/cpu_s3c2410.h> • #include <asm/io.h> • #include <linux/vmalloc.h> • #define IOPORT_MAJOR 220 /*定義主設備號*/ • int gpio_open(struct inode*,struct file*); //函數聲明 • int gpio_release(struct inode*,struct file*); • int gpio_ctl_ioctl(struct inode*,struct file*,unsigned int,unsigned long); • static struct file_operations gpio_ctl_fops={ • ioctl: gpio_ctl_ioctl, • open : gpio_open, • release: gpio_release, • };
字元設備程式gpiodrv.c • #define LED1_ON() (GPFDAT &= ~0x10) • #define LED2_ON() (GPFDAT &= ~0x20) • #define LED3_ON() (GPFDAT &= ~0x40) • #define LED4_ON() (GPFDAT &= ~0x80) • #define LED1_OFF() (GPFDAT |= 0x10) • #define LED2_OFF() (GPFDAT |= 0x20) • #define LED3_OFF() (GPFDAT |= 0x40) • #define LED4_OFF() (GPFDAT |= 0x80) • static int LedStatus; • void LedSet(int led) • { • LedStatus = led; • if(LedStatus&1) • LED1_ON(); • else • LED1_OFF(); • if(LedStatus&2) • LED2_ON(); • else • LED2_OFF(); • if(LedStatus&4) • LED3_ON(); • else • LED3_OFF(); • if(LedStatus&8) • LED4_ON(); • else • LED4_OFF(); • }
字元設備程式gpiodrv.c • void LedDisp(void) • { • LedSet(0x08); //LED點亮/熄滅狀態設置 • udelay(0x500000); //延時函數 • LedSet(0x04); //LED點亮/熄滅狀態設置 • udelay(0x500000); • LedSet(0x02); //LED點亮/熄滅狀態設置 • udelay(0x500000); • LedSet(0x01); //LED點亮/熄滅狀態設置 • udelay(0x500000); • LedSet(0x02); //LED點亮/熄滅狀態設置 • udelay(0x500000); • LedSet(0x04); //LED點亮/熄滅狀態設置 • udelay(0x500000); • LedSet(0x08); //LED點亮/熄滅狀態設置 • udelay(0x500000); • }
字元設備程式gpiodrv.c • static int __init gpio_init(void) • { • int err=0; • printk("gpio_init\n"); • err=register_chrdev(IOPORT_MAJOR,"gpio",&gpio_ctl_fops); • if(err) • { • printk("fail to register\n"); • return -1; • } • printk("success to register\n"); • return 0; • }
字元設備程式gpiodrv.c • int gpio_open(struct inode *inode,struct file *fllp) • { • GPFCON=0x5500; • GPFUP=0xff; • printk("open gpio devices\n"); • return 0; • } • int gpio_release(struct inode *inode,struct file *filp) • { • printk("release this device\n"); • return 0; • }
字元設備程式gpiodrv.c • int gpio_ctl_ioctl(struct inode *inode,struct file *flip,unsigned int command,unsigned long arg) • { • int err=0; • if(command==1){ • while(arg--) • { • LedDisp(); • printk("...."); • } • printk("\n"); • return 0; • } • return err; • }
字元設備程式gpiodrv.c說明 • 將硬體設備當作檔案處理 • 所有操作就在file_operations結構體裏面 • 就是檔案的open/read/write/close等操作 • 剩餘放到一個ioctl函數裏面做處理 • 檔案系統處理的檔所需要的資訊在 • inode(索引結點)資料結構中 • 提供了關於特別設備檔/dev/DriverName • DriverName可能是任何一個設備檔 • 如hda0 • 在Linux系統中 • 通過用register_chrdev • 向系統註冊字元型設備驅動程式 • int register_chrdev(unsigned int major,const char *name,struct file_operations *fops)
驅動程式的Makefile檔 • CROSS= /work/cgf/2410/2.95.3/bin/arm-linux- • CFLAGS=-D__KERNEL__ • CFLAGS+=-DMODULE • CFLAGS+=-I/work/cgf/2410/2.4.18-rmk7/include • CFLAGS+=-I/work/cgf/2410/2.4.18-rmk7/include/linux • CFLAGS+=-I/work/cgf/2410/2.95.3/arm-linux\include • CFLAGS+=-Wall -Wstrict-prototypes -Wno-trigraphs -Os -mapcs • CFLAGS+=-fno-strict-aliasing -fno-common -fno-common -pipe -mapcs-32 • CFLAGS+=-march=armv4 -mtune=arm9tdmi -mshort-load-bytes -msoft-float • CFLAGS+=-DKBUILD_BASENAME=gpiodrv • all:gpiodrv.o • gpiodrv.o:gpiodrv.c • $(CROSS)gcc $(CFLAGS) -c -o gpiodrv.o gpiodrv.c • clean: • rm -f *.o
編譯安裝驅動程式 • 將gpiodrv.c和這個Makefile放置在同一個新建目錄下 • 進入這個目錄 • 輸入make後 • 編譯成功後將在這個目錄下產生一個gpiodrv.o的文件 • 將gpiodrv.o下載到/tmp目錄下 • 可以通過ftp,zx下載 • 動態載入設備驅動模組 • insmod gpiodrv.o • 如果載入成功 • 可以通過cat /proc/devices查看該設備的相關資訊 • 卸載設備驅動模組 • rmmod gpiodrv
#include <stdio.h> #include <stdlib.h> //system #include <fcntl.h> #include <errno.h> #include <unistd.h> #include <linux/delay.h> #include <sys/ioctl.h> #define DEVICE_GPIOTEST "/dev/gpio" //設備節點 int main(int argc, char *argv[]) { int fd; int val=-1; fd=open(DEVICE_GPIOTEST,O_RDONLY);//打開設備 if(fd<0) { perror("can not open device"); exit(1); } while(1){ printf("please select number to run program\n"); printf("1:led on \n2:quit "); scanf("%d",&val); if(val==1) ioctl(fd,1,10); else if(val==2){ close(fd); } } return 0; } 測試程式gpio_test.c
測試程式gpio_test.c • 將gpio_test.c • 放置在一個新建目錄下 • 進入該目錄下,輸入命令 • /work/cgf/2410/2.95.3/bin/arm-linux-gcc –o gpio_test gpio_test.c • 編譯成功後 • 將在該目錄下產生gpio_test可執行檔 • 要注意交叉編譯工具 • arm-linux-gcc的路徑要設置正確 • 這裏是 /work/cgf/2410/2.95.3/bin/.
驅動程式測試 • (1)先讓FS2410XP教學平臺進入Linux環境 • 利用超級終端來顯示,進入Linux命令行的模式下 • (2)輸入命令cd /tmp,進入tmp目錄 • 因為/tmp是在SDRAM中,可以放資料 • (3)將gpiodrv.o和gpio_test下載到/tmp目錄下。 • 在這裏我們採用的的rz命令來傳輸的 • 也可以利用ftp來傳輸 • rz命令是通過Zmodem協議來傳輸的 • 先在教學平臺的下輸入rz命令(Linux環境下) • 接著點選超級終端機的“傳送”—>“發送檔” • 在彈出的對話方塊中設置然後點選發送 • 資料傳輸完後 • 再Enter,接著通過ls來查看/tmp目錄下是否有gpiodrv.o檔案,gpio_test的下載過程是一樣的。
驅動程式測試 • (4)gpiodrv.o和gpio_test下載成功後 • 接下來我們要進行真正的載入和執行的工作了 • 改變gpio_test的屬性,命令如下 • chmod 755 gpio_test • (5)載入gpiodrv.o模組 • insmod gpiodrv.o • (6)建立gpio設備節點 • mknod /dev/gpio c 220 0 • /dev/gpio為該設備驅動程式的設備名 • c表明該設備為字元設備 • 220為該設備的主設備號 • 0為從設備號 • (7)執行gpio_test程式 • ./gpio_test • gpio_test程式執行起來後 • 有相應的功能選項說明