#include <linux/module.h> /*EXPORT_SYMBOL_GPL ())*/ #include<linux/moduleparam.h>/*module_param(variable,type,perm); */ #include <linux/init.h>/*module_init(init_function); module_exit(cleanup_function); */ #include <linux/kdev_t.h> /*dev_t*/ #include <linux/fs.h>/* everything... */ #include <linux/cdev.h> /*struct cdev *cdev_alloc(void); */ #include <linux/device.h> /*struct class*/ #include <asm/arch/regs-gpio.h> /*S3C2410_GPB5*/ #include <asm/hardware.h> /* s3c2410_gpio_cfgpin(unsigned int pin, unsigned int function)*/ #include<linux/ioctl.h> #include <asm/uaccess.h> /* copy_*_user access_ok*/
#include "devleds.h"
static int leds_major, leds_minor = 0; static struct cdev cdev; //字符设备结构
static struct class *leds_class; dev_t dev;//设备号
static unsigned long leds_table[] = { //led的引脚定义表
S3C2410_GPB5, S3C2410_GPB6, S3C2410_GPB7, S3C2410_GPB8 }; static unsigned int leds_cfg_table[] = { //led引脚功能定义表
S3C2410_GPB5_OUTP, S3C2410_GPB6_OUTP, S3C2410_GPB7_OUTP, S3C2410_GPB8_OUTP, }; static int leds_open(struct inode *inode, struct file *filp) { int i; // for(i = 0; i < 4; i++){ //引脚初始化,由于内核在已经初始化过一次,本处不必在初始化,否则得不到结果
//s3c2410_gpio_cfgpin(leds_table[i], leds_cfg_table[i]);//arch/arm/plat-s3c24xx/gpio.c:void s3c2410_gpio_cfgpin(unsigned int pin, unsigned int function)
} return 0; } static int leds_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { int err = 0, i; if (_IOC_TYPE(cmd) != LEDS_IOC_MAGIC) return -ENOTTY; if (_IOC_NR(cmd) > LEDS_IOC_MAXNR) return -ENOTTY; /* * the direction is a bitmask, and VERIFY_WRITE catches R/W * transfers. `Type' is user-oriented, while * access_ok is kernel-oriented, so the concept of "read" and * "write" is reversed */ if (_IOC_DIR(cmd) & _IOC_READ) err = !access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd)); else if (_IOC_DIR(cmd) & _IOC_WRITE) err = !access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd)); if (err) return -EFAULT; printk(KERN_WARNING"Here\n"); switch(cmd) { case LEDS_IOCRESET: for(i = 0; i < 4; i++){ s3c2410_gpio_setpin(leds_table[i], 1); } printk(KERN_WARNING"Here\n"); return 0; case LEDS_IOCSON: s3c2410_gpio_setpin(leds_table[arg], 0); return 0; case LEDS_IOCSOFF: s3c2410_gpio_setpin(leds_table[arg], 1); return 0; default: return -EINVAL; } return 0; } static struct file_operations leds_fops = { .owner = THIS_MODULE, .open = leds_open, .ioctl = leds_ioctl }; static int __init leds_init(void) //模块初始化
{ int result; PDEBUG("Debug Opend!\n"); 我写来测试调试是否打开了的 if (leds_major) { dev = MKDEV(leds_major, leds_minor); result = register_chrdev_region(dev, 1, DEV_NAME);//此处为静态分配主设备号
} else { result = alloc_chrdev_region(&dev, leds_minor, 1, DEV_NAME);//动态分配主设备号,此设备号为0
leds_major = MAJOR(dev);//获取主设备号的宏
} if (result < 0) { printk(KERN_WARNING "Leds: can't get major %d\n", leds_major); return result; }else { printk(KERN_WARNING"Registered ok \nLeds_major = %d\n", leds_major); } cdev_init(&cdev, &leds_fops) ;//初始化最先定义的字符设备结构
cdev.owner = THIS_MODULE; cdev.ops = &leds_fops; result = cdev_add(&cdev, dev, 1);//通知内核有该结构注册,注意考虑失败
if(result < 0){ printk(KERN_WARNING"cdev_add failed!\n"); return result; } leds_class = class_create(THIS_MODULE, DEV_NAME);//creat自己的设备节点
if(IS_ERR(leds_class)) { printk(KERN_ALERT"Err:faile in leds_class!\n"); return -1; } /*创建设备节点,名字为DEVICE_NAME ,主设备号用上面动态生成的dev*/ class_device_create(leds_class, NULL, dev, NULL, DEV_NAME); printk(KERN_WARNING"Leds Module Initialed!\n"); return 0; } static void __exit leds_exit(void) { int devno = MKDEV(leds_major, leds_minor ); unregister_chrdev_region(devno, 1);//销毁设备号
cdev_del(&cdev);//销毁字符设备结构
class_device_destroy(leds_class, devno); //销毁注册的类
class_destroy(leds_class); printk(KERN_WARNING"Leds Module exit!\n"); } module_init(leds_init); module_exit(leds_exit); MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("CHARACTER DEVICE DRVER"); MODULE_AUTHOR();
|