#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");
|