#include <linux/fs.h> #include <linux/module.h> #include <linux/errno.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/cdev.h> #include <linux/ioport.h> #include <linux/pci.h> #include <asm/uaccess.h> #include <asm/io.h> /* 次设备号: * 0 - 所有的灯 * 1 - led1 * 2 - led2 * 3 - led3 * 4 - led4 */ static int major; static struct class *led_class; static volatile unsigned long * gpfcon; // = (volatile unsigned long *)0x56000050; static volatile unsigned long * gpfdat; // = (volatile unsigned long *)0x56000054; int led_open(struct inode *inode, struct file *file) { int minor = iminor(inode); if (minor > 4) return -EINVAL; /* 配置GPIO为输出引脚 */ if (minor == 0) { *gpfcon &= ~0xff00; /*设置gpf4,5,6,7为输出引脚*/ *gpfcon |= 0x5500; } else { *gpfcon &= ~(0x3 << ((minor+3)*2)); /*否则单独设置某个引脚为输出功能*/ *gpfcon |= (0x1 << ((minor+3)*2));; } return 0; } ssize_t led_write(struct file *file, const char __user *buf, size_t size, loff_t *offset) { char ker_buf[1]; int minor = iminor(file->f_path.dentry->d_inode); /* 根据buf传入的值点/灭灯 */ /* buf[0] - 亮/灭 , 0 - 亮, 1 - 灭 */ if (size != 1) { return -EINVAL; } copy_from_user(ker_buf, buf, 1); if ((ker_buf[0] != 0) && (ker_buf[0] != 1)) return -EINVAL; if (minor == 0) { if (ker_buf[0]) { // 全灭 *gpfdat |= (0xf<<4); } else { // 全亮 *gpfdat &= ~(0xf<<4); } } else { if (ker_buf[0]) { // 某个LED *gpfdat |= (0x1<<(minor + 3)); } else { // 某个LED *gpfdat &= ~(0x1<<(minor + 3)); } } return 1; } static int led_ioctl(struct inode *inode, struct file *file, unsigned int cmd,unsigned long arg) { unsigned int minor = iminor(inode); if(minor>4) return -1; switch(cmd) { case 0: if (minor == 0) { printk("leds right all\n");(用于调试,在串口上能够观察执行到了这步没有) // 全亮 *gpfdat &= ~(0xf<<4); } // 某个LED 亮 *gpfdat &= ~(0x1<<(minor + 3)); break; case 1: if (minor == 0) { // 全灭 *gpfdat |= (0xf<<4); } // 某个LED 灭 printk("led off \n"); *gpfdat |= (0x1<<(minor + 3)); break; default : break; } return 0; } static const struct file_operations led_fops = { .owner = THIS_MODULE, .write = led_write, .open = led_open, .ioctl =led_ioctl, }; int led_init(void) { int i; major = register_chrdev(0, "led", &led_fops); /* sysfs 自动创建设备节点 */ led_class = class_create(THIS_MODULE, "led_class"); class_device_create(led_class, NULL, MKDEV(major, 0), NULL, "leds"); // /dev/leds for (i = 1; i <= 4; i++) class_device_create(led_class, NULL, MKDEV(major, i), NULL, "led%d", i); // /dev/led1,2,3,4 gpfcon = ioremap(0x56000050, 8); /* 得到虚拟地址 */ gpfdat = gpfcon + 1; return 0; } void led_exit(void) { int i; unregister_chrdev(major, "led"); for (i = 0; i <= 4; i++) class_device_destroy(led_class, MKDEV(major, i)); class_destroy(led_class); iounmap(gpfcon); } module_init(led_init); module_exit(led_exit); MODULE_LICENSE("GPL"); |