點亮led過程分析

在mini2440中,led,按鍵等驅動默認已經被編譯入內核,所以一直不知道同一個硬件設備資源能不能作爲多個模塊,編譯入內核。

故重寫了一個myled.ko,系統默認是led.ko,並用應用程序檢測。

myled.c 

#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/gpio.h>
#include <linux/ioctl.h>
#include <linux/cdev.h>
#include <linux/mm.h>
#include <linux/device.h>
#include <mach/regs-gpio.h>
#include <mach/hardware.h>
#include <asm/uaccess.h>
#include <asm/atomic.h>
#include <asm/unistd.h>
//**************
static struct device *dev;
//*************
#define DEVICE_NAME "myled"
static struct cdev *cdevp=NULL;//定義一個cdev結構體,並初始化
static dev_t devno;//定義一個設備號
static unsigned long led_table[] = {
   S3C2410_GPB(5),//定義端口
    S3C2410_GPB(6),
    S3C2410_GPB(7),
    S3C2410_GPB(8),
};
static unsigned int led_cfg_table[] = {
    S3C2410_GPIO_OUTPUT,//定義寄存器狀態
    S3C2410_GPIO_OUTPUT,
    S3C2410_GPIO_OUTPUT,
    S3C2410_GPIO_OUTPUT,
};
static int s3c2440_leds_ioctl(struct inode *inode,struct file *filp,unsigned int cmd,unsigned long arg)
{
    switch(cmd)
    {
        case 0:
        case 1:
            if(arg>3)
            {
                return -EINVAL;
             }
        s3c2410_gpio_setpin(led_table[arg],!cmd);
        return 0;
        default:
            return -EINVAL;
     }
}
//應用程序與驅動映
static struct file_operations myled_fops = {
    .owner = THIS_MODULE,
    .ioctl = s3c2440_leds_ioctl,
};
//**************
static struct class *led_class;
//**************
static int __init myled_init_module(void)
{
    int ret;
    int i,err;
    ret = alloc_chrdev_region(&devno,0,1,DEVICE_NAME);//註冊設備
    if(ret < 0)
    {
        printk(DEVICE_NAME "can't get the major number\n");
        return ret;
    }
//****************************
    led_class= class_create(THIS_MODULE,DEVICE_NAME);
  if(IS_ERR(led_class))
{
printk("Err: failed in leds-class.\n");
return -1;
}
   dev=device_create(led_class,NULL,devno,NULL,DEVICE_NAME);
//**************************
    cdevp = cdev_alloc();//動態申請一個cdev內存
    cdev_init(cdevp,&myled_fops);//初始化cdev
    cdevp->owner = THIS_MODULE;
    err=cdev_add(cdevp,devno,1);
    if(err)
    {
    printk(KERN_NOTICE "Error %d adding cdev",err);
      unregister_chrdev_region(devno,1);
       return -EFAULT;
    }
     for(i=0;i<4;i++)
    {
        s3c2410_gpio_cfgpin(led_table[i],led_cfg_table[i]);
         s3c2410_gpio_setpin(led_table[i],1)
    }
    printk(DEVICE_NAME "\tinitialized! 2012-12-9\n");
    return 0;
}
static void __exit myled_exit_module(void)
{
    cdev_del(cdevp);
    unregister_chrdev_region(devno,1);
//****************
    device_destroy(led_class,devno);
    class_destroy(led_class);
/*****************
    printk(DEVICE_NAME "\tunloaded by tong2012-12-9\n");

}
module_init(myled_init_module);
module_exit(myled_exit_module);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("tong 2012-12-9");

Makefile如下

ifneq ($(KERNELRELEASE),)
obj-m:=myled.o
else
KDIR := /opt/FriendlyARM/mini2440/linux-2.6.32.2_fa
all:
make -C $(KDIR) M=$(PWD) modules ARCH=arm CROSS_COMPILE=arm-linux-
clean:
rm -f *.ko *.o *.mod.o *.mod.c *.symvers
endif

拷貝到開發板上,insmod myled.ko可在/dev下生成設備節點myled.ko

現在採用系統給出的例程,但修改設備節點爲myled,

led.c (必須使用交叉編譯器)

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
int main(int argc, char **argv)
{
int on;
int led_no;
int fd;
if (argc != 3 || sscanf(argv[1], "%d", &led_no) != 1 || sscanf(argv[2],"%d", &on) != 1 ||
   on < 0 || on > 1 || led_no < 0 || led_no > 3) {
fprintf(stderr, "Usage: leds led_no 0|1\n");
exit(1);
}
fd = open("/dev/myled", 0);
if (fd < 0) {
fd = open("/dev/myled", 0);
}
if (fd < 0) {
perror("open device leds");
exit(1);
}
ioctl(fd, on, led_no);
close(fd);
return 0;
}


先用/etc/rc.d/init.d/leds stop關閉系統初始化中,開啓的讓四個led循環閃動的服務,

通過ioctl函數可以控制讓哪個led,是亮還是滅,能成功。

說明了,同一個硬件設備資源能被作爲多個模塊,換成不同的名字,互不干擾,也就是說可以同時硬件資源可以爲應用程序中的多種服務工作,可以聯想一下智能手機是如何工作的。


發佈了43 篇原創文章 · 獲贊 15 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章