[Linux Kernel] gpio_request_one

초기화 할 때 gpio_request 를 하고 값을 셋팅하는 걸 한방에 할 수 있는 방법!
gpio_request_one 을 쓰시라~

int gpio_request_one(unsigned gpio, unsigned long flags, const char *label);

기존의 GPIOF_ 가 다음과 같으므로

* GPIOF_DIR_IN		- to configure direction as input 
* GPIOF_DIR_OUT		- to configure direction as output

* GPIOF_INIT_LOW - as output, set initial level to LOW
* GPIOF_INIT_HIGH	- as output, set initial level to HIGH

flags 에는 다음과 같은 값들을 쓸 수 있다. 이름을 보면 대충 뭐하는지 다 알 듯.

* GPIOF_IN		- configure as input
* GPIOF_OUT_INIT_LOW	- configured as output, initial level LOW
* GPIOF_OUT_INIT_HIGH	- configured as output, initial level HIGH

그리고 array 로 만들어서 한방에 할 수도 있다.

static struct gpio leds_gpios[] = { 
	{ 32, GPIOF_OUT_INIT_HIGH, "Power LED" }, /* default to ON */
	{ 33, GPIOF_OUT_INIT_LOW,  "Green LED" }, /* default to OFF */
	{ 34, GPIOF_OUT_INIT_LOW,  "Red LED"   }, /* default to OFF */
	{ 35, GPIOF_OUT_INIT_LOW,  "Blue LED"  }, /* default to OFF */
	{ ... },
};

err = gpio_request_array(leds_gpios, ARRAY_SIZE(leds_gpios)); 
if (err)
	...

당연히 array 를 free하는 것도 있다.

gpio_free_array(leds_gpios, ARRAY_SIZE(leds_gpios))

request 할 때 맨 뒤의 label 을 만들 때 kasprintf() 를 이용하면 내부에서 kmalloc 해서 잡아준다. 런타임에 label을 정하거나 할 때 유용히 쓸 수 있다.

 char *label = kasprintf(GFP_KERNEL, “LED %d”, i);

 gpio_request_one(32, GPIOF_OUT_INIT_HIGH, label);

 …
 gpio_free(32);
 kfree(label);

이 문서의 라이센스는 GPL을 따른다(This document is released under the GPL license.)

참고 : 
http://lwn.net/Articles/369182/  

[gcc] gcc 확장 __builtin_constant_p(exp)

Documentation/CodingStyle에서 inline disease 에 언급된 (slab 기준) kmalloc 구현을 살펴보다가 눈에 띄어서 정리해 둔다.
__builtin_constant_p(exp) 는 컴파일 타임에 상수로 정해질 수 있는 경우에 1을, 아닌 경우에는 0을 리턴한다. 따라서 이 조건에 따라 다른 코드를 사용함으로 써 최적화할 수 있도록 할 수 있다.

(이 글을 쓰는 시점인 v3.3-rc6 기준)kmalloc 의 경우 다음과 같이 구현되어 있다.

include/linux/slab_def.h

static __always_inline void *kmalloc(size_t size, gfp_t flags)

{
	struct kmem_cache *cachep;
	void *ret;

	if (__builtin_constant_p(size)) {
		int i = 0;

		if (!size)
			return ZERO_SIZE_PTR;

#define CACHE(x) \
		if (size <= x) \
			goto found; \
		else \
			i++;
#include <linux/kmalloc_sizes.h>
#undef CACHE
		return NULL;
found:
#ifdef CONFIG_ZONE_DMA
		if (flags & GFP_DMA)
			cachep = malloc_sizes[i].cs_dmacachep;
		else
#endif
			cachep = malloc_sizes[i].cs_cachep;

		ret = kmem_cache_alloc_trace(size, cachep, flags);

		return ret;
	}
	return __kmalloc(size, flags);
}

이외에도 __always_inline 사용, CACHE(x) 매크로를 상황에 따라 define하고 linux/kmalloc_sizes.h 헤더를 include 하여 사용하는 부분은 매우 흥미롭다. __always_inline 은 gcc의 function attribute 를 이용한다.

이 글의 라이센스는 GPL 을 따른다(This document is released under the GPL licence.).

참고 : 
http://gcc.gnu.org/onlinedocs/gcc-4.6.3/gcc/Other-Builtins.html