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一下!!!