linux驱动学习笔记(S3C2440的LED驱动)

驱动程序:

/*whjled.c*/

#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/errno.h>
#include <linux/ioctl.h>
#include <linux/cdev.h>
#include <linux/gpio.h>
#include <asm/uaccess.h>

#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <asm/irq.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/list.h>
#include <linux/pci.h>
#include <asm/atomic.h>
#include <asm/unistd.h>

#define LED_ON  1
#define LED_OFF 0
#define DEVICE_NAME "whjled"
#define LED_MAJOR 98

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 *file,
       unsigned int cmd,
       unsigned long arg)
{
    if(arg>3)
    {
        printk("Led's number error,pleasecheck!");    
        return -EINVAL;
    }
    switch(cmd)
    {
        case LED_ON:
        s3c2410_gpio_setpin(led_table[arg],0);//led low light
        return 0;
        case LED_OFF:
        s3c2410_gpio_setpin(led_table[arg], 1);
        return 0;
        default:
        return -EINVAL;
    }
}

static struct file_operations dev_fops =
{
    .owner = THIS_MODULE,
    .ioctl = s3c2440_leds_ioctl,
};

static int __init dev_init(void)
{
     int ret;
     int i;
     ret = register_chrdev(LED_MAJOR,DEVICE_NAME,&dev_fops);
    
     if(ret<0)
     {
         printk(DEVICE_NAME"uninitialized\n");
         return ret;
     }
     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"initialized\n");
     return 0;
}

static void __exit dev_exit(void)
{
    unregister_chrdev(LED_MAJOR,DEVICE_NAME);
}

module_init(dev_init);
module_exit(dev_exit);

驱动文件对应的Makefile为:

obj-m:=whjled.o
PWD:=$(shell pwd)
KDIR:=/home/linux-2.6.32.2c

all:
    $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules

clean:
    rm -rf *.o *.ko *.mod.c *.mod.o *.symvers

将whjled.c与Makefile放在同一文件夹内(linux环境)执行make,生成whjled.ko。将whjled.ko拷贝至根文件系统的tmp文件夹下(我使用的是nfs根文件系统)。

在/tmp文件夹下加载驱动模块:输入insmod whjled.ko,若创建成功,可通过cat /proc/devices查看到设备whjled与其主设备号98.

在/dev文件夹下建立设备节点:输入mknod whjled c 98 1,若成功,可通过ls /dev查看到设备文件
测试程序如下:
/*cpp.c*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#define LED_DEVICE  "/dev/whjled"

int main(int argc,char *argv[])
{
    int fd,cmd,num;
    
    fd = open(LED_DEVICE,0);

    num=atoi(argv[1]);

    cmd=atoi(argv[2]);   

    if(fd < 0)
    {
        printf("can't open/dev/leds!\n");
        exit(0);
    }   

    ioctl(fd,cmd,num);
    exit(0);
}
将驱动程序放在linux环境内,执行arm-linux-gcc-static cpp.c -o cpp,可得到可执行文件cpp。将cpp拷贝至根文件系统的/tmp文件夹下,就可通过
./cpp 0 0//led0灭

./cpp 0 1//led0亮

./cpp 1 0

./cpp 1 1
.....

./cpp 3 1
操作 LED 。
注意:

1、注册设备的时候,有两种方式:一种是使用register_chrdev(LED_MAJOR,DEVICE_NAME,&dev_fops),LED_MAJOR为定义的主设备号,DEVICE_NAME为定义的设备名称,dev_fops为定义的文件操作结构体。使用该函数向系统注册字符型设备驱动程序,主设备号LED_MAJOR自己定义,如该值为0则系统自动分配主设备号;另一种是使用misc_register(&misc)。如果是非标准设备则使用 misc_register,即一些字符设备不符合预先确定的字符设备范畴,就用这种方式,它固定使用主设备号10注册,如果多个设备次设备号不同。

2、使用register_chrdev(LED_MAJOR,DEVICE_NAME,&dev_fops)注册字符设备驱动程序时,如果有多个设备使用该函数注册驱动程序,LED_MAJOR不能相同,否则几个设备都无法注册(我已在友善的板子上验证)。如果模块使用该方式注册并且LED_MAJOR为0(自动分配主设备号),使用insmod命令加载模块时会在终端显示分配的主设备号和次设备号,在/dev目录下建立该节点,比如设备leds,如果加载该模块时分配的主设备号和次设备号为253和0,则建立节点:mknodleds c 253 0。使用register_chrdev(LED_MAJOR,DEVICE_NAME,&dev_fops)注册字符设备驱动程序时都要手动建立节点,否则在应用程序无法打开该设备。

3、由于我使用的是静态链接的根文件系统所以要加“-static”选项。


  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值