Effective C++ 条款08:别让异常逃离析构函数
2026/6/10 7:51:43
最近在工作中遇到了gpio解析失败的问题,跟踪发现设备树配置的字符串不匹配,在这里再次学习并记录下。
/** * devm_gpiod_get - Resource-managed gpiod_get() * @dev: GPIO consumer * @con_id: function within the GPIO consumer * @flags: optional GPIO initialization flags * * Managed gpiod_get(). GPIO descriptors returned from this function are * automatically disposed on driver detach. See gpiod_get() for detailed * information about behavior and return values. */structgpio_desc*__must_checkdevm_gpiod_get(structdevice*dev,constchar*con_id,enumgpiod_flagsflags){returndevm_gpiod_get_index(dev,con_id,0,flags);}此接口是linux内核标准接口,下面来解析下其具体的参数函义:
enumgpiod_flags{GPIOD_ASIS=0,GPIOD_IN=GPIOD_FLAGS_BIT_DIR_SET,GPIOD_OUT_LOW=GPIOD_FLAGS_BIT_DIR_SET|GPIOD_FLAGS_BIT_DIR_OUT,GPIOD_OUT_HIGH=GPIOD_FLAGS_BIT_DIR_SET|GPIOD_FLAGS_BIT_DIR_OUT|GPIOD_FLAGS_BIT_DIR_VAL,GPIOD_OUT_LOW_OPEN_DRAIN=GPIOD_OUT_LOW|GPIOD_FLAGS_BIT_OPEN_DRAIN,GPIOD_OUT_HIGH_OPEN_DRAIN=GPIOD_OUT_HIGH|GPIOD_FLAGS_BIT_OPEN_DRAIN,};static__maybe_unusedconstchar*constgpio_suffixes[]={"gpios","gpio"};structgpio_desc*of_find_gpio(structdevice_node*np,constchar*con_id,unsignedintidx,unsignedlong*flags){charprop_name[32];/* 32 is max size of property name */enumof_gpio_flagsof_flags;constof_find_gpio_quirk*q;structgpio_desc*desc;unsignedinti;/* Try GPIO property "foo-gpios" and "foo-gpio" */for(i=0;i<ARRAY_SIZE(gpio_suffixes);i++){if(con_id)snprintf(prop_name,sizeof(prop_name),"%s-%s",con_id,gpio_suffixes[i]);elsesnprintf(prop_name,sizeof(prop_name),"%s",gpio_suffixes[i]);desc=of_get_named_gpiod_flags(np,prop_name,idx,&of_flags);if(!gpiod_not_found(desc))break;}/* Properly named GPIO was not found, try workarounds */for(q=of_find_gpio_quirks;gpiod_not_found(desc)&&*q;q++)desc=(*q)(np,con_id,idx,&of_flags);if(IS_ERR(desc))returndesc;*flags=of_convert_gpio_flags(of_flags);returndesc;}structof_phandle_args{structdevice_node*np;intargs_count;uint32_targs[MAX_PHANDLE_ARGS];};staticstructgpio_chip*of_find_gpiochip_by_xlate(structof_phandle_args*gpiospec){returngpiochip_find(gpiospec,of_gpiochip_match_node_and_xlate);}structgpio_chip*gpiochip_find(void*data,int(*match)(structgpio_chip*gc,void*data)){structgpio_device*gdev;structgpio_chip*gc=NULL;unsignedlongflags;spin_lock_irqsave(&gpio_lock,flags);list_for_each_entry(gdev,&gpio_devices,list)if(gdev->chip&&match(gdev->chip,data)){gc=gdev->chip;break;}spin_unlock_irqrestore(&gpio_lock,flags);returngc;}上述代码很明显,轮询所有的gpio控制器。从而找到匹配的控制器,匹配的规则也很简单就两点:
staticintof_gpiochip_match_node_and_xlate(structgpio_chip*chip,void*data){structof_phandle_args*gpiospec=data;returndevice_match_of_node(&chip->gpiodev->dev,gpiospec->np)&&chip->of_xlate&&chip->of_xlate(chip,gpiospec,NULL)>=0;}staticstructgpio_desc*of_xlate_and_get_gpiod_flags(structgpio_chip*chip,structof_phandle_args*gpiospec,enumof_gpio_flags*flags){intret;if(chip->of_gpio_n_cells!=gpiospec->args_count)returnERR_PTR(-EINVAL);ret=chip->of_xlate(chip,gpiospec,flags);if(ret<0)returnERR_PTR(ret);returngpiochip_get_desc(chip,ret);}这里的函数实现完全依赖控制器,代码逻辑比较简单,这里要搞懂这个实现。需要找一个gpio控制器来研究下,这里以gpio-sprd.c为例
staticintsprd_gpio_probe(structplatform_device*pdev){structgpio_irq_chip*irq;structsprd_gpio*sprd_gpio;sprd_gpio=devm_kzalloc(&pdev->dev,sizeof(*sprd_gpio),GFP_KERNEL);if(!sprd_gpio)return-ENOMEM;sprd_gpio->irq=platform_get_irq(pdev,0);if(sprd_gpio->irq<0)returnsprd_gpio->irq;sprd_gpio->base=devm_platform_ioremap_resource(pdev,0);if(IS_ERR(sprd_gpio->base))returnPTR_ERR(sprd_gpio->base);spin_lock_init(&sprd_gpio->lock);sprd_gpio->chip.label=dev_name(&pdev->dev);sprd_gpio->chip.ngpio=SPRD_GPIO_NR;sprd_gpio->chip.base=-1;sprd_gpio->chip.parent=&pdev->dev;sprd_gpio->chip.request=sprd_gpio_request;sprd_gpio->chip.free=sprd_gpio_free;sprd_gpio->chip.get=sprd_gpio_get;sprd_gpio->chip.set=sprd_gpio_set;sprd_gpio->chip.direction_input=sprd_gpio_direction_input;sprd_gpio->chip.direction_output=sprd_gpio_direction_output;irq=&sprd_gpio->chip.irq;gpio_irq_chip_set_chip(irq,&sprd_gpio_irqchip);irq->handler=handle_bad_irq;irq->default_type=IRQ_TYPE_NONE;irq->parent_handler=sprd_gpio_irq_handler;irq->parent_handler_data=sprd_gpio;irq->num_parents=1;irq->parents=&sprd_gpio->irq;returndevm_gpiochip_add_data(&pdev->dev,&sprd_gpio->chip,sprd_gpio);}这里此控制器的定义,从上可以看出此控制器并没有定义。如果控制器没有定义此回调函数,则会使用系统默认提供的回调函数of_gpio_simple_xlate
此函数是公用的回调函数,如果控制器定义了自己的xlate函数则使用控制器自身的,如果没有就会使用此函数。到这里gpio的解析流程就基本走完了,对gpio子系统认识进一步加深。