场景:对方公司提供了内核源码,但是和提供的硬件不匹配,但是可以保证的是驱动是正常的.只是io配置略有不同.此步骤是很关键的一个大前提
上电后发现硬件的心跳灯不亮,但是硬件是保证正常的
1.查看系统日志
[root@NetRouter /]# dmesg |grep led
[ 1.495117] Registered led device: system-led:yellow
[ 1.495330] leds-gpio: probe of leds-gpio failed with error -16
查看linux错误代码16 为系统资源繁忙
http://blog.chinaunix.net/uid-26111972-id-3400556.html
Linux 错误码列表
#define EBUSY 16 /* Device or resource busy */
查看IO使用资源:
[root@NetRouter /]# cat /sys/kernel/debug/gpio
GPIOs 0-31, gpio:
gpio-20 (ft5x16_ts_irq ) in hi
GPIOs 32-63, gpio:
GPIOs 64-95, gpio:
GPIOs 96-127, gpio:
gpio-100 (buzzer gpio ) out lo
gpio-111 (Watchdog feed ) out lo
没有注册上,正常注册上后,会有相关信息可以查询到
由于使用的是3.2内核,所以io配置都在这里体现:
arch/arm/mach-NetRouter/board-NetRouter.c
相关知识:
1. Linux GPIO引脚号从0开始。
2. NetRouter一共有4组GPIO,分别是GPIO0[0…31],GPIO1[0…31],GPIO2[0…31],GPIO3[0…31],共128个GPIO。这是GPIO0[0…31]对应的Linux GPIO引脚号为0…31,GPIO1[0…31]对应的引脚号为32…63,GPIO3[0…31]对应的引脚号为64…95,GPIO4[0…31]对应的引脚号为[96…127]。
内核中gpio对应引脚号的计算公式如下所示:
以NetRouter 心跳灯为例,操作该led灯的gpio为GPIO4_8,如下所示:
#define GPIO_TO_PIN(bank, gpio) (32 * (bank) + (gpio))
则经过计算NetRouter:heart 的led灯gpio引脚号为:32 X 4 + 8=136,所以在用户空间下操作gpio136即是操作该心跳灯。
所以查看 GPIO_TO_PIN(4,8),发现没有调用,这就奇怪,查找陷入了僵局\
回头再来看看整个led的资源,如下
static struct gpio_led NetRouter_leds[] = {
{
.name = "NetRouter:heart",
.gpio = GPIO_TO_PIN(4, 8),
.active_low = 0,
.default_trigger = "heartbeat",
},
{
.name = "test:red",
.gpio = GPIO_TO_PIN(4, 9),
.active_low = 0,
.default_trigger = "none",
},
};
然后查看4_9这个,发现在mmc中使用了.有可能是一个资源占用,导致整个驱动加载不了.提示的16不是第一个资源,而是第二个资源占用了.所以将test:red 这个资源屏蔽
static struct NetRouter_hsmmc_info NetRouter_mmc[] __initdata = {
{
.mmc = 2,
.caps = MMC_CAP_4_BIT_DATA,
.gpio_cd = -EINVAL,
.gpio_wp = -EINVAL,
.ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34,
},
{
.mmc = 1,
.caps = MMC_CAP_4_BIT_DATA,
.gpio_cd = GPIO_TO_PIN(4,9),
.gpio_wp = -EINVAL,
.ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34,
},
{} /* Terminator */
};
查看led的引脚
[root@NetRouter /]# dmesg |grep led
[ 0.000000] Memory policy: ECC disabled, Data cache writeback
[ 0.109405] omap_hwmod: gfx: failed to hardreset
[ 0.125274] omap_hwmod: pruss: failed to hardreset
[ 0.209411] TxFifo Empty intr disabled
[ 0.209411] musb0: Enabled SW babble control
[ 0.209777] musb-hdrc.0: bulk split disabled
[ 0.209777] musb-hdrc.0: bulk combine disabled
[ 0.210754] TxFifo Empty intr disabled
[ 0.210754] musb1: Enabled SW babble control
[ 0.211090] musb-hdrc.1: bulk split disabled
[ 0.211090] musb-hdrc.1: bulk combine disabled
[ 0.927978] console [ttyO0] enabled
[ 1.267425] gadget: userspace failed to provide iSerialNumber
[ 1.504150] Registered led device: system-led:yellow
没有占用的日志了
查看使用资源:
[root@NetRouter /]# cat /sys/kernel/debug/gpio
GPIOs 0-31, gpio:
gpio-20 (ft5x16_ts_irq ) in hi
GPIOs 32-63, gpio:
GPIOs 64-95, gpio:
GPIOs 96-127, gpio:
gpio-100 (buzzer gpio ) out lo
gpio-103 (NetRouter:heart ) out lo
gpio-111 (Watchdog feed ) out lo
gpio-112 (mmc_cd ) in lo
mmc_cd NetRouter:heart 也注册上了,打完收工!!!!!!!!!!!!!!!!!
驱动配置
先进入内核图形配置界面(操作方法参考内核3.1.2配置内核),然后进入Device Drivers界面:
Device Drivers --->
-*- GPIO Support --->
[*] /sys/class/gpio/... (sysfs interface)
用户空间应用 - Sysfs
●定制内核时开启对GPIO sysfs的支持
Device Drivers --->
GPIO Support --->
/sys/class/gpio/…(sysfs interface)
●Sysfs使用方法
下面以GPIO0_30为例,说明在用户空间使用GPIO的方法
导出GPIO引脚:
$ echo 30 > /sys/calss/gpio/export (执行后,在当今前目录生成gpio30节点)
设置GPIO引脚方向:
$ echo out > /sys/class/gpio/gpio30/direction (配置为输出)
$ echo in > /sys/class/gpio/gpio30/direction (配置为输入
输出电平(引脚配置为输出时):
$ echo 1 > /sys/class/gpio/gpio30/value (输出高电平)
$ echo 0 > /sys/class/gpio/gpio30/value (输出低电平)
读取电平(引脚配置为输入时):
$ cat /sys/class/gpio/gpio30/value (若输入高电平则返回1,否则返回0)
注销GPIO引脚:
$ echo 30 > /sys/class/gpio/unexport
注意:
在本驱动以前已使用的GPIO引脚无法通过sysfs控制。执行如下命令可以看到已被使用的GPIO引脚:
$ mount -t debugfs debugfs /sys/kernel/debug
$ cat /sys/kernel/debug/gpio
[root@EVB335X gpio]# echo 103 > export
[root@EVB335X gpio]# ls
export gpio103@ gpiochip0@ gpiochip32@ gpiochip64@ gpiochip96@ unexport
[root@EVB335X gpio]# echo 1 > gpio
gpio103/ gpiochip0/ gpiochip32/ gpiochip64/ gpiochip96/
[root@EVB335X gpio]# echo 1 > gpio103/
active_low edge subsystem/ value
direction power/ uevent
[root@EVB335X gpio]# echo 1 > gpio103/value
[root@EVB335X gpio]# echo 0 > gpio103/value
[root@EVB335X gpio]# echo 1 > gpio103/value
[root@EVB335X gpio]# echo 1 > gpio103/value
[root@EVB335X gpio]# echo 0 > gpio103/value
[root@EVB335X gpio]# echo out > gpio103/direction
[root@EVB335X gpio]# echo 0 > gpio103/value
[root@EVB335X gpio]# echo 1 > gpio103/value
[root@EVB335X gpio]# echo 0 > gpio103/value
[root@EVB335X gpio]# echo 1 > gpio103/value
[root@EVB335X gpio]# echo 1 > gpio103/value
[root@EVB335X gpio]# echo 0 > gpio103/value
[root@EVB335X gpio]# ls
export gpio103@ gpiochip0@ gpiochip32@ gpiochip64@ gpiochip96@ unexport
[root@EVB335X gpio]# echo 48 > export
[root@EVB335X gpio]# echo in > gpio48/direction
[root@EVB335X gpio]# cat gpio48/value
0
[root@EVB335X gpio]# cat gpio48/value
1
[root@EVB335X gpio]# cat gpio48/value
1
[root@EVB335X gpio]# cat gpio48/value
1
[root@EVB335X gpio]# cat gpio48/value
1
[root@EVB335X gpio]# cat gpio48/value
0
[root@EVB335X gpio]# cat gpio48/value
0
[root@EVB335X gpio]# pwd
/sys/class/gpio
1. GPIO的char型驱动,这里主要就是点个灯,感受一下驱动的设计和硬件的控制驱动程序:
代码:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/leds.h>
#include <linux/io.h>
#include <linux/semaphore.h>
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <mach/gpio.h>
#include <plat/mux.h>
#include <linux/gpio.h>
/*******************************************/
#define NAME \"leds\"
#define GPIO_TO_PIN(bank, gpio) (32 * (bank) + (gpio))
static int major =251;//定义主设备号
/*******************************************/
void led_on(void)
{
gpio_set_value(GPIO_TO_PIN(1,22), 1);
}
void led_off(void)
{
gpio_set_value(GPIO_TO_PIN(1,22), 0);
}
void led_init(void)
{
int result;
/* Allocating GPIOs and setting direction */
result = gpio_request(GPIO_TO_PIN(1,22), \"Leds\");//usr1
if (result != 0)
printk(\"gpio_request(1_22) failed!\n\");
result = gpio_direction_output(GPIO_TO_PIN(1,22), 1);
if (result != 0)
printk(\"gpio_direction(1_22) failed!\n\");
}
struct light_dev
{
struct cdev cdev;
unsigned char value;
};
struct light_dev *light_devp;
MODULE_AUTHOR(\"chenzhufly\");
MODULE_LICENSE(\"Dual BSD/GPL\");
// 打开和关闭函数
int light_open(struct inode *inode,struct file *filp)
{
struct light_dev *dev;
// 获得设备结构体指针
dev = container_of(inode->i_cdev,struct light_dev,cdev);
// 让设备结构体作为设备的私有信息
filp->private_data = dev;
return 0;
}
int light_release(struct inode *inode,struct file *filp)
{
return 0;
}
// ioctl
int light_ioctl(struct file *filp,unsigned int cmd,
unsigned long arg)
{
struct light_dev *dev = filp->private_data;
switch(cmd)
{
case 0:
dev->value = 0;
led_off();
break;
case 1:
dev->value = 1;
led_on();
break;
default:
return -ENOTTY;
// break;
}
return 0;
}
struct file_operations light_fops =
{
.owner = THIS_MODULE,
.unlocked_ioctl = light_ioctl,
.open = light_open,
.release = light_release,
};
// 模块加载函数
int light_init(void)
{
int ret;
led_init();
printk(KERN_ALERT \"led modules is install\n\");
ret=register_chrdev(major,NAME,&light_fops);
if(ret<0)
{
printk(\"unable to register myled driver!\n\");
return ret;
}
return 0;
}
// 模块卸载函数
void light_cleanup(void)
{
unregister_chrdev(major,NAME);
printk(\"Goodbye,cruel world!\n\");
}
module_init(light_init);
module_exit(light_cleanup);
---------------------------------------------------------
1. GPIO的char型驱动,这里主要就是点个灯,感受一下驱动的设计和硬件的控制驱动程序:
代码:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/leds.h>
#include <linux/io.h>
#include <linux/semaphore.h>
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <mach/gpio.h>
#include <plat/mux.h>
#include <linux/gpio.h>
/*******************************************/
#define NAME \"leds\"
#define GPIO_TO_PIN(bank, gpio) (32 * (bank) + (gpio))
static int major =251;//定义主设备号
/*******************************************/
void led_on(void)
{
gpio_set_value(GPIO_TO_PIN(1,22), 1);
}
void led_off(void)
{
gpio_set_value(GPIO_TO_PIN(1,22), 0);
}
void led_init(void)
{
int result;
/* Allocating GPIOs and setting direction */
result = gpio_request(GPIO_TO_PIN(1,22), \"Leds\");//usr1
if (result != 0)
printk(\"gpio_request(1_22) failed!\n\");
result = gpio_direction_output(GPIO_TO_PIN(1,22), 1);
if (result != 0)
printk(\"gpio_direction(1_22) failed!\n\");
}
struct light_dev
{
struct cdev cdev;
unsigned char value;
};
struct light_dev *light_devp;
MODULE_AUTHOR(\"chenzhufly\");
MODULE_LICENSE(\"Dual BSD/GPL\");
// 打开和关闭函数
int light_open(struct inode *inode,struct file *filp)
{
struct light_dev *dev;
// 获得设备结构体指针
dev = container_of(inode->i_cdev,struct light_dev,cdev);
// 让设备结构体作为设备的私有信息
filp->private_data = dev;
return 0;
}
int light_release(struct inode *inode,struct file *filp)
{
return 0;
}
// ioctl
int light_ioctl(struct file *filp,unsigned int cmd,
unsigned long arg)
{
struct light_dev *dev = filp->private_data;
switch(cmd)
{
case 0:
dev->value = 0;
led_off();
break;
case 1:
dev->value = 1;
led_on();
break;
default:
return -ENOTTY;
// break;
}
return 0;
}
struct file_operations light_fops =
{
.owner = THIS_MODULE,
.unlocked_ioctl = light_ioctl,
.open = light_open,
.release = light_release,
};
// 模块加载函数
int light_init(void)
{
int ret;
led_init();
printk(KERN_ALERT \"led modules is install\n\");
ret=register_chrdev(major,NAME,&light_fops);
if(ret<0)
{
printk(\"unable to register myled driver!\n\");
return ret;
}
return 0;
}
// 模块卸载函数
void light_cleanup(void)
{
unregister_chrdev(major,NAME);
printk(\"Goodbye,cruel world!\n\");
}
module_init(light_init);
module_exit(light_cleanup);
上电后发现硬件的心跳灯不亮,但是硬件是保证正常的
1.查看系统日志
[root@NetRouter /]# dmesg |grep led
[ 1.495117] Registered led device: system-led:yellow
[ 1.495330] leds-gpio: probe of leds-gpio failed with error -16
查看linux错误代码16 为系统资源繁忙
http://blog.chinaunix.net/uid-26111972-id-3400556.html
Linux 错误码列表
#define EBUSY 16 /* Device or resource busy */
查看IO使用资源:
[root@NetRouter /]# cat /sys/kernel/debug/gpio
GPIOs 0-31, gpio:
gpio-20 (ft5x16_ts_irq ) in hi
GPIOs 32-63, gpio:
GPIOs 64-95, gpio:
GPIOs 96-127, gpio:
gpio-100 (buzzer gpio ) out lo
gpio-111 (Watchdog feed ) out lo
没有注册上,正常注册上后,会有相关信息可以查询到
由于使用的是3.2内核,所以io配置都在这里体现:
arch/arm/mach-NetRouter/board-NetRouter.c
相关知识:
1. Linux GPIO引脚号从0开始。
2. NetRouter一共有4组GPIO,分别是GPIO0[0…31],GPIO1[0…31],GPIO2[0…31],GPIO3[0…31],共128个GPIO。这是GPIO0[0…31]对应的Linux GPIO引脚号为0…31,GPIO1[0…31]对应的引脚号为32…63,GPIO3[0…31]对应的引脚号为64…95,GPIO4[0…31]对应的引脚号为[96…127]。
内核中gpio对应引脚号的计算公式如下所示:
以NetRouter 心跳灯为例,操作该led灯的gpio为GPIO4_8,如下所示:
#define GPIO_TO_PIN(bank, gpio) (32 * (bank) + (gpio))
则经过计算NetRouter:heart 的led灯gpio引脚号为:32 X 4 + 8=136,所以在用户空间下操作gpio136即是操作该心跳灯。
所以查看 GPIO_TO_PIN(4,8),发现没有调用,这就奇怪,查找陷入了僵局\
回头再来看看整个led的资源,如下
static struct gpio_led NetRouter_leds[] = {
{
.name = "NetRouter:heart",
.gpio = GPIO_TO_PIN(4, 8),
.active_low = 0,
.default_trigger = "heartbeat",
},
{
.name = "test:red",
.gpio = GPIO_TO_PIN(4, 9),
.active_low = 0,
.default_trigger = "none",
},
};
然后查看4_9这个,发现在mmc中使用了.有可能是一个资源占用,导致整个驱动加载不了.提示的16不是第一个资源,而是第二个资源占用了.所以将test:red 这个资源屏蔽
static struct NetRouter_hsmmc_info NetRouter_mmc[] __initdata = {
{
.mmc = 2,
.caps = MMC_CAP_4_BIT_DATA,
.gpio_cd = -EINVAL,
.gpio_wp = -EINVAL,
.ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34,
},
{
.mmc = 1,
.caps = MMC_CAP_4_BIT_DATA,
.gpio_cd = GPIO_TO_PIN(4,9),
.gpio_wp = -EINVAL,
.ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34,
},
{} /* Terminator */
};
查看led的引脚
[root@NetRouter /]# dmesg |grep led
[ 0.000000] Memory policy: ECC disabled, Data cache writeback
[ 0.109405] omap_hwmod: gfx: failed to hardreset
[ 0.125274] omap_hwmod: pruss: failed to hardreset
[ 0.209411] TxFifo Empty intr disabled
[ 0.209411] musb0: Enabled SW babble control
[ 0.209777] musb-hdrc.0: bulk split disabled
[ 0.209777] musb-hdrc.0: bulk combine disabled
[ 0.210754] TxFifo Empty intr disabled
[ 0.210754] musb1: Enabled SW babble control
[ 0.211090] musb-hdrc.1: bulk split disabled
[ 0.211090] musb-hdrc.1: bulk combine disabled
[ 0.927978] console [ttyO0] enabled
[ 1.267425] gadget: userspace failed to provide iSerialNumber
[ 1.504150] Registered led device: system-led:yellow
没有占用的日志了
查看使用资源:
[root@NetRouter /]# cat /sys/kernel/debug/gpio
GPIOs 0-31, gpio:
gpio-20 (ft5x16_ts_irq ) in hi
GPIOs 32-63, gpio:
GPIOs 64-95, gpio:
GPIOs 96-127, gpio:
gpio-100 (buzzer gpio ) out lo
gpio-103 (NetRouter:heart ) out lo
gpio-111 (Watchdog feed ) out lo
gpio-112 (mmc_cd ) in lo
mmc_cd NetRouter:heart 也注册上了,打完收工!!!!!!!!!!!!!!!!!
驱动配置
先进入内核图形配置界面(操作方法参考内核3.1.2配置内核),然后进入Device Drivers界面:
Device Drivers --->
-*- GPIO Support --->
[*] /sys/class/gpio/... (sysfs interface)
用户空间应用 - Sysfs
●定制内核时开启对GPIO sysfs的支持
Device Drivers --->
GPIO Support --->
/sys/class/gpio/…(sysfs interface)
●Sysfs使用方法
下面以GPIO0_30为例,说明在用户空间使用GPIO的方法
导出GPIO引脚:
$ echo 30 > /sys/calss/gpio/export (执行后,在当今前目录生成gpio30节点)
设置GPIO引脚方向:
$ echo out > /sys/class/gpio/gpio30/direction (配置为输出)
$ echo in > /sys/class/gpio/gpio30/direction (配置为输入
输出电平(引脚配置为输出时):
$ echo 1 > /sys/class/gpio/gpio30/value (输出高电平)
$ echo 0 > /sys/class/gpio/gpio30/value (输出低电平)
读取电平(引脚配置为输入时):
$ cat /sys/class/gpio/gpio30/value (若输入高电平则返回1,否则返回0)
注销GPIO引脚:
$ echo 30 > /sys/class/gpio/unexport
注意:
在本驱动以前已使用的GPIO引脚无法通过sysfs控制。执行如下命令可以看到已被使用的GPIO引脚:
$ mount -t debugfs debugfs /sys/kernel/debug
$ cat /sys/kernel/debug/gpio
[root@EVB335X gpio]# echo 103 > export
[root@EVB335X gpio]# ls
export gpio103@ gpiochip0@ gpiochip32@ gpiochip64@ gpiochip96@ unexport
[root@EVB335X gpio]# echo 1 > gpio
gpio103/ gpiochip0/ gpiochip32/ gpiochip64/ gpiochip96/
[root@EVB335X gpio]# echo 1 > gpio103/
active_low edge subsystem/ value
direction power/ uevent
[root@EVB335X gpio]# echo 1 > gpio103/value
[root@EVB335X gpio]# echo 0 > gpio103/value
[root@EVB335X gpio]# echo 1 > gpio103/value
[root@EVB335X gpio]# echo 1 > gpio103/value
[root@EVB335X gpio]# echo 0 > gpio103/value
[root@EVB335X gpio]# echo out > gpio103/direction
[root@EVB335X gpio]# echo 0 > gpio103/value
[root@EVB335X gpio]# echo 1 > gpio103/value
[root@EVB335X gpio]# echo 0 > gpio103/value
[root@EVB335X gpio]# echo 1 > gpio103/value
[root@EVB335X gpio]# echo 1 > gpio103/value
[root@EVB335X gpio]# echo 0 > gpio103/value
[root@EVB335X gpio]# ls
export gpio103@ gpiochip0@ gpiochip32@ gpiochip64@ gpiochip96@ unexport
[root@EVB335X gpio]# echo 48 > export
[root@EVB335X gpio]# echo in > gpio48/direction
[root@EVB335X gpio]# cat gpio48/value
0
[root@EVB335X gpio]# cat gpio48/value
1
[root@EVB335X gpio]# cat gpio48/value
1
[root@EVB335X gpio]# cat gpio48/value
1
[root@EVB335X gpio]# cat gpio48/value
1
[root@EVB335X gpio]# cat gpio48/value
0
[root@EVB335X gpio]# cat gpio48/value
0
[root@EVB335X gpio]# pwd
/sys/class/gpio
1. GPIO的char型驱动,这里主要就是点个灯,感受一下驱动的设计和硬件的控制驱动程序:
代码:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/leds.h>
#include <linux/io.h>
#include <linux/semaphore.h>
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <mach/gpio.h>
#include <plat/mux.h>
#include <linux/gpio.h>
/*******************************************/
#define NAME \"leds\"
#define GPIO_TO_PIN(bank, gpio) (32 * (bank) + (gpio))
static int major =251;//定义主设备号
/*******************************************/
void led_on(void)
{
gpio_set_value(GPIO_TO_PIN(1,22), 1);
}
void led_off(void)
{
gpio_set_value(GPIO_TO_PIN(1,22), 0);
}
void led_init(void)
{
int result;
/* Allocating GPIOs and setting direction */
result = gpio_request(GPIO_TO_PIN(1,22), \"Leds\");//usr1
if (result != 0)
printk(\"gpio_request(1_22) failed!\n\");
result = gpio_direction_output(GPIO_TO_PIN(1,22), 1);
if (result != 0)
printk(\"gpio_direction(1_22) failed!\n\");
}
struct light_dev
{
struct cdev cdev;
unsigned char value;
};
struct light_dev *light_devp;
MODULE_AUTHOR(\"chenzhufly\");
MODULE_LICENSE(\"Dual BSD/GPL\");
// 打开和关闭函数
int light_open(struct inode *inode,struct file *filp)
{
struct light_dev *dev;
// 获得设备结构体指针
dev = container_of(inode->i_cdev,struct light_dev,cdev);
// 让设备结构体作为设备的私有信息
filp->private_data = dev;
return 0;
}
int light_release(struct inode *inode,struct file *filp)
{
return 0;
}
// ioctl
int light_ioctl(struct file *filp,unsigned int cmd,
unsigned long arg)
{
struct light_dev *dev = filp->private_data;
switch(cmd)
{
case 0:
dev->value = 0;
led_off();
break;
case 1:
dev->value = 1;
led_on();
break;
default:
return -ENOTTY;
// break;
}
return 0;
}
struct file_operations light_fops =
{
.owner = THIS_MODULE,
.unlocked_ioctl = light_ioctl,
.open = light_open,
.release = light_release,
};
// 模块加载函数
int light_init(void)
{
int ret;
led_init();
printk(KERN_ALERT \"led modules is install\n\");
ret=register_chrdev(major,NAME,&light_fops);
if(ret<0)
{
printk(\"unable to register myled driver!\n\");
return ret;
}
return 0;
}
// 模块卸载函数
void light_cleanup(void)
{
unregister_chrdev(major,NAME);
printk(\"Goodbye,cruel world!\n\");
}
module_init(light_init);
module_exit(light_cleanup);
---------------------------------------------------------
1. GPIO的char型驱动,这里主要就是点个灯,感受一下驱动的设计和硬件的控制驱动程序:
代码:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/leds.h>
#include <linux/io.h>
#include <linux/semaphore.h>
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <mach/gpio.h>
#include <plat/mux.h>
#include <linux/gpio.h>
/*******************************************/
#define NAME \"leds\"
#define GPIO_TO_PIN(bank, gpio) (32 * (bank) + (gpio))
static int major =251;//定义主设备号
/*******************************************/
void led_on(void)
{
gpio_set_value(GPIO_TO_PIN(1,22), 1);
}
void led_off(void)
{
gpio_set_value(GPIO_TO_PIN(1,22), 0);
}
void led_init(void)
{
int result;
/* Allocating GPIOs and setting direction */
result = gpio_request(GPIO_TO_PIN(1,22), \"Leds\");//usr1
if (result != 0)
printk(\"gpio_request(1_22) failed!\n\");
result = gpio_direction_output(GPIO_TO_PIN(1,22), 1);
if (result != 0)
printk(\"gpio_direction(1_22) failed!\n\");
}
struct light_dev
{
struct cdev cdev;
unsigned char value;
};
struct light_dev *light_devp;
MODULE_AUTHOR(\"chenzhufly\");
MODULE_LICENSE(\"Dual BSD/GPL\");
// 打开和关闭函数
int light_open(struct inode *inode,struct file *filp)
{
struct light_dev *dev;
// 获得设备结构体指针
dev = container_of(inode->i_cdev,struct light_dev,cdev);
// 让设备结构体作为设备的私有信息
filp->private_data = dev;
return 0;
}
int light_release(struct inode *inode,struct file *filp)
{
return 0;
}
// ioctl
int light_ioctl(struct file *filp,unsigned int cmd,
unsigned long arg)
{
struct light_dev *dev = filp->private_data;
switch(cmd)
{
case 0:
dev->value = 0;
led_off();
break;
case 1:
dev->value = 1;
led_on();
break;
default:
return -ENOTTY;
// break;
}
return 0;
}
struct file_operations light_fops =
{
.owner = THIS_MODULE,
.unlocked_ioctl = light_ioctl,
.open = light_open,
.release = light_release,
};
// 模块加载函数
int light_init(void)
{
int ret;
led_init();
printk(KERN_ALERT \"led modules is install\n\");
ret=register_chrdev(major,NAME,&light_fops);
if(ret<0)
{
printk(\"unable to register myled driver!\n\");
return ret;
}
return 0;
}
// 模块卸载函数
void light_cleanup(void)
{
unregister_chrdev(major,NAME);
printk(\"Goodbye,cruel world!\n\");
}
module_init(light_init);
module_exit(light_cleanup);