| #include<linux/module.h> #include<linux/init.h> #include<linux/fs.h> #include<linux/cdev.h> #include<linux/mm.h> #include<linux/ioport.h> #include<linux/interrupt.h> #include<linux/delay.h> #include<linux/device.h> #include<linux/platform_device.h> #include<asm/io.h> #include<asm/uaccess.h> MODULE_LICENSE("GPL"); MODULE_AUTHOR("zhanglong"); /* *板子上的led1,2,4,8分别对应连在GPF4,5,6,7上 * *GPFCON ==> 0x56000050 *GPFDAT ==> 0x56000054 *GPFUP ==> 0x56000058 * */ #define IO_PHYS 0x56000000 #define GPFCON_OFFSET 0x50 #define GPFDAT_OFFSET 0x54 #define GPFUP_OFFSET 0x58 struct led_device_s { struct cdev dev; dev_t no; struct class_device *led_classdev; short *io_gpfcon; char *io_gpfdat; char *io_gpfup; }; struct led_device_s my_led; void zl_release(struct device*dev) { printk("device release.\n"); } struct resource zl_res[]= { { .start = IO_PHYS, .end = IO_PHYS + SZ_4K, .flags = IORESOURCE_IO, }, #if 0 { .start = IRQ_EINT2, .end = IRQ_EINT2, .flags = IORESOURCE_IRQ, }, #endif }; struct platform_device zl_dev = { .name = "zl_device", //this string will be show as /sys/devices/platform/zl_device.0 .dev = { .release = zl_release, .platform_data = &my_led, }, .num_resources = ARRAY_SIZE(zl_res), .resource = zl_res, }; unsigned int devnum = 0; struct class*my_class; ssize_t my_read(structfile *fp,char __user *buf, size_t count, loff_t*off) { return 4;//不能返回0, 否则读相关设备时会卡住. } ssize_t my_write(structfile *fp,const char __user*buf,size_t count, loff_t*off) { struct led_device_s *get = fp->private_data; unsigned int minor; char value; copy_from_user(&value, buf, 1); #if 0 minor = MINOR(get->no); *(get->io_gpfcon)&=~(3<<((minor* 2)+ 8)); *(get->io_gpfcon)|=(1 <<((minor* 2)+ 8)); *(get->io_gpfup)&=~(1<<(minor + 4)); if((*buf== 0)||(*buf== 48)){ *(get->io_gpfdat)&=~(1<<(minor + 4)); } else{ *(get->io_gpfdat)|=(1 <<(minor + 4)); } #else *(get->io_gpfcon)&=~(0xff<< 8); *(get->io_gpfcon)|=(0x55 << 8); *(get->io_gpfup)&=~(0xf0); if((value>= 0)&&(value <= 15)){ *(get->io_gpfdat)= ((value& 0xf)<< 4); } elseif((value>='0')&&(value <='9')){ *(get->io_gpfdat)= ((value& 0xf)<< 4); } elseif((value>='a')&&(value <='f')){ *(get->io_gpfdat)= ((value- 97 + 10)<< 4); } elseif((value>='A')&&(value <='F')){ *(get->io_gpfdat)= ((value- 65 + 10)<< 4); } else{ } #endif return 4; } int my_open(struct inode*no,struct file*fp) { fp->private_data= container_of(no->i_cdev,struct led_device_s, dev); //printk(" kernel: open.\n"); return 0; } int my_release(struct inode*no,struct file*fp) { //printk(" kernel: release.\n"); return 0; } struct file_operations my_ops = { .open= my_open, .release = my_release, .read= my_read, .write= my_write, }; int zl_probe(struct device* dev) { struct platform_device *pdev = container_of(dev,struct platform_device, dev); struct resource *res = pdev->resource; struct led_device_s *pled = pdev->dev.platform_data; int ret = 0; char *virt = NULL; u32 i; for(i= 0; i< pdev->num_resources; i++){ if(IORESOURCE_IO& res[i].flags){ virt = ioremap(res[i].start,(res[i].end- res[i].start)); break; } } if(virt==NULL){ printk("[%s-L%d]:virt == NULL\n",__func__,__LINE__); return -1; } pled->io_gpfcon= virt + GPFCON_OFFSET; pled->io_gpfdat= virt + GPFDAT_OFFSET; pled->io_gpfup= virt + GPFUP_OFFSET; pled->no= MKDEV(52, devnum); cdev_init(&pled->dev,&my_ops); cdev_add(&pled->dev, pled->no, 1); pled->led_classdev= device_create(my_class,NULL, pled->no,&(pled->dev),"mydev_led.%d", devnum); if(IS_ERR(pled->led_classdev)){ printk("[%s-L%d]: device_create.\n",__func__,__LINE__); return PTR_ERR(pled->led_classdev); } devnum++; printk("driver zl_probe.\n"); return ret; } int zl_remove(struct device* dev) { struct platform_device *pdev = container_of(dev,struct platform_device, dev); struct led_device_s *pled = pdev->dev.platform_data; device_destroy(my_class, pled->no); cdev_del(&pled->dev); printk("driver zl_remove.\n"); return 0; } struct device_driver zl_driver_struct = { .name = "zl_device",//this string will be show as /sys/bus/platform/drivers/zl_device .bus = &platform_bus_type, .probe = zl_probe, .remove= zl_remove, }; int test_init(void) { int ret = 0; driver_register(&zl_driver_struct); my_class = class_create(THIS_MODULE,"myclass_led"); if (IS_ERR(my_class)){ printk("[%s-%d]: class_create.\n",__func__,__LINE__); return PTR_ERR(my_class); } ret = register_chrdev_region(MKDEV(52,0), 4, "my_led"); if (ret){ printk("[%s-L%d]: register_chrdev_region.\n",__func__,__LINE__); return ret; } platform_device_register(&zl_dev); return ret; } void test_exit(void) { platform_device_unregister(&zl_dev); class_destroy(my_class); driver_unregister(&zl_driver_struct); } module_init(test_init); module_exit(test_exit); |