Примеры, демонстрирующие взаимодействие минидрайверов с оборудованием
Этот пример демонстрирует взаимодействие минидрайвера с оборудованием. Следует помнить, что отображение аппаратных регистров меняется в зависимости от того, на каком этапе процесса загрузки вызывается минидрайвер. Этот переход обрабатывается на этапах MDRIVER_STARTUP_PREPARE
и MDRIVER_STARTUP_FINI
.
/** Здесь показан более сложный минидрайвер для вымышленного устройства с именем MYBUS.* Это устройство обладает следующими характеристиками:** - набор 8-разрядных регистров (состояния и данных) расположен по адресу 0xFF000000 (MBAR)* - при приеме символа в порт MYBUS генерируется прерывание 56** По этому адресу находятся регистры для чтения и записи.*/#include "startup.h" /* этот файл входит в состав BSP */typedef unsigned char U8;typedef unsigned short U16;typedef unsigned int U32;/************** Регистры MYBUS **************/typedef struct MYBUS_register_set {volatile U8 interrupt_status;volatile U8 data_register;volatile U8 control_register;volatile U8 extra1;volatile U8 extra2;volatile U8 extra3;volatile U8 extra4;volatile U8 extra5;} MYBUS_regs_t;/************** Регистры GPIO **************/typedef struct GPIO_register_set {volatile U32 gpio0;volatile U32 gpio1;} GPIO_regs_t;/******* Область данных минидрайвера *******/typedef struct{MYBUS_regs *MYBUS_REGS; /* это значение совпадает с PREKERNEL или POSTKERNEL */MYBUS_regs *MYBUS_REGS_PREKERNEL_START; /* регистрация отображений, которые используются до запуска ядра */MYBUS_regs *MYBUS_REGS_POSTKERNEL_START; /* регистрация отображений, которые используются после запуска ядра */U16 total_message_counter; /* суммарное количество вызовов мини-обработчика */U16 process_counter; /* количество вызовов после запуска ядра */U16 kernel_counter; /* количество вызовов в процессе загрузки ядра */U16 data_len; /* длина фрагмента области данных, в которой хранятся данные */} MYBUS_data_t;/* Базовые физические адреса и смещения */#define MBAR_BASE 0xff000000#define GPIO_OFFSET 0x0C00#define MYBUS_OFFSET 0x2400/* параметры регистров управления */#define CTRL_INTERRUPT_ON 0x01#define CTRL_INTERRUPT_OFF 0x00/** Функция инициализации оборудования MYBUS. Эта функция вызывается однократно при запуске минидрайвера.** INPUTS Нет* OUTPUTS Нет*/static MYBUS_regs_t * MYBUS_Init( void ){GPIO_regs_t *GPIO_REGS_P;MYBUS_regs_t *MYBUS_REGS_P;U32 data_byte;if ((GPIO_REGS_P = (GPIO_regs_t *)startup_memory_map( 0x40, MBAR_BASE + GPIO_OFFSET,PROT_READ | PROT_WRITE | PROT_NOCACHE )) == 0 ){startup_memory_unmap( (unsigned)GPIO_REGS_P );return (0);}/* Измените регистры GPIO нужным образом */Data = GPIO_REGS_P->gpio0;Data = Data & 0xFFF0FFFF;GPIO_REGS_P->gpio0 = Data;/* конец настройки регистров GPIO */startup_memory_unmap( (void *)PORT_REGS_P );if ( (MYBUS_REGS_P = (MYBUS_regs_t *)startup_memory_map( 0x10, MBAR_BASE + MYBUS_OFFSET,PROT_READ | PROT_WRITE | PROT_NOCACHE )) == 0 ){startup_memory_unmap( (unsigned)MYBUS_REGS_P );return (0);}/* инициализация MYBUS и включение прерывания *//* запись необходимых значений в MYBUS_REGS_P и включение источника прерываний */MYBUS_REGS_P->control_register = CTRL_INTERRUPT_ON;kprintf( "MYBUS is initialized\n" );return (MYBUS_REGS_P);}/** int mini_mybus_handler( void )*/int mini_mybus_handler( int state, void *data ){U8 *dptr;U8 StatusReg;U8 notValid;MYBUS_data_t *mdata;int val;mdata = (MYBUS_data_t *)data;dptr = data + sizeof( MYBUS_data_t );if ( state == MDRIVER_INTR_ATTACH ){kprintf( "Real driver is attaching .. mini-driver was called %d times\n",mdata->total_message_counter );/* Запрещение прерывания MYBUS */mdata->MYBUS_REGS_POSTKERNEL->control_register = CTRL_INTERRUPT_OFF;return (1);} else if ( state == MDRIVER_INIT ){/* При первом вызове - инициализация оборудования и настройка данных */mdata->MYBUS_REGS_PREKERNEL = MYBUS_Init();if ( mdata->MYBUS_REGS_PREKERNEL == 0 )return (1);/* местоположение регистра по умолчанию с учетом того, что мы находимся в PREKERNEL */mdata->MYBUS_REGS = mdata->MYBUS_REGS_PREKERNEL;mdata->total_message_counter = 0; /* инициализация количества принятых сообщений */mdata->process_counter = 0;mdata->kernel_counter = 0;} else if ( state == MDRIVER_PROCESS ){mdata->process_counter++;} else if ( state == MDRIVER_KERNEL ){mdata->kernel_counter++;} else if ( state == MDRIVER_STARTUP_PREPARE ){/* по окончании запуска *//* применяется функция callout_io_map или callout_memory_map */kprintf( "I am in STARTUP PREPARE %x\n", mdata->total_message_counter );if ( (mdata->MYBUS_REGS_POSTKERNEL = (MYBUS_regs_t *)(callout_memory_map( 0x10, MBAR_BASE + MYBUS_OFFSET,PROT_READ | PROT_WRITE | PROT_NOCACHE )) ){/* серьезная ошибка, отключение прерывания и завершение работы минидрайвера */mdata->MYBUS_REGS_PREKERNEL->control_register = CTRL_INTERRUPT_OFF;return (1);}}/* Здесь мы используем MYBUS_REGS. Мы можем находиться на этапе запуска,* загрузки ядра или выполнения системы *//* cчитывание регистра состояния прерываний непосредственно после входа в обработчик */StatusReg = mdata->MYBUS_REGS->interrupt_status;/* увеличение счетчика сообщений */mdata->total_message_counter++;switch ( StatusReg ){/* считывание данных и их добавление в область данных (за полем data_len структуры MYBUS_data_t) *//* очистка источника прерывания перед возвратом */...}if ( state == MDRIVER_STARTUP_FINI ){val = mdata->total_message_counter;kprintf( "I am in state STARTUP FINI. Total messages processed=%x \n", val );/* запуск завершен ... переход к использованию отображений POSTKERNEL */mdata->MYBUS_REGS = mdata->MYBUS_REGS_POSTKERNEL;}return (0);}
Предыдущий раздел: перейти