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
Line 
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/** @addtogroup ne2000
31 * @{
32 */
33
34/** @file
35 * NE2000 network interface implementation.
36 */
37
38#include <assert.h>
39#include <async.h>
40#include <async_obsolete.h>
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>
47#include <ns.h>
48#include <ns_obsolete.h>
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>
55#include <nil_remote.h>
56#include "dp8390.h"
57
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))
64
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))
71
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
79static bool irc_service = false;
80static int irc_phone = -1;
81
82/** NE2000 kernel interrupt command sequence.
83 *
84 */
85static irq_cmd_t ne2k_cmds[] = {
86 {
87 /* Read Interrupt Status Register */
88 .cmd = CMD_PIO_READ_8,
89 .addr = NULL,
90 .dstarg = 2
91 },
92 {
93 /* Mask supported interrupt causes */
94 .cmd = CMD_BTEST,
95 .value = (ISR_PRX | ISR_PTX | ISR_RXE | ISR_TXE | ISR_OVW |
96 ISR_CNT | ISR_RDC),
97 .srcarg = 2,
98 .dstarg = 3,
99 },
100 {
101 /* Predicate for accepting the interrupt */
102 .cmd = CMD_PREDICATE,
103 .value = 4,
104 .srcarg = 3
105 },
106 {
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 */
117 .cmd = CMD_PIO_WRITE_A_8,
118 .addr = NULL,
119 .srcarg = 3
120 },
121 {
122 /* Read Transmit Status Register */
123 .cmd = CMD_PIO_READ_8,
124 .addr = NULL,
125 .dstarg = 3
126 },
127 {
128 .cmd = CMD_ACCEPT
129 }
130};
131
132/** NE2000 kernel interrupt code.
133 *
134 */
135static irq_code_t ne2k_code = {
136 sizeof(ne2k_cmds) / sizeof(irq_cmd_t),
137 ne2k_cmds
138};
139
140/** Handle the interrupt notification.
141 *
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).
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)
153{
154 device_id_t device_id = IRQ_GET_DEVICE(*call);
155 netif_device_t *device;
156 int nil_phone;
157 ne2k_t *ne2k;
158
159 fibril_rwlock_read_lock(&netif_globals.lock);
160
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;
166
167 fibril_rwlock_read_unlock(&netif_globals.lock);
168
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 }
187}
188
189/** Change the network interface state.
190 *
191 * @param[in,out] device Network interface.
192 * @param[in] state New state.
193 *
194 */
195static void change_state(netif_device_t *device, device_state_t state)
196{
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);
213 }
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;
226
227 netif_device_t *device;
228 int rc = find_device(device_id, &device);
229 if (rc != EOK)
230 return rc;
231
232 ne2k_t *ne2k = (ne2k_t *) device->specific;
233
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;
242
243 netif_device_t *device;
244 int rc = find_device(device_id, &device);
245 if (rc != EOK)
246 return rc;
247
248 ne2k_t *ne2k = (ne2k_t *) device->specific;
249
250 address->value = ne2k->mac;
251 address->length = ETH_ADDR;
252 return EOK;
253}
254
255int netif_probe_message(device_id_t device_id, int irq, void *io)
256{
257 netif_device_t *device =
258 (netif_device_t *) malloc(sizeof(netif_device_t));
259 if (!device)
260 return ENOMEM;
261
262 ne2k_t *ne2k = (ne2k_t *) malloc(sizeof(ne2k_t));
263 if (!ne2k) {
264 free(device);
265 return ENOMEM;
266 }
267
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 }
275
276 bzero(device, sizeof(netif_device_t));
277 bzero(ne2k, sizeof(ne2k_t));
278
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;
291 }
292
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;
298 }
299
300 printf("%s: Ethernet card at I/O address %p, IRQ %d, MAC ",
301 NAME, port, irq);
302
303 unsigned int i;
304 for (i = 0; i < ETH_ADDR; i++)
305 printf("%02x%c", ne2k->mac[i], i < 5 ? ':' : '\n');
306
307 return EOK;
308}
309
310int netif_start_message(netif_device_t *device)
311{
312 if (device->state != NETIF_ACTIVE) {
313 ne2k_t *ne2k = (ne2k_t *) device->specific;
314
315 ne2k_cmds[0].addr = ne2k->port + DP_ISR;
316 ne2k_cmds[3].addr = ne2k->port + DP_IMR;
317 ne2k_cmds[4].addr = ne2k_cmds[0].addr;
318 ne2k_cmds[5].addr = ne2k->port + DP_TSR;
319
320 int rc = register_irq(ne2k->irq, device->device_id,
321 device->device_id, &ne2k_code);
322 if (rc != EOK)
323 return rc;
324
325 rc = ne2k_up(ne2k);
326 if (rc != EOK) {
327 unregister_irq(ne2k->irq, device->device_id);
328 return rc;
329 }
330
331 change_state(device, NETIF_ACTIVE);
332
333 if (irc_service)
334 async_obsolete_msg_1(irc_phone, IRC_ENABLE_INTERRUPT, ne2k->irq);
335 }
336
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);
346 unregister_irq(ne2k->irq, device->device_id);
347 change_state(device, NETIF_STOPPED);
348 }
349
350 return device->state;
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;
360
361 if (device->state != NETIF_ACTIVE) {
362 netif_pq_release(packet_get_id(packet));
363 return EFORWARD;
364 }
365
366 ne2k_t *ne2k = (ne2k_t *) device->specific;
367
368 /*
369 * Process the packet queue
370 */
371
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);
378
379 return EOK;
380}
381
382int netif_initialize(void)
383{
384 sysarg_t apic;
385 sysarg_t i8259;
386
387 if (((sysinfo_get_value("apic", &apic) == EOK) && (apic))
388 || ((sysinfo_get_value("i8259", &i8259) == EOK) && (i8259)))
389 irc_service = true;
390
391 if (irc_service) {
392 while (irc_phone < 0)
393 irc_phone = service_obsolete_connect_blocking(SERVICE_IRC, 0, 0);
394 }
395
396 async_set_interrupt_received(irq_handler);
397
398 return service_register(SERVICE_NE2000);
399}
400
401int main(int argc, char *argv[])
402{
403 /* Start the module */
404 return netif_module_start();
405}
406
407/** @}
408 */
Note: See TracBrowser for help on using the repository browser.