S3C2410的一个LED的驱动程序

Environment: linux 2.6.22

Tools: arm-linux-gcc

platform:S3C2410 board

====================================分割线=======================================

#ifndef _LED_H_
#define _LED_H_

#ifdef LED_DEBUG
#  ifdef __KERNEL__
     /* This one if debugging is on, and kernel space */
#    define PDEBUG(fmt, args...) printk( KERN_DEBUG "led: " fmt, ## args)
#  else
     /* This one for user space */
#    define PDEBUG(fmt, args...) fprintf(stderr, fmt, ## args)
#  endif
#else
#  define PDEBUG(fmt, args...) /* not debugging: nothing */

#endif

// #define __MULTI_MIN__  //为了后面的拓展,将一个一个LED灯作为一个个的从设备

#ifndef __MULTI_MIN__

#ifndef LED_MAJOR
#define LED_MAJOR 0   /* dynamic major by default */
#endif

#ifndef LED_NR_DEVS
#define LED_NR_DEVS 1    /* led0 through ledx, LED1-3 as one device no min jor */
#endif

#else

#ifndef LED_MAJOR
#define LED_MAJOR 0   /* dynamic major by default */
#endif

#ifndef LED_NR_DEVS
#define LED_NR_DEVS 3    /* led0 through ledx, LED1-3 as one device no min jor */
#endif

#endif

#define LED1_ON  0x11
#define LED1_OFF 0x10

#define LED2_ON  0x21
#define LED2_OFF 0x20

#define LED3_ON  0x31
#define LED3_OFF 0x30

struct led_dev {
char LedStatus;         //LED 的状态,未用到
struct semaphore sem;     /* mutual exclusion semaphore     */  //互斥信号,没有用到
struct cdev cdev;  /* Char device structure*/
};

#endif
//====================================分割线=======================================
//led.c
//#include 
#include  //add by lqh
#include 
#include 
#include 
#include  /* printk() */
#include  /* kmalloc() */
#include  /* everything... */
#include  /* error codes */
#include  /* size_t */
#include 
#include  /* O_ACCMODE */
#include 
#include 
#include  /* cli(), *_flags */
#include  /* copy_*_user */
#include 
#include 
#include 
#include 

#include "led.h" /* local definitions */

#define UNUSEND(param) 

#define LEDON 0x00
#define LEDOFF 0x01

int led_major =   LED_MAJOR;
int led_minor =   0;
int led_nr_devs = LED_NR_DEVS; /* number of bare led devices */

module_param(led_major, int, S_IRUGO);
module_param(led_minor, int, S_IRUGO);
module_param(led_nr_devs, int, S_IRUGO);

MODULE_AUTHOR("Liqinghan for LED control ");
MODULE_LICENSE("Dual BSD/GPL");

struct led_dev *led_devices; /* allocated in led_init_module */

int led_open(struct inode *inode, struct file *filp)
{

s3c2410_gpio_cfgpin(S3C2410_GPF4, S3C2410_GPF4_OUTP);
s3c2410_gpio_cfgpin(S3C2410_GPF5, S3C2410_GPF5_OUTP);
s3c2410_gpio_cfgpin(S3C2410_GPF6, S3C2410_GPF5_OUTP);

s3c2410_gpio_setpin(S3C2410_GPF4, LEDOFF);
s3c2410_gpio_setpin(S3C2410_GPF5, LEDOFF);
s3c2410_gpio_setpin(S3C2410_GPF6, LEDOFF);

return 0;          /* success */
}

ssize_t led_read(struct file *filp, char __user *buf, size_t count,
                loff_t *f_pos)
{
UNUSEND(filp);
UNUSEND(buf);
UNUSEND(count);
UNUSEND(f_pos);
return count;

}

ssize_t led_write(struct file *filp, const char __user *buf, size_t count,
                loff_t *f_pos)
{
char val ;
UNUSEND(filp);
UNUSEND(count);
UNUSEND(f_pos);

if(copy_from_user(&val,buf,1))
return -EFAULT;

switch(val){
case LED1_ON:
s3c2410_gpio_setpin(S3C2410_GPF4, LEDON);
break;
case LED1_OFF:
s3c2410_gpio_setpin(S3C2410_GPF4, LEDOFF);
break;
case LED2_ON:
s3c2410_gpio_setpin(S3C2410_GPF5, LEDON);
break;
case LED2_OFF:
s3c2410_gpio_setpin(S3C2410_GPF5, LEDOFF);
break;
case LED3_ON:
s3c2410_gpio_setpin(S3C2410_GPF6, LEDON);
break;
case LED3_OFF:
s3c2410_gpio_setpin(S3C2410_GPF6, LEDOFF);
break;

default: break;

}
return - EINVAL;
}


struct file_operations led_fops = {
.owner =    THIS_MODULE,
.read =     led_read,
.write =    led_write,
.open =     led_open,
};


/*
 * Set up the char_dev structure for this device.
 */
static void led_setup_cdev(struct led_dev *dev, int index)
{
int err, devno = MKDEV(led_major, led_minor + index);


cdev_init(&dev->cdev, &led_fops);
dev->cdev.owner = THIS_MODULE;
dev->cdev.ops = &led_fops;
err = cdev_add (&dev->cdev, devno, 1);

if (err)
printk(KERN_NOTICE "Error %d adding led%d", err, index);
}


void led_exit_module(void){
cdev_del(&led_devices->cdev);
kfree(led_devices);
unregister_chrdev_region(MKDEV(led_major,led_minor),1);
}


int led_init_module(void)
{
int result;
dev_t dev = 0;


/*
 * Get a range of minor numbers to work with, asking for a dynamic
 * major unless directed otherwise at load time.
 */
if (led_major) {
dev = MKDEV(led_major, led_minor);
result = register_chrdev_region(dev, led_nr_devs, "led");
}
 else{
result = alloc_chrdev_region(&dev, led_minor, led_nr_devs,"led");
led_major = MAJOR(dev);
}
if (result < 0) {
printk(KERN_WARNING "led: can't get major %d\n", led_major);
return result;
}
led_devices = kmalloc( sizeof(struct led_dev), GFP_KERNEL);

if (!led_devices) {
result = -ENOMEM;
goto fail;  /* Make this more graceful */
}
memset(led_devices, 0, sizeof(struct led_dev));
led_setup_cdev(led_devices, 0);

dev = MKDEV(led_major, led_minor);
return 0; /* succeed */

  fail:
  if(led_devices){
kfree(led_devices);
}
unregister_chrdev_region(dev,led_minor);

return result;
}

module_init(led_init_module);
module_exit(led_exit_module);


====================================分割线=======================================

//note:本程序没有在板子上验证过,尚不知会不会有效,等我有空在去验证!

====================================分割线=======================================

Makefile:

KERN_DIR = /home/liqinghan/linux-2.6.22

all:
make -C $(KERN_DIR) M=`pwd` modules 

clean:
make -C $(KERN_DIR) M=`pwd` modules clean
rm -rf modules.order

obj-m += led.o

====================================分割线=======================================

编译 make,没有问题。等待我去实验哈!!

总结:感觉驱动架构就是一个框框,然后让我们往里面填写我们需要都的功能!!!但是对于这个框框的理解也很费力啊!

对于给程序我是按照scull的程序改过来的,还未在我的板子试验过,有空再实验吧! Mark一下!!!


你可能感兴趣的:(armlinux)