Class create linux kernel

Framework for registering Linux kernel driver as class device / How to add new class to Linux kernel

Following simple driver code shows, how to add a new class with name “hello_as_class” can be added to linux kernel.

#include /* Needed by all modules */ #include /* Needed for KERN_INFO */ #include /* Needed for the macros */ #include // for struct class static struct class hello_class = < .name = "hello_as_class", .owner = THIS_MODULE, >; static int __init hello_init(void) < class_register(&hello_class); printk(KERN_INFO "Hello, world\n"); return 0; >static void __exit hello_exit(void) < class_unregister(&hello_class); printk(KERN_INFO "Goodbye, world\n"); >module_init(hello_init); module_exit(hello_exit); MODULE_LICENSE("GPL");

Now, we will write the makefile to get this code compiled as,

obj-m += hello.o all: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules clean: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

We can check whether this driver is inserted or not as,

$ lsmod | grep hello hello 16384 0 

This driver will create a directory as, /sys/class/hello_as_class

 $ cd /sys/class/hello_as_class 

Now, if we see kernel source code, struct class has been declared in include/linux/device.h as,

/** * struct class - device classes * @name: Name of the class. * @owner: The module owner. * @class_attrs: Default attributes of this class. * @dev_groups: Default attributes of the devices that belong to the class. * @dev_kobj: The kobject that represents this class and links it into the hierarchy. * @dev_uevent: Called when a device is added, removed from this class, or a * few other things that generate uevents to add the environment * variables. * @devnode: Callback to provide the devtmpfs. * @class_release: Called to release this class. * @dev_release: Called to release the device. * @suspend: Used to put the device to sleep mode, usually to a low power * state. * @resume: Used to bring the device from the sleep mode. * @shutdown: Called at shut-down time to quiesce the device. * @ns_type: Callbacks so sysfs can detemine namespaces. * @namespace: Namespace of the device belongs to this class. * @pm: The default device power management operations of this class. * @p: The private data of the driver core, no one other than the * driver core can touch this. * * A class is a higher-level view of a device that abstracts out low-level * implementation details. Drivers may see a SCSI disk or an ATA disk, but, * at the class level, they are all simply disks. Classes allow user space * to work with devices based on what they do, rather than how they are * connected or how they work. */

Источник

Читайте также:  Stream what you hear linux

Class create linux kernel

Библиотека сайта rus-linux.net

Интерфейс /sys

Одно из главных «приобретений» ядра, начинающееся от версий 2.6 — это появление единой унифицированной модель представления устройств в Linux. Главные составляющие, сделавшие возможным её существование, это файловая система sysfs и дуальный к ней (поддерживаемый ею) пакет пользовательского пространства udev . Модель устройств— это единый механизм для представления устройств и описания их топологии в системе. Декларируется множество преимуществ, которые обусловлены созданием единого представления устройств:

  • Уменьшается дублирование кода.
  • Используется механизм для выполнения общих, часто встречающихся функций, таких как счетчики использования.
  • Возможность систематизации всех устройств в системе, возможность просмотра состояний устройств и определения, к какой шине то или другое устройство подключено.
  • Обеспечивается возможность связывания устройств с их драйверами и наоборот.
  • Появляется возможность разделения устройств на категории в соответствии с различными классификациями, таких как устройства ввода, без знания физической топологии устройств.
  • Обеспечивается возможность просмотра иерархии устройств от листьев к корню и выключения питания устройств в правильном порядке.

Файловая система sysfs возникла первоначально из нужды поддерживать последовательность действий в динамическом управлении электропитанием (иерархия устройств при включении-выключении) и для поддержки горячего подключения устройств (то есть в обеспечение последнего пункта перечисления). Но позже модель оказалась гораздо плодотворнее. Сама по себе эта система является весьма сложной и объёмной, и о ней одной можно и нужно писать отдельную книгу. Но в контексте нашего рассмотрения нас интересует, в первую голову, возможность создания интерфейса из модуля к файловым именам, в файловой системе /sys . Эта возможность весьма напоминает то, как модуль создаёт файловые имена в подсистеме /proc .

Базовым понятием модели представления устройств являются объекты struct kobject (определяется в файле ). Тип struct kobjec по смыслу аналогичен абстрактному базовому классу Object в объектно-ориентированных языков программирования, как С# и Java. Этот тип определяет общую функциональность, такую как счетчик ссылок, имя, указатель на родительский объект, что позволяет создавать объектную иерархию.

Зачастую объекты struct kobject сами по себе не создаются и не используются, они встраиваются в другие структуры данных, после чего те приобретают свойства, присущие struct kobject , например, такие, как встраиваемость в иерархию объектов. Вот как это выражается в определении уже известной нас структуры представления символьного устройства:

Во внешнем представлении в /sys , в интересующем нас смысле, каждому объекту struct kobject соответствует каталог, что видно и из самого определения:

Но это вовсе не означает, что каждый инициализированный объект автоматически экспортируется в файловую систему /sys . Для того, чтобы объект сделать видимым в /sys , необходимо вызвать:

Читайте также:  Where is linux kernel located

int kobject_add( struct kobject*kobj );

Но это не придётся делать явно нам в примерах ниже, просто по той простой причине, что используемые для регистрации имён в /sys высокоуровневые вызовы API ( class_create() ) делают это за нас.

Таким образом, объекты struct kobject естественным образом отображаются в каталоги пространства имён /sys . Файловая система sysfs это дерево каталогов без файлов. А как создать файлы в этих каталогах, в содержимое которых отображаются данные ядра? Каждый объект struct kobject (каталог) содержит (через свой компонент struct kobj_type ) массив структур struct attribute :

