source: mainline/uspace/srv/hw/netif/dp8390/dp8390.c@ 7922dea

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 7922dea was 7922dea, checked in by martin@…>, 14 years ago

further code simplification

  • Property mode set to 100644
File size: 16.9 KB
RevLine 
[e0854e3]1/*
2 * Copyright (c) 2009 Lukas Mejdrech
3 * Copyright (c) 2011 Martin Decky
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/*
31 * This code is based upon the NE2000 driver for MINIX,
32 * distributed according to a BSD-style license.
33 *
34 * Copyright (c) 1987, 1997, 2006 Vrije Universiteit
35 * Copyright (c) 1992, 1994 Philip Homburg
36 * Copyright (c) 1996 G. Falzoni
37 *
38 */
39
[21580dd]40/** @addtogroup dp8390
41 * @{
42 */
43
44/** @file
45 * DP8390 network interface core implementation.
46 */
47
48#include <assert.h>
[2687bdb]49#include <byteorder.h>
[21580dd]50#include <errno.h>
[14f1db0]51#include <netif_local.h>
[c69d327]52#include <net/packet.h>
[39d70ec]53#include <nil_interface.h>
[0a866eeb]54#include <packet_client.h>
[21580dd]55#include "dp8390_drv.h"
56#include "dp8390_port.h"
57#include "dp8390.h"
[2a6e4ac2]58#include "ne2000.h"
[21580dd]59
[39d70ec]60/** Read a memory block byte by byte.
61 *
[21580dd]62 * @param[in] port The source address.
63 * @param[out] buf The destination buffer.
64 * @param[in] size The memory block size in bytes.
[39d70ec]65 *
[21580dd]66 */
[aadf01e]67static void outsb(port_t port, void * buf, size_t size);
[21580dd]68
[39d70ec]69/** Read a memory block word by word.
70 *
[21580dd]71 * @param[in] port The source address.
72 * @param[out] buf The destination buffer.
73 * @param[in] size The memory block size in bytes.
[39d70ec]74 *
[21580dd]75 */
[aadf01e]76static void outsw(port_t port, void * buf, size_t size);
[21580dd]77
[39d70ec]78/*
79 * Some clones of the dp8390 and the PC emulator 'Bochs' require the CR_STA
[21580dd]80 * on writes to the CR register. Additional CR_STAs do not appear to hurt
[39d70ec]81 * genuine dp8390s.
[21580dd]82 */
[95ff5c4]83#define CR_EXTRA CR_STA
[21580dd]84
[74864ac]85static void dp_init(dpeth_t *dep);
86static void dp_reinit(dpeth_t *dep);
87static void dp_reset(dpeth_t *dep);
[39d70ec]88static void dp_recv(int nil_phone, device_id_t device_id, dpeth_t *dep);
89static int dp_pkt2user(int nil_phone, device_id_t device_id, dpeth_t *dep, int page, int length);
[74864ac]90static void conf_hw(dpeth_t *dep);
91static void insb(port_t port, void *buf, size_t size);
92static void insw(port_t port, void *buf, size_t size);
[21580dd]93
[95ff5c4]94int do_probe(dpeth_t *dep)
95{
[21580dd]96 /* This is the default, try to (re)locate the device. */
97 conf_hw(dep);
[66b628a]98 if (!dep->up)
[21580dd]99 /* Probe failed, or the device is configured off. */
[95ff5c4]100 return EXDEV;
101
[66b628a]102 if (dep->up)
[21580dd]103 dp_init(dep);
[95ff5c4]104
[21580dd]105 return EOK;
106}
107
[66b628a]108/** Initialize and/or start the network interface.
109 *
110 * @param[in,out] dep The network interface structure.
111 *
112 * @return EOK on success.
113 * @return EXDEV if the network interface is disabled.
114 *
115 */
116int do_init(dpeth_t *dep)
[95ff5c4]117{
[66b628a]118 if (!dep->up)
[aa1e202]119 /* FIXME: Perhaps call do_probe()? */
[21580dd]120 return EXDEV;
[95ff5c4]121
[66b628a]122 assert(dep->up);
123 assert(dep->enabled);
[95ff5c4]124
[21580dd]125 dp_reinit(dep);
126 return EOK;
127}
128
[95ff5c4]129void do_stop(dpeth_t *dep)
130{
[66b628a]131 if ((dep->up) && (dep->enabled)) {
[aadf01e]132 outb_reg0(dep, DP_CR, CR_STP | CR_DM_ABORT);
[7922dea]133 ne_stop(dep);
134
[66b628a]135 dep->enabled = false;
136 dep->stopped = false;
[e3fe7df]137 dep->sending = false;
138 dep->send_avail = false;
[21580dd]139 }
140}
141
[7922dea]142static void dp_user2nic(dpeth_t *dep, void *buf, size_t offset, int nic_addr, size_t size)
143{
144 size_t ecount = size & ~1;
145
146 outb_reg0(dep, DP_ISR, ISR_RDC);
147
148 if (dep->de_16bit) {
149 outb_reg0(dep, DP_RBCR0, ecount & 0xff);
150 outb_reg0(dep, DP_RBCR1, ecount >> 8);
151 } else {
152 outb_reg0(dep, DP_RBCR0, size & 0xff);
153 outb_reg0(dep, DP_RBCR1, size >> 8);
154 }
155
156 outb_reg0(dep, DP_RSAR0, nic_addr & 0xff);
157 outb_reg0(dep, DP_RSAR1, nic_addr >> 8);
158 outb_reg0(dep, DP_CR, CR_DM_RW | CR_PS_P0 | CR_STA);
159
160 if (dep->de_16bit) {
161 void *ptr = buf + offset;
162
163 if (ecount != 0) {
164 outsw(dep->de_data_port, ptr, ecount);
165 size -= ecount;
166 offset += ecount;
167 ptr += ecount;
168 }
169
170 if (size) {
171 assert(size == 1);
172
173 uint16_t two_bytes;
174
175 memcpy(&(((uint8_t *) &two_bytes)[0]), ptr, 1);
176 outw(dep->de_data_port, two_bytes);
177 }
178 } else
179 outsb(dep->de_data_port, buf + offset, size);
180
181 unsigned int i;
182 for (i = 0; i < 100; i++) {
183 if (inb_reg0(dep, DP_ISR) & ISR_RDC)
184 break;
185 }
186
187 if (i == 100)
188 fprintf(stderr, "Remote DMA failed to complete\n");
189}
190
[95ff5c4]191int do_pwrite(dpeth_t *dep, packet_t *packet, int from_int)
[21580dd]192{
193 int size;
194 int sendq_head;
[95ff5c4]195
[66b628a]196 assert(dep->up);
197 assert(dep->enabled);
[95ff5c4]198
[e3fe7df]199 if (dep->send_avail) {
200 fprintf(stderr, "Send already in progress\n");
[39d70ec]201 return EBUSY;
[21580dd]202 }
[95ff5c4]203
[b187536]204 sendq_head = dep->de_sendq_head;
205 if (dep->de_sendq[sendq_head].sq_filled) {
206 if (from_int)
207 fprintf(stderr, "dp8390: should not be sending\n");
[e3fe7df]208 dep->send_avail = true;
209 dep->sending = false;
[39d70ec]210
211 return EBUSY;
[b187536]212 }
213
[e3fe7df]214 assert(!dep->sending);
[95ff5c4]215
[40559a96]216 void *buf = packet_get_data(packet);
[aadf01e]217 size = packet_get_data_length(packet);
[95ff5c4]218
219 if (size < ETH_MIN_PACK_SIZE || size > ETH_MAX_PACK_SIZE_TAGGED) {
[74864ac]220 fprintf(stderr, "dp8390: invalid packet size\n");
[21580dd]221 return EINVAL;
222 }
[95ff5c4]223
[7922dea]224 dp_user2nic(dep, buf, 0, dep->de_sendq[sendq_head].sq_sendpage
225 * DP_PAGESIZE, size);
[096234b]226 dep->de_sendq[sendq_head].sq_filled = true;
227
[95ff5c4]228 if (dep->de_sendq_tail == sendq_head) {
[21580dd]229 outb_reg0(dep, DP_TPSR, dep->de_sendq[sendq_head].sq_sendpage);
230 outb_reg0(dep, DP_TBCR1, size >> 8);
[95ff5c4]231 outb_reg0(dep, DP_TBCR0, size & 0xff);
[096234b]232 outb_reg0(dep, DP_CR, CR_TXP | CR_EXTRA); /* there it goes .. */
[95ff5c4]233 } else
234 dep->de_sendq[sendq_head].sq_size = size;
[21580dd]235
236 if (++sendq_head == dep->de_sendq_nr)
[b187536]237 sendq_head = 0;
[95ff5c4]238
[21580dd]239 assert(sendq_head < SENDQ_NR);
[95ff5c4]240 dep->de_sendq_head = sendq_head;
[e3fe7df]241 dep->sending = true;
[39d70ec]242
243 if (from_int)
244 return EOK;
245
[e3fe7df]246 dep->sending = false;
[95ff5c4]247
[21580dd]248 return EOK;
249}
250
[95ff5c4]251void dp_init(dpeth_t *dep)
[21580dd]252{
253 int dp_rcr_reg;
[d3c9b60]254 int i;
[95ff5c4]255
[21580dd]256 /* General initialization */
[66b628a]257 dep->enabled = false;
258 dep->stopped = false;
[e3fe7df]259 dep->sending = false;
260 dep->send_avail = false;
[7922dea]261 ne_init(dep);
[95ff5c4]262
[66b628a]263 printf("Ethernet address ");
[506a805]264 for (i = 0; i < 6; i++)
265 printf("%x%c", dep->de_address.ea_addr[i], i < 5 ? ':' : '\n');
[d3c9b60]266
267 /*
268 * Initialization of the dp8390 following the mandatory procedure
[21580dd]269 * in reference manual ("DP8390D/NS32490D NIC Network Interface
270 * Controller", National Semiconductor, July 1995, Page 29).
271 */
[d3c9b60]272
[21580dd]273 /* Step 1: */
274 outb_reg0(dep, DP_CR, CR_PS_P0 | CR_STP | CR_DM_ABORT);
[d3c9b60]275
[21580dd]276 /* Step 2: */
277 if (dep->de_16bit)
278 outb_reg0(dep, DP_DCR, DCR_WORDWIDE | DCR_8BYTES | DCR_BMS);
279 else
280 outb_reg0(dep, DP_DCR, DCR_BYTEWIDE | DCR_8BYTES | DCR_BMS);
[d3c9b60]281
[21580dd]282 /* Step 3: */
283 outb_reg0(dep, DP_RBCR0, 0);
284 outb_reg0(dep, DP_RBCR1, 0);
[d3c9b60]285
[21580dd]286 /* Step 4: */
[66b628a]287 dp_rcr_reg = RCR_AB; /* Enable broadcasts */
[d3c9b60]288
[21580dd]289 outb_reg0(dep, DP_RCR, dp_rcr_reg);
[d3c9b60]290
[21580dd]291 /* Step 5: */
292 outb_reg0(dep, DP_TCR, TCR_INTERNAL);
[d3c9b60]293
[21580dd]294 /* Step 6: */
295 outb_reg0(dep, DP_BNRY, dep->de_startpage);
296 outb_reg0(dep, DP_PSTART, dep->de_startpage);
297 outb_reg0(dep, DP_PSTOP, dep->de_stoppage);
[d3c9b60]298
[21580dd]299 /* Step 7: */
300 outb_reg0(dep, DP_ISR, 0xFF);
[d3c9b60]301
[21580dd]302 /* Step 8: */
303 outb_reg0(dep, DP_IMR, IMR_PRXE | IMR_PTXE | IMR_RXEE | IMR_TXEE |
[d3c9b60]304 IMR_OVWE | IMR_CNTE);
305
[21580dd]306 /* Step 9: */
307 outb_reg0(dep, DP_CR, CR_PS_P1 | CR_DM_ABORT | CR_STP);
[d3c9b60]308
[21580dd]309 outb_reg1(dep, DP_PAR0, dep->de_address.ea_addr[0]);
310 outb_reg1(dep, DP_PAR1, dep->de_address.ea_addr[1]);
311 outb_reg1(dep, DP_PAR2, dep->de_address.ea_addr[2]);
312 outb_reg1(dep, DP_PAR3, dep->de_address.ea_addr[3]);
313 outb_reg1(dep, DP_PAR4, dep->de_address.ea_addr[4]);
314 outb_reg1(dep, DP_PAR5, dep->de_address.ea_addr[5]);
[d3c9b60]315
[21580dd]316 outb_reg1(dep, DP_MAR0, 0xff);
317 outb_reg1(dep, DP_MAR1, 0xff);
318 outb_reg1(dep, DP_MAR2, 0xff);
319 outb_reg1(dep, DP_MAR3, 0xff);
320 outb_reg1(dep, DP_MAR4, 0xff);
321 outb_reg1(dep, DP_MAR5, 0xff);
322 outb_reg1(dep, DP_MAR6, 0xff);
323 outb_reg1(dep, DP_MAR7, 0xff);
[d3c9b60]324
[21580dd]325 outb_reg1(dep, DP_CURR, dep->de_startpage + 1);
[d3c9b60]326
[21580dd]327 /* Step 10: */
328 outb_reg0(dep, DP_CR, CR_DM_ABORT | CR_STA);
[d3c9b60]329
[21580dd]330 /* Step 11: */
331 outb_reg0(dep, DP_TCR, TCR_NORMAL);
[d3c9b60]332
333 inb_reg0(dep, DP_CNTR0); /* Reset counters by reading */
[21580dd]334 inb_reg0(dep, DP_CNTR1);
335 inb_reg0(dep, DP_CNTR2);
[d3c9b60]336
[21580dd]337 /* Finish the initialization. */
[66b628a]338 dep->enabled = true;
[d3c9b60]339 for (i = 0; i < dep->de_sendq_nr; i++)
[21580dd]340 dep->de_sendq[i].sq_filled= 0;
[d3c9b60]341
342 dep->de_sendq_head = 0;
343 dep->de_sendq_tail = 0;
[21580dd]344}
345
[b590c21]346static void dp_reinit(dpeth_t *dep)
[21580dd]347{
348 int dp_rcr_reg;
[b590c21]349
[21580dd]350 outb_reg0(dep, DP_CR, CR_PS_P0 | CR_EXTRA);
[b590c21]351
[66b628a]352 /* Enable broadcasts */
353 dp_rcr_reg = RCR_AB;
[b590c21]354
[21580dd]355 outb_reg0(dep, DP_RCR, dp_rcr_reg);
356}
357
[b590c21]358static void dp_reset(dpeth_t *dep)
[21580dd]359{
360 int i;
[b590c21]361
[21580dd]362 /* Stop chip */
363 outb_reg0(dep, DP_CR, CR_STP | CR_DM_ABORT);
364 outb_reg0(dep, DP_RBCR0, 0);
365 outb_reg0(dep, DP_RBCR1, 0);
[b590c21]366
367 for (i = 0; i < 0x1000 && ((inb_reg0(dep, DP_ISR) & ISR_RST) == 0); i++)
[21580dd]368 ; /* Do nothing */
[b590c21]369
370 outb_reg0(dep, DP_TCR, TCR_1EXTERNAL | TCR_OFST);
371 outb_reg0(dep, DP_CR, CR_STA | CR_DM_ABORT);
[21580dd]372 outb_reg0(dep, DP_TCR, TCR_NORMAL);
[b590c21]373
374 /* Acknowledge the ISR_RDC (remote DMA) interrupt. */
375 for (i = 0; i < 0x1000 && ((inb_reg0(dep, DP_ISR) &ISR_RDC) == 0); i++)
[21580dd]376 ; /* Do nothing */
[b590c21]377
378 outb_reg0(dep, DP_ISR, inb_reg0(dep, DP_ISR) & ~ISR_RDC);
379
380 /*
381 * Reset the transmit ring. If we were transmitting a packet, we
[21580dd]382 * pretend that the packet is processed. Higher layers will
383 * retransmit if the packet wasn't actually sent.
384 */
[b590c21]385 dep->de_sendq_head = 0;
386 dep->de_sendq_tail = 0;
387
388 for (i = 0; i < dep->de_sendq_nr; i++)
389 dep->de_sendq[i].sq_filled = 0;
390
[e3fe7df]391 dep->send_avail = false;
[66b628a]392 dep->stopped = false;
[21580dd]393}
394
[d8d8bbd]395static uint8_t isr_acknowledge(dpeth_t *dep)
396{
[efa8aec6]397 uint8_t isr = inb_reg0(dep, DP_ISR);
[d8d8bbd]398 if (isr != 0)
399 outb_reg0(dep, DP_ISR, isr);
400
401 return isr;
402}
403
404void dp_check_ints(int nil_phone, device_id_t device_id, dpeth_t *dep, uint8_t isr)
[21580dd]405{
[6fc0edd]406 int tsr;
[21580dd]407 int size, sendq_tail;
[0777f4c5]408
[efa8aec6]409 for (; (isr & 0x7f) != 0; isr = isr_acknowledge(dep)) {
[0777f4c5]410 if (isr & (ISR_PTX | ISR_TXE)) {
411 if (isr & ISR_TXE)
[21580dd]412 dep->de_stat.ets_sendErr++;
[0777f4c5]413 else {
[21580dd]414 tsr = inb_reg0(dep, DP_TSR);
[0777f4c5]415
416 if (tsr & TSR_PTX)
417 dep->de_stat.ets_packetT++;
418
419 if (tsr & TSR_COL)
420 dep->de_stat.ets_collision++;
421
422 if (tsr & TSR_ABT)
423 dep->de_stat.ets_transAb++;
424
425 if (tsr & TSR_CRS)
426 dep->de_stat.ets_carrSense++;
427
428 if ((tsr & TSR_FU) && (++dep->de_stat.ets_fifoUnder <= 10))
[66b628a]429 printf("FIFO underrun\n");
[0777f4c5]430
431 if ((tsr & TSR_CDH) && (++dep->de_stat.ets_CDheartbeat <= 10))
[66b628a]432 printf("CD heart beat failure\n");
[0777f4c5]433
434 if (tsr & TSR_OWC)
435 dep->de_stat.ets_OWC++;
[21580dd]436 }
[0777f4c5]437
438 sendq_tail = dep->de_sendq_tail;
439
440 if (!(dep->de_sendq[sendq_tail].sq_filled)) {
[66b628a]441 printf("PTX interrupt, but no frame to send\n");
[21580dd]442 continue;
443 }
[0777f4c5]444
[efa8aec6]445 dep->de_sendq[sendq_tail].sq_filled = false;
[0777f4c5]446
[21580dd]447 if (++sendq_tail == dep->de_sendq_nr)
[0777f4c5]448 sendq_tail = 0;
449
450 dep->de_sendq_tail = sendq_tail;
451
452 if (dep->de_sendq[sendq_tail].sq_filled) {
453 size = dep->de_sendq[sendq_tail].sq_size;
[21580dd]454 outb_reg0(dep, DP_TPSR,
[0777f4c5]455 dep->de_sendq[sendq_tail].sq_sendpage);
[21580dd]456 outb_reg0(dep, DP_TBCR1, size >> 8);
[0777f4c5]457 outb_reg0(dep, DP_TBCR0, size & 0xff);
[21580dd]458 outb_reg0(dep, DP_CR, CR_TXP | CR_EXTRA);
459 }
[0777f4c5]460
[e3fe7df]461 dep->send_avail = false;
[21580dd]462 }
[0777f4c5]463
[aa1e202]464 if (isr & ISR_PRX)
465 dp_recv(nil_phone, device_id, dep);
[21580dd]466
[0777f4c5]467 if (isr & ISR_RXE)
468 dep->de_stat.ets_recvErr++;
469
470 if (isr & ISR_CNT) {
[21580dd]471 dep->de_stat.ets_CRCerr += inb_reg0(dep, DP_CNTR0);
472 dep->de_stat.ets_frameAll += inb_reg0(dep, DP_CNTR1);
473 dep->de_stat.ets_missedP += inb_reg0(dep, DP_CNTR2);
474 }
[0777f4c5]475
[aa1e202]476 if (isr & ISR_OVW)
[21580dd]477 dep->de_stat.ets_OVW++;
[0777f4c5]478
479 if (isr & ISR_RDC) {
[21580dd]480 /* Nothing to do */
481 }
[0777f4c5]482
483 if (isr & ISR_RST) {
484 /*
[66b628a]485 * This means we got an interrupt but the ethernet
486 * chip is shutdown. We set the flag 'stopped'
[21580dd]487 * and continue processing arrived packets. When the
488 * receive buffer is empty, we reset the dp8390.
489 */
[66b628a]490 dep->stopped = true;
[21580dd]491 break;
492 }
493 }
[0777f4c5]494
[66b628a]495 if (dep->stopped) {
[0777f4c5]496 /*
[66b628a]497 * The chip is stopped, and all arrived
498 * frames are delivered.
[21580dd]499 */
500 dp_reset(dep);
501 }
[39d70ec]502
[e3fe7df]503 dep->sending = false;
[21580dd]504}
505
[7922dea]506static void dp_getblock(dpeth_t *dep, int page, size_t offset, size_t size, void *dst)
507{
508 offset = page * DP_PAGESIZE + offset;
509
510 outb_reg0(dep, DP_RBCR0, size & 0xff);
511 outb_reg0(dep, DP_RBCR1, size >> 8);
512 outb_reg0(dep, DP_RSAR0, offset & 0xff);
513 outb_reg0(dep, DP_RSAR1, offset >> 8);
514 outb_reg0(dep, DP_CR, CR_DM_RR | CR_PS_P0 | CR_STA);
515
516 if (dep->de_16bit) {
517 assert((size % 2) == 0);
518 insw(dep->de_data_port, dst, size);
519 } else
520 insb(dep->de_data_port, dst, size);
521}
522
[39d70ec]523static void dp_recv(int nil_phone, device_id_t device_id, dpeth_t *dep)
[21580dd]524{
525 dp_rcvhdr_t header;
[04729b1e]526 int pageno, curr, next;
[d3a0af7]527 size_t length;
[21580dd]528 int packet_processed, r;
[74864ac]529 uint16_t eth_type;
[b590c21]530
[74864ac]531 packet_processed = false;
[21580dd]532 pageno = inb_reg0(dep, DP_BNRY) + 1;
[b590c21]533 if (pageno == dep->de_stoppage)
534 pageno = dep->de_startpage;
535
536 do {
[21580dd]537 outb_reg0(dep, DP_CR, CR_PS_P1 | CR_EXTRA);
538 curr = inb_reg1(dep, DP_CURR);
539 outb_reg0(dep, DP_CR, CR_PS_P0 | CR_EXTRA);
[b590c21]540
541 if (curr == pageno)
542 break;
543
[7922dea]544 dp_getblock(dep, pageno, (size_t) 0, sizeof(header), &header);
545 dp_getblock(dep, pageno, sizeof(header) +
546 2 * sizeof(ether_addr_t), sizeof(eth_type), &eth_type);
[b590c21]547
548 length = (header.dr_rbcl | (header.dr_rbch << 8)) - sizeof(dp_rcvhdr_t);
[21580dd]549 next = header.dr_next;
[b590c21]550 if ((length < ETH_MIN_PACK_SIZE) || (length > ETH_MAX_PACK_SIZE_TAGGED)) {
[66b628a]551 printf("Packet with strange length arrived: %zu\n", length);
[21580dd]552 next= curr;
[b590c21]553 } else if ((next < dep->de_startpage) || (next >= dep->de_stoppage)) {
[66b628a]554 printf("Strange next page\n");
[21580dd]555 next= curr;
[b590c21]556 } else if (header.dr_status & RSR_FO) {
557 /*
558 * This is very serious, so we issue a warning and
559 * reset the buffers
[21580dd]560 */
[66b628a]561 printf("FIFO overrun, resetting receive buffer\n");
[21580dd]562 dep->de_stat.ets_fifoOver++;
563 next = curr;
[66b628a]564 } else if ((header.dr_status & RSR_PRX) && (dep->enabled)) {
[39d70ec]565 r = dp_pkt2user(nil_phone, device_id, dep, pageno, length);
[fc23ef6]566 if (r != EOK)
[21580dd]567 return;
[b590c21]568
[74864ac]569 packet_processed = true;
[21580dd]570 dep->de_stat.ets_packetR++;
571 }
[b590c21]572
[21580dd]573 if (next == dep->de_startpage)
574 outb_reg0(dep, DP_BNRY, dep->de_stoppage - 1);
575 else
576 outb_reg0(dep, DP_BNRY, next - 1);
[b590c21]577
[21580dd]578 pageno = next;
[b590c21]579 } while (!packet_processed);
[21580dd]580}
581
[7922dea]582static void dp_nic2user(dpeth_t *dep, int nic_addr, void *buf, size_t offset, size_t size)
[21580dd]583{
[7922dea]584 size_t ecount = size & ~1;
[b590c21]585
[7922dea]586 if (dep->de_16bit) {
587 outb_reg0(dep, DP_RBCR0, ecount & 0xFF);
588 outb_reg0(dep, DP_RBCR1, ecount >> 8);
589 } else {
590 outb_reg0(dep, DP_RBCR0, size & 0xff);
591 outb_reg0(dep, DP_RBCR1, size >> 8);
592 }
[b590c21]593
[7922dea]594 outb_reg0(dep, DP_RSAR0, nic_addr & 0xff);
595 outb_reg0(dep, DP_RSAR1, nic_addr >> 8);
596 outb_reg0(dep, DP_CR, CR_DM_RR | CR_PS_P0 | CR_STA);
[b590c21]597
[7922dea]598 if (dep->de_16bit) {
599 void *ptr = buf + offset;
600
601 if (ecount != 0) {
602 insw(dep->de_data_port, ptr, ecount);
603 size -= ecount;
604 offset += ecount;
605 ptr += ecount;
606 }
607
608 if (size) {
609 assert(size == 1);
610
611 uint16_t two_bytes = inw(dep->de_data_port);
612 memcpy(ptr, &(((uint8_t *) &two_bytes)[0]), 1);
613 }
614 } else
615 insb(dep->de_data_port, buf + offset, size);
[21580dd]616}
617
[39d70ec]618static int dp_pkt2user(int nil_phone, device_id_t device_id, dpeth_t *dep, int page, int length)
[21580dd]619{
620 int last, count;
[46d4d9f]621 packet_t *packet;
[b590c21]622
[aadf01e]623 packet = netif_packet_get_1(length);
[b590c21]624 if (!packet)
[aadf01e]625 return ENOMEM;
[b590c21]626
[40559a96]627 void *buf = packet_suffix(packet, length);
[b590c21]628
[21580dd]629 last = page + (length - 1) / DP_PAGESIZE;
[b590c21]630 if (last >= dep->de_stoppage) {
631 count = (dep->de_stoppage - page) * DP_PAGESIZE - sizeof(dp_rcvhdr_t);
632
[7922dea]633 dp_nic2user(dep, page * DP_PAGESIZE + sizeof(dp_rcvhdr_t),
634 buf, 0, count);
635 dp_nic2user(dep, dep->de_startpage * DP_PAGESIZE,
[40559a96]636 buf, count, length - count);
[b590c21]637 } else {
[7922dea]638 dp_nic2user(dep, page * DP_PAGESIZE + sizeof(dp_rcvhdr_t),
639 buf, 0, length);
[21580dd]640 }
[b590c21]641
[39d70ec]642 nil_received_msg(nil_phone, device_id, packet, SERVICE_NONE);
[b590c21]643
[fc23ef6]644 return EOK;
[21580dd]645}
646
[d3a0af7]647static void conf_hw(dpeth_t *dep)
[21580dd]648{
[8f5e2527]649 if (!ne_probe(dep)) {
[66b628a]650 printf("No ethernet card found at %#lx\n", dep->de_base_port);
651 dep->up = false;
[21580dd]652 return;
653 }
[d3a0af7]654
[66b628a]655 dep->up = true;
656 dep->enabled = false;
657 dep->stopped = false;
[e3fe7df]658 dep->sending = false;
659 dep->send_avail = false;
[21580dd]660}
661
662static void insb(port_t port, void *buf, size_t size)
663{
664 size_t i;
[d3a0af7]665
666 for (i = 0; i < size; i++)
[aadf01e]667 *((uint8_t *) buf + i) = inb(port);
[21580dd]668}
669
670static void insw(port_t port, void *buf, size_t size)
671{
672 size_t i;
[d3a0af7]673
674 for (i = 0; i * 2 < size; i++)
[aadf01e]675 *((uint16_t *) buf + i) = inw(port);
[21580dd]676}
677
678static void outsb(port_t port, void *buf, size_t size)
679{
680 size_t i;
[d3a0af7]681
682 for (i = 0; i < size; i++)
[aadf01e]683 outb(port, *((uint8_t *) buf + i));
[21580dd]684}
685
686static void outsw(port_t port, void *buf, size_t size)
687{
688 size_t i;
[d3a0af7]689
690 for (i = 0; i * 2 < size; i++)
[aadf01e]691 outw(port, *((uint16_t *) buf + i));
[21580dd]692}
693
694/** @}
695 */
Note: See TracBrowser for help on using the repository browser.