源码:
1 /***************************************************************************** 2 简 述:简单字符型驱动程序,手动静态分配设备号,手动创建设备节点 3 ******************************************************************************/ 4 #include <linux/module.h> 5 #include <linux/moduleparam.h> 6 #include <linux/cdev.h> 7 #include <linux/fs.h> 8 #include <linux/wait.h> 9 #include <linux/poll.h> 10 #include <linux/sched.h> 11 #include <linux/irq.h> 12 #include <asm/irq.h> 13 #include <linux/interrupt.h> 14 15 16 #include <mach/map.h> 17 #include <mach/gpio.h> 18 #include <mach/regs-gpio.h> 19 #include <plat/gpio-cfg.h> 20 21 #include <linux/slab.h> 22 23 #define DEVICE_NAME "buttons" 24 25 struct button_desc { 26 int gpio; 27 int number; 28 char *name; 29 }; 30 31 static struct button_desc buttons[] = { 32 { S5PV210_GPH2(0), 0, "KEY0" }, 33 { S5PV210_GPH2(1), 1, "KEY1" }, 34 { S5PV210_GPH2(2), 2, "KEY2" }, 35 { S5PV210_GPH2(3), 3, "KEY3" }, 36 { S5PV210_GPH3(0), 4, "KEY4" }, 37 { S5PV210_GPH3(1), 5, "KEY5" }, 38 { S5PV210_GPH3(2), 6, "KEY6" }, 39 { S5PV210_GPH3(3), 7, "KEY7" }, 40 }; 41 #define OK (0) 42 #define ERROR (-1) 43 44 struct cdev *gDev; 45 struct file_operations *gFile; 46 dev_t devNum; 47 unsigned int subDevNum = 1; 48 int reg_major = 232; 49 int reg_minor = 0; 50 51 52 static irqreturn_t button_interrupt(int irq, void *dev_id) 53 { 54 struct button_desc *bdata = (struct button_desc *)dev_id; 55 56 int down; 57 unsigned tmp; 58 59 tmp = gpio_get_value(bdata->gpio); 60 61 /* active low */ 62 down = !tmp; 63 printk("KEY %d: %08x\n", bdata->number, down); 64 65 return IRQ_HANDLED; 66 } 67 68 int butsOpen(struct inode *p, struct file *f) 69 { 70 71 int irq; 72 int i; 73 int err = 0; 74 printk(KERN_EMERG"butsOpen\r\n"); 75 for (i = 0; i < ARRAY_SIZE(buttons); i++) { 76 if (!buttons[i].gpio) 77 continue; 78 79 irq = gpio_to_irq(buttons[i].gpio); 80 err = request_irq(irq, button_interrupt, IRQ_TYPE_EDGE_BOTH, 81 buttons[i].name, (void *)&buttons[i]); 82 if (err) 83 break; 84 } 85 86 if (err) { 87 i--; 88 for (; i >= 0; i--) { 89 if (!buttons[i].gpio) 90 continue; 91 92 irq = gpio_to_irq(buttons[i].gpio); 93 disable_irq(irq); 94 free_irq(irq, (void *)&buttons[i]); 95 } 96 97 return -EBUSY; 98 } 99 return 0; 100 } 101 102 103 104 105 int charDrvInit(void) 106 { 107 108 devNum = MKDEV(reg_major, reg_minor); 109 110 printk(KERN_EMERG"devNum is %d\r\n", devNum); 111 if(OK == register_chrdev_region(devNum, subDevNum, DEVICE_NAME)) 112 { 113 printk(KERN_EMERG"register_chrdev_region ok\r\n"); 114 } 115 else 116 { 117 printk(KERN_EMERG"register_chrdev_region error\r\n"); 118 return ERROR; 119 } 120 /*if(OK == alloc_chrdev_region(&devNum, subDevNum, subDevNum,"test")) 121 { 122 printk(KERN_EMERG"register_chrdev_region ok\r\n"); 123 } 124 else 125 { 126 printk(KERN_EMERG"register_chrdev_region error\r\n"); 127 return ERROR; 128 }*/ 129 130 gDev = kzalloc(sizeof(struct cdev), GFP_KERNEL); 131 gFile = kzalloc(sizeof(struct file_operations), GFP_KERNEL); 132 133 gFile->open = butsOpen; 134 //注册设备函数到file_operations结构体gFile 135 136 //gDev->owner = THIS_MODULE; 137 gFile->owner = THIS_MODULE; 138 cdev_init(gDev, gFile); 139 //在cdev结构体中添加指针指向file_operations结构体gFile 140 cdev_add(gDev, devNum, 3); 141 //建立设备号与cdev结构体联系 142 printk(KERN_EMERG"button driver initial done...\r\n"); 143 return 0; 144 } 145 146 void __exit charDrvExit(void) 147 { 148 int i; 149 150 cdev_del(gDev); 151 unregister_chrdev_region(devNum, subDevNum); 152 return; 153 } 154 module_init(charDrvInit); 155 module_exit(charDrvExit); 156 MODULE_LICENSE("GPL");View Code
1 int butsOpen(struct inode *p, struct file *f) 2 { 3 4 int irq; 5 int i; 6 int err = 0; 7 printk(KERN_EMERG"butsOpen\r\n"); 8 for (i = 0; i < ARRAY_SIZE(buttons); i++) { 9 if (!buttons[i].gpio) 10 continue; 11 12 irq = gpio_to_irq(buttons[i].gpio); 13 err = request_irq(irq, button_interrupt, IRQ_TYPE_EDGE_BOTH, 14 buttons[i].name, (void *)&buttons[i]); 15 if (err) 16 break; 17 } 18 19 if (err) { 20 i--; 21 for (; i >= 0; i--) { 22 if (!buttons[i].gpio) 23 continue; 24 25 irq = gpio_to_irq(buttons[i].gpio); 26 disable_irq(irq); 27 free_irq(irq, (void *)&buttons[i]); 28 } 29 30 return -EBUSY; 31 } 32 return 0; 33 }
1 #define gpio_to_irq __gpio_to_irq
1 int __gpio_to_irq(unsigned gpio) 2 { 3 struct gpio_chip *chip; 4 chip = gpio_to_chip(gpio); 5 return chip->to_irq ? chip->to_irq(chip, gpio - chip->base) : -ENXIO; 6 }
1 static inline struct gpio_chip *gpio_to_chip(unsigned gpio) 2 { 3 return gpio_desc[gpio].chip;//此处的gpio_desc[gpio].chip实际完成赋值在gpio-s5pv210.c中的s5pv210_gpiolib_init(void)函数中实现 4 }
gpio_desc[gpio].chip实际完成赋值在gpio-s5pv210.c中的s5pv210_gpiolib_init(void)函数中的实现:
1 static __init int s5pv210_gpiolib_init(void) 2 { 3 struct s3c_gpio_chip *chip = s5pv210_gpio_4bit; 4 int nr_chips = ARRAY_SIZE(s5pv210_gpio_4bit); 5 int gpioint_group = 0; 6 int i = 0; 7 8 for (i = 0; i < nr_chips; i++, chip++) { 9 if (chip->config == NULL) { 10 chip->config = &gpio_cfg; 11 chip->group = gpioint_group++; 12 } 13 if (chip->base == NULL) 14 chip->base = S5PV210_BANK_BASE(i); 15 } 16 17 samsung_gpiolib_add_4bit_chips(s5pv210_gpio_4bit, nr_chips); 18 s5p_register_gpioint_bank(IRQ_GPIOINT, 0, S5P_GPIOINT_GROUP_MAXNR); 19 20 return 0; 21 }
1 static struct s3c_gpio_chip s5pv210_gpio_4bit[] = { 2 { 3 .chip = { 4 .base = S5PV210_GPA0(0), 5 .ngpio = S5PV210_GPIO_A0_NR, 6 .label = "GPA0", 7 }, 8 }, { 9 .chip = { 10 .base = S5PV210_GPA1(0), 11 .ngpio = S5PV210_GPIO_A1_NR, 12 .label = "GPA1", 13 }, 14 }, { 15 .chip = { 16 .base = S5PV210_GPB(0), 17 .ngpio = S5PV210_GPIO_B_NR, 18 .label = "GPB", 19 }, 20 }, { 21 .chip = { 22 .base = S5PV210_GPC0(0), 23 .ngpio = S5PV210_GPIO_C0_NR, 24 .label = "GPC0", 25 }, 26 }, { 27 .chip = { 28 .base = S5PV210_GPC1(0), 29 .ngpio = S5PV210_GPIO_C1_NR, 30 .label = "GPC1", 31 }, 32 }, { 33 .chip = { 34 .base = S5PV210_GPD0(0), 35 .ngpio = S5PV210_GPIO_D0_NR, 36 .label = "GPD0", 37 }, 38 }, { 39 .chip = { 40 .base = S5PV210_GPD1(0), 41 .ngpio = S5PV210_GPIO_D1_NR, 42 .label = "GPD1", 43 }, 44 }, { 45 .chip = { 46 .base = S5PV210_GPE0(0), 47 .ngpio = S5PV210_GPIO_E0_NR, 48 .label = "GPE0", 49 }, 50 }, { 51 .chip = { 52 .base = S5PV210_GPE1(0), 53 .ngpio = S5PV210_GPIO_E1_NR, 54 .label = "GPE1", 55 }, 56 }, { 57 .chip = { 58 .base = S5PV210_GPF0(0), 59 .ngpio = S5PV210_GPIO_F0_NR, 60 .label = "GPF0", 61 }, 62 }, { 63 .chip = { 64 .base = S5PV210_GPF1(0), 65 .ngpio = S5PV210_GPIO_F1_NR, 66 .label = "GPF1", 67 }, 68 }, { 69 .chip = { 70 .base = S5PV210_GPF2(0), 71 .ngpio = S5PV210_GPIO_F2_NR, 72 .label = "GPF2", 73 }, 74 }, { 75 .chip = { 76 .base = S5PV210_GPF3(0), 77 .ngpio = S5PV210_GPIO_F3_NR, 78 .label = "GPF3", 79 }, 80 }, { 81 .chip = { 82 .base = S5PV210_GPG0(0), 83 .ngpio = S5PV210_GPIO_G0_NR, 84 .label = "GPG0", 85 }, 86 }, { 87 .chip = { 88 .base = S5PV210_GPG1(0), 89 .ngpio = S5PV210_GPIO_G1_NR, 90 .label = "GPG1", 91 }, 92 }, { 93 .chip = { 94 .base = S5PV210_GPG2(0), 95 .ngpio = S5PV210_GPIO_G2_NR, 96 .label = "GPG2", 97 }, 98 }, { 99 .chip = { 100 .base = S5PV210_GPG3(0), 101 .ngpio = S5PV210_GPIO_G3_NR, 102 .label = "GPG3", 103 }, 104 }, { 105 .config = &gpio_cfg_noint, 106 .chip = { 107 .base = S5PV210_GPI(0), 108 .ngpio = S5PV210_GPIO_I_NR, 109 .label = "GPI", 110 }, 111 }, { 112 .chip = { 113 .base = S5PV210_GPJ0(0), 114 .ngpio = S5PV210_GPIO_J0_NR, 115 .label = "GPJ0", 116 }, 117 }, { 118 .chip = { 119 .base = S5PV210_GPJ1(0), 120 .ngpio = S5PV210_GPIO_J1_NR, 121 .label = "GPJ1", 122 }, 123 }, { 124 .chip = { 125 .base = S5PV210_GPJ2(0), 126 .ngpio = S5PV210_GPIO_J2_NR, 127 .label = "GPJ2", 128 }, 129 }, { 130 .chip = { 131 .base = S5PV210_GPJ3(0), 132 .ngpio = S5PV210_GPIO_J3_NR, 133 .label = "GPJ3", 134 }, 135 }, { 136 .chip = { 137 .base = S5PV210_GPJ4(0), 138 .ngpio = S5PV210_GPIO_J4_NR, 139 .label = "GPJ4", 140 }, 141 }, { 142 .config = &gpio_cfg_noint, 143 .chip = { 144 .base = S5PV210_MP01(0), 145 .ngpio = S5PV210_GPIO_MP01_NR, 146 .label = "MP01", 147 }, 148 }, { 149 .config = &gpio_cfg_noint, 150 .chip = { 151 .base = S5PV210_MP02(0), 152 .ngpio = S5PV210_GPIO_MP02_NR, 153 .label = "MP02", 154 }, 155 }, { 156 .config = &gpio_cfg_noint, 157 .chip = { 158 .base = S5PV210_MP03(0), 159 .ngpio = S5PV210_GPIO_MP03_NR, 160 .label = "MP03", 161 }, 162 }, { 163 .config = &gpio_cfg_noint, 164 .chip = { 165 .base = S5PV210_MP04(0), 166 .ngpio = S5PV210_GPIO_MP04_NR, 167 .label = "MP04", 168 }, 169 }, { 170 .config = &gpio_cfg_noint, 171 .chip = { 172 .base = S5PV210_MP05(0), 173 .ngpio = S5PV210_GPIO_MP05_NR, 174 .label = "MP05", 175 }, 176 }, { 177 .base = (S5P_VA_GPIO + 0xC00), 178 .config = &gpio_cfg_noint, 179 .irq_base = IRQ_EINT(0), 180 .chip = { 181 .base = S5PV210_GPH0(0), 182 .ngpio = S5PV210_GPIO_H0_NR, 183 .label = "GPH0", 184 .to_irq = samsung_gpiolib_to_irq, 185 }, 186 }, { 187 .base = (S5P_VA_GPIO + 0xC20), 188 .config = &gpio_cfg_noint, 189 .irq_base = IRQ_EINT(8), 190 .chip = { 191 .base = S5PV210_GPH1(0), 192 .ngpio = S5PV210_GPIO_H1_NR, 193 .label = "GPH1", 194 .to_irq = samsung_gpiolib_to_irq, 195 }, 196 }, { 197 .base = (S5P_VA_GPIO + 0xC40), 198 .config = &gpio_cfg_noint, 199 .irq_base = IRQ_EINT(16), 200 .chip = { 201 .base = S5PV210_GPH2(0), 202 .ngpio = S5PV210_GPIO_H2_NR, 203 .label = "GPH2", 204 .to_irq = samsung_gpiolib_to_irq, 205 }, 206 }, { 207 .base = (S5P_VA_GPIO + 0xC60), 208 .config = &gpio_cfg_noint, 209 .irq_base = IRQ_EINT(24), 210 .chip = { 211 .base = S5PV210_GPH3(0), 212 .ngpio = S5PV210_GPIO_H3_NR, 213 .label = "GPH3", 214 .to_irq = samsung_gpiolib_to_irq, 215 }, 216 }, 217 };struct s3c_gpio_chip s5pv210_gpio_4bit[]
1 void __init samsung_gpiolib_add_4bit_chips(struct s3c_gpio_chip *chip, 2 int nr_chips) 3 { 4 for (; nr_chips > 0; nr_chips--, chip++) { 5 samsung_gpiolib_add_4bit(chip); 6 s3c_gpiolib_add(chip); 7 } 8 }
1 __init void s3c_gpiolib_add(struct s3c_gpio_chip *chip) 2 { 3 struct gpio_chip *gc = &chip->chip;//将struct s3c_gpio_chip结构体成员结构体chip赋值给struct gpio_chip结构体局部变量gc 4 int ret; 5 6 BUG_ON(!chip->base); 7 BUG_ON(!gc->label); 8 BUG_ON(!gc->ngpio); 9 10 spin_lock_init(&chip->lock); 11 12 if (!gc->direction_input) 13 gc->direction_input = s3c_gpiolib_input; 14 if (!gc->direction_output) 15 gc->direction_output = s3c_gpiolib_output; 16 if (!gc->set) 17 gc->set = s3c_gpiolib_set; 18 if (!gc->get) 19 gc->get = s3c_gpiolib_get; 20 21 #ifdef CONFIG_PM 22 if (chip->pm != NULL) { 23 if (!chip->pm->save || !chip->pm->resume) 24 printk(KERN_ERR "gpio: %s has missing PM functions\n", 25 gc->label); 26 } else 27 printk(KERN_ERR "gpio: %s has no PM function\n", gc->label); 28 #endif 29 30 /* gpiochip_add() prints own failure message on error. */ 31 ret = gpiochip_add(gc); 32 if (ret >= 0) 33 s3c_gpiolib_track(chip); 34 }
1 int gpiochip_add(struct gpio_chip *chip) 2 { 3 unsigned long flags; 4 int status = 0; 5 unsigned id; 6 int base = chip->base; 7 8 if ((!gpio_is_valid(base) || !gpio_is_valid(base + chip->ngpio - 1)) 9 && base >= 0) { 10 status = -EINVAL; 11 goto fail; 12 } 13 14 spin_lock_irqsave(&gpio_lock, flags); 15 16 if (base < 0) { 17 base = gpiochip_find_base(chip->ngpio); 18 if (base < 0) { 19 status = base; 20 goto unlock; 21 } 22 chip->base = base; 23 } 24 25 /* these GPIO numbers must not be managed by another gpio_chip */ 26 for (id = base; id < base + chip->ngpio; id++) { 27 if (gpio_desc[id].chip != NULL) { 28 status = -EBUSY; 29 break; 30 } 31 } 32 if (status == 0) { 33 for (id = base; id < base + chip->ngpio; id++) { 34 gpio_desc[id].chip = chip;//在这里gpio_desc[id].chip和struct s3c_gpio_chip建立联系 35 36 /* REVISIT: most hardware initializes GPIOs as 37 * inputs (often with pullups enabled) so power 38 * usage is minimized. Linux code should set the 39 * gpio direction first thing; but until it does, 40 * we may expose the wrong direction in sysfs. 41 */ 42 gpio_desc[id].flags = !chip->direction_input 43 ? (1 << FLAG_IS_OUT) 44 : 0; 45 } 46 } 47 48 of_gpiochip_add(chip); 49 50 unlock: 51 spin_unlock_irqrestore(&gpio_lock, flags); 52 53 if (status) 54 goto fail; 55 56 status = gpiochip_export(chip); 57 if (status) 58 goto fail; 59 60 return 0; 61 fail: 62 /* failures here can mean systems won't boot... */ 63 pr_err("gpiochip_add: gpios %d..%d (%s) failed to register\n", 64 chip->base, chip->base + chip->ngpio - 1, 65 chip->label ? : "generic"); 66 return status; 67 }