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

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

undo development effort which was neither finished nor properly debugged yet
(this unbreaks networking once again)

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