Me gustaría exponer algunas configuraciones de mi dispositivo a través de sysfs. Si lo entiendo bien, un controlador puede tener varios dispositivos, por lo que debe haber una instancia de la variable de configuración por dispositivo. Esto debería ser bastante fácil usando DEVICE_ATTR
macro.
Al revisar las fuentes, noté que también hay DEVICE_INT_ATTR
y otras con diferentes tipos. Me pregunto cuál es el uso previsto, ya que usan device_show_int
funciones que apuntan al dispositivo, pero en realidad no lo usan:
ssize_t device_store_int(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
{
struct dev_ext_attribute *ea = to_ext_attr(attr);
int ret;
long new;
ret = kstrtol(buf, 0, &new);
if (ret)
return ret;
if (new > INT_MAX || new < INT_MIN)
return -EINVAL;
*(int *)(ea->var) = new;
/* Always return full write size even if we didn't consume all */
return size;
}
EXPORT_SYMBOL_GPL(device_store_int);
Busqué fuentes del kernel para esas macros, y parece que funcionan con una variable global. Por ejemplo DEVICE_INT_ATTR
, se usa en drivers/base/core.c para mca_cfg.tolerant
:
static DEVICE_INT_ATTR(tolerant, 0644, mca_cfg.tolerant);
pero la mca_cfg
variable es en realidad global, no está vinculada a un dispositivo:
struct mca_config mca_cfg __read_mostly = {
.bootlog = -1,
/*... */
.tolerant = 1,
.monarch_timeout = -1
};
lo que hace que parezca un atributo de controlador (no de dispositivo).
También verifiqué el compromiso que agrega estas macros, pero no me ayudó mucho.
Solución del problema
Usted toma correctamente esa DEVICE_INT_ATTR
y otras macros de esa familia para atributos "globales", que store
y los show
métodos no usan dev
parámetros.
Si desea definir un atributo, que se puede vincular a varios dispositivos, puede escribir su propio método store
y obtener información sobre el valor de.show
dev
Por ejemplo, al tener un dispositivo
struct my_device
{
struct device base;
int repetition;
};
podría exponer su repetition
campo en el atributo usando el siguiente show
método:
// Shows value of 'repetition' field of my_device.
static ssize_t repetition_show(struct device *dev, struct device_attribute *attr, char *buf)
{
// Obtain pointer to the real device structure.
struct my_device* my_dev = container_of(dev, struct my_device, base);
return sprintf(buf, "%d\n", my_dev->repetition);
}
La estructura de tal atributo podría inicializarse usando una __ATTR
macro:
static struct device_attribute repetition_attr =
__ATTR(repetition, S_IRUGO, repetition_show, NULL);
Hacer atributos "genéricos"
Suponga que la estructura de su dispositivo contiene muchos int
campos, que desea exponer a través de atributos:
struct my_device
{
struct device base;
int repetition;
int counter;
int value;
};
En ese caso, podría generalizar la definición de atributo, por lo que no necesita crear muchas show
(y store
) funciones.
Por ejemplo, podría almacenar el desplazamiento del campo expuesto en su estructura de atributos:
struct device_bounded_attr
{
struct device_attribute base_attr;
size_t field_offset;
};
// Initializer for struct device_bounded_attr
//
// - real_device_type - type of the actual device structure
// - device_member - member of type 'struct device' in the actual device structure
// - field_member - member in actual device structure which you want to expose as attribute.
#define BOUNDED_ATTR(name, mode, show, store, real_device_type, device_member, field_member) { \
.base_attr = __ATTR(name, mode, show, store), \
.field_offset = offsetof(real_device_type, field_member) - offsetof(real_device_type, device_member)
}
Usando este campo, puede reescribir show
el método de la siguiente manera:
// Shows value of integer field, stored in device.
static ssize_t bounded_attr_show(struct device *dev, struct device_attribute *attr, char *buf)
{
// Obtain pointer to the real attribute structure.
struct device_bounded_attr* bounded_attr = container_of(attr, struct device_bounded_attr, base_attr);
// Having offset of the field, calculate pointer to it
int field_ptr* = (int*)(((char*)dev) + bounded_attr->field_offset);
return sprintf(buf, "%d\n", *field_ptr);
}
Entonces los atributos se pueden declarar de la siguiente manera:
static struct device_bounded_attr repetition_attr =
BOUNDED_ATTR(repetition, S_IRUGO, bounded_attr_show, NULL, struct my_device, base, repetition);
static struct device_bounded_attr counter_attr =
BOUNDED_ATTR(counter, S_IRUGO, bounded_attr_show, NULL, struct my_device, base, counter);
static struct device_bounded_attr value_attr =
BOUNDED_ATTR(counter, S_IRUGO, bounded_attr_show, NULL, struct my_device, base, value);
No hay comentarios:
Publicar un comentario