request_mem_region()实际上做什么以及何时需要它?

我正在研究编写嵌入式Linux驱动程序,并决定开发一些GPIO以确保我正确理解本书(LDD3,第9.4.1节) 。

我可以按照预期控制正确的GPIO引脚(使其高低,用万用表探测); 但是,我测试了2个代码,一个是request_mem_region() ,另一个没有。 我期待一个没有失败的人,但两个都工作得很好。

代码为request_mem_region

 if( request_mem_region( PIN3_CONF_PHYS, MAPPED_SIZE_GPIO_CONF,DEVICE_NAME ) == NULL ) { printk( KERN_ALERT "GPIO_140_141_conf_phys error:%s: unable to obtain I/O memory address 0x%08llX\n", DEVICE_NAME, PIN3_CONF_PHYS ); return -EBUSY; } pin3_conf = (u32)ioremap( PIN3_CONF_PHYS, MAPPED_SIZE_GPIO_CONF); pin4_conf = (u32)ioremap( PIN4_CONF_PHYS, MAPPED_SIZE_GPIO_CONF); pin5_conf = (u32)ioremap( PIN5_CONF_PHYS, MAPPED_SIZE_GPIO_CONF); pin6_conf = (u32)ioremap( PIN6_CONF_PHYS, MAPPED_SIZE_GPIO_CONF); //----------------------------------------------------------------- if( request_mem_region( GPIO_BANK5_PHYS, MAPPED_SIZE_GPIO_5,DEVICE_NAME ) == NULL ) { printk( KERN_ALERT "error:%s: unable to obtain I/O memory address 0x%08llX\n", DEVICE_NAME, GPIO_BANK5_PHYS ); return -EBUSY; } gpio_virt = (u32)ioremap( GPIO_BANK5_PHYS, MAPPED_SIZE_GPIO_5 ); //some iowrite32() functions continue... 

没有request_mem_region()代码:

 pin3_conf = (u32)ioremap( PIN3_CONF_PHYS, MAPPED_SIZE_GPIO_CONF); pin4_conf = (u32)ioremap( PIN4_CONF_PHYS, MAPPED_SIZE_GPIO_CONF); pin5_conf = (u32)ioremap( PIN5_CONF_PHYS, MAPPED_SIZE_GPIO_CONF); pin6_conf = (u32)ioremap( PIN6_CONF_PHYS, MAPPED_SIZE_GPIO_CONF); gpio_virt = (u32)ioremap( GPIO_BANK5_PHYS, MAPPED_SIZE_GPIO_5 ); //some iowrite32() functions continue... 

我可以从两种情况中看到的唯一区别是执行cat /proc/iomemrequest_mem_region()将显示另一行显示49056000-49056097 : GPIO3

我的问题是为什么需要request_mem_region() ,因为我仍然可以只用ioremap()与硬件地址通信? 那么我们什么时候才真正需要使用request_mem_region()

谢谢你的回复!

request_mem_region告诉内核你的驱动程序将使用这个范围的I / O地址,这将阻止其他驱动程序通过request_mem_region对同一区域进行任何重叠调用。 这种机制不做任何类型的映射,它是一种纯粹的预留机制,它依赖于所有内核设备驱动程序必须很好的事实,并且它们必须调用request_mem_region ,检查返回值,并在出现错误时正常运行。

因此,没有request_mem_region ,您的代码可以正常工作,这只是因为它不符合内核编码规则。

但是,您的代码不符合内核编码风格。 此外,还有一个现有的基础设施来处理GPIO,名为gpiolib,你应该使用它而不是手动重新映射你的GPIO库寄存器。 你在做哪个平台?

现在不推荐在设备驱动程序中使用request_mem_region()和ioremap()。 您应该使用下面的“托管”函数,这样可以简化驱动程序编码和error handling:

 devm_ioremap() devm_iounmap() devm_ioremap_resource(), Takes care of both the request and remapping operations 

https://bootlin.com/doc/training/linux-kernel/linux-kernel-slides.pdf slide 276