/*****************************************************************************
簡 述:簡單字符型驅動程序,手動靜態分配設備號,手動創建設備節點
******************************************************************************/
#include <linux/module.h>
#include #include #include #include #include #include #define DEVICE_NAME 'leds' struct button_desc { int gpio; int number; char *name; }; struct led_desc { int gpio; int number; char *name; }; static struct button_desc buttons[] = { { S5PV210_GPH2(0), 0, 'KEY0' }, { S5PV210_GPH2(1), 1, 'KEY1' }, { S5PV210_GPH2(2), 2, 'KEY2' }, { S5PV210_GPH2(3), 3, 'KEY3' }, { S5PV210_GPH3(0), 4, 'KEY4' }, { S5PV210_GPH3(1), 5, 'KEY5' }, { S5PV210_GPH3(2), 6, 'KEY6' }, { S5PV210_GPH3(3), 7, 'KEY7' }, }; static struct led_desc leds[] = { {S5PV210_GPJ2(0),1,'LED1'}, {S5PV210_GPJ2(1),2,'LED2'}, {S5PV210_GPJ2(2),3,'LED3'}, {S5PV210_GPJ2(3),4,'LED4'}, }; #define OK (0) #define ERROR (-1) dev_t devNum; unsigned int subDevNum = 1;//要申請的次設備號個數 int reg_major = 234; int reg_minor = 0; static irqreturn_t button_interrupt(int irq, void *dev_id) { struct button_desc *bdata = (struct button_desc *)dev_id; int down; unsigned tmp; tmp = gpio_get_value(bdata->gpio); /* active low */ down = !tmp; printk('KEY %d: %08xn', bdata->number, down); if(bdata->number < 4) { gpio_set_value(leds[bdata->number].gpio,0); printk('LED %d: On n',leds[bdata->number].number); } else { gpio_set_value(leds[(bdata->number) - 4].gpio,1); printk('LED %d: OFF n',leds[(bdata->number)-4].number); } return IRQ_HANDLED; } int butsOpen(struct inode *p, struct file *f) { int irq; int i; int err = 0; printk(KERN_EMERG'butsOpenrn'); for (i = 0; i < ARRAY_SIZE(buttons); i++) { if (!buttons[i].gpio) continue; irq = gpio_to_irq(buttons[i].gpio); // irq = IRQ_EINT(16)+i =160+i 'S5PV210_GPH2(i)' //irq = IRQ_EINT(24)+i =168+i 'S5PV210_GPH3(i)' err = request_irq(irq, button_interrupt, IRQ_TYPE_EDGE_FALLING, buttons[i].name, (void *)&buttons[i]); if (err) break; } for(i = 0; i if(!leds[i].gpio) continue; gpio_direction_output(leds[i].gpio,1); } if (err) { i--; for (; i >= 0; i--) { if (!buttons[i].gpio) continue; irq = gpio_to_irq(buttons[i].gpio); disable_irq(irq); free_irq(irq, (void *)&buttons[i]); } return -EBUSY; } return 0; } static const struct file_operations gFile = { .owner = THIS_MODULE, .open = butsOpen, }; int charDrvInit(void) { devNum = MKDEV(reg_major, reg_minor); printk(KERN_EMERG'devNum is %drn', devNum); if(OK == register_chrdev(reg_major, DEVICE_NAME, &gFile)) { printk(KERN_EMERG 'register_chrdev_region okrn'); } else { printk(KERN_EMERG'register_chrdev_region errorrn'); return ERROR; } printk(KERN_EMERG 'button driver initial done...rn'); return 0; } void __exit charDrvExit(void) { int i,irq; unregister_chrdev(reg_major, DEVICE_NAME); for (i = 0; i < ARRAY_SIZE(buttons); i++) { if (!buttons[i].gpio) continue; irq = gpio_to_irq(buttons[i].gpio); disable_irq(irq); free_irq(irq, (void *)&buttons[i]); } return; } module_init(charDrvInit);//執行insmod時會執行此行代碼并調用charDrvInit,驅動開始 module_exit(charDrvExit);//執行rmmod時,結束 MODULE_LICENSE('GPL'); MODULE_AUTHOR('LiuB'); 復制代碼 res = register_chrdev(I2C_MAJOR, 'i2c', &i2cdev_fops); 復制代碼 res = register_chrdev(I2C_MAJOR, 'i2c', &i2cdev_fops); static inline int register_chrdev(unsigned int major, const char *name, const struct file_operations *fops) { return __register_chrdev(major, 0, 256, name, fops); } int __register_chrdev(unsigned int major, unsigned int baseminor, unsigned int count, const char *name,const struct file_operations *fops) { struct char_device_struct *cd; struct cdev *cdev; cd = __register_chrdev_region(major, baseminor, count, name); { struct char_device_struct *cd, **cp; cd = kzalloc(sizeof(struct char_device_struct), GFP_KERNEL); cd->major = major; cd->baseminor = baseminor; cd->minorct = minorct; strlcpy(cd->name, name, sizeof(cd->name)); i = major_to_index(major); for (cp = &chrdevs[i]; *cp; cp = &(*cp)->next) 。。。。。 //找到可以添加新的設備的位置*cp //此處cd為鏈表中唯一節點,cd->next = NULL,所以這句代碼相當于在cd鏈表后添加一個節點*cp cd->next = *cp; //繼續讓cd指向鏈表尾 *cp = cd; mutex_unlock(&chrdevs_lock); return cd; } cdev = cdev_alloc();//給局部結構體變量cdev分配空間 //將register_chrdev(I2C_MAJOR, 'i2c', &i2cdev_fops)中的i2cdev_fops結構體的具體內容賦給新建的cdev結構體 cdev->owner = fops->owner; cdev->ops = fops; kobject_set_name(&cdev->kobj, '%s', name); //添加設備 err = cdev_add(cdev, MKDEV(cd->major, baseminor), count); { //dev= MKDEV(cd->major, baseminor) cdev->dev = dev;//添加設備號 cdev->count = count;//設備個數 //將指定的設備號加入到管理設備號及其對應設備的kobj_map結構體中的probe數組中 return kobj_map(cdev_map, dev, count, NULL, exact_match, exact_lock, p); } cd->cdev = cdev;//將賦值完成的cdev傳到結構體cd中的cdev結構體成員 return major ? 0 : cd->major; } 退出for循環的四種情況:for (cp = &chrdevs[i]; *cp; cp = &(*cp)->next)
1、已存在的主設備號大于即將新添加的主設備號
2、已存在的主設備號等于即將新添加的主設備號&&并且次設備最小號大于新注冊的次設備最小號
3、已存在的主設備號等于即將新添加的主設備號&&次設備最小號等于新注冊的次設備最小號
4、已存在的主設備號等于即將新添加的主設備號&&次設備最小號小于新注冊的次設備最小號&&新注冊的次設備最小號小于已存在的次設備號范圍(最小號+個數)
注:
1、對于第一種情況跳過下面的if判斷注冊到鏈表中
2、對于第二、三、四種情況在跳出for循環后繼續進行下面判斷來分析是否沖突,如果不沖突則注冊到鏈表中
上一篇:字符設備驅動(1)代碼分析---之gpio_get_value
下一篇:三星S5-PV210內存初始化
推薦閱讀最新更新時間:2025-04-23 17:43


設計資源 培訓 開發板 精華推薦
- 使用 STMicroelectronics 的 L99MOD54XPTR 的參考設計
- 使用 ROHM Semiconductor 的 BD9141MUV 的參考設計
- 使用 NXP Semiconductors 的 TDA1519C 的參考設計
- TB62717F 24 位恒流驅動器(3x8 位移位寄存器/鎖存器)的典型應用
- LT1764AEFE-2.5 并聯 LDO 穩壓器以實現更高輸出電流的典型應用
- LT1634BIS8-1.25 超準確 ±4.096V 輸出電壓基準的典型應用
- 具有遲滯功能的 LM358ADR2G 比較器的典型應用
- NCP3065SOBCKGEVB:降壓演示評估板
- 臺州路橋中學PCB-NFC校園卡
- 使用 ROHM Semiconductor 的 BD25GA5WEFJ 的參考設計