Die meisten Hardware-Schnittstellen werden mit Hilfe eines Interrupt-Handlers gesteuert. Die Schnittstelle unterbricht den Prozessor, um eines von zwei möglichen Ereignissen mitzuteilen: Entweder ist ein neues Paket angekommen, oder die Übertragung eines ausgehenden Paketes wurde abgeschlossen. Diese Generalisierung ist nicht immer ganz richtig, trifft aber bei allen Problemen der asynchronen Paket-Übertragung zu. Das Parallel Line Internet Protocol (PLIP) und das Point-to-Point Protocol (PPP) sind Beispiele für Schnittstellen, die nicht in diese Generalisierung passen. Sie haben es mit den gleichen Ereignissen zu tun, aber die Interrupt-Verarbeitung auf der unteren Ebene ist geringfügig anders.
Die normale Interrupt-Routine kann den Unterschied zwischen einem Interrupt wegen eines neu eingetroffenen Paketes und einem Interrupt wegen einer vollständig durchgeführten Übertragung anhand eines Status-Registers auf dem physikalischen Gerät selbst feststellen. snull arbeitet ähnlich, wenn auch dieser Zustandswert in der Software implementiert wird und in dev->priv steht. Der Interrupt-Handler für eine Netzwerk-Schnittstelle sieht folgendermaßen aus:
void snull_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
int statusword;
struct snull_priv *priv;
/*
* Wie ueblich den "Geraete"-Zeiger auf gemeinsam genutzte Handler
* ueberpruefen, dann "struct net_device* dev" zuweisen.
*/
struct net_device *dev = (struct net_device *)dev_id;
/* ... und bei der Hardware ueberpruefen, ob das unser Geraet ist */
if (!dev /*paranoid*/ ) return;
/* Das Geraet sperren */
priv = (struct snull_priv *) dev->priv;
spin_lock(&priv->lock);
/* Statuswert holen: richtige Geraete verwenden I/O-Anweisungen */
statusword = priv->status;
if (statusword & SNULL_RX_INTR) {
/* an snull_rx zur Bearbeitung senden */
snull_rx(dev, priv->rx_packetlen, priv->rx_packetdata);
}
if (statusword & SNULL_TX_INTR) {
/* eine Uebertragung ist erledigt: den skb freigeben */
priv->stats.tx_packets++;
priv->stats.tx_bytes += priv->tx_packetlen;
dev_kfree_skb(priv->skb);
}
/* Das Geraet freigeben und fertig */
spin_unlock(&priv->lock);
return;
} |
Die erste Aufgabe des Handlers ist es, den Zeiger auf die richtige net_device-Struktur zu finden. Dieser Zeiger stammt normalerweise aus dem Zeiger dev_id, der als Argument übergeben wird.
Der interessante Teil des Handlers behandelt abgeschlossene Übertragungen. In diesem Fall wird die Statistik aktualisiert und dev_kfree_skb aufgerufen, um den (nicht mehr benötigten) Socket-Buffer an das System zurückzugeben. Wenn Ihr Treiber die Übertragungswarteschlange vorübergehend angehalten hat, ist dies auch die richtige Stelle, um sie mit netif_wake_queue wieder in Gang zu bringen.
Zum Empfangen der Pakete ist dagegen keine besondere Interrupt-Behandlung notwendig. Es muß lediglich snull_rx aufgerufen werden.