1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
| #include <linux/module.h> #include <linux/init.h> #include <linux/fs.h> #include <linux/device.h> #include <linux/slab.h> #include <linux/platform_device.h>
#include <asm/io.h> #include <asm/uaccess.h>
#include "plat_led.h"
struct samsung *platled;
static int platled_open(struct inode *inode, struct file *fops) { writeb(readb(platled->reg_base+4) & (~platled->reg->dat_clr), platled->reg_base+4); return 0; }
static int platled_close(struct inode *inode, struct file *fops) { return 0; }
static ssize_t platled_write(struct file *fops, const char __user *buf, size_t size, loff_t *fpos) { int value;
copy_from_user(&value, buf, size);
if (value) writeb((readb(platled->reg_base+4) & (~platled->reg->dat_clr)) | platled->reg->dat_set, platled->reg_base+4); else writeb(readb(platled->reg_base+4) & (~platled->reg->dat_clr), platled->reg_base+4); return 0; }
const struct file_operations platled_fops = { .open = platled_open, .release = platled_close, .write = platled_write, };
static int led_register(void) { int ret;
platled = kmalloc(sizeof(struct samsung), GFP_KERNEL); if (platled == NULL) { printk("kmalloc fail!\n"); return -ENOMEM; }
platled->major = register_chrdev(0, "plat_led", &platled_fops); if (platled->major < 0) { printk("register_chrdev fail!\n"); ret = -EFAULT; goto chrdev_err; }
platled->cls = class_create(THIS_MODULE, "plat_led"); if (platled->cls < 0) { printk("class_create fail!\n"); ret = -EFAULT; goto class_err; }
platled->dev = device_create(platled->cls, NULL, MKDEV(platled->major, 0), NULL, "plat_led"); if (platled->dev < 0) { printk("device_create fail!\n"); ret = -EFAULT; goto device_err; }
return 0;
device_err: class_destroy(platled->cls);
class_err: unregister_chrdev(platled->major, "plat_led");
chrdev_err: kfree(platled);
return ret; }
static void led_unregister(void) { device_destroy(platled->cls, MKDEV(platled->major, 0)); class_destroy(platled->cls); unregister_chrdev(platled->major, "plat_led"); kfree(platled); }
int plat_led_probe(struct platform_device *pdev) { int ret; struct resource *res;
ret = led_register(); if (ret < 0) { printk("plat_led_probe fail\n"); return -EFAULT; }
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res == NULL) { printk("platform_get_resource fail\n"); return -ENODEV; }
platled->reg = pdev->dev.platform_data; platled->reg_base = ioremap(res->start, resource_size(res)); writel((readl(platled->reg_base) & (~platled->reg->ctl_clr)) | platled->reg->ctl_set, platled->reg_base);
return 0; }
int plat_led_remove(struct platform_device *pdev) { iounmap(platled->reg_base); led_unregister(); return 0; }
const struct platform_device_id led_id_table[] = { {"plat_led", 0x1234}, };
struct platform_driver led_pdrv = { .probe = plat_led_probe, .remove = plat_led_remove, .driver = { .name = "red_led", }, .id_table = led_id_table, };
static int __init plat_led_drv_init(void) { platform_driver_register(&led_pdrv);
return 0; }
static void __exit plat_led_drv_exit(void) { platform_driver_unregister(&led_pdrv); }
module_init(plat_led_drv_init); module_exit(plat_led_drv_exit);
MODULE_LICENSE("GPL"); MODULE_AUTHOR("Aaron Lee");
|