[Kos-dev] [ATA] Alternate Status Register -> IRQ ?

Christophe kos-dev@enix.org
Mon, 4 Feb 2002 11:57:10 +0100


----- Original Message -----
From: <thomas.petazzoni@enix.org>
To: <kos-dev@enix.org>
Sent: Monday, February 04, 2002 10:05 AM
Subject: [Kos-dev] [ATA] Alternate Status Register -> IRQ ?


> salut,
>
> ca commence a marcher de mieux en mieux. mais j'ai encore un
> soucis. lorsque l'IRQ 14 est activee, est que je met le bit nIEN a 1
> dans le Alternate Status Register, et bien je me choppe une
> IRQ. Est-ce normal ?

Il n'existe pas de bit nIEN dans l'Alternate Status Register. En fait, c'est
le Device Control Register. Pourquoi ? parce que quand tu lis sur ce port,
tu lis un registre et quand tu écris sur ce même port tu écris sur un autre
registre du contrôleur ATA. J'ergote peut-être, mais il ne faudrait pas
semer le doute en mélangeant les noms de registre sous prétexte qu'ils se
partagent la même adresse de port. Donc appelle-le ATA-DC ou comme tu veux
et évite de reprendre ATA-ASTAT quand tu écris dans ce port.

N'importe comment, le fait de mettre à 1 ce bit dans le registre Device
Control (ATA-DC) arrête la génération des IRQ pour la suite des commandes
envoyées, pas pour l'IRQ en cours.

Lis le registre Status (ATA-STAT) pour libérer l'IRQ juste avant. Si cela
persiste, juste après.

> Comment faire pour ne pas me chopper une IRQ ? J'ai essaye de mask
> l'IRQ avant puis de la demasker apres l'ecriture, mais elle arrive
> juste au moment ou je demaske (normal).

Lis en boucle le registre Status juste avant l'écriture dans le registre
Device Control, jusqu'à ce que le contrôleur soit prêt (0x50). Là, tu
démasque pour voir. La ligne INTRQ du contrôleur est maintenue aussi
longtemps que tu n'interviens pas avec le registre Status.

> voici le bout de code
>
>   printk("Trying primary\n");
>   init_ide(0x1F0);
>
>   printk("Trying secondary\n");
>   init_ide(0x170);
>
>   register_irq_handler(14, ide_handler);
>
>   /* select drive */
>   printk("Selecting drive\n");
>   outb(ATA_D_IBM | device, 0x1F0 + ATA_DRIVE);
>   usleep(1);
>
Bon voyons ce que dit la doc ATA/ATAPI-4 :

"When the device is selected by writing to the Device/Head register while an
interrupt is pending, INTRQ shall be asserted within 400 ns of the negation
of DIOW- that writes the Device/Head register. When the device is deselected
by writing to the Device/Head register while an interrupt is pending, INTRQ
shall be negated within 400 ns of the negation of DIOW- that writes the
Device/Head register."

J'inverserais : d'abord la sélection ou non de l'Interrupt Enable, puis la
sélection du device.

>   printk("Writing status\n");
>   outb(ATA_A_IDS | ATA_A_4BIT, 0x1F0 + ATA_ALTPORT);
>   usleep(1);

Argh ! qu'est ce que c'est que ce truc, on NE peut JAMAIS écrire dans le
registre Alternate Status !? écrire dans un registre de status, c'est
impossible avec le contrôleur ATA et ça n'a pas de sens. Et puis utilise des
noms standards, car je n'y comprends rien à tes ATA_A_IDS et autre. Ces noms
sont standards et tu les trouves dans les docs ATA/ATAPI.

>
>   ==> ICI BLING IRQ 14 :( <==
>   printk("Status for drive is : 0x%x\n", inb(0x1F0 + ATA_STATUS));
>
>   printk("Sencind cmd\n");
>   outb(ATA_C_ATA_IDENTIFY, 0x1F0 + ATA_CMD);

Note que d'écrire une commande a le même effet que le registre Status sur
l'état de la ligne INTRQ.

> Est-ce normal ? Avez-vous une solution ?
>

-Attendre que le registre Alternate Status nous signale que le contrôleur
est à nouveau prêt.
-Lire au moins une fois le registre Status, au cas où la ligne INTRQ serait
encore active.
-Mettre le bit nIEN à 1 dans le registre Device Control.
-Activer le device souhaité dans le registre Drive Head.
-Attendre que le registre Status nous signale que le contrôleur est à
nouveau prêt.
-Exécuter ta commande dans le registre Command.

Pour le reste, je pense que t'es assez grand. ;-)