驅動程式:
/*whjled.c*/
#include<mach/regs-gpio.h>
#include <mach/hardware.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/ioctl.h>
#include <linux/cdev.h>
#include <linux/gpio.h>
#include <asm/uaccess.h>
#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <asm/irq.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/list.h>
#include <linux/pci.h>
#include <asm/atomic.h>
#include <asm/unistd.h>
#define LED_ON 1
#define LED_OFF 0
#define DEVICE_NAME "whjled"
#define LED_MAJOR 98
static unsigned long led_table [] =
{
S3C2410_GPB(5),
S3C2410_GPB(6),
S3C2410_GPB(7),
S3C2410_GPB(8),
};
static unsigned int led_cfg_table [] =
{
S3C2410_GPIO_OUTPUT,
S3C2410_GPIO_OUTPUT,
S3C2410_GPIO_OUTPUT,
S3C2410_GPIO_OUTPUT,
};
static int s3c2440_leds_ioctl(
struct inode *inode,
struct file *file,
unsigned int cmd,
unsigned long arg)
{
if(arg>3)
{
printk("Led's number error,pleasecheck!");
return -EINVAL;
}
switch(cmd)
{
case LED_ON:
s3c2410_gpio_setpin(led_table[arg],0);//led low light
return 0;
case LED_OFF:
s3c2410_gpio_setpin(led_table[arg], 1);
return 0;
default:
return -EINVAL;
}
}
static struct file_operations dev_fops =
{
.owner = THIS_MODULE,
.ioctl = s3c2440_leds_ioctl,
};
static int __init dev_init(void)
{
int ret;
int i;
ret = register_chrdev(LED_MAJOR,DEVICE_NAME,&dev_fops);
if(ret<0)
{
printk(DEVICE_NAME"uninitialized\n");
return ret;
}
for (i = 0; i < 4; i++)
{
s3c2410_gpio_cfgpin(led_table[i],led_cfg_table[i]);
s3c2410_gpio_setpin(led_table[i], 1);
}
printk (DEVICE_NAME"initialized\n");
return 0;
}
static void __exit dev_exit(void)
{
unregister_chrdev(LED_MAJOR,DEVICE_NAME);
}
module_init(dev_init);
module_exit(dev_exit);
驅動檔案對應的Makefile為:
obj-m:=whjled.o
PWD:=$(shell pwd)
KDIR:=/home/linux-2.6.32.2c
all:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
clean:
rm -rf *.o *.ko *.mod.c *.mod.o *.symvers
將whjled.c與Makefile放在同一檔案夾內(linux環境)執行make,產生whjled.ko。將whjled.ko拷貝至根檔案系統的tmp檔案夾下(我使用的是nfs根檔案系統)。
在/tmp檔案夾下載入驅動模組:輸入insmod whjled.ko,若建立成功,可通過cat /proc/devices查看到裝置whjled與其主裝置號98.
在/dev檔案夾下建立裝置節點:輸入mknod whjled c 98 1,若成功,可通過ls /dev查看到裝置檔案
測試程式如下:
/*cpp.c*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define LED_DEVICE "/dev/whjled"
int main(int argc,char *argv[])
{
int fd,cmd,num;
fd = open(LED_DEVICE,0);
num=atoi(argv[1]);
cmd=atoi(argv[2]);
if(fd < 0)
{
printf("can't open/dev/leds!\n");
exit(0);
}
ioctl(fd,cmd,num);
exit(0);
}
將驅動程式放在linux環境內,執行arm-linux-gcc-static cpp.c -o cpp,可得到可執行檔cpp。將cpp拷貝至根檔案系統的/tmp檔案夾下,就可通過
./cpp 0 0//led0滅
./cpp 0 1//led0亮
./cpp 1 0
./cpp 1 1
.....
./cpp 3 1
操作 LED 。
注意:
1、註冊裝置的時候,有兩種方式:一種是使用register_chrdev(LED_MAJOR,DEVICE_NAME,&dev_fops),LED_MAJOR為定義的主裝置號,DEVICE_NAME為定義的裝置名稱,dev_fops為定義的檔案操作結構體。使用該函數向系統註冊字元型裝置驅動程式,主裝置號LED_MAJOR自己定義,如該值為0則系統自動分配主裝置號;另一種是使用misc_register(&misc)。如果是非標準裝置則使用
misc_register,即一些字元裝置不符合預先確定的字元裝置範疇,就用這種方式,它固定使用主裝置號10註冊,如果多個裝置次裝置號不同。
2、使用register_chrdev(LED_MAJOR,DEVICE_NAME,&dev_fops)註冊字元裝置驅動程式時,如果有多個裝置使用該函數註冊驅動程式,LED_MAJOR不能相同,否則幾個裝置都無法註冊(我已在友善的板子上驗證)。如果模組使用該方式註冊並且LED_MAJOR為0(自動分配主裝置號),使用insmod命令載入模組時會在終端顯示分配的主裝置號和次裝置號,在/dev目錄下建立該節點,比如裝置leds,如果載入該模組時分配的主裝置號和次裝置號為253和0,則建立節點:mknodleds
c 253 0。使用register_chrdev(LED_MAJOR,DEVICE_NAME,&dev_fops)註冊字元裝置驅動程式時都要手動建立節點,否則在應用程式無法開啟該裝置。
3、由於我使用的是靜態連結的根檔案系統所以要加“-static”選項。