Операционная система ЗОСРВ «Нейтрино» > Руководство разработчика > Основные принципы системной разработки > Запуск системы, быстрая активация устройств > Быстрая активация устройств > Общие сведения > Взаимодействие с оборудованием в минидрайвере



Взаимодействие с оборудованием в минидрайвере

Примеры, демонстрирующие взаимодействие минидрайверов с оборудованием

Этот пример демонстрирует взаимодействие минидрайвера с оборудованием. Следует помнить, что отображение аппаратных регистров меняется в зависимости от того, на каком этапе процесса загрузки вызывается минидрайвер. Этот переход обрабатывается на этапах 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);
}




Предыдущий раздел: перейти