学习控制发光二极管代码心得
2024-09-29 来源:cnblogs
LED的完整驱动代码
#include #include #include #include #include #include #include #define DEVICE_NAME 's3c6410_leds' #define DEVICE_COUNT 1 // 设备数量 #define S3C6410_LEDS_MAJOR 0 // 默认主设备号 #define S3C6410_LEDS_MINOR 234 // 默认次设备号 #define PARAM_SIZE 3 //定义数组长度 static unsigned char mem[4]; // 保存4个Leds的设置状态 static int major = S3C6410_LEDS_MAJOR; static int minor = S3C6410_LEDS_MINOR; static dev_t dev_number; // 设备号 static int leds_state = 1; static char *params[] = {'string1', 'string2','string3'}; static int param_size = PARAM_SIZE; static struct class *leds_class = NULL; /*********5.控制LED**********/ // s3c6410_leds_ioctl函数用于接收向LED驱动传递的命令和参数,通过I/O命令控制LED static long s3c6410_leds_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { //命令只能是0或1 switch (cmd) { unsigned tmp; case 0: case 1: if (arg > 4) { return -EINVAL; } //读取GPMDAT寄存器的当前值 tmp = ioread32(S3C64XX_GPMDAT); if (cmd == 1) { tmp &= (~(1 << arg)); } else { tmp |= (1 << arg); } //向GPMDAT寄存器写入数据 iowrite32(tmp, S3C64XX_GPMDAT); return 0; default: return -EINVAL; } } //s3c6410_leds_write函数用于接收向/dev/s3c6410_leds设备文件写入的字符串 static ssize_t s3c6410_leds_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { unsigned tmp = count; unsigned long i = 0; memset(mem, 0, 4);//将mem数组所有元素的值都设为0 //最多写入4个字符,多余的字符将忽略 if (count > 4) { tmp = 4; } if (copy_from_user(mem, buf, tmp)) { return -EFAULT; } else { for (i = 0; i < 4; i++) { tmp = ioread32(S3C64XX_GPMDAT); if (mem[i] == '1') { tmp &= (~(1 << i)); } else { tmp |= (1 << i); } iowrite32(tmp, S3C64XX_GPMDAT); } return count; } } static struct file_operations dev_fops ={ .owner = THIS_MODULE, .unlocked_ioctl = s3c6410_leds_ioctl, .write = s3c6410_leds_write }; static struct cdev leds_cdev; /********2.创建设备文件(/dev/s3c6410_leds)********/ static int leds_create_device(void) { int ret = 0; int err = 0; // 第1步: 初始化cdev的成员,并建立cdev和file_operations之间的连接 cdev_init(&leds_cdev, &dev_fops); leds_cdev.owner = THIS_MODULE; //第2步:主设备号>0,通过指定设备号的方式注册字符设备区域 if (major > 0) { //指定设备号的两种方式:直接在代码中指定(硬编码),动态分配 // 获取设备号(主设备号和次设备号) dev_number = MKDEV(major, minor); err = register_chrdev_region(dev_number, DEVICE_COUNT, DEVICE_NAME); if (err < 0) { printk(KERN_WARNING 'register_chrdev_region() failedn'); return err; } } else { err = alloc_chrdev_region(&leds_cdev.dev, 10, DEVICE_COUNT, DEVICE_NAME); if (err < 0)//注册字符设备区域失败 { printk(KERN_WARNING 'alloc_chrdev_region() failedn'); return err; } //一般采用分别指定主设备号和次设备号的方式指定设备号。 major = MAJOR(leds_cdev.dev); minor = MINOR(leds_cdev.dev); //dev_number = MKDEV(major, minor); dev_number = leds_cdev.dev; } //第3步:将字符设备添加到内核中的字符设备数组中 ret = cdev_add(&leds_cdev, dev_number, DEVICE_COUNT); //第4步:使用class_create宏创建struct class leds_class = class_create(THIS_MODULE, DEVICE_NAME); //第5步:创建设备文件 device_create(leds_class, NULL, dev_number, NULL, DEVICE_NAME); return ret; } /********4.设置寄存器与初始化LED驱动*******/ static void leds_init_gpm(int leds_default) { int tmp = 0; // 初始化端口配置寄存器 tmp = ioread32(S3C64XX_GPMCON); tmp &= (~0xFFFF); tmp |= 0x1111; // 0001000100010001 iowrite32(tmp, S3C64XX_GPMCON); // 初始化端口上拉电路寄存器 tmp = ioread32(S3C64XX_GPMPUD); tmp &= (~0xFF); tmp |= 0xAA; // 01010101 iowrite32(tmp, S3C64XX_GPMPUD); // 初始化端口数据寄存器 tmp = ioread32(S3C64XX_GPMDAT); tmp &= (~0xF); tmp |= leds_default; iowrite32(tmp, S3C64XX_GPMDAT); } /********1. 初始化LED驱动*********/ static int leds_init(void) { int ret; ret = leds_create_device(); leds_init_gpm(~leds_state); printk(DEVICE_NAME'tinitializedn'); //输出params数组中的值 printk('param0t%sn', params[0]); printk('param1t%sn', params[1]); printk('param2t%sn', params[2]); return ret; } /*********3.卸载LED驱动的设备文件*********/ static void leds_destroy_device(void) { //移除通过device_create函数建立的字符设备 device_destroy(leds_class, dev_number); if (leds_class) //销毁struct class class_destroy(leds_class); //注销字符设备区域 unregister_chrdev_region(dev_number, DEVICE_COUNT); return; } static void leds_exit(void) { leds_destroy_device();//卸载LED驱动的设备文件 printk(DEVICE_NAME'texit!n'); } //LED驱动的模块参数 module_init(leds_init); module_exit(leds_exit); module_param(leds_state, int, S_IRUGO|S_IWUSR); //下面一行是指定数组类型模块参数的相关信息 module_param_array(params, charp, ¶m_size, S_IRUGO|S_IWUSR); MODULE_LICENSE('GPL'); MODULE_AUTHOR('Lining');
上一篇:LED:控制发光二极管
下一篇:U-boot内核移植步骤