原创
linux下LED驱动(使用register_chrdev_region)
本来使用register_chrdev()注册,看编译之下2.6.30已经对它不支持拉。转而用register_chrdev_region().
驱动文件(module)
/***********************
name: leds.c
copyright: loop
build date: 2010.3.7
************************/
#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 <asm/uaccess.h>
#include <asm/atomic.h>
#include <asm/unistd.h>
#define DEVICE_NAME "led"
#define LED_MAJOR 200
/* 用来指定LED所用的GPIO引脚 */
static unsigned long led_table [] =
{
S3C2410_GPB5,
S3C2410_GPB6,
S3C2410_GPB7,
S3C2410_GPB8,
};
/* 用来指定GPIO引脚的功能:输出 */
static unsigned int led_cfg_table [] =
{
S3C2410_GPB5_OUTP,
S3C2410_GPB6_OUTP,
S3C2410_GPB7_OUTP,
S3C2410_GPB8_OUTP,
};
static int Led_open(
struct inode *inode,
struct file *file)
{
int i;
for (i=0; i<4; i++)
{
s3c2410_gpio_cfgpin(led_table
, led_cfg_table);
}
return 0;
}
static int Led_ioctl(
struct inode *inode,
struct file *file,
unsigned int cmd,
unsigned long arg)
{
if (arg > 4)
{
return -EINVAL;
}
switch(cmd)
{
case 0:
// 设置指定引脚的输出电平为0
s3c2410_gpio_setpin(led_table[arg], 0);
return 0;
case 1:
// 设置指定引脚的输出电平为1
s3c2410_gpio_setpin(led_table[arg], 1);
return 0;
default:
return -EINVAL;
}
}
static struct file_operations leds_fops = {
.owner = THIS_MODULE,
.open = Led_open,
.ioctl = Led_ioctl,
};
struct led_dev_g
{
struct cdev cdev;
}led_dev;
static void Led_setup_cdev(void)
{
int err, devno = MKDEV(LED_MAJOR, 0);
cdev_init(&led_dev.cdev, &leds_fops);
led_dev.cdev.owner = THIS_MODULE;
led_dev.cdev.ops = &leds_fops;
err = cdev_add(&led_dev.cdev, devno, 1);
if (err)
printk("Error %d\n", err);
else
printk("have finish add\n");
}
static int __init Led_init(void)
{
int ret;
dev_t devno = MKDEV(LED_MAJOR, 0);
ret = register_chrdev_region(devno, 1, DEVICE_NAME);
if (ret < 0)
{
printk (DEVICE_NAME " can't register\n");
return ret;
}
Led_setup_cdev();
printk (DEVICE_NAME " Initialized \n");
return 0;
}
static void __exit Led_exit(void)
{
cdev_del(&led_dev.cdev);
unregister_chrdev_region(MKDEV(LED_MAJOR, 0), 1);
printk(DEVICE_NAME " exit\n");
}
module_init(Led_init);
module_exit(Led_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("loop zhong");
MODULE_DESCRIPTION("GPIO control for EmbedSky SKY2440/TQ2440 Board");
用户空间,测试程序
/***************
name : test_led
**************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
int main(int argc, char **argv)
{
int i;
int led_no;
int fd;
if (argc != 2 || sscanf(argv[1], "%d", &led_no) != 1 ||
led_no < 0 || led_no > 1) {
fprintf(stderr, "Usage: test_led 0|1\n");
exit(1);
}
fd = open("/dev/led_for_loop", 0);
if (fd < 0) {
perror("open device led");
exit(1);
}
for (i=0; i<4; i++)
{
ioctl(fd, 1, i);
}
printf("now let's go with the led trip, come on\n");
sleep(3);
if (led_no)
{
for (i=0; i<4; i++)
{
ioctl(fd, 0, i);
sleep(3);
ioctl(fd, 1, i);
}
}
else
{
for (i=0; i<4; i++)
{
ioctl(fd, 0, 3-i);
sleep(3);
ioctl(fd, 1, 3-i);
}
}
printf("performan is over, thank you\n");
close(fd);
return 0;
}
-------------------------------
之后
#insmod leds.ko
#lsmod (可以看到leds模块已经添加; 但在/dev下看不到 设备名为led的)
#mknod /dev/led_for_loop c 200 0 (这个主,次设备号必须与leds.c 文件定义的一致,设备名字则可以任意改)
#test_led 1 (即可以驱动led拉)
-----------------------------
对比用misc_register()来注册。
static struct file_operations dev_fops = {
.owner = THIS_MODULE,
.ioctl = tq2440_gpio_ioctl,
};
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++)
{
s3c2410_gpio_cfgpin(gpio_table, gpio_cfg_table);
s3c2410_gpio_setpin(gpio_table, 0);
}
ret = misc_register(&misc);
printk ("retrun value is %d\n", ret);
printk (DEVICE_NAME" initialized\n");
return ret;
}
以下摘自http://hi.baidu.com/pnalson/blog/item/02208d6ec0cddad080cb4a6c.html
杂项设备(misc device)
杂项设备也是在嵌入式系统中用得比较多的一种设备驱动。在 Linux 内核的include\linux目录下有Miscdevice.h文件,要把自己定义的misc device从设备定义在这里。其实是因为这些字符设备不符合预先确定的字符设备范畴,所有这些设备采用主编号10 ,一起归于misc device,其实misc_register就是用主标号10调用register_chrdev()的。
也就是说,misc设备其实也就是特殊的字符设备。
字符设备(char device)
使用
register_chrdev(LED_MAJOR,DEVICE_NAME,&dev_fops)注册字符设备驱动程序时,如果有多个设
备使用该函数注册驱动程序,LED_MAJOR不能相同,否则几个设备都无法注册(我已验证)。如果模块使用该方式注册并且 LED_MAJOR为0(自动分配主设备号 ),使用insmod命令加载模块时会在终端显示分配的主设备号和次设备号,在/dev目录下建立该节点,比如 设备leds,如果加载该模块时分配的主设备号和次设备号为253和0,则建立节点:mknod leds c 253 0。使用register_chrdev (LED_MAJOR,DEVICE_NAME,&dev_fops)注册字符设备驱动程序时都要手动建 立节点 ,否则在应用程序无法打开该设备。
文章评论(0条评论)
登录后参与讨论