首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

OK6410的第一个驱动程序--点灯

OK6410的第一个驱动程序--点灯

开始自己的嵌入式之旅了。一切神秘的面纱均可以由闪亮的LED揭开。
贴上自己的驱动程序:
#include<linux/kernel.h>
#include<linux/module.h>
#include<linux/init.h>
#include<linux/fs.h>
#include<linux/pci.h>
#include<linux/ioctl.h>
#include<linux/types.h>
#include<linux/cdev.h>
#include<linux/device.h>
#include<linux/gpio.h>
#include<mach/hardware.h>
#include<mach/regs-gpio.h>
#include<mach/gpio-bank-m.h>
#include<plat/gpio-cfg.h>
#include <mach/map.h>

#define DEVICE_NAME "s3c6410leds"
#define LED_ON 1
#define LED_OFF 0
dev_t devid;


static int leds_open(struct inode *inode , struct file *file)
{
  unsigned tmp;

  for(tmp=0;tmp<4;tmp++)
  s3c_gpio_cfgpin(S3C64XX_GPM(tmp),S3C_GPIO_SFN(1));

  return 0;
}

static long leds_ioctl( struct file *filp,unsigned int cmd,
                        unsigned long arg)
                     
{

  if(arg>4) return -EINVAL;
  //tmp = __raw_readl(S3C64XX_GPMDAT);

  switch(cmd)
  {
    case LED_ON:  //tmp &= ~(1<<arg); writel(tmp,S3C64XX_GPMDAT);
                  gpio_set_value(S3C64XX_GPM(arg),0);
                  return 0;
    case LED_OFF: //tmp |= 1<<arg; writel(tmp,S3C64XX_GPMDAT);
                  gpio_set_value(S3C64XX_GPM(arg),1);
                  return 0;
    default: return -EINVAL;
  }
}

static struct file_operations leds_ops = {
    .owner = THIS_MODULE,
    .open = leds_open,
    .unlocked_ioctl = leds_ioctl,
};

static struct cdev *cdev_led;
static struct class *led_class;

static int __init s3c6410_leds_init(void)
{
  int val;
  unsigned tmp;

  tmp = readl(S3C64XX_GPMPUD); //pull up gpiom0~3
  tmp &= ~(0xffff);
  tmp |= 0xaa;
  writel(tmp,S3C64XX_GPMPUD);

//  devid = MKDEV(LED_MAJOR,0);
//  val = register_chrdev_region(devid,1,DEVICE_NAME);
  val = alloc_chrdev_region(&devid,0,1,DEVICE_NAME);
  if(val) return -1;

  cdev_led = cdev_alloc();
  cdev_init(cdev_led,&leds_ops);
  val = cdev_add(cdev_led,devid,1);
  if(val)
  {
//   printk(KERN_INFO "Add device led error!\n");
    return -1;
  }

  led_class = class_create(THIS_MODULE,DEVICE_NAME);
  device_create(led_class,NULL,devid,NULL,"%s",DEVICE_NAME);

// printk(KERN_INFO "LED Initilized I'm in! ^_^ \n");
  return 0;
}

static void __exit s3c6410_leds_exit(void)
{
  cdev_del(cdev_led);
  device_destroy(led_class,devid);
  class_destroy(led_class);  
  unregister_chrdev_region(devid, 1);
}

module_init(s3c6410_leds_init);
module_exit(s3c6410_leds_exit);


MODULE_AUTHOR("embedded lover");
MODULE_DESCRIPTION("s3c6410 led test");
MODULE_LICENSE("GPL");

在linux2.6版本之后我们是可以让驱动程序自动建立设备节点文件的,注意下这点。
下面是自己的测试程序:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/ioctl.h>

#define LED_ON 1
#define LED_OFF 0

int main(int argc, char **argv)
{
  int fd = -1;
  unsigned int led_no;

  fd = open("/dev/s3c6410leds",0);
  if(fd<0)
  {
    printf("Can not open device leds\n");
    return -1;
  }

  led_no = strtoul(argv[1],0,0) - 1;
  if(!strcmp(argv[2],"on"))
  {
    ioctl(fd,LED_ON,led_no);
  }

  else if(!strcmp(argv[2],"off"))
  {
    ioctl(fd,LED_OFF,led_no);
  }

  else goto err;

  close(fd);
  return 0;



err:
  if(fd>0) close(fd);
  return -1;

}



在写完驱动程序后有两个方法可以编译成可加载的.ko模块文件,一个是将驱动放到内核原码的driver/char目录下,再在Makefile下新增一个obj-m += name.o。再在顶层文件夹下执行make modules ,然后就可以在driver/char下找到对应的.ko文件。另外一个方法就是自己写makefile了,这样也方便。
Makefile如下:
---------------------------------------------
all: default
obj-m += create_chrdev.o

default:
    make -C /home/xu/Myworks/kernel/linux-2.6.22 M=`pwd` modules
clean:
    make -C /home/xu/Myworks/kernel/linux-2.6.22 M=`pwd` clean
最后将模块文件加载到目标板上:insmod,移除模块用:rmmod。
返回列表