Chinaunix首页 | 论坛 | 博客
  • 博客访问: 654497
  • 博文数量: 128
  • 博客积分: 4385
  • 博客等级: 上校
  • 技术积分: 1546
  • 用 户 组: 普通用户
  • 注册时间: 2010-07-22 14:05
文章分类

全部博文(128)

文章存档

2012年(2)

2011年(51)

2010年(75)

分类: 嵌入式

2010-08-11 11:10:34

方法一: 使用ioctl控制+cdev

#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-ubuntu"
static struct cdev *cdevp=NULL;
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 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;
    }
    cdevp = cdev_alloc();
//动态分配cdev空间
     cdev_init(cdevp,&myled_fops);
//初始化struct cdev内核字符设备
     cdevp->owner = THIS_MODULE;
    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! 2010-6-23\n");
    return 0;
}

static void __exit myled_exit_module(void)
{
    cdev_del(cdevp);
    unregister_chrdev_region(devno,1);
    printk(DEVICE_NAME "\tunloaded by Ubuntu2010-6-23\n");
}

module_init(myled_init_module);
module_exit(myled_exit_module);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Ubuntu2010-6-23");


方法二:采用cdev+文件操作的写函数实现

#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[] = {
//硬件资源GPB5,GPB6,GPB7,GPB8
   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 "\tunload!2010-6-23\n");
}

module_init(myled_init);
module_exit(myled_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Ubuntu2010-6-22");


方法一的测试代码: led_ioctl_test.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
// open() close()
#include <unistd.h>
// read() write()
#define LED_ON 1
#define LED_OFF 0
int main(void)
{
    int fd,i;
    fd = open("/lib/modules/2.6.32.2/myled-ioctl", 0);
    if (fd < 0)
    {
        printf("open device /lib/modulew/2.6.32.2/myled-ioctl error!\n");
    }
    else
    {
        while(1)
        {
            for(i=0;i<4;i++)
            {
                printf("led%d is on!\n",i);
                ioctl(fd,LED_ON,i);
                sleep(1);
//等待1秒再做下一步操作
                 printf("led%d is off!\n",i);
                ioctl(fd,LED_OFF,i);
                sleep(1);
             }
             if(i==4)
                 i=0;
        }
        close(fd);
    }
    return 0;
}


方法二的测试代码:led_test.c

//要使编号为0的灯亮输入01,熄灭则输入00。依此类推。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>

int main(void)
{
    int fd;
//文件描述符
     char ch[3];
//这里至少为3个字符,因为输入00后有个回车符.
     for(;;)
    {
    
//led0为字符设备,mknod创建的节点,在/lib/modules/2.6.32.2/目录下面执行#mknod -m 666 led0 c 251 0
         fd = open("/lib/modules/2.6.32.2/led0", O_WRONLY);
        if(fd == -1)
        {
            perror("open error\n");
            return 0;
        }
        scanf("%s", ch);
        if(write(fd, ch, 2) == -1)
        {
            perror("write error\n");
        }
        printf("OK\n");
        close(fd);
    }
return 0;
}

给出一个简单的Makefile文件:

KERNELDIR = /home/yuzexi/Working/mini2440/linux-2.6.32.2
PWD := $(shell pwd)
INSTALLDIR = /home/yuzexi/Working/rootfs/lib/modules

CROSS_COMPILE = /usr/local/arm/4.3.2/bin/arm-linux-
CC = $(CROSS_COMPILE)gcc

obj-m := myled-ioctl.o

modules:
    $(MAKE) -C $(KERNELDIR) M=$(PWD) modules

modules_install:
    cp    myled-ioctl.ko $(INSTALLDIR)

clean:
    rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c *.order *.symvers

.PHONY:modules modules_install clean

阅读(4271) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~