Mouse PS/2
O mouse PS/2 compartilha exatamente o mesmo controlador 8042 que o teclado PS/2 já cobre, mas através do segundo canal auxiliar do controlador, e fala um protocolo baseado em pacotes completamente diferente que precisa ser explicitamente habilitado antes de o dispositivo reportar qualquer coisa.
Habilitando o segundo canal
Seção intitulada “Habilitando o segundo canal”O controlador 8042 multiplexa duas portas de dispositivo atrás do mesmo par de portas de I/O (0x60 para dados, 0x64 para comandos), e a segunda, convencionalmente conectada ao mouse, comumente fica desabilitada até o software explicitamente ativá-la: o comando 0xA8 a habilita, e o comando 0x20 (lê o byte de configuração) seguido de 0x60 (escreve-o de volta) com o bit de habilitação de interrupção da segunda porta definido é o que permite ao controlador de fato levantar uma interrupção quando dados de mouse chegam, espelhando a mesma sequência de comando de controlador que o artigo do teclado já descreve para o primeiro canal.
mov al, 0xA8 ; habilita a segunda porta PS/2out 0x64, al
mov al, 0x20 ; lê o byte de configuraçãoout 0x64, alin al, 0x60or al, 0x02 ; define o bit 1: habilita IRQ12 (interrupção da segunda porta)mov ah, almov al, 0x60 ; escreve o byte de configuraçãoout 0x64, almov al, ahout 0x60, alEscrever um byte para o próprio mouse, em vez de para o controlador, adicionalmente exige prefixar a escrita com o comando 0xD4 na porta 0x64, o que diz ao controlador para rotear o próximo byte da porta de dados para o segundo canal em vez do primeiro; omitir esse prefixo envia o byte para o canal do teclado em vez disso, uma fonte comum de um mouse que silenciosamente nunca responde ao que parece um comando corretamente formatado.
Sequência de inicialização
Seção intitulada “Sequência de inicialização”Um mouse assume por padrão o modo de polling (reportando dados só quando explicitamente perguntado) em vez de reportar movimento por conta própria, então um driver precisa enviar o comando Enable Data Reporting (0xF4), prefixado com 0xD4 como acima, para trocá-lo para o modo streaming, onde o dispositivo envia um pacote automaticamente no momento em que tem dados novos de movimento ou botão em vez de esperar ser sondado.
mouse_write: mov al, 0xD4 out 0x64, al ; o próximo byte vai para o mouse, não para o teclado mov al, 0xF4 ; Enable Data Reporting out 0x60, al ; espera 0xFA (ACK) de volta na porta 0x60Um dispositivo bem-comportado reconhece a maioria dos comandos com 0xFA antes de agir sobre eles, o que um driver deveria checar em vez de presumir que todo comando silenciosamente tem sucesso, já que um mouse que nunca recebeu o comando de habilitação simplesmente fica quieto em vez de reportar um erro que o driver poderia de outra forma detectar diretamente.
O formato do pacote
Seção intitulada “O formato do pacote”Uma vez em streaming, o mouse envia um pacote de tamanho fixo, três bytes para um mouse padrão ou quatro quando um scroll wheel está presente, toda vez que tem dados novos para reportar, sempre começando com um byte cujo bit 3 está definido, uma propriedade que um driver pode usar para ressincronizar se um byte for perdido ou corrompido no meio do fluxo.
Byte 0: overflow-Y | overflow-X | sinal-Y | sinal-X | 1 | botão-meio | botão-direito | botão-esquerdoByte 1: movimento X (com sinal, relativo, -256 a 255)Byte 2: movimento Y (com sinal, relativo, -256 a 255)Byte 3: delta de scroll (com sinal), presente só com mouse de scroll wheelMovimento X e Y são cada um um delta relativo de 8 bits com sinal, não uma posição absoluta, com o bit de sinal correspondente no byte 0 estendendo esse valor de 8 bits para um inteiro completo com sinal antes de um driver somá-lo a qualquer posição de cursor que esteja rastreando; os bits de overflow no mesmo byte sinalizam um movimento grande o suficiente para o campo de 8 bits não conseguir representar com precisão, uma condição rara mas real que um driver deveria limitar ou descartar em vez de silenciosamente aceitar um delta que deu a volta e está incorreto.
void handle_mouse_packet(uint8_t b0, uint8_t b1, uint8_t b2) { int dx = b1 - ((b0 << 4) & 0x100); // estende o sinal usando o bit 4 do byte 0 int dy = b2 - ((b0 << 3) & 0x100); // estende o sinal usando o bit 5 do byte 0
cursor_x += dx; cursor_y -= dy; // Y tipicamente é invertido em relação a coordenadas de tela}Notas de implementação
Seção intitulada “Notas de implementação”Como os dois canais PS/2 levantam interrupções no mesmo controlador mas em duas linhas de IRQ diferentes (IRQ1 para o teclado, IRQ12 para o mouse), o handler de mouse de um driver precisa ler exatamente o número de bytes que um pacote exige e não mais antes de retornar, rastreando estado de fronteira de pacote através de interrupções da mesma forma que um driver de teclado rastreia sequências de scancode de múltiplos bytes, já que um handler que lê um byte por interrupção sem lembrar em qual byte do pacote atual está vai desalinhar todo pacote depois do primeiro byte perdido ou extra. Um mouse de scroll wheel precisa ser explicitamente negociado para seu modo de quatro bytes através de uma sequência específica e de outra forma sem sentido de comandos de definição de taxa de amostragem (0xF3 com valores 200, 100, 80 em sequência, depois um comando de identificação confirmando que o mouse respondeu trocando de modo) em vez de simplesmente ser detectado a partir do hardware sozinho, uma peculiaridade de como essa extensão foi retrofitada num protocolo sem mecanismo dedicado algum de negociação de capacidade próprio.
Referências
Seção intitulada “Referências”- ^ IBM, Personal System/2 Hardware Interface Technical Reference: a mesma especificação de controlador 8042 que a citação do próprio artigo do teclado cobre, incluindo o canal auxiliar (mouse).
Ver também
Seção intitulada “Ver também”- Teclado PS/2: o controlador 8042, suas portas de I/O, e a discussão de tratamento de IRQ sobre a qual o segundo canal deste artigo se apoia diretamente.