Вот каждая такая структура (определена в ) и является определением одного файла, содержащегося в рассматриваемом каталоге:

А показанная там же структура таблицы операций ( struct sysfs_ops ) содержит два поля — определения функций show(. ) и store(. ) , соответственно, чтения и записи символьного поля данных ядра, отображаемых этим файлом (и сами функции и их прототипы показаны в примере ниже).

Этих сведений о sysfs нам должно быть достаточно для создания интерфейса модуля в пространство имён /sys , но перед тем, как переходить к примеру, остановимся в два слова на аналогичностях и различиях /proc и /sys в качестве интерфейса для отображения модулем подконтрольных ему данных ядра. Различия систем /proc и /sys — складываются главным образом на основе негласных соглашений и устоявшихся традиций:

  • информация терминальных имён /proc — комплексная, обычно содержит большие объёмы текстовой информации, иногда это таблицы, и даже с заголовками, проясняющими смысл столбцов таблицы;
  • информацию терминальных имён /sys (атрибутов) рекомендуется оформлять в виде а). простых, б). символьных значений, в). представляющих значения, соответствующие скалярным типам данных языка C ( int, long, char[] );

$ cat /proc/partitions | head -n5

major minor #blocks name 33 0 10022040 hde 33 1 3783276 hde1 33 2 1 hde2

В первом случае это (потенциально) обширная таблица, с сформированным заголовком таблицы, разъясняющим смысл колонок, а во втором — представление целочисленных значений.

А теперь мы готовы перейти к рассмотрению возможного вида модуля (архив sys.tgz ), читающего и пишущего из/в атрибута-имени, им созданного в /sys (большая часть происходящего в этом модуле, за исключения регистрации имён в /sys нам уже известно):

#include #include #include #include #include #include #define LEN_MSG 160 static char buf_msg[ LEN_MSG + 1 ] = "Hello from module!\n"; /* LINUX_VERSION_CODE > KERNEL_VERSION(2,6,32) struct class_attribute < struct attribute attr; ssize_t (*show)(struct class *class, struct class_attribute *attr, char *buf); ssize_t (*store)(struct class *class, struct class_attribute *attr, const char *buf, size_t count); >; LINUX_VERSION_CODE ; */ /* sysfs show() method. Calls the show() method corresponding to the individual sysfs file */ #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,32) static ssize_t x_show( struct class *class, struct class_attribute *attr, char *buf ) < #else static ssize_t x_show( struct class *class, char *buf ) < #endif strcpy( buf, buf_msg ); printk( "read %d\n", strlen( buf ) ); return strlen( buf ); >/* sysfs store() method. Calls the store() method corresponding to the individual sysfs file */ #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,32) static ssize_t x_store( struct class *class, struct class_attribute *attr, const char *buf, size_t count ) < #else static ssize_t x_store( struct class *class, const char *buf, size_t count ) < #endif printk( "write %d\n" , count ); strncpy( buf_msg, buf, count ); buf_msg[ count ] = '\0'; return count; >/* #define CLASS_ATTR(_name, _mode, _show, _store) \ struct class_attribute class_attr_##_name = __ATTR(_name, _mode, _show, _store) */ CLASS_ATTR( xxx, 0666, &x_show, &x_store ); static struct class *x_class; int __init x_init( void ) < int res; x_class = class_create( THIS_MODULE, "x-class" ); if( IS_ERR( x_class ) ) printk( "bad class create\n" ); res = class_create_file( x_class, &class_attr_xxx ); /* extern int __must_check class_create_file(struct class *class, const struct class_attribute *attr); */ printk( "'xxx' module initialized\n" ); return 0; > void x_cleanup( void ) < /* extern void class_remove_file(struct class *class, const struct class_attribute *attr); */ class_remove_file( x_class, &class_attr_xxx ); class_destroy( x_class ); return; > module_init( x_init ); module_exit( x_cleanup ); MODULE_LICENSE( "GPL" );

Примечание: В первых строках кода (в виде комментариев) приведены варианты определений (взято из хэдер-файлов), отличающихся даже не между версиями ядра, а между близкими подверсиями ядра: код проверялся в версиях 2.6.32 и 2.6.35 — это лишний раз говорит о волатильности API ядра, и, особенно, ещё не устоявшейся подсистемы sysfs .

Читайте также:  Linux создать том fdisk

-rw-rw-rw- 1 root root 4096 Мар 30 21:54 xxx

-rw-rw-rw- 1 root root 4096 Мар 30 21:54 xxx

$ echo 12345 > /sys/class/x-class/xxx

holders initstate notes refcnt sections srcversion

cat: /sys/class/x-class/xxx: Нет такого файла или каталога

На этом мы и остановимся в рассмотрении подсистемы /sys . Потому, как сейчас функции /sys в Linux расширились настолько, что об этой файловой подсистеме одной можно и нужно писать отдельную книгу: все устройства в системе (сознательно стараниями его автора, или даже помимо его воли) — находят отображения в /sys , а сопутствующая ей подсистема пользовательского пространства udev динамически управляет правилами создания имён и полномочия доступа к ним. Но это — совершенно другая история. Мы же в кратком примере рассмотрели совершенно частную задачу: как из собственного модуля создать интерфейс к именам в /sys , для создания диагностических или управляющих интерфейсов этого модуля.

Предыдущий раздел: Оглавление Следующий раздел:
Интерфейс /proc Сеть

Источник

Оцените статью
Adblock
detector