GPIO的驅動模型
阿新 • • 發佈:2018-12-30
一、概述 GPIO是嵌入式系統最簡單、最常用的資源了,比如點亮LED,控制蜂鳴器,輸出高低電平,檢測按鍵,等等。GPIO分輸入和輸出,在davinci linux中,有關GPIO的最底層的暫存器驅動,\arch\arm\mach-davinci目錄下的gpio.c,這個是暫存器級的驅動,搞過微控制器MCU的朋友應該比較熟悉暫存器級的驅動。 GPIO的驅動主要就是讀取GPIO口的狀態,或者設定GPIO口的狀態。就是這麼簡單,但是為了能夠寫好的這個驅動,在LINUX上作了一些軟體上的分層。為了讓其它驅動可以方便的操作到GPIO,在LINUX裡實現了對GPIO操作的統一介面,這個介面實則上就是GPIO驅動的框架,具體的實現檔案為gpiolib.c在配置核心的時候,我們必須使用CONFIG_GENERIC_GPIO這個巨集來支援GPIO驅動。 GPIO是與硬體體系密切相關的,linux提供一個模型來讓驅動統一處理GPIO,即各個板卡都有實現自己的gpio_chip控制模組:request, free,input,output, get,set,irq...然後把控制模組註冊到核心中,這時會改變全域性gpio陣列:gpio_desc[]. 當用戶請求gpio時,就會到這個陣列中找到,並呼叫這個GPIO對應的gpio_chip的處理函式。gpio實現為一組可用的 gpio_chip, 由驅動傳入對應 gpio的全域性序號去 request, dataout,datain, free. 這時會呼叫gpio_chip中具體的實現。 gpio是一組可控制元件的腳,由多個暫存器同時控制。通過設定對應的暫存器可以達到設定GPIO口對應狀態與功能。資料狀態,輸入輸出方向,清零,中斷(那個邊沿觸發), 一般是一組(bank)一組的。 暫存器讀寫函式: __raw_writel() __raw_writeb() __raw_readl() __raw_readb() 二、linux 中GPIO模型的結構 //表示一個gpio口,含對應的gpio_chip. //對於每一個gpio,都有一個gpio描述符,這個描述符包含了這個gpio所屬的控制器即chip和一些標誌,label等 struct gpio_desc { struct gpio_chip *chip; unsigned long flags; /* flag symbols are bit numbers */ #define FLAG_REQUESTED 0 #define FLAG_IS_OUT 1 #define FLAG_RESERVED 2 #define FLAG_EXPORT 3 /* protected by sysfs_lock */ #define FLAG_SYSFS 4 /* exported via /sys/class/gpio/control */ #define FLAG_TRIG_FALL 5 /* trigger on falling edge */ #define FLAG_TRIG_RISE 6 /* trigger on rising edge */ #define FLAG_ACTIVE_LOW 7 /* sysfs value has active low */ #define FLAG_OPEN_DRAIN 8 /* Gpio is open drain type */ #define FLAG_OPEN_SOURCE 9 /* Gpio is open source type */ #define ID_SHIFT 16 /* add new flags before this one */ #define GPIO_FLAGS_MASK ((1 << ID_SHIFT) - 1) #define GPIO_TRIGGER_MASK (BIT(FLAG_TRIG_FALL) | BIT(FLAG_TRIG_RISE)) #ifdef CONFIG_DEBUG_FS const char *label; #endif }; //採用了一個具有ARCH_NR_GPIOS大小的gpio描述符陣列。這個描述符陣列便代表了系統所有的gpio。 static struct gpio_desc gpio_desc[ARCH_NR_GPIOS];//ARCH_NR_GPIOS=144,即系統現在有144個GPIO口 //static struct davinci_gpio_controller chips[DIV_ROUND_UP(DAVINCI_N_GPIO, 32)];//將144個GPIO分成每32個一組 //一組GPIO控制器結構,例如GPIO0和GPIO1是一組(共32個GPIO口),共用一組暫存器,所以GPIO0和GPIO1荷載一起用chips[0]來控制 ///共有144個GPIO,分為4組(GPIO0~GPIO8),每組有2個banks(即GPIO0和GPIO1為1組),每組最多可以有32個GPIO,每組的控制暫存器空間有10個。 struct davinci_gpio_controller { struct gpio_chip chip;//每組對應的gpio_chip int irq_base;//每組對應的中斷 spinlock_t lock;//自旋鎖 void __iomem *regs;//每組的暫存器地址 void __iomem *set_data;//設定資料暫存器地址 void __iomem *clr_data;//清除資料暫存器地址 void __iomem *in_data;//輸入資料暫存器地址 }; //每一個davinci_gpio_controller結構都對應於一個gpio_chip結構,gpio_chip既可看成是davinci_gpio_controller結構的補充 //表示一個gpio controller.通過這個結構抽象化所有的GPIO源,而讓板上其它的模組可以用相同的介面呼叫使用這些GPIO。 struct gpio_chip { const char *label; struct device *dev; struct module *owner; int (*request)(struct gpio_chip *chip,unsigned offset);//請求gpio void *free)(struct gpio_chip *chip,unsigned offset);//釋放gpio int (*get_direction)(struct gpio_chip *chip,unsigned offset); int (*direction_input)(struct gpio_chip *chip,unsigned offset);//配置gpio為輸入,返回當前gpio狀態 int (*get)(struct gpio_chip *chip,unsigned offset);//獲取gpio的狀態 int (*direction_output)(struct gpio_chip *chip,unsigned offset, int value);//配置gpio為輸出,並設定為value int (*set_debounce)(struct gpio_chip *chip,unsigned offset, unsigned debounce);//設定消抖動時間,尤其是gpio按鍵時有用 void (*set)(struct gpio_chip *chip,unsigned offset, int value);//設定gpio為value值 int (*to_irq)(struct gpio_chip *chip,unsigned offset);//把gpio號轉換為中斷號 void (*dbg_show)(struct seq_file *s,struct gpio_chip *chip); int base;// 這個gpio控制器的gpio開始編號 u16 ngpio;//這個gpio控制器說控制的gpio數 const char *const *names; unsigned can_sleep:1; unsigned exported:1; #if defined(CONFIG_OF_GPIO) struct device_node *of_node; int of_gpio_n_cells; int (*of_xlate)(struct gpio_chip *gc,const struct of_phandle_args *gpiospec, u32 *flags); #endif #ifdef CONFIG_PINCTRL struct list_head pin_ranges; #endif }; //GPIO暫存器結構 struct davinci_gpio_regs { u32 dir; // gpio方向設定暫存器 u32 out_data; // gpio設定為輸出時,表示輸出狀態(0或1) u32 set_data; // gpio設定為輸出時,用於輸出高電平 u32 clr_data; // gpio設定為輸出時,用於輸出低電平 u32 in_data; // gpio設定為輸入時,用於讀取輸入值 u32 set_rising; // gpio中斷上升沿觸發設定 u32 clr_rising; // gpio中斷上升沿觸發清除 u32 set_falling; // gpio中斷下降沿觸發設定 u32 clr_falling; // gpio中斷下降沿觸發清除 u32 intstat; // gpio中斷狀態位,由硬體設定,可讀取,寫1時清除。 }; struct gpio { unsigned gpio;//gpio號 unsigned long flags;//gpio標誌 const char *label;//gpio名 }; 三、GPIO的初始化 1.首先設定GPIO的管腳複用暫存器 static __init void da850_evm_init(void) { //....... ret = davinci_cfg_reg_list(da850_gpio_test_pins); if (ret) pr_warning("da850_evm_init: gpio test ping mux setup failed: %d\n", ret); //....... } 2.根據板級結構的資源初始化chips陣列,此函式在系統初始化時自動呼叫 static struct davinci_gpio_controller chips[DIV_ROUND_UP(DAVINCI_N_GPIO, 32)];//將144個GPIO分成每32個一組 static int __init davinci_gpio_setup(void) { int i, base; unsigned ngpio; struct davinci_soc_info *soc_info = &davinci_soc_info;//板級資源結構 struct davinci_gpio_regs *regs; if (soc_info->gpio_type != GPIO_TYPE_DAVINCI)//判斷GPIO型別 return 0; ngpio = soc_info->gpio_num;//GPIO數量144 if (ngpio == 0){ pr_err("GPIO setup: how many GPIOs?\n"); return -EINVAL; } if (WARN_ON(DAVINCI_N_GPIO < ngpio))//DAVINCI_N_GPIO=144 ngpio = DAVINCI_N_GPIO; gpio_base = ioremap(soc_info->gpio_base, SZ_4K);//將GPIO的暫存器物理基地址(#define DA8XX_GPIO_BASE 0x01e26000)對映到記憶體中 if (WARN_ON(!gpio_base)) return -ENOMEM; //共有144個GPIO,分為4組(GPIO0~GPIO8),每組有2個banks(即GPIO0和GPIO1為1組),每組最多可以有32個GPIO,每組的控制暫存器空間有10個。 //chips[0]--chips[4],base值為0,32,64,96,128,ngpio分別為:32,32,32,32,16 for (i= 0, base = 0; base < ngpio;i++, base += 32){ chips[i].chip.label= "DaVinci"; //設定操作函式 chips[i].chip.direction_input= davinci_direction_in; chips[i].chip.get= davinci_gpio_get; chips[i].chip.direction_output= davinci_direction_out; chips[i].chip.set= davinci_gpio_set; chips[i].chip.base= base;//每一組開始的GPIO號 //每組控制的GPIO個數,一般為32個 chips[i].chip.ngpio= ngpio - base; if (chips[i].chip.ngpio > 32) chips[i].chip.ngpio= 32; spin_lock_init(&chips[i].lock); //找到這組GPIO的暫存器地址,初始化chips結構 regs = gpio2regs(base); chips[i].regs= regs;//設定每組的暫存器 chips[i].set_data= ?s->set_data; chips[i].clr_data= ?s->clr_data; chips[i].in_data= ?s->in_data; gpiochip_add(&chips[i].chip);//註冊gpio_chip } //chips陣列新增到板級資源中 soc_info->gpio_ctlrs = chips; soc_info->gpio_ctlrs_num = DIV_ROUND_UP(ngpio, 32); davinci_gpio_irq_setup();//設定GPIO中斷 return 0; } pure_initcall(davinci_gpio_setup);//linux初始化時會自動呼叫 static struct davinci_gpio_regs __iomem __init *gpio2regs(unsigned gpio) { void __iomem *ptr; //根據GPIO的基地址累加,其中基地址(gpio_base+0)是REVID(Revision ID Register)暫存器 //(gpio_base+8)是BINTEN(GPIO Interrupt Per-Bank Enable Register)暫存器 //所以第一組暫存器從基地址+0x10開始 if (gpio < 32 * 1) ptr = gpio_base + 0x10; else if (gpio < 32 * 2) ptr = gpio_base + 0x38; else if (gpio < 32 * 3) ptr = gpio_base + 0x60; else if (gpio < 32 * 4) ptr = gpio_base + 0x88; else if (gpio < 32 * 5) ptr = gpio_base + 0xb0; else ptr = NULL; return ptr; } int gpiochip_add(struct gpio_chip *chip) { unsigned long flags; int status = 0; unsigned id; int base = chip->base; //檢測gpio的有效性,判斷這組GPIO的起始號是否在有效範圍內 if ((!gpio_is_valid(base) || !gpio_is_valid(base + chip->ngpio - 1))&& base >= 0){ status = -EINVAL; goto fail; } spin_lock_irqsave(&gpio_lock, flags); //如果這組GPIO的起始號小於0,則動態的分配gpio的開始索引。 if (base < 0){ base = gpiochip_find_base(chip->ngpio);//這個函式在gpiolib.c中,在gpio_desc[]中分配chip->ngpio個空間(從最後往前分配),返回第一個index if (base < 0){ status = base; goto unlock; } chip->base = base; } //確保這些分配的gpio號沒有被其他chip佔用 for (id = base; id < base + chip->ngpio; id++){ if (gpio_desc[id].chip != NULL){ status = -EBUSY; break; } } //填充gpio_desc,將該組內的每個GPIO口的gpio_desc結構和該組的控制結構chip聯絡起來 if (status == 0){ for (id = base; id < base + chip->ngpio; id++){ gpio_desc[id].chip = chip; gpio_desc[id].flags = !chip->direction_input? (1 << FLAG_IS_OUT): 0;//設定GPIO口標誌 } } of_gpiochip_add(chip); unlock: spin_unlock_irqrestore(&gpio_lock, flags); if (status) goto fail; status = gpiochip_export(chip);//與sysfs檔案系統有關,這裡不關心 if (status) goto fail; return 0; fail: /* failures here can mean systems won't boot... */ pr_err("gpiochip_add: gpios %d..%d (%s) failed to register\n",chip->base, chip->base + chip->ngpio - 1,chip->label ? : "generic"); return status; } 四.gpio的申請 //所謂申請就是檢測GPIO描述符desc->flags的FLAG_REQUESTED標誌,已申請的話該標誌是1,否則是0 //往往多個gpio作為一個數組來進行申請 int gpio_request_array(struct gpio *array, size_t num) { int i, err; for (i= 0; i < num; i++, array++){//遍歷陣列中的每一個GPIO,gpio是GPIO號,flags是輸入輸出標誌等,label是其取一個名字 err = gpio_request_one(array->gpio, array->flags, array->label); if (err) goto err_free; } return 0; err_free: while (i--) gpio_free((--array)->gpio); return err; } int gpio_request_one(unsigned gpio, unsigned long flags, constchar *label) { int err; //gpio則為你要申請的哪一個管腳,label則是為其取一個名字。 err = gpio_request(gpio,label); if (err) return err; if (flags & GPIOF_DIR_IN)//GPIO標誌是輸入 err = gpio_direction_input(gpio);//設定管腳為輸入 else//GPIO標誌是輸出 err = gpio_direction_output(gpio,(flags & GPIOF_INIT_HIGH) ? 1: 0);//根據標誌確定輸出1還是0 if (err) gpio_free(gpio); return err; } int gpio_request(unsigned gpio, constchar *label) { struct gpio_desc *desc; struct gpio_chip *chip; int status = -EINVAL; unsigned long flags; //遮蔽中斷 spin_lock_irqsave(&gpio_lock, flags); if (!gpio_is_valid(gpio))//判斷是否有效,也就是引數的取值範圍判斷 goto done; //根據GPIO號找到對應的GPIO描述符結構 desc = &gpio_desc[gpio]; chip = desc->chip;//找到該GPIO所在的組控制器 if (chip == NULL) goto done; //計數加1 if (!try_module_get(chip->owner)) goto done; //這裡測試並設定flags的第FLAG_REQUESTED位,如果沒有被申請就返回該位的原值0 if (test_and_set_bit(FLAG_REQUESTED, &desc->flags)== 0){ desc_set_label(desc,label ? : "?");//設定GPIO描述符結構desc的label欄位 status = 0; } else { status = -EBUSY; module_put(chip->owner); goto done; } if (chip->request){/* chip->request may sleep */ spin_unlock_irqrestore(&gpio_lock, flags); status = chip->request(chip, gpio - chip->base); spin_lock_irqsave(&gpio_lock, flags); if (status < 0){ desc_set_label(desc, NULL); module_put(chip->owner); clear_bit(FLAG_REQUESTED, &desc->flags); } } done: if (status) pr_debug("gpio_request: gpio-%d (%s) status %d\n",gpio,label ? : "?", status); spin_unlock_irqrestore(&gpio_lock, flags); return status; } 五.GPIO的操作 1.設定GPIO為輸出或輸入 int gpio_direction_input(unsigned gpio) { unsigned long flags; struct gpio_chip *chip; struct gpio_desc *desc = &gpio_desc[gpio]; int status = -EINVAL; spin_lock_irqsave(&gpio_lock, flags); //判斷GPIO號是否有效 if (!gpio_is_valid(gpio)) goto fail; //找到GPIO對應的gpio_chip結構 chip = desc->chip; if (!chip || !chip->get || !chip->direction_input) goto fail; //確保此GPIO是在此組內,chip->base是此組GPIO的起始號,chip->ngpio是此組GPIO的個數 gpio -= chip->base; if (gpio >= chip->ngpio) goto fail; //確保GPIO已申請 status = gpio_ensure_requested(desc, gpio); if (status < 0) goto fail; //到這裡可以確保GPIO是有效的 spin_unlock_irqrestore(&gpio_lock, flags); might_sleep_if(chip->can_sleep); //status=0 if (status){ status = chip->request(chip, gpio); if (status < 0){ pr_debug("GPIO-%d: chip request fail, %d\n",chip->base + gpio, status); goto lose; } } //呼叫底層的已經設定過的操作,這裡即davinci_direction_in status = chip->direction_input(chip, gpio); if (status == 0)//返回成功 clear_bit(FLAG_IS_OUT, &desc->flags);//清除輸出標誌 lose: return status; fail: spin_unlock_irqrestore(&gpio_lock, flags); if (status) pr_debug("%s: gpio-%d status %d\n",__func__, gpio, status); return status; } int gpio_direction_output(unsigned gpio, int value) { //.........GPIO的檢查,同上函式 //呼叫底層的已經設定過的操作,這裡即davinci_direction_out status = chip->direction_output(chip, gpio, value); if (status == 0)//返回成功 set_bit(FLAG_IS_OUT, &desc->flags);//設定輸出標誌 lose: return status; fail: spin_unlock_irqrestore(&gpio_lock, flags); if (status) pr_debug("%s: gpio-%d status %d\n",__func__, gpio, status); return status; } //根據前邊對gpio_chip結構的初始化,會呼叫\arch\arm\mach-davinci\gpio.c裡的函式 static int davinci_direction_in(struct gpio_chip *chip, unsigned offset) { return __davinci_direction(chip, offset, false, 0); } static int davinci_direction_out(struct gpio_chip *chip, unsigned offset, int value) { return __davinci_direction(chip, offset, true, value); } static inline int __davinci_direction(struct gpio_chip *chip,unsigned offset, bool out, int value) { struct davinci_gpio_controller *d = chip2controller(chip); struct davinci_gpio_regs __iomem *g = d->regs;//找到此組GPIO的控制暫存器地址 unsigned long flags; u32 temp; u32 mask = 1 << offset; spin_lock_irqsave(&d->lock, flags); temp = __raw_readl(&g->dir);//讀出當前暫存器的輸入輸出方向 if (out){//為1設定輸出 temp &= ~mask; __raw_writel(mask, value ? &g->set_data: &g->clr_data);//確定是用於輸出高電平還是輸出低電平 } else {//為0設定為輸入 temp |= mask; } __raw_writel(temp, &g->dir);//寫入方向暫存器 spin_unlock_irqrestore(&d->lock, flags); return 0; } 2.獲取gpio的狀態 int __gpio_get_value(unsigned gpio) { struct gpio_chip *chip; chip = gpio_to_chip(gpio); WARN_ON(chip->can_sleep); return chip->get ? chip->get(chip, gpio - chip->base): 0;//呼叫davinci_gpio_get } static int davinci_gpio_get(struct gpio_chip *chip, unsigned offset) { struct davinci_gpio_controller *d = chip2controller(chip); struct davinci_gpio_regs __iomem *g = d->regs; return (1 << offset) & __raw_readl(&g->in_data); } 3.設定GPIO的值 void __gpio_set_value(unsigned gpio, int value) { struct gpio_chip *chip; chip = gpio_to_chip(gpio); WARN_ON(chip->can_sleep); chip->set(chip, gpio - chip->base, value);//呼叫davinci_gpio_set } static void davinci_gpio_set(struct gpio_chip *chip, unsigned offset, int value) { struct davinci_gpio_controller *d = chip2controller(chip); struct davinci_gpio_regs __iomem *g = d->regs; __raw_writel((1 << offset), value ? &g->set_data: &g->clr_data); } 六、GPIO驅動編寫 1.首先要申請GPIO口 2.註冊裝置 3.建立GPIO的sysfs相關檔案 #define GPIO_MAJOR 199 // major device NO. #define GPIO_MINOR 0 // minor device NO. #define DEVICE_NAME "omapl138_gpios" /*定義裝置驅動的名字,或裝置節點名稱*/ #define SET_OUTPUT_LOW 0 #define SET_OUTPUT_HIGH 1 #define GET_VALUE 2 #define SET_INPUT 3 static struct class *gpio_class; static struct gpio gpio_array[] = { /*{ GPIO_TO_PIN(0, 0), GPIOF_OUT_INIT_LOW, "RTU_WDI_SIGNAL" },will request fail*/ { GPIO_TO_PIN(0, 1), GPIOF_OUT_INIT_HIGH,"RTU_PLC_BAK_IO1"}, { GPIO_TO_PIN(0, 2), GPIOF_OUT_INIT_LOW, "RTU_CHG_EN" }, { GPIO_TO_PIN(0, 3), GPIOF_IN, "RTU_CHG_PG"}, { GPIO_TO_PIN(0, 5), GPIOF_IN, "RTU_USB_OC_OUT"}, { GPIO_TO_PIN(0, 6), GPIOF_OUT_INIT_LOW, "RTU_RUN_IND_LED" }, { GPIO_TO_PIN(1, 10), GPIOF_IN, "RTU_TSC_BUSY"}, { GPIO_TO_PIN(1, 11), GPIOF_IN, "RTU_PENIRQn"}, { GPIO_TO_PIN(1, 12), GPIOF_OUT_INIT_LOW,"RTU_uP_Q26x_RESET" }, { GPIO_TO_PIN(1, 13), GPIOF_OUT_INIT_HIGH,"RTU_uP_GPRS_PWR_EN" }, { GPIO_TO_PIN(1, 14), GPIOF_OUT_INIT_HIGH,"RTU_uP_Q26x_ON/OFF" }, { GPIO_TO_PIN(2, 1), GPIOF_OUT_INIT_LOW,"RTU_PLC_Reset" }, { GPIO_TO_PIN(2, 2), GPIOF_OUT_INIT_LOW,"RTU_PLC_T_Reg" }, { GPIO_TO_PIN(2, 4), GPIOF_OUT_INIT_LOW,"RTU_PLC_BAK_IO2" }, { GPIO_TO_PIN(2, 5), GPIOF_OUT_INIT_LOW,"RTU_RS485_RE" }, { GPIO_TO_PIN(2, 15), GPIOF_OUT_INIT_HIGH,"RTU_CHPWR_CS" }, { GPIO_TO_PIN(3, 9), GPIOF_OUT_INIT_HIGH,"RTU_RS485_DE" }, { GPIO_TO_PIN(6, 1), GPIOF_OUT_INIT_HIGH,"RTU_uP_VPIF_CLKO3" }, { GPIO_TO_PIN(6, 9), GPIOF_IN, "RTU_KEY_IN2"}, { GPIO_TO_PIN(6, 11), GPIOF_IN, "RTU_ALARM_IN5"}, { GPIO_TO_PIN(6, 15), GPIOF_OUT_INIT_HIGH,"RTU_uP_RESETOUTn"}, }; static int gpio_open(struct inode *inode,struct file *file) { printk(KERN_WARNING"gpio open success!\n"); return 0; } static int gpio_release(struct inode *inode, struct file *filp) { printk (KERN_ALERT "Device gpio released\n"); return 0; } static int gpio_read(struct file*f,char *dst,size_tsize,loff_t*offset) { unsigned char num; __copy_to_user(&num,dst,1); #ifdef DEBUG printk("__copy_to_user:%d\n",num); #endif return 0; } static int gpio_write(struct file*f,constchar *src,size_tsize,loff_t *offset) { unsigned char num; __copy_from_user(&num,src,1); #ifdef DEBUG printk("__copy_from_user:%d\n",num); #endif return 0; } static long gpio_ioctl(struct file *file,unsigned int cmd,unsigned long gpio) { int i; unsigned long gpio_num = (gpio/100)*16+gpio%100; for (i= 0; i < ARRAY_SIZE(gpio_array);i++){ if(gpio_array[i].gpio== gpio_num) goto valid_gpio; } return -1; valid_gpio: switch(cmd)//cmd表示應用程式傳入的 GPIO 動作 { case SET_OUTPUT_LOW://0 { gpio_direction_output(gpio_num, 0); break; } case SET_OUTPUT_HIGH://1 { gpio_direction_output(gpio_num, 1); break; } case GET_VALUE://2 { return gpio_get_value(gpio_num); } case SET_INPUT://3 { gpio_direction_input(gpio_num); break; } default: { printk(KERN_EMERG "GPIO command mistake!!!\n"); break; } } return 0; } static const struct file_operations gpio_fops= { .owner = THIS_MODULE, .open = gpio_open, .release = gpio_release, .read = gpio_read, .write = gpio_write, .unlocked_ioctl = gpio_ioctl, }; static int __init gpio_init(void)/*核心初始化會呼叫該函式*/ { int ret; ret = gpio_request_array(gpio_array, ARRAY_SIZE(gpio_array)); if (ret < 0) { printk(KERN_EMERG "GPIO request failed\n"); goto request_failed; } dev_t my_dev_no; struct cdev *gpio_cdev; gpio_cdev = cdev_alloc(); if(gpio_cdev == NULL) { printk(KERN_EMERG "Cannot alloc cdev\n"); goto request_failed; } cdev_init(gpio_cdev,&gpio_fops); gpio_cdev->owner=THIS_MODULE; int result=alloc_chrdev_region(&my_dev_no,0,1,DEVICE_NAME); if(result < 0) { printk(KERN_EMERG "alloc_chrdev_region failed\n"); goto request_failed; } ret=cdev_add(gpio_cdev,my_dev_no,1); ret = register_chrdev(GPIO_MAJOR, DEVICE_NAME, &gpio_fops);//驅動字元裝置 if(ret < 0) { printk(KERN_EMERG "GPIO register failed\n"); goto request_failed; } //在sysfs檔案系統下建立一個類 gpio_class = class_create(THIS_MODULE, DEVICE_NAME); //device_create-->device_create_vargs-->device_register建立相應的sysfs檔案(如dev檔案),用於udev根據sysfs檔案系統下的dev檔案建立裝置節點 device_create(gpio_class, NULL, MKDEV(GPIO_MAJOR, GPIO_MINOR), NULL, DEVICE_NAME); return ret; request_failed: gpio_free_array(gpio_array, ARRAY_SIZE(gpio_array)); return ret; } static void __exit gpio_exit(void) { device_destroy(gpio_class, MKDEV(GPIO_MAJOR, GPIO_MINOR)); class_unregister(gpio_class); class_destroy(gpio_class); unregister_chrdev(GPIO_MAJOR, DEVICE_NAME); } module_init(gpio_init); module_exit(gpio_exit); MODULE_LICENSE("GPL"); MODULE_VERSION ("v2.0"); MODULE_AUTHOR("wbl <>"); MODULE_DESCRIPTION("OMAPL138 GPIO driver");