mini2440之led的几种驱动方式

1.混杂设备驱动

#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 <linux/gpio.h>
#include <asm/uaccess.h>
#include <asm/atomic.h>
#include <asm/unistd.h>
//注意,结构体定义及声明,后面有;
//函数末尾是没有;的
#define DEVICE_NAME "leds"
//用static表示,此函数/变量只在本文件中被调用
//extern,可被外部文件调用
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 sbc2440_leds_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);
return 0;
default:
return -EINVAL;
}
}
//应用程序函数接口和驱动程序函数接口映射
static struct file_operations dev_fops = {
.owner = THIS_MODULE,
.ioctl = sbc2440_leds_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(led_table[i], led_cfg_table[i]);
s3c2410_gpio_setpin(led_table[i], 0);
}
//misc_register调用了misc结构体,misc又调用了dev_fops结构体,dev_fops结构体又调用了各个文件控制函数
//本文件主要是ioctl函数
ret = misc_register(&misc);//混杂设备注册
printk (DEVICE_NAME"\tinitialized\n");
return ret;
}
static void __exit dev_exit(void)
{
misc_deregister(&misc);//混杂设备注销
}
//驱动模块,先看module_init,module_exit,通过这两个宏名,往上看函数是怎么调用的
module_init(dev_init);
module_exit(dev_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("FriendlyARM Inc.");

2.一般字符设备 cdev+ioctl

#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 <mach/regs-gpio.h>
#include <mach/hardware.h>
#include <asm/uaccess.h>
#include <asm/atomic.h>
#include <asm/unistd.h>
#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 intcmd,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 int __init myled_init_module(void)
{
     int ret;
    int i,err;                 
//动态分配返回的设备号,起始次设备号,要注册的设备号个数,设备号(体现在/proc/devices)
    ret = alloc_chrdev_region(&devno,0,1,DEVICE_NAME); //动态注册设备号
    if(ret < 0)
    {
        printk(DEVICE_NAME "can't get the major number\n");
        return ret;
    }
    cdevp = cdev_alloc();//动态分配cdev空间
     cdev_init(cdevp,&myled_fops);//初始化struct cdev内核字符设备,
//初始化cdev的成员,建立cdev和file_operation之间连接。
     cdevp->owner = THIS_MODULE;
                                //向系统添加一个cdev
    err=cdev_add(cdevp,devno,1);//添加到内核系统,成功返回0,失败返回-1
     if(err)
    {
     printk(KERN_NOTICE "Error %d adding cdev",err);
     unregister_chrdev_region(devno,1);//函数原型void unregister_chrdev_region(dev_t first,unsigned int count);
       return -EFAULT;
    }
    //初始化leds
     for(i=0;i<4;i++)
    {
        s3c2410_gpio_cfgpin(led_table[i],led_cfg_table[i]);//配置对应的leds为输出状态
         s3c2410_gpio_setpin(led_table[i],1);//初始化时全部熄灭


    }
    printk(DEVICE_NAME "\tinitialized!\n");
    return 0;
}

static void __exit myled_exit_module(void)
{
    cdev_del(cdevp);//向系统删除一个cdev
    unregister_chrdev_region(devno,1);
    printk(DEVICE_NAME "\tremove!\n");
}

module_init(myled_init_module);
module_exit(myled_exit_module);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("fedora");

3.一般字符设备驱动cdev+write

#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/mm.h>
#include <linux/cdev.h>
#include <linux/gpio.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/unistd.h>
#include <mach/regs-gpio.h>
#include <mach/hardware.h>

#define DEVICE_NAME "leds" //设备名称
struct cdev dev;    //定义内核内部的字符设备dev
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[] = {    //led的管脚配置为输出状态
   S3C2410_GPIO_OUTPUT,
  S3C2410_GPIO_OUTPUT,
  S3C2410_GPIO_OUTPUT,
  S3C2410_GPIO_OUTPUT,
};

//对led进行写操作
static ssize_t myled_write(struct file *filp,const char __user *buf,size_t count,loff_t *f_pos)
{
  char ch[2];//字符数组,用来存储用户空间的数据.
   //函数原型:unsigned long copy_from_user(void *to,const void __user *from,unsigne long count);
   copy_from_user(&ch,buf,2);//用户空间buf缓冲区的数据传给字符数组ch[2]中,2表示传送的字节数!
   int ledno =(int)ch[0]-48;//第一个字符代表led的下标号,第二个字符代表对应的led状态.
   int status =(int)ch[1]-48;//字符'0'的ASCII码值为48
   s3c2410_gpio_setpin(led_table[ledno],!status);//调用内部函数来设置相应的led状态.
   return 1;
}
//文件操作结构体
static struct file_operations myled_fops = {
  .owner = THIS_MODULE,
  .write = myled_write,
};
static int __init myled_init(void)
{
  int i,ret;
  //动态分配设备号.函数的原型int alloc_chrdev_region(dev_t *dev,unsigned int firstminor,unsigned int count,char *name); firstminor是第一个要用的次设备号,一般为0,count是请求的连续设备编号的总数,这里为1
  ret = alloc_chrdev_region(&devno,0,1,DEVICE_NAME);
  if(ret<0)
  {
    printk(KERN_WARNING "myled: can't get major %d\n",MAJOR(devno));
    return ret;
  }
  //初始化led
   for(i=0;i<4;i++)
    {
     s3c2410_gpio_cfgpin(led_table[i],led_cfg_table[i]);
     s3c2410_gpio_setpin(led_table[i],0);//初始化点亮4个led
     }
    //初始化cdev 并向系统注册.
   //字符设备的注册,注册一个独立的cdev设备的步骤
   //1,为struct cdev分配空间,可以直接声明struct cedv dev,也可以调用cdev_alloc()动态分配;2,初始化struct cdev,调用cdev_init();3,初始化cdev.owner;4,cdev设置完成后,通知内核struct cdev的信息,调用cdev_add();
   //函数原型void cdev_init(struct cdev *cdev,const struct file_operations *fops);
   cdev_init(&dev,&myled_fops);//将内核内部的cdev设备和led的文件操作结构联系起来.
   dev.owner = THIS_MODULE;
  int err;
  //函数原型int cdev_add(struct cdev *p,dev_t dev,unsigned count);
   err = cdev_add(&dev,devno,1);
  if(err)
    {
     printk(KERN_NOTICE "Error %d adding cdev",err);
     unregister_chrdev_region(devno,1);//函数原型void unregister_chrdev_region(dev_t first,unsigned int count);
       return -EFAULT;
    }
  printk(DEVICE_NAME "\tinitialized 2010-6-23\n");
  return 0;
}

static void __exit myled_exit(void)
{
   cdev_del(&dev);//函数原型:void cdev_del(struct cdev *p);
   unregister_chrdev_region(devno,1);//函数原型void unregister_chrdev_region(dev_t first,unsigned int count);
   printk(DEVICE_NAME "\tremove\n");
}

module_init(myled_init);
module_exit(myled_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("fedora");


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值