Skip to content

Instantly share code, notes, and snippets.

@nelsoncole
Last active January 1, 2018 13:07
Show Gist options
  • Save nelsoncole/92f843b0ef4fc6161cdbe4a5eced2657 to your computer and use it in GitHub Desktop.
Save nelsoncole/92f843b0ef4fc6161cdbe4a5eced2657 to your computer and use it in GitHub Desktop.
Teste de PS/2 mouse (Borland C++ 3.1 - MS-DOS)
/* C¢digo para o Borland C++ 3.1.
coloquei delays de 1us entre escritas/leituras para o KBDC.
coloquei verificação de acknowledge depois de mouse_writes.
Ainda travando
OK! Tio Fred estamos lidando com dispositivos seriais, na verade dois dispositivos partilhando o mesmo Chip,
sabes o aquão trasçueiros eles são.
Ao que parce o código merecer uma reescrita completa, tentei altera-lo no mínimo
*/
#include <stddef.h>
#include <dos.h>
#include <conio.h>
char buttons = 0;
char mouse_x = 0;
char mouse_y = 0;
// Tio Fred estas variaves também devem ser globais senão zeramos a cada irq12
char mouse_data[3];
int pos = 0;
enum kbdc_reg {
KBDC_OUTPUT,
KBDC_INPUT
};
// Ponteiro para o antigo vetor 0x74 (irq12).
static void interrupt (far *oldvect)(void) = NULL;
// handler que vai ser chamado pela ISR da IRQ 12.
// Note que o handler é chamado para cada byte disponibilizado
// pelo auxiliary device (mouse)... Isso está certo?
static void interrupt far mouse_handler(void)
{
mouse_data[pos++] = inportb(0x60);
if (pos == 3)
{
// Tio Fred ! Eu nao sei o porquê mas em meu VM (Qemu), nalguma das vezes os dados vêm nesta ordem.
// Inco somente acontece quando o cusor do mouse está por fora do VM, no meio de sua configuração
// penso que seja a falta da confirmação do KBDC_OK (0xAA)
buttons = mouse_data[0];
mouse_x = mouse_data[1];
mouse_y = mouse_data[2];
pos = 0;
}
outportb(0xa0, 0x20); // EOI.
// Tio Fred o PIC 1 Também deve enviar um EOI, devido o modo cascata IRQ2
outportb(0x20,0x20);
// enable(); // STI (é necessário aqui?). Não, não é necessário
}
#define io_delay() asm { out 0x80,al }
static void mouse_wait(enum kbdc_reg buff)
{
int time_out =0; // E o zero?
// Ok... vamos fazer isso, no m ximo 65536 vezes.
if (buff == KBDC_OUTPUT)
{
while (--time_out)
// Se temos dados no output buffer, sai...
if (inportb(0x64) & 1)
break;
}
else
while (--time_out)
// Se o input buffer est  limpo, sai...
if (!(inportb(0x64) & 2))
break;
}
static void mouse_write(unsigned char data)
{
mouse_wait(KBDC_INPUT);
outportb(0x64, 0xD4);
io_delay();
mouse_wait(KBDC_INPUT);
outportb(0x60, data);
io_delay();
}
static unsigned char mouse_read(void)
{
unsigned char b;
mouse_wait(KBDC_OUTPUT);
b = inportb(0x60);
io_delay();
return b;
}
void mouse_install(void)
{
unsigned char ram0;
// mascara IRQ1 e IRQ12. (Dica do Nelson Cole).
disable();
outportb(0x21, inport(0x21) | (1 << 1));
outportb(0xa1, inport(0xa1) | (1 << 4));
mouse_wait(KBDC_INPUT);
outportb(0x64,0xAD); // Desativar a primeira porta PS/2
mouse_wait(KBDC_INPUT);
outportb(0x64,0xA7); /* Desativar a segunda porta PS/2, hahaha por default ela já vem desativada, só pra constar */
// Habilita IRQ 12 no KBDC.
mouse_wait(KBDC_INPUT);
outportb(0x64, 0x20);
io_delay();
mouse_wait(KBDC_OUTPUT);
ram0 = (inportb(0x60) | 2);
io_delay();
mouse_wait(KBDC_INPUT);
outportb(0x64, 0x60);
io_delay();
mouse_wait(KBDC_INPUT);
outportb(0x60, ram0);
io_delay();
// Habilita a primeira porta PS/2
mouse_wait(KBDC_INPUT);
outportb(0x64,0xAE);
io_delay();
// Habilita o auxiliary device.
mouse_wait(KBDC_INPUT);
outportb(0x64, 0xa8);
io_delay();
// Espera terminar
mouse_wait(KBDC_INPUT);
// Reseta mouse.
mouse_write(0xff);
while (mouse_read() == 0xfA); // Espera os dados descer (ACK)
// while (mouse_read() != 0xaa); // Reset Ack!
// FIXME: Trava logo que tenta mouse_read(), acima...
// Restaura defaults do PS/2 mouse.
mouse_write(0xf6);
// while (mouse_read() != 0xfA) // Ack
// Habilita o mouse streaming
mouse_write(0xf4);
while (mouse_read() == 0xfA); // Espera os dados descer (ACK)
mouse_wait(KBDC_INPUT); // Espera nossa controladora terminar
// Instala o novo ISR, mantendo o velho.
oldvect = getvect(0x74);
setvect(0x74, mouse_handler);
// desmascara a IRQ12 e IRQ1 no PIC.
outportb(0xa1, inportb(0xa1) & ~(1 << 4));
outportb(0x21, inportb(0x21) & ~(1 << 1));
enable();
}
void mouse_uninstall(void)
{
unsigned char ram0;
// Mascara IRQ1 e IRQ12 no PIC.
disable();
outportb(0x21, inport(0x21) | (1 << 1));
outportb(0xa1, inport(0xa1) | (1 << 4));
mouse_wait(KBDC_INPUT);
outportb(0x64,0xAD); // Desativar a primeira porta PS/2
mouse_wait(KBDC_INPUT);
outportb(0x64,0xA7); // Desativar a segunda porta PS/2
// Desabilita IRQ 12 no KBDC.
mouse_wait(KBDC_INPUT);
outportb(0x64, 0x20);
io_delay();
mouse_wait(KBDC_OUTPUT);
ram0 = (inportb(0x60) & ~2);
mouse_wait(KBDC_INPUT);
outportb(0x64, 0x60);
io_delay();
mouse_wait(KBDC_INPUT);
outportb(0x60, ram0);
io_delay();
// Desabilita o auxiliary device.
mouse_wait(KBDC_INPUT);
outportb(0x64, 0xa7);
io_delay();
mouse_wait(KBDC_INPUT);
// Retorna com a velha ISR para a IRQ 12.
setvect(0x74, oldvect);
// Habilita a primeira porta PS/2
mouse_wait(KBDC_INPUT);
outportb(0x64,0xAE);
io_delay();
mouse_wait(KBDC_INPUT);
// desmascara aIRQ1 no PIC.
outportb(0x21, inportb(0x21) & ~(1 << 1));
enable();
}
void main(void)
{
mouse_install();
// Enquanto não clicou no botão esquerdo...
while(!(buttons & 1))
// Imprime as coordenadas.
cprintf("(%d, %d)\r", mouse_x, mouse_y);
cprintf("\nFeliz ano novo!");
mouse_uninstall();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment