第一个Linux驱动-s3c6410 gpio

ITlover00 2011-03-29

前段时间学着写了第一个linux下的驱动,很简单,基于友善之臂的tiny6410,通过控制GPIOK4-7输入输出来控制板上的4个led。led的驱动友善已经提供,不过我自己写的有些不一样,是按照标准的char驱动来写的,下面是全过程。

注意:此代码基于友善之臂提供的已经移植好的linux2.6.36核心

第一步编写驱动代码

//tiny6410_gpio.c

#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 <asm/uaccess.h>
#include <asm/atomic.h>
#include <asm/unistd.h>

#include <mach/map.h>
#include <mach/regs-clock.h>
#include <mach/regs-gpio.h>

#include <plat/gpio-cfg.h>
#include <mach/gpio-bank-e.h>
#include <mach/gpio-bank-k.h>

#define DEVICE_NAME "tiny6410_gpio" //驱动名字
#define DEVICE_MAJOR 100 //主设备号
static int tiny6410_gpio_major=DEVICE_MAJOR;

//自己定义的描述gpio的结构体
struct tiny6410_gpio_dev
{
 struct cdev cdev;//描述字符型设备的cdev结构体
 unsigned *conf0;
 unsigned *conf1;
 unsigned *data;
 unsigned *pud;
};

//初始化dev内的寄存器地址

struct tiny6410_gpio_dev dev=
{
 .conf0=S3C64XX_GPKCON,
 .conf1=S3C64XX_GPKCON1,
 .data=S3C64XX_GPKDAT,
 .pud=S3C64XX_GPKPUD,
};

//这个驱动仅实现read和write函数,一个字节代表一个灯的状态

ssize_t tiny6410_gpio_read (struct file *filp, char __user *buf_user, size_t size, loff_t *f_pos)
{
 unsigned val,i;
 val=size;
 i=*f_pos;
 printk("start read start:%x size:%d\r\n",i,val);//输出调试信息。很奇怪,直接输出*f_pos和size数值回不对,只能中转一下
 if(*f_pos>=4 || size==0)
 {
  put_user(0,buf_user);
  return 0;
 }
 val=readl(dev.data);
 printk("raw val:%x\r\n",val);
 val=(val>>(4+*f_pos))&0xf;
 for(i=0;i<((size+*f_pos)>4?4-*f_pos:size);i++)
  put_user((val>>i)&0x01,buf_user+i);
 printk("get val:%x max index:%d\r\n",val,i);
 return 0;
}


//ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
ssize_t tiny6410_gpio_write (struct file *filp, const char __user *buf_user, size_t size, loff_t *f_pos)
{
 unsigned char writesize,i,data[4];
 unsigned raw;
 printk("start write start:%x,size:%d",*f_pos,size);
 if(*f_pos>=4)
 {
  return size;
 }
 writesize=4-copy_from_user(data,buf_user,size);
 if(writesize==0)
 {
  printk("write size 0!\r\n");
  return size;
 }
 raw=readl(dev.data);
 printk("source val:%x,write size:%d\r\n",raw,writesize);
 for(i=0;i<((writesize+*f_pos)>4?4-*f_pos:writesize);i++)
 {
  raw&=~(1<<(i+*f_pos+4));
  raw|=((data[i]?1:0)<<(i+4+*f_pos));
 }
 writel(raw,dev.data);
 printk("write end! dest val:%x max index:\r\n",raw,i);
 return 4-writesize; 
}


//这个结构体内的函数是驱动编写主要修改的地方
static struct file_operations dev_fops = {
 .owner   = THIS_MODULE,
 //.unlocked_ioctl = sbc2440_leds_ioctl,
 .read  = tiny6410_gpio_read,
 .write  = tiny6410_gpio_write,
};

static int tiny6410_gpio_setup_cdev()
{
 int devno=MKDEV(tiny6410_gpio_major,0);
 cdev_init(&dev.cdev,&dev_fops);
 dev.cdev.owner=THIS_MODULE;
 return cdev_add(&dev.cdev,devno,1);//添加一个cdev结构体
}

相关推荐