您的位置:首页 > 运维架构 > Linux

linux2.6.32 led 设备驱动及应用程序

2013-06-27 22:39 288 查看
沉迷于游戏有一段时间了,该学习了,上次写了helloword驱动,感觉要有点长进,今天就开始搞led驱动。

#include <linux/kernel.h>

#include <linux/init.h>

#include <linux/device.h>

#include <linux/module.h>

#include <linux/fs.h>

#include <linux/errno.h>

#include <linux/interrupt.h>

#include <linux/ioport.h>

#include <linux/io.h>

#include <mach/hardware.h>

#include <mach/gpio-fns.h>

#include <asm/irq.h>

#include <mach/regs-gpio.h>

#define DEVICE_NAME "leds"

#define LED_MAJOR 231

#define LED_ON 0

#define LED_OFF 1

static struct class *leds_class;

static unsigned long led_pin_table[] = {

S3C2410_GPB(5),

S3C2410_GPB(6),

S3C2410_GPB(7),

S3C2410_GPB(8),

};

static int s3c24xx_leds_open(struct inode *inode, struct file *file)

{

int i;

for(i = 0; i < 4; i++){

s3c2410_gpio_cfgpin(led_pin_table[i], S3C2410_GPIO_OUTPUT);

}

return 0;

}

static int s3c24xx_leds_ioctl(

struct inode *inode,

struct file *file,

unsigned int cmd,

unsigned long arg)

{

if(arg > 4)

return -EINVAL;

switch(cmd){

case LED_ON:

s3c2410_gpio_setpin(led_pin_table[arg], 0);

return 0;

case LED_OFF:

s3c2410_gpio_setpin(led_pin_table[arg], 1);

return 0;

default:

return -EINVAL;

}

}

static struct file_operations s3c24xx_leds_fops = {

.owner = THIS_MODULE,

.open = s3c24xx_leds_open,

.ioctl = s3c24xx_leds_ioctl,

};

static int __init s3c24xx_leds_init(void)

{

int ret;

printk(KERN_INFO "Linux led V1.0\n");

ret = register_chrdev(LED_MAJOR,DEVICE_NAME,&s3c24xx_leds_fops);

if(ret < 0){

printk(KERN_WARNING DEVICE_NAME"canot register major number!\n");

return ret;

}

leds_class = class_create(THIS_MODULE,"leds"); //创建类

if(IS_ERR(leds_class))

{

unregister_chrdev(LED_MAJOR, DEVICE_NAME);

return PTR_ERR(leds_class);

}

device_create(leds_class, NULL, MKDEV(LED_MAJOR,0), NULL, "leds"); //创建设备,在insmod后会自动创建leds设备,不用手动mknod创建节点了

printk(KERN_INFO DEVICE_NAME" initialized!\n");

return 0;

}

static void __exit s3c24xx_leds_exit(void)

{

device_destroy(leds_class, MKDEV(LED_MAJOR, 0));

class_destroy(leds_class);

unregister_chrdev(LED_MAJOR, DEVICE_NAME);

printk(KERN_INFO DEVICE_NAME" exited!\n");

}

module_init(s3c24xx_leds_init);

module_exit(s3c24xx_leds_exit);

MODULE_LICENSE("GPL");

/*

* leds.c - The first kernel app programming

*/

#include <stdio.h>

#include <string.h>

#include <stdlib.h>

#include <unistd.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <sys/ioctl.h>

void usage(char *exename)

{

printf("Usage:\n");

printf(" %s <led_no> <on/off>\n",exename);

printf(" led_no = 1, 2, 3, 4.\n");

}

int main(int argc, char *argv[])

{

int led_no;

int fd = -1;

if(argc != 3)

goto err;



fd = open("/dev/leds", 0); //打开设备用open,注意open和fopen的区别

if(fd < 0)

{

printf("Can't open /dev/leds\n");

exit(1); //注意exit和return的区别

}

led_no = strtoul(argv[1], 0, 0)-1;

if(led_no > 3 || led_no < 0)

goto err;

if(!strcmp(argv[2], "on")){

ioctl(fd, 0, led_no);

}else if(!strcmp(argv[2], "off")){

ioctl(fd, 1, led_no);

}else{

goto err;

}

close(fd);

return 0;

err:

if(fd > 0)

close(fd);

usage(argv[0]);

return -1;

}

#

# This file is write for the first drivers

# Copyright (c) 2013 sxbg

#obj-m := hello.o

#obj-m := led.o

#hello-objs := hello.o

obj-m += hello.o

obj-m += led.o

ARM_LINUX_KERNEL := /home/sxbg/Downloads/linux

CURRENT_PATH := $(shell pwd)

all:

$(MAKE) -C $(ARM_LINUX_KERNEL) M=$(CURRENT_PATH) modules

clean:

$(MAKE) -C $(ARM_LINUX_KERNEL) M=$(CURRENT_PATH) clean

网上大部分的驱动程序需要手动创建设备节点,此驱动程序的亮点在于自动创建设备节点,程序尽量的规范,请读者特别是和我一样的菜鸟认真体会,其实最好的驱动的代码范例还是内核,笔者的驱动也参见了内核相关代码:

/drivers/isdn/capi/capi.c中有如下代码

static int __init capi_init(void)

{

char *p;

char *compileinfo;

int major_ret;

if ((p = strchr(revision, ':')) != NULL && p[1]) {

strlcpy(rev, p + 2, sizeof(rev));

if ((p = strchr(rev, '$')) != NULL && p > rev)

*(p-1) = 0;

} else

strcpy(rev, "1.0");

major_ret = register_chrdev(capi_major, "capi20", &capi_fops);

if (major_ret < 0) {

printk(KERN_ERR "capi20: unable to get major %d\n", capi_major);

return major_ret;

}

capi_class = class_create(THIS_MODULE, "capi");

if (IS_ERR(capi_class)) {

unregister_chrdev(capi_major, "capi20");

return PTR_ERR(capi_class);

}

device_create(capi_class, NULL, MKDEV(capi_major, 0), NULL, "capi");

#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE

if (capinc_tty_init() < 0) {

device_destroy(capi_class, MKDEV(capi_major, 0));

class_destroy(capi_class);

unregister_chrdev(capi_major, "capi20");

return -ENOMEM;

}

#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */

proc_init();

#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE

#if defined(CONFIG_ISDN_CAPI_CAPIFS) || defined(CONFIG_ISDN_CAPI_CAPIFS_MODULE)

compileinfo = " (middleware+capifs)";

#else

compileinfo = " (no capifs)";

#endif

#else

compileinfo = " (no middleware)";

#endif

printk(KERN_NOTICE "capi20: Rev %s: started up with major %d%s\n",

rev, capi_major, compileinfo);

return 0;

}

static void __exit capi_exit(void)

{

proc_exit();

device_destroy(capi_class, MKDEV(capi_major, 0));

class_destroy(capi_class);

unregister_chrdev(capi_major, "capi20");

#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE

capinc_tty_exit();

#endif

printk(KERN_NOTICE "capi: Rev %s: unloaded\n", rev);

}

where there is a will,there is a way.

只要我们正确的面对,linux驱动没有想象中的那么可怕。

有疑问的细节请参考 嵌入式Linux之我行——LED驱动在2440上的实例开发
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: