ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [LINUX][KERNEL] sysfs attribute 구조체 및 매크로 상속 관계
    Linux/kernel 2023. 8. 3. 02:28

    목적

    - 어느 날 문득 sysfs attribute를 만들려고 하는데, ATTR과 DEVICE_ATTR 중에 뭘 써야할 지 고민했다. 그래서 정리를 좀 해보려고 한다.

     

    내용

    - 결론부터 말하면 모든 *_DEVICE_ATTR[_*] 패밀리들은 결국 ATTR[_*]을 상속한다. 결국 최상위가 ATTR[_*]란 소리이다.

     

    구조는 아래와 같다.

     

    /include/linux/sysfs.h
    struct attribute {
    	const char		*name;
    	umode_t			mode;
    #ifdef CONFIG_DEBUG_LOCK_ALLOC
    	bool			ignore_lockdep:1;
    	struct lock_class_key	*key;
    	struct lock_class_key	skey;
    #endif
    };
    
    ...
    ...
    
    /include/linux/device.h
    struct device_attribute {
    	struct attribute	attr;
    	ssize_t (*show)(struct device *dev, struct device_attribute *attr,
    			char *buf);
    	ssize_t (*store)(struct device *dev, struct device_attribute *attr,
    			 const char *buf, size_t count);
    };
    
    ...
    ...
    
    /include/linux/iio/sysfs.h
    struct iio_dev_attr {
    	struct device_attribute dev_attr;
    	u64 address;
    	struct list_head l;
    	struct iio_chan_spec const *c;
    };
    
    ...
    ...
    
    struct sensor_device_attribute{
    	struct device_attribute dev_attr;
    	int index;
    };

     

    구조체 상속 구조는 다음과 같다.

     

    • struct sensor_device_attribute -> 제일 최하위
    • struct iio_dev_attr 
      • struct device_attribute
        • strcut attribute -> 제일 최상위

     


    구조체의 상속 구조와 다르게 매크로는 조금 다르다.

     

    #define DEVICE_ATTR(_name, _mode, _show, _store) \
    	struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store)
        
    ...
    ...
    
    
    #define SENSOR_ATTR(_name, _mode, _show, _store, _index)	\
    	{ .dev_attr = __ATTR(_name, _mode, _show, _store),	\
    	  .index = _index }
          
    ...
    ...
    
    
    #define IIO_ATTR(_name, _mode, _show, _store, _addr)		\
    	{ .dev_attr = __ATTR(_name, _mode, _show, _store),	\
    	  .address = _addr }
    
    ...
    ...
    
    #define __ATTR(_name, _mode, _show, _store) {				\
    	.attr = {.name = __stringify(_name),				\
    		 .mode = VERIFY_OCTAL_PERMISSIONS(_mode) },		\
    	.show	= _show,						\
    	.store	= _store,						\
    }

     

    매크로 상속 구조는 다음과 같다.

     

    • DEVICE_ATTR 
    • SENSOR_ATTR 
    • IIO_ATTR
      • __ATTR 

     

    매크로 구조에서 주의할 점이 있다. 구조체 변수를 정적으로 선언해주는 매크로와 구조체 변수는 선언하지 않고, 그 안에 값을 채워주는 매크로로 나눌 수 있다.

     

     

    /* 
    	- 정적으로 변수를 해주는 매크로 
    	- 예를 들어, DEVICE_ATTR(yohda, 0644, NULL, NULL); 를 작성하면 dev_attr_yohda 라는 변수를 정적으로 선언한다.
    */
    #define DEVICE_ATTR(_name, _mode, _show, _store) \
    	struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store)
       
    
    /* 
    	- 정적으로 변수를 선언해주지 않는다.
    	- struct sensor_device_attribute yohda_attr = SENSOR_ATTR(yohda, 0644, NULL, NULL, 0); 과 같이 작성해야 한다.
    */
    #define SENSOR_ATTR(_name, _mode, _show, _store, _index)	\
    	{ .dev_attr = __ATTR(_name, _mode, _show, _store),	\
    	  .index = _index }

     

     

    결론

    - 나는 주로 간단한 몇 개 되지 않는 2~3개 정도의 attribute들은 정적 선언 매크로를 사용한다. 그러나 hwmon나 iio쪽 driver 코드들을 보면 group 단위의 많은 attribute가 필요할 때는, 속성을 채워주는 형식의 매크로를 많이 사용한다.

Designed by Tistory.