📄 plip.c
字号:
return TIMEOUT; } c0 = read_status(dev); printk(KERN_WARNING "%s: transmit timeout(%d,%02x)\n", dev->name, snd->state, c0); } else error = HS_TIMEOUT; nl->enet_stats.tx_errors++; nl->enet_stats.tx_aborted_errors++; } else if (nl->connection == PLIP_CN_RECEIVE) { if (rcv->state == PLIP_PK_TRIGGER) { /* Transmission was interrupted. */ spin_unlock_irq(&nl->lock); return OK; } if (error != ERROR) { /* Timeout */ if (++nl->timeout_count <= 3) { spin_unlock_irq(&nl->lock); /* Try again later */ return TIMEOUT; } c0 = read_status(dev); printk(KERN_WARNING "%s: receive timeout(%d,%02x)\n", dev->name, rcv->state, c0); } nl->enet_stats.rx_dropped++; } rcv->state = PLIP_PK_DONE; if (rcv->skb) { kfree_skb(rcv->skb); rcv->skb = NULL; } snd->state = PLIP_PK_DONE; if (snd->skb) { dev_kfree_skb(snd->skb); snd->skb = NULL; } spin_unlock_irq(&nl->lock); if (error == HS_TIMEOUT) { DISABLE(dev->irq); synchronize_irq(); } disable_parport_interrupts (dev); netif_stop_queue (dev); nl->connection = PLIP_CN_ERROR; write_data (dev, 0x00); return TIMEOUT;}static intplip_none(struct net_device *dev, struct net_local *nl, struct plip_local *snd, struct plip_local *rcv){ return OK;}/* PLIP_RECEIVE --- receive a byte(two nibbles) Returns OK on success, TIMEOUT on timeout */inline static intplip_receive(unsigned short nibble_timeout, struct net_device *dev, enum plip_nibble_state *ns_p, unsigned char *data_p){ unsigned char c0, c1; unsigned int cx; switch (*ns_p) { case PLIP_NB_BEGIN: cx = nibble_timeout; while (1) { c0 = read_status(dev); udelay(PLIP_DELAY_UNIT); if ((c0 & 0x80) == 0) { c1 = read_status(dev); if (c0 == c1) break; } if (--cx == 0) return TIMEOUT; } *data_p = (c0 >> 3) & 0x0f; write_data (dev, 0x10); /* send ACK */ *ns_p = PLIP_NB_1; case PLIP_NB_1: cx = nibble_timeout; while (1) { c0 = read_status(dev); udelay(PLIP_DELAY_UNIT); if (c0 & 0x80) { c1 = read_status(dev); if (c0 == c1) break; } if (--cx == 0) return TIMEOUT; } *data_p |= (c0 << 1) & 0xf0; write_data (dev, 0x00); /* send ACK */ *ns_p = PLIP_NB_BEGIN; case PLIP_NB_2: break; } return OK;}/* * Determine the packet's protocol ID. The rule here is that we * assume 802.3 if the type field is short enough to be a length. * This is normal practice and works for any 'now in use' protocol. * * PLIP is ethernet ish but the daddr might not be valid if unicast. * PLIP fortunately has no bus architecture (its Point-to-point). * * We can't fix the daddr thing as that quirk (more bug) is embedded * in far too many old systems not all even running Linux. */ static unsigned short plip_type_trans(struct sk_buff *skb, struct net_device *dev){ struct ethhdr *eth; unsigned char *rawp; skb->mac.raw=skb->data; skb_pull(skb,dev->hard_header_len); eth= skb->mac.ethernet; if(*eth->h_dest&1) { if(memcmp(eth->h_dest,dev->broadcast, ETH_ALEN)==0) skb->pkt_type=PACKET_BROADCAST; else skb->pkt_type=PACKET_MULTICAST; } /* * This ALLMULTI check should be redundant by 1.4 * so don't forget to remove it. */ if (ntohs(eth->h_proto) >= 1536) return eth->h_proto; rawp = skb->data; /* * This is a magic hack to spot IPX packets. Older Novell breaks * the protocol design and runs IPX over 802.3 without an 802.2 LLC * layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This * won't work for fault tolerant netware but does for the rest. */ if (*(unsigned short *)rawp == 0xFFFF) return htons(ETH_P_802_3); /* * Real 802.2 LLC */ return htons(ETH_P_802_2);}/* PLIP_RECEIVE_PACKET --- receive a packet */static intplip_receive_packet(struct net_device *dev, struct net_local *nl, struct plip_local *snd, struct plip_local *rcv){ unsigned short nibble_timeout = nl->nibble; unsigned char *lbuf; switch (rcv->state) { case PLIP_PK_TRIGGER: DISABLE(dev->irq); /* Don't need to synchronize irq, as we can safely ignore it */ disable_parport_interrupts (dev); write_data (dev, 0x01); /* send ACK */ if (net_debug > 2) printk(KERN_DEBUG "%s: receive start\n", dev->name); rcv->state = PLIP_PK_LENGTH_LSB; rcv->nibble = PLIP_NB_BEGIN; case PLIP_PK_LENGTH_LSB: if (snd->state != PLIP_PK_DONE) { if (plip_receive(nl->trigger, dev, &rcv->nibble, &rcv->length.b.lsb)) { /* collision, here dev->tbusy == 1 */ rcv->state = PLIP_PK_DONE; nl->is_deferred = 1; nl->connection = PLIP_CN_SEND; queue_task(&nl->deferred, &tq_timer); enable_parport_interrupts (dev); ENABLE(dev->irq); return OK; } } else { if (plip_receive(nibble_timeout, dev, &rcv->nibble, &rcv->length.b.lsb)) return TIMEOUT; } rcv->state = PLIP_PK_LENGTH_MSB; case PLIP_PK_LENGTH_MSB: if (plip_receive(nibble_timeout, dev, &rcv->nibble, &rcv->length.b.msb)) return TIMEOUT; if (rcv->length.h > dev->mtu + dev->hard_header_len || rcv->length.h < 8) { printk(KERN_WARNING "%s: bogus packet size %d.\n", dev->name, rcv->length.h); return ERROR; } /* Malloc up new buffer. */ rcv->skb = dev_alloc_skb(rcv->length.h + 2); if (rcv->skb == NULL) { printk(KERN_ERR "%s: Memory squeeze.\n", dev->name); return ERROR; } skb_reserve(rcv->skb, 2); /* Align IP on 16 byte boundaries */ skb_put(rcv->skb,rcv->length.h); rcv->skb->dev = dev; rcv->state = PLIP_PK_DATA; rcv->byte = 0; rcv->checksum = 0; case PLIP_PK_DATA: lbuf = rcv->skb->data; do if (plip_receive(nibble_timeout, dev, &rcv->nibble, &lbuf[rcv->byte])) return TIMEOUT; while (++rcv->byte < rcv->length.h); do rcv->checksum += lbuf[--rcv->byte]; while (rcv->byte); rcv->state = PLIP_PK_CHECKSUM; case PLIP_PK_CHECKSUM: if (plip_receive(nibble_timeout, dev, &rcv->nibble, &rcv->data)) return TIMEOUT; if (rcv->data != rcv->checksum) { nl->enet_stats.rx_crc_errors++; if (net_debug) printk(KERN_DEBUG "%s: checksum error\n", dev->name); return ERROR; } rcv->state = PLIP_PK_DONE; case PLIP_PK_DONE: /* Inform the upper layer for the arrival of a packet. */ rcv->skb->protocol=plip_type_trans(rcv->skb, dev); netif_rx(rcv->skb); nl->enet_stats.rx_bytes += rcv->length.h; nl->enet_stats.rx_packets++; rcv->skb = NULL; if (net_debug > 2) printk(KERN_DEBUG "%s: receive end\n", dev->name); /* Close the connection. */ write_data (dev, 0x00); spin_lock_irq(&nl->lock); if (snd->state != PLIP_PK_DONE) { nl->connection = PLIP_CN_SEND; spin_unlock_irq(&nl->lock); queue_task(&nl->immediate, &tq_immediate); mark_bh(IMMEDIATE_BH); enable_parport_interrupts (dev); ENABLE(dev->irq); return OK; } else { nl->connection = PLIP_CN_NONE; spin_unlock_irq(&nl->lock); enable_parport_interrupts (dev); ENABLE(dev->irq); return OK; } } return OK;}/* PLIP_SEND --- send a byte (two nibbles) Returns OK on success, TIMEOUT when timeout */inline static intplip_send(unsigned short nibble_timeout, struct net_device *dev, enum plip_nibble_state *ns_p, unsigned char data){ unsigned char c0; unsigned int cx; switch (*ns_p) { case PLIP_NB_BEGIN: write_data (dev, data & 0x0f); *ns_p = PLIP_NB_1; case PLIP_NB_1: write_data (dev, 0x10 | (data & 0x0f)); cx = nibble_timeout; while (1) { c0 = read_status(dev); if ((c0 & 0x80) == 0) break; if (--cx == 0) return TIMEOUT; udelay(PLIP_DELAY_UNIT); } write_data (dev, 0x10 | (data >> 4)); *ns_p = PLIP_NB_2; case PLIP_NB_2: write_data (dev, (data >> 4)); cx = nibble_timeout; while (1) { c0 = read_status(dev); if (c0 & 0x80) break; if (--cx == 0) return TIMEOUT; udelay(PLIP_DELAY_UNIT); } *ns_p = PLIP_NB_BEGIN; return OK; } return OK;}/* PLIP_SEND_PACKET --- send a packet */static intplip_send_packet(struct net_device *dev, struct net_local *nl, struct plip_local *snd, struct plip_local *rcv){ unsigned short nibble_timeout = nl->nibble; unsigned char *lbuf; unsigned char c0; unsigned int cx; if (snd->skb == NULL || (lbuf = snd->skb->data) == NULL) { printk(KERN_DEBUG "%s: send skb lost\n", dev->name); snd->state = PLIP_PK_DONE; snd->skb = NULL; return ERROR; } switch (snd->state) { case PLIP_PK_TRIGGER: if ((read_status(dev) & 0xf8) != 0x80) return HS_TIMEOUT; /* Trigger remote rx interrupt. */ write_data (dev, 0x08); cx = nl->trigger; while (1) { udelay(PLIP_DELAY_UNIT); spin_lock_irq(&nl->lock); if (nl->connection == PLIP_CN_RECEIVE) { spin_unlock_irq(&nl->lock); /* Interrupted. */ nl->enet_stats.collisions++; return OK; } c0 = read_status(dev); if (c0 & 0x08) { spin_unlock_irq(&nl->lock); DISABLE(dev->irq); synchronize_irq(); if (nl->connection == PLIP_CN_RECEIVE) { /* Interrupted. We don't need to enable irq, as it is soon disabled. */ /* Yes, we do. New variant of {enable,disable}_irq *counts* them. -- AV */ ENABLE(dev->irq); nl->enet_stats.collisions++; return OK; } disable_parport_interrupts (dev); if (net_debug > 2) printk(KERN_DEBUG "%s: send start\n", dev->name); snd->state = PLIP_PK_LENGTH_LSB; snd->nibble = PLIP_NB_BEGIN; nl->timeout_count = 0; break; } spin_unlock_irq(&nl->lock); if (--cx == 0) { write_data (dev, 0x00); return HS_TIMEOUT; } } case PLIP_PK_LENGTH_LSB: if (plip_send(nibble_timeout, dev, &snd->nibble, snd->length.b.lsb)) return TIMEOUT; snd->state = PLIP_PK_LENGTH_MSB; case PLIP_PK_LENGTH_MSB: if (plip_send(nibble_timeout, dev, &snd->nibble, snd->length.b.msb)) return TIMEOUT; snd->state = PLIP_PK_DATA; snd->byte = 0; snd->checksum = 0; case PLIP_PK_DATA: do if (plip_send(nibble_timeout, dev, &snd->nibble, lbuf[snd->byte])) return TIMEOUT; while (++snd->byte < snd->length.h); do snd->checksum += lbuf[--snd->byte]; while (snd->byte); snd->state = PLIP_PK_CHECKSUM; case PLIP_PK_CHECKSUM: if (plip_send(nibble_timeout, dev, &snd->nibble, snd->checksum)) return TIMEOUT; nl->enet_stats.tx_bytes += snd->skb->len; dev_kfree_skb(snd->skb); nl->enet_stats.tx_packets++; snd->state = PLIP_PK_DONE; case PLIP_PK_DONE: /* Close the connection */ write_data (dev, 0x00); snd->skb = NULL; if (net_debug > 2) printk(KERN_DEBUG "%s: send end\n", dev->name); nl->connection = PLIP_CN_CLOSING; nl->is_deferred = 1; queue_task(&nl->deferred, &tq_timer); enable_parport_interrupts (dev); ENABLE(dev->irq); return OK; } return OK;}static intplip_connection_close(struct net_device *dev, struct net_local *nl, struct plip_local *snd, struct plip_local *rcv){ spin_lock_irq(&nl->lock); if (nl->connection == PLIP_CN_CLOSING) { nl->connection = PLIP_CN_NONE; netif_wake_queue (dev); } spin_unlock_irq(&nl->lock); if (nl->should_relinquish) { nl->should_relinquish = nl->port_owner = 0; parport_release(nl->pardev); } return OK;}/* PLIP_ERROR --- wait till other end settled */static intplip_error(struct net_device *dev, struct net_local *nl, struct plip_local *snd, struct plip_local *rcv){ unsigned char status; status = read_status(dev); if ((status & 0xf8) == 0x80) { if (net_debug > 2) printk(KERN_DEBUG "%s: reset interface.\n", dev->name); nl->connection = PLIP_CN_NONE; nl->should_relinquish = 0; netif_start_queue (dev); enable_parport_interrupts (dev); ENABLE(dev->irq); netif_wake_queue (dev); } else { nl->is_deferred = 1; queue_task(&nl->deferred, &tq_timer); } return OK;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -