#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <asm/irq.h>
#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/delay.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/ioctl.h>
#include <linux/cdev.h>
#include <linux/string.h>
#include <linux/list.h>
#include <linux/pci.h>
#include <linux/gpio.h>
#include <asm/uaccess.h>
#include <asm/atomic.h>
#include <asm/unistd.h>
#define DEVICE_NAME "leds" //設備名(/dev/leds)
//LED 對應的GPIO 端口列表
static unsigned long led_table[] =
{
S3C2410_GPB(5),
S3C2410_GPB(6),
S3C2410_GPB(7),
S3C2410_GPB(8),
};
//LED 對應端口將要輸出的狀態列表
static unsigned int led_cfg_table[] = {
S3C2410_GPIO_OUTPUT,
S3C2410_GPIO_OUTPUT,
S3C2410_GPIO_OUTPUT,
S3C2410_GPIO_OUTPUT,
};
/*ioctl 函數的實現
* 在應用/用戶層將通過ioctl 函數向內核傳遞參數,以控制LED 的輸出狀態
*/
static int sbc2440_leds_ioctl(
struct inode *inode,
struct file *file,
unsigned int cmd,
unsigned long arg)
{
switch(cmd) {
case 0:
case 1:
if (arg > 4)
{
return -EINVAL;
}
//根據應用/用戶層傳遞來的參數(取反),通過s3c2410_gpio_setpin
// 函數設置LED 對應的端口寄存器,
//s3c_gpio_setpin(led_table[arg], !cmd);
gpio_set_value(led_table[arg], !cmd);
return 0;
default:
return -EINVAL;
}
}
/*
* 設備函數操作集,在此只有ioctl 函數,通常還有read, write,
open, close 等,因爲本LED 驅動在下面已經
* 註冊爲misc 設備,因此也可以不用open/close
*/
static struct file_operations dev_fops = {
.owner = THIS_MODULE,
.ioctl = sbc2440_leds_ioctl,
};
/*
* 把LED 驅動註冊爲MISC 設備
*/
static struct miscdevice misc = {
.minor = MISC_DYNAMIC_MINOR, //動態設備號
.name = DEVICE_NAME,
.fops = &dev_fops,
};
/*
* 設備初始化
*/
static int __init dev_init(void)
{
int ret;
int i;
for (i = 0; i < 4; i++) {
//設置LED 對應的端口寄存器爲輸出(OUTPUT)
s3c2410_gpio_cfgpin(led_table[i], led_cfg_table[i]);
//設置LED
// 對應的端口寄存器爲低電平輸出,在模塊加載結束後,四個LED
// 應該是全部都是發光
// //狀態
s3c2410_gpio_setpin(led_table[i], 0);
}
ret = misc_register(&misc); //註冊設備
printk (DEVICE_NAME"\tinitialized\n");
//打印初始化信息
return ret;
}
static void __exit dev_exit(void)
{
misc_deregister(&misc);
}
module_init(dev_init);
//模塊初始化,僅當使用insmod/podprobe
//命令加載時有用,如果設備不是通過模塊方式加載,此處將不會被調用
module_exit(dev_exit);//卸載模塊,當該設備通過模塊方式加載後,可以通過rmmod
// 命令卸載,將調用此函數
MODULE_LICENSE("GPL"); //版權信息
MODULE_AUTHOR("RenZhe gzs"); //開發者信息
Makefile文件:
KDIR = /work/src/linux-2.6.32.2/
appgcc = /work/toolschain/arm-2013.05/bin/arm-none-linux-gnueabi-gcc
obj-m := led.o
all:
make -C $(KDIR) M=$(PWD)
sudo cp led.ko /work/nfs/root/root#編譯後複製到nfs
clean:
make -C $(KDIR) M=$(PWD) clean
源碼已經在2.6內核編譯通過,修改Makefile文件後編譯
make -C /work/src/linux-3.10.17/ M=/work/drivers/arm_led
make[1]: 正在進入目錄 `/work/src/linux-3.10.17'
LD /work/drivers/arm_led/built-in.o
CC [M] /work/drivers/arm_led/led.o
/work/drivers/arm_led/led.c:80: error: unknown field 'ioctl' specified in initializer
/work/drivers/arm_led/led.c:80: warning: initialization from incompatible pointer type
/work/drivers/arm_led/led.c: In function 'dev_init':
/work/drivers/arm_led/led.c:102: error: implicit declaration of function 's3c2410_gpio_cfgpin'
/work/drivers/arm_led/led.c:107: error: implicit declaration of function 's3c2410_gpio_setpin'
make[2]: *** [/work/drivers/arm_led/led.o] 錯誤 1
make[1]: *** [_module_/work/drivers/arm_led] 錯誤 2
make[1]:正在離開目錄 `/work/src/linux-3.10.17'
make: *** [all] 錯誤 2
原因是:在3.10.17內核上file_operations發生了重大的改變:
原先的
int (*ioctl)(struct inode*, struct file*, unsigned int, unsigned long);
被改爲了
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
因而在實際驅動中,我們需要將原先的寫的ioctl函數頭給改成下面的unlocked_ioctl,在file_operations結構體的填充中也是一樣。
error: unknown field 'ioctl' specified in initializer問題是由於3.10.17內核之後 去掉了原來的ioctl,添加兩個新的成員,所以會出錯
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
所以修改源文件中file_operations內.ioctl 改爲 .compat_ioctl 即可
至於警告是因爲參數減少了一個,去掉即可
用cgvg查找3.10內核目錄發現沒有(設置IO口爲輸出)s3c2410_gpio_cfgpin這個函數,對照/drivers/leds/leds-s3c24xx.c這個驅動文件發現設置輸出的函數改爲了gpio_direction_output函數原型爲gpio_direction_output(unisgned gpio, int value);第一個參數爲GPIO,第二個爲新gpio_set_value(port_num,0/1)值gpio_set_value(port_num,0/1)
s3c2410_gpio_setpin對應函數gpio_set_value(port_num,0/1)設置新狀態
以下是轉載內容:
在kernel 2.6.36 中已經完全刪除了struct file_operations 中的ioctl 函數指針,取而代之的是unlocked_ioctl 。
(以上內容爲轉載)