Инициализация асинхронного адаптера
Первое, что должна сделать программа, работающая с асинхронным адаптером - установить протокол обмена и скорость передачи данных. После загрузки операционной системы для асинхронных адаптеров устанавливается скорость 2400 бод, не выполняется проверка на четность, используются один стоповый бит и восьмибитовая длина передаваемого символа. Вы можете изменить этот режим командой MS-DOS MODE.
Выполнив ввод из порта 3FBh, программа может получить текущий режим адаптера. Для установки нового режима измените нужные вам поля и запишите новый байт режима по адресу 3FBh.
Если вам надо задать новое значение скорости обмена данными, перед записью байта режима установите старший бит этого байта в 1. Затем последовательно двумя командами вывода загрузите делитель частоты тактового генератора. Младший байт запишите в порт 3F8h, старший - в порт 3F9h.
Перед началом работы необходимо также проинициализировать регистр управления прерываниями (порт 3F9h), даже если в вашей программе не используются прерывания от асинхронного адаптера. Если прерывания вам не нужны, запишите в этот порт значение 0.
На этом инициализацию можно считать законченной.
Для того, чтобы узнать текущее состояние асинхронного адаптера, вы можете использовать следующую функцию:
/** *.Name aux_stat *.Title Определение режима асинхронного адаптера * *.Descr Эта функция считывает текущий режим * асинхронного порта и записывает его * в структуру с типом AUX_MODE. * *.Proto void aux_stat(AUX_MODE *mode, int port); * *.Params AUX_MODE mode - структура, описывающая * протокол и режим работы порта: * * typedef struct _AUX_MODE_ { * * union { * struct { * unsigned char len : 2, // длина символа * stop : 1, // число стоп-битов * parity : 2, // контроль четности * stuck_parity : 1, // фиксация четности * en_break_ctl : 1, // установка перерыва * dlab : 1; // загрузка регистра * // делителя * } ctl_word; * char ctl; * } ctl_aux; * * unsigned long baud; // скорость передачи данных * * } AUX_MODE; * * int port - номер асинхронного адаптера: * 0 - COM1, 1 - COM2 * *.Return Ничего * *.Sample aux_test.c **/
#include <stdio.h> #include <conio.h> #include "sysp.h"
void aux_stat(AUX_MODE *mode, int port) {
unsigned long b;
// Запоминаем режим адаптера
mode->ctl_aux.ctl = (char)inp(0x3fb - 0x100 * port);
// Устанавливаем старший бит режима // для считывания текушей скорости передачи
outp(0x3fb - 0x100 * port, mode->ctl_aux.ctl | 0x80);
// Считываем значение регистра делителя
b = inp(0x3f9 - 0x100 * port); b = b << 8; b += inp(0x3f8 - 0x100 * port);
// Преобразуем его в боды
switch (b) { case 1040: b = 110; break; case 768: b = 150; break; case 384: b = 300; break; case 192: b = 600; break; case 96: b = 1200; break; case 48: b = 2400; break; case 24: b = 4800; break; case 12: b = 9600; break; case 6: b = 19200; break; case 3: b = 38400; break; case 2: b = 57600; break; case 1: b = 115200; break; default: b=0; break; }
mode->baud = b;
// Восстанавливаем состояние адаптера
outp(0x3fb - 0x100 * port, mode->ctl_aux.ctl & 0x7f);
}
Прочитав состояние адаптера, вы можете изменить нужные вам поля в структуре AUX_MODE и вызвать функцию aux_init() для изменения параметров адаптера:
/** *.Name aux_init *.Title Инициализация асинхронного адаптера * *.Descr Эта функция инициализирует асинхронные * адаптеры, задавая протокол обмена данными * и скорость обмена данными. * *.Proto int aux_init(AUX_MODE *mode, int port, * int imask); * *.Params AUX_MODE *mode - указатель на структуру, * описывающую протокол и режим работы * порта; * * int port - номер асинхронного адаптера: * 0 - COM1, 1 - COM2 * * int imask - значение для регистра маски * прерываний * *.Return 0 - инициализация выполнена успешно; * 1 - ошибки в параметрах инициализации. * *.Sample aux_test.c **/
#include <stdio.h> #include <conio.h> #include "sysp.h"
int aux_init(AUX_MODE *mode, int port, int imask) {
unsigned div; char ctl;
// Вычисляем значение для делителя
switch (mode->baud) { case 110: div = 1040; break; case 150: div = 768; break; case 300: div = 384; break; case 600: div = 192; break; case 1200: div = 96; break; case 2400: div = 48; break; case 4800: div = 24; break; case 9600: div = 12; break; case 19200: div = 6; break; case 38400: div = 3; break; case 57600: div = 2; break; case 115200: div =1; break; default: return(-1); break; }
// Записываем значение делителя частоты
ctl = inp(0x3fb - 0x100 * port); outp(0x3fb - 0x100 * port, ctl | 0x80);
outp(0x3f9 - 0x100 * port, (div >> 8) & 0x00ff); outp(0x3f8 - 0x100 * port, div & 0x00ff);
// Записываем новое управляющее слово
outp(0x3fb - 0x100 * port, mode->ctl_aux.ctl & 0x7f);
// Устанавливаем регистр управления прерыванием
outp(0x3f9 - 0x100 * port, imask);
return(0);
}