source: mainline/uspace/srv/hw/netif/ne2000/ne2000.c@ a5bad72

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since a5bad72 was 79ae36dd, checked in by Martin Decky <martin@…>, 15 years ago

new async framework with integrated exchange tracking

  • strict isolation between low-level IPC and high-level async framework with integrated exchange tracking
    • each IPC connection is represented by an async_sess_t structure
    • each IPC exchange is represented by an async_exch_t structure
    • exchange management is either based on atomic messages (EXCHANGE_ATOMIC), locking (EXCHANGE_SERIALIZE) or connection cloning (EXCHANGE_CLONE)
  • async_obsolete: temporary compatibility layer to keep old async clients working (several pieces of code are currently broken, but only non-essential functionality)
  • IPC_M_PHONE_HANGUP is now method no. 0 (for elegant boolean evaluation)
  • IPC_M_DEBUG_ALL has been renamed to IPC_M_DEBUG
  • IPC_M_PING has been removed (VFS protocol now has VFS_IN_PING)
  • console routines in libc have been rewritten for better abstraction
  • additional use for libc-private header files (FILE structure opaque to the client)
  • various cstyle changes (typos, indentation, missing externs in header files, improved comments, etc.)
  • Property mode set to 100644
File size: 9.0 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
[3c106e88]30/** @addtogroup ne2000
[21580dd]31 * @{
32 */
33
34/** @file
[3c106e88]35 * NE2000 network interface implementation.
[21580dd]36 */
37
[3c106e88]38#include <assert.h>
39#include <async.h>
[79ae36dd]40#include <async_obsolete.h>
[3c106e88]41#include <ddi.h>
42#include <errno.h>
43#include <err.h>
44#include <malloc.h>
45#include <sysinfo.h>
46#include <ipc/services.h>
[79ae36dd]47#include <ns.h>
48#include <ns_obsolete.h>
[3c106e88]49#include <ipc/irc.h>
50#include <net/modules.h>
51#include <packet_client.h>
52#include <adt/measured_strings.h>
53#include <net/device.h>
54#include <netif_skel.h>
[fe8dfa6]55#include <nil_remote.h>
[21580dd]56#include "dp8390.h"
57
[3c106e88]58/** Return the device from the interrupt call.
59 *
60 * @param[in] call The interrupt call.
61 *
62 */
63#define IRQ_GET_DEVICE(call) ((device_id_t) IPC_GET_IMETHOD(call))
[21580dd]64
[3c106e88]65/** Return the ISR from the interrupt call.
66 *
67 * @param[in] call The interrupt call.
68 *
69 */
70#define IRQ_GET_ISR(call) ((int) IPC_GET_ARG2(call))
[21580dd]71
[7300c37]72/** Return the TSR from the interrupt call.
73 *
74 * @param[in] call The interrupt call.
75 *
76 */
77#define IRQ_GET_TSR(call) ((int) IPC_GET_ARG3(call))
78
[57d129e]79static bool irc_service = false;
[3c106e88]80static int irc_phone = -1;
[21580dd]81
[f902d36]82/** NE2000 kernel interrupt command sequence.
[3c106e88]83 *
[21580dd]84 */
[3c106e88]85static irq_cmd_t ne2k_cmds[] = {
86 {
[abe95c9]87 /* Read Interrupt Status Register */
[3c106e88]88 .cmd = CMD_PIO_READ_8,
89 .addr = NULL,
90 .dstarg = 2
91 },
92 {
[abe95c9]93 /* Mask supported interrupt causes */
[3c106e88]94 .cmd = CMD_BTEST,
[abe95c9]95 .value = (ISR_PRX | ISR_PTX | ISR_RXE | ISR_TXE | ISR_OVW |
96 ISR_CNT | ISR_RDC),
[3c106e88]97 .srcarg = 2,
98 .dstarg = 3,
99 },
100 {
[abe95c9]101 /* Predicate for accepting the interrupt */
[3c106e88]102 .cmd = CMD_PREDICATE,
[7300c37]103 .value = 4,
[3c106e88]104 .srcarg = 3
105 },
106 {
[abe95c9]107 /*
108 * Mask future interrupts via
109 * Interrupt Mask Register
110 */
111 .cmd = CMD_PIO_WRITE_8,
112 .addr = NULL,
113 .value = 0
114 },
115 {
116 /* Acknowledge the current interrupt */
[3c106e88]117 .cmd = CMD_PIO_WRITE_A_8,
118 .addr = NULL,
119 .srcarg = 3
120 },
[7300c37]121 {
122 /* Read Transmit Status Register */
123 .cmd = CMD_PIO_READ_8,
124 .addr = NULL,
125 .dstarg = 3
126 },
[3c106e88]127 {
128 .cmd = CMD_ACCEPT
129 }
130};
[21580dd]131
[f902d36]132/** NE2000 kernel interrupt code.
[3c106e88]133 *
[21580dd]134 */
[3c106e88]135static irq_code_t ne2k_code = {
136 sizeof(ne2k_cmds) / sizeof(irq_cmd_t),
137 ne2k_cmds
138};
[21580dd]139
[3c106e88]140/** Handle the interrupt notification.
141 *
[7300c37]142 * This is the interrupt notification function. It is quarantied
143 * that there is only a single instance of this notification
144 * function running at one time until the return from the
145 * ne2k_interrupt() function (where the interrupts are unmasked
146 * again).
[3c106e88]147 *
148 * @param[in] iid Interrupt notification identifier.
149 * @param[in] call Interrupt notification.
150 *
151 */
152static void irq_handler(ipc_callid_t iid, ipc_call_t *call)
[21580dd]153{
[3c106e88]154 device_id_t device_id = IRQ_GET_DEVICE(*call);
155 netif_device_t *device;
156 int nil_phone;
157 ne2k_t *ne2k;
[d3c9b60]158
[3c106e88]159 fibril_rwlock_read_lock(&netif_globals.lock);
[d3c9b60]160
[3c106e88]161 if (find_device(device_id, &device) == EOK) {
162 nil_phone = device->nil_phone;
163 ne2k = (ne2k_t *) device->specific;
164 } else
165 ne2k = NULL;
[d3c9b60]166
[3c106e88]167 fibril_rwlock_read_unlock(&netif_globals.lock);
[d3c9b60]168
[7300c37]169 if (ne2k != NULL) {
170 link_t *frames =
171 ne2k_interrupt(ne2k, IRQ_GET_ISR(*call), IRQ_GET_TSR(*call));
172
173 if (frames != NULL) {
174 while (!list_empty(frames)) {
175 frame_t *frame =
176 list_get_instance(frames->next, frame_t, link);
177
178 list_remove(&frame->link);
179 nil_received_msg(nil_phone, device_id, frame->packet,
180 SERVICE_NONE);
181 free(frame);
182 }
183
184 free(frames);
185 }
186 }
[21580dd]187}
188
[3c106e88]189/** Change the network interface state.
[7922dea]190 *
[3c106e88]191 * @param[in,out] device Network interface.
192 * @param[in] state New state.
[7922dea]193 *
194 */
[3c106e88]195static void change_state(netif_device_t *device, device_state_t state)
[21580dd]196{
[3c106e88]197 if (device->state != state) {
198 device->state = state;
199
200 const char *desc;
201 switch (state) {
202 case NETIF_ACTIVE:
203 desc = "active";
204 break;
205 case NETIF_STOPPED:
206 desc = "stopped";
207 break;
208 default:
209 desc = "unknown";
210 }
211
212 printf("%s: State changed to %s\n", NAME, desc);
[21580dd]213 }
[3c106e88]214}
215
216int netif_specific_message(ipc_callid_t callid, ipc_call_t *call,
217 ipc_call_t *answer, size_t *count)
218{
219 return ENOTSUP;
220}
221
222int netif_get_device_stats(device_id_t device_id, device_stats_t *stats)
223{
224 if (!stats)
225 return EBADMEM;
[d3c9b60]226
[3c106e88]227 netif_device_t *device;
228 int rc = find_device(device_id, &device);
229 if (rc != EOK)
230 return rc;
[d3c9b60]231
[3c106e88]232 ne2k_t *ne2k = (ne2k_t *) device->specific;
[d3c9b60]233
[3c106e88]234 memcpy(stats, &ne2k->stats, sizeof(device_stats_t));
235 return EOK;
236}
237
238int netif_get_addr_message(device_id_t device_id, measured_string_t *address)
239{
240 if (!address)
241 return EBADMEM;
[d3c9b60]242
[3c106e88]243 netif_device_t *device;
244 int rc = find_device(device_id, &device);
245 if (rc != EOK)
246 return rc;
[d3c9b60]247
[3c106e88]248 ne2k_t *ne2k = (ne2k_t *) device->specific;
[d3c9b60]249
[3c106e88]250 address->value = ne2k->mac;
251 address->length = ETH_ADDR;
252 return EOK;
[21580dd]253}
254
[3c106e88]255int netif_probe_message(device_id_t device_id, int irq, void *io)
[21580dd]256{
[3c106e88]257 netif_device_t *device =
258 (netif_device_t *) malloc(sizeof(netif_device_t));
259 if (!device)
260 return ENOMEM;
[506a805]261
[3c106e88]262 ne2k_t *ne2k = (ne2k_t *) malloc(sizeof(ne2k_t));
263 if (!ne2k) {
264 free(device);
265 return ENOMEM;
266 }
[506a805]267
[3c106e88]268 void *port;
269 int rc = pio_enable((void *) io, NE2K_IO_SIZE, &port);
270 if (rc != EOK) {
271 free(ne2k);
272 free(device);
273 return rc;
274 }
[506a805]275
[3c106e88]276 bzero(device, sizeof(netif_device_t));
277 bzero(ne2k, sizeof(ne2k_t));
[506a805]278
[3c106e88]279 device->device_id = device_id;
280 device->nil_phone = -1;
281 device->specific = (void *) ne2k;
282 device->state = NETIF_STOPPED;
283
284 rc = ne2k_probe(ne2k, port, irq);
285 if (rc != EOK) {
286 printf("%s: No ethernet card found at I/O address %p\n",
287 NAME, port);
288 free(ne2k);
289 free(device);
290 return rc;
[21580dd]291 }
[506a805]292
[3c106e88]293 rc = netif_device_map_add(&netif_globals.device_map, device->device_id, device);
294 if (rc != EOK) {
295 free(ne2k);
296 free(device);
297 return rc;
[21580dd]298 }
[506a805]299
[3c106e88]300 printf("%s: Ethernet card at I/O address %p, IRQ %d, MAC ",
301 NAME, port, irq);
[506a805]302
[3c106e88]303 unsigned int i;
304 for (i = 0; i < ETH_ADDR; i++)
305 printf("%02x%c", ne2k->mac[i], i < 5 ? ':' : '\n');
[506a805]306
[3c106e88]307 return EOK;
[21580dd]308}
309
[3c106e88]310int netif_start_message(netif_device_t *device)
[21580dd]311{
[3c106e88]312 if (device->state != NETIF_ACTIVE) {
313 ne2k_t *ne2k = (ne2k_t *) device->specific;
314
315 ne2k_cmds[0].addr = ne2k->port + DP_ISR;
[abe95c9]316 ne2k_cmds[3].addr = ne2k->port + DP_IMR;
317 ne2k_cmds[4].addr = ne2k_cmds[0].addr;
[6b22c97]318 ne2k_cmds[5].addr = ne2k->port + DP_TSR;
[3c106e88]319
[ffa2c8ef]320 int rc = register_irq(ne2k->irq, device->device_id,
[3c106e88]321 device->device_id, &ne2k_code);
322 if (rc != EOK)
323 return rc;
324
325 rc = ne2k_up(ne2k);
326 if (rc != EOK) {
[ffa2c8ef]327 unregister_irq(ne2k->irq, device->device_id);
[3c106e88]328 return rc;
329 }
330
[43b4314]331 change_state(device, NETIF_ACTIVE);
332
[3c106e88]333 if (irc_service)
[79ae36dd]334 async_obsolete_msg_1(irc_phone, IRC_ENABLE_INTERRUPT, ne2k->irq);
[3c106e88]335 }
[506a805]336
[3c106e88]337 return device->state;
338}
339
340int netif_stop_message(netif_device_t *device)
341{
342 if (device->state != NETIF_STOPPED) {
343 ne2k_t *ne2k = (ne2k_t *) device->specific;
344
345 ne2k_down(ne2k);
[ffa2c8ef]346 unregister_irq(ne2k->irq, device->device_id);
[3c106e88]347 change_state(device, NETIF_STOPPED);
348 }
[506a805]349
[fe8dfa6]350 return device->state;
[3c106e88]351}
352
353int netif_send_message(device_id_t device_id, packet_t *packet,
354 services_t sender)
355{
356 netif_device_t *device;
357 int rc = find_device(device_id, &device);
358 if (rc != EOK)
359 return rc;
[506a805]360
[3c106e88]361 if (device->state != NETIF_ACTIVE) {
362 netif_pq_release(packet_get_id(packet));
363 return EFORWARD;
[21580dd]364 }
[506a805]365
[3c106e88]366 ne2k_t *ne2k = (ne2k_t *) device->specific;
[506a805]367
[3c106e88]368 /*
369 * Process the packet queue
370 */
[506a805]371
[3c106e88]372 do {
373 packet_t *next = pq_detach(packet);
374 ne2k_send(ne2k, packet);
375 netif_pq_release(packet_get_id(packet));
376 packet = next;
377 } while (packet);
[506a805]378
[3c106e88]379 return EOK;
[21580dd]380}
381
[3c106e88]382int netif_initialize(void)
383{
384 sysarg_t apic;
385 sysarg_t i8259;
386
[57d129e]387 if (((sysinfo_get_value("apic", &apic) == EOK) && (apic))
388 || ((sysinfo_get_value("i8259", &i8259) == EOK) && (i8259)))
389 irc_service = true;
[3c106e88]390
391 if (irc_service) {
[007e6efa]392 while (irc_phone < 0)
[79ae36dd]393 irc_phone = service_obsolete_connect_blocking(SERVICE_IRC, 0, 0);
[3c106e88]394 }
395
396 async_set_interrupt_received(irq_handler);
397
[79ae36dd]398 return service_register(SERVICE_NE2000);
[3c106e88]399}
400
401int main(int argc, char *argv[])
[21580dd]402{
[3c106e88]403 /* Start the module */
404 return netif_module_start();
[21580dd]405}
406
407/** @}
408 */
Note: See TracBrowser for help on using the repository browser.