bet5365提款风控审核:十一、Linux驱动程序开发(4) - 字符设备驱动(3)-LED设备驱动和应用程序
来源:百度文库 编辑:偶看新闻 时间:2024/05/02 13:33:27
以下是扬创开发板给的led例程,将对应用程序和驱动程序进行详细注释和分析,并验证!
/*
* LED interface driver for utu2440
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
* bit.lili@gmail.com 2007-6
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define LED_DRIVER "utu2440 LED Driver v1.00"
static unsigned long led_table [] = {
S3C2410_GPF4,
S3C2410_GPF5,
S3C2410_GPF6,
S3C2410_GPF7,
};
static int led_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg);
/*ioctl(fd, on, led_number);
inode 和 filp 指针是对应应用程序传递的文件描述符 fd 的值,
和传递给 open 方法的相同参数*/
static int led_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_table[arg], !cmd);
/*给寄存器赋值,使某一位置1或0,led亮,给寄存器置0,因此对cmd取反*/
/*通过s3c2410_gpio_setpin()来做,此函数为驱动函数的核心操作*/
/*case 0和case 1操作一样*/
default:
return -EINVAL;
}
return 0;
}
/*设备驱动文件操作结构体*/
static struct file_operations led_fops = {
.ioctl = led_ioctl,
};
static struct miscdevice led_dev = {
MISC_DYNAMIC_MINOR,
"led",
&led_fops
};
/*
struct miscdevice {
int minor; //MISC_DYNAMIC_MINOR
const char *name;//"led"
const struct file_operations *fops; //&led_fops
struct list_head list;
struct device *parent;
struct device *this_device;
};
此结构体是注册混合设备所需要的参 数。主要有:
minor:次设备号,所有的misc设备共用一个主设备号,所以注册misc设备时只要次设备号就可以了。利用次设备号来区分设备的。
name:misc设备名。
*fops:misc设备文件操作结构体。其它三个参数很少用
*/
static int led_init(void)
{
pr_info("%s\n", LED_DRIVER);
/*printk(KERN_INFO fmt, ##arg)
#defineKERN_INFO"<6>" 提示信息,如驱动程序启动时,打印硬件 信息
没有指定日志级别的printk语句默认采用的级别是 DEFAULT_ MESSAGE_LOGLEVEL
(这个默认级别一般为<4>,即与KERN_WARNING在一个级别上),
其定义在linux26/kernel/printk.c中可以找到。
下面是一个比较简单的使用
printk(KERN_INFO "INFO\n"); //这里可以使用数字代替 KERN_INFO,
即可以写成printk(<6> "INFO\n");
在这个格式的定义中,日志级别和信息文本之间不能够使用逗号隔开,
因为系统在进行编译的时候,将日志级别转换成字符串于后面的文本信息进行连 接。*/
misc_register(&led_dev);// misc设备注册
/*非标准设备使用 misc_register,即一些字符设备不符合预先确定的 字符设备范畴,
这些设备就用主编号10一起归于"其他类型",misc_register()用主编号10调用 register_chrdev(),设备名称和函数表指针通过miscdevice数据结构获得。同样,miscdevice 数据结构还保存设备驱动程序所使用 的次要号码。*/
return 0;
}
static void __exit led_exit(void)
{
misc_deregister(&led_dev);
/*misc(混合,其他类型,不能严格划分的设备类 型)类设备的注销函数,成功返回为0,错误返回一个错误代码*/
}
module_init(led_init);
module_exit(led_exit);
MODULE_AUTHOR("lili bit.lili@gmail.com");
MODULE_LICENSE("GPL");
应用程序:
#include /*标准输入输出库,像sscanf函数,fprintf函数都是在这个库里*/
#include
#include /*一些宏的定义在这里面,像stderr*/
#include /*文件操作控制库,像ioctl函数就在这里*/
/*执行:./led 1 1*/
int main(int argc, char **argv)
/*argc表示参数的个数,而参数都存放在argv里,它是指针数组*/
{
int on; /*led的开关状态,从第三个参数中获取*/
int led_number; /*led的编号,从第二个参数中获取*/
int fd; /*设备号,将从打开的leds设备获得*/
/*获取参数,并作参数的检验*/
/*scanf/sscanf 函数的返回值反映的是按照指定的格 式符正确读入的数据的个数
(sscanf(argv[1], "%d", &led_number)返回正确,应等于1)。
如果输入数据与指定格式不符,则会产 生输入错误。遇到输入错误,scanf函数会立即终止,返回已经成功读取的 数据的个数。所以,通过scanf函数的返回值和指定输入数据的个数 (由格式符决定)的比较,可以判断数据输入是否成功。
*/
if (argc != 3 || sscanf(argv[1], "%d", &led_number) != 1 || sscanf(argv[2],"%d", &on) != 1 ||on < 0 || on > 1 || led_number < 0 || led_number > 3) {
fprintf(stderr, "Usage:\n");
fprintf(stderr, "\t led led_number on|off\n");
fprintf(stderr, "Options:\n");
fprintf(stderr, "\t led_number from 0 to 3\n");
fprintf(stderr, "\t on 1 off 0\n");
/*stdout -- 标准输出设备 (printf("..")) 同 stdout。
stderr -- 标准错误输出设备
两者默认向屏幕输出。
但如果用转向标准输出到磁盘文件, 则可看出两者区别。stdout输出到磁盘文件,stderr在屏幕*/
exit(1);
}
fd = open("/dev/led", 0);
/*驱动程序可以不实现open这个函数,在这种情况下,设备的打开操作永远成功。*/
if (fd < 0) {
perror("open device /dev/led");
exit(1);
}
ioctl(fd, on, led_number);
close(fd);
return 0;
}
总结:
上面是点亮led的应用程序和驱动程序,在应用程序中,可以根据需要进行修改, 比如让led闪烁等等,驱动程序和应用程序分别给了详细注释,如有错误欢迎指正!程序已在扬创开发板上验证,但验证中发现第二个led不亮,还不知为什么,望高手指点!
/*
* LED interface driver for utu2440
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
* bit.lili@gmail.com 2007-6
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define LED_DRIVER "utu2440 LED Driver v1.00"
static unsigned long led_table [] = {
S3C2410_GPF4,
S3C2410_GPF5,
S3C2410_GPF6,
S3C2410_GPF7,
};
static int led_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg);
/*ioctl(fd, on, led_number);
inode 和 filp 指针是对应应用程序传递的文件描述符 fd 的值,
和传递给 open 方法的相同参数*/
static int led_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_table[arg], !cmd);
/*给寄存器赋值,使某一位置1或0,led亮,给寄存器置0,因此对cmd取反*/
/*通过s3c2410_gpio_setpin()来做,此函数为驱动函数的核心操作*/
/*case 0和case 1操作一样*/
default:
return -EINVAL;
}
return 0;
}
/*设备驱动文件操作结构体*/
static struct file_operations led_fops = {
.ioctl = led_ioctl,
};
static struct miscdevice led_dev = {
MISC_DYNAMIC_MINOR,
"led",
&led_fops
};
/*
struct miscdevice {
int minor; //MISC_DYNAMIC_MINOR
const char *name;//"led"
const struct file_operations *fops; //&led_fops
struct list_head list;
struct device *parent;
struct device *this_device;
};
此结构体是注册混合设备所需要的参 数。主要有:
minor:次设备号,所有的misc设备共用一个主设备号,所以注册misc设备时只要次设备号就可以了。利用次设备号来区分设备的。
name:misc设备名。
*fops:misc设备文件操作结构体。其它三个参数很少用
*/
static int led_init(void)
{
pr_info("%s\n", LED_DRIVER);
/*printk(KERN_INFO fmt, ##arg)
#defineKERN_INFO"<6>" 提示信息,如驱动程序启动时,打印硬件 信息
没有指定日志级别的printk语句默认采用的级别是 DEFAULT_ MESSAGE_LOGLEVEL
(这个默认级别一般为<4>,即与KERN_WARNING在一个级别上),
其定义在linux26/kernel/printk.c中可以找到。
下面是一个比较简单的使用
printk(KERN_INFO "INFO\n"); //这里可以使用数字代替 KERN_INFO,
即可以写成printk(<6> "INFO\n");
在这个格式的定义中,日志级别和信息文本之间不能够使用逗号隔开,
因为系统在进行编译的时候,将日志级别转换成字符串于后面的文本信息进行连 接。*/
misc_register(&led_dev);// misc设备注册
/*非标准设备使用 misc_register,即一些字符设备不符合预先确定的 字符设备范畴,
这些设备就用主编号10一起归于"其他类型",misc_register()用主编号10调用 register_chrdev(),设备名称和函数表指针通过miscdevice数据结构获得。同样,miscdevice 数据结构还保存设备驱动程序所使用 的次要号码。*/
return 0;
}
static void __exit led_exit(void)
{
misc_deregister(&led_dev);
/*misc(混合,其他类型,不能严格划分的设备类 型)类设备的注销函数,成功返回为0,错误返回一个错误代码*/
}
module_init(led_init);
module_exit(led_exit);
MODULE_AUTHOR("lili bit.lili@gmail.com");
MODULE_LICENSE("GPL");
应用程序:
#include
#include
#include
#include
/*执行:./led 1 1*/
int main(int argc, char **argv)
/*argc表示参数的个数,而参数都存放在argv里,它是指针数组*/
{
int on; /*led的开关状态,从第三个参数中获取*/
int led_number; /*led的编号,从第二个参数中获取*/
int fd; /*设备号,将从打开的leds设备获得*/
/*获取参数,并作参数的检验*/
/*scanf/sscanf 函数的返回值反映的是按照指定的格 式符正确读入的数据的个数
(sscanf(argv[1], "%d", &led_number)返回正确,应等于1)。
如果输入数据与指定格式不符,则会产 生输入错误。遇到输入错误,scanf函数会立即终止,返回已经成功读取的 数据的个数。所以,通过scanf函数的返回值和指定输入数据的个数 (由格式符决定)的比较,可以判断数据输入是否成功。
*/
if (argc != 3 || sscanf(argv[1], "%d", &led_number) != 1 || sscanf(argv[2],"%d", &on) != 1 ||on < 0 || on > 1 || led_number < 0 || led_number > 3) {
fprintf(stderr, "Usage:\n");
fprintf(stderr, "\t led led_number on|off\n");
fprintf(stderr, "Options:\n");
fprintf(stderr, "\t led_number from 0 to 3\n");
fprintf(stderr, "\t on 1 off 0\n");
/*stdout -- 标准输出设备 (printf("..")) 同 stdout。
stderr -- 标准错误输出设备
两者默认向屏幕输出。
但如果用转向标准输出到磁盘文件, 则可看出两者区别。stdout输出到磁盘文件,stderr在屏幕*/
exit(1);
}
fd = open("/dev/led", 0);
/*驱动程序可以不实现open这个函数,在这种情况下,设备的打开操作永远成功。*/
if (fd < 0) {
perror("open device /dev/led");
exit(1);
}
ioctl(fd, on, led_number);
close(fd);
return 0;
}
总结:
上面是点亮led的应用程序和驱动程序,在应用程序中,可以根据需要进行修改, 比如让led闪烁等等,驱动程序和应用程序分别给了详细注释,如有错误欢迎指正!程序已在扬创开发板上验证,但验证中发现第二个led不亮,还不知为什么,望高手指点!
linux 应用程序开发
嵌入式linux开发问题
网卡驱动程序开发
求嵌入式linux开发详细流程(步骤)?
Linux是谁开发出来的?
linux下的图形界面开发
delphi能否开发usb驱动程序
Linux驱动程序的工作原理
Linux下开发和Windows下开发各有啥优缺点?
嵌入式LINUX系统图形界面GUI 开发流程
linux下安装程序图形开发工具
嵌入式Linux开发一定要了解内核吗?
在win中开发linux程序
驱动程序的开发技术有哪些??
用在windows xp的程序能用在linux上吗?(例如驱动程序等)
安装LINUX 出现未找到任何驱动程序
linux安装好了为什么不要驱动程序
无线 UBS网卡 linux 驱动程序源码
闪存在LINUX中要驱动程序吗
初一、十一(打一字)
“十一”
linux?这个是哪国开发的系统。。哪里可以下载
linux是用什么东西开发出来的
linux操作系统的开发公司和国家分别是什么?