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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 64d2b10 was 007e6efa, checked in by Martin Decky <martin@…>, 14 years ago
  • libc routines for registering services and connecting to services via NS
  • async_connect_to_me()
  • 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>
45#include <ipc/ipc.h>
46#include <ipc/services.h>
[007e6efa]47#include <ipc/ns.h>
[3c106e88]48#include <ipc/irc.h>
49#include <net/modules.h>
50#include <packet_client.h>
51#include <adt/measured_strings.h>
52#include <net/device.h>
53#include <netif_skel.h>
[fe8dfa6]54#include <nil_remote.h>
[21580dd]55#include "dp8390.h"
56
[3c106e88]57/** Return the device from the interrupt call.
58 *
59 * @param[in] call The interrupt call.
60 *
61 */
62#define IRQ_GET_DEVICE(call) ((device_id_t) IPC_GET_IMETHOD(call))
[21580dd]63
[3c106e88]64/** Return the ISR from the interrupt call.
65 *
66 * @param[in] call The interrupt call.
67 *
68 */
69#define IRQ_GET_ISR(call) ((int) IPC_GET_ARG2(call))
[21580dd]70
[7300c37]71/** Return the TSR from the interrupt call.
72 *
73 * @param[in] call The interrupt call.
74 *
75 */
76#define IRQ_GET_TSR(call) ((int) IPC_GET_ARG3(call))
77
[3c106e88]78static int irc_service = 0;
79static int irc_phone = -1;
[21580dd]80
[f902d36]81/** NE2000 kernel interrupt command sequence.
[3c106e88]82 *
[21580dd]83 */
[3c106e88]84static irq_cmd_t ne2k_cmds[] = {
85 {
[abe95c9]86 /* Read Interrupt Status Register */
[3c106e88]87 .cmd = CMD_PIO_READ_8,
88 .addr = NULL,
89 .dstarg = 2
90 },
91 {
[abe95c9]92 /* Mask supported interrupt causes */
[3c106e88]93 .cmd = CMD_BTEST,
[abe95c9]94 .value = (ISR_PRX | ISR_PTX | ISR_RXE | ISR_TXE | ISR_OVW |
95 ISR_CNT | ISR_RDC),
[3c106e88]96 .srcarg = 2,
97 .dstarg = 3,
98 },
99 {
[abe95c9]100 /* Predicate for accepting the interrupt */
[3c106e88]101 .cmd = CMD_PREDICATE,
[7300c37]102 .value = 4,
[3c106e88]103 .srcarg = 3
104 },
105 {
[abe95c9]106 /*
107 * Mask future interrupts via
108 * Interrupt Mask Register
109 */
110 .cmd = CMD_PIO_WRITE_8,
111 .addr = NULL,
112 .value = 0
113 },
114 {
115 /* Acknowledge the current interrupt */
[3c106e88]116 .cmd = CMD_PIO_WRITE_A_8,
117 .addr = NULL,
118 .srcarg = 3
119 },
[7300c37]120 {
121 /* Read Transmit Status Register */
122 .cmd = CMD_PIO_READ_8,
123 .addr = NULL,
124 .dstarg = 3
125 },
[3c106e88]126 {
127 .cmd = CMD_ACCEPT
128 }
129};
[21580dd]130
[f902d36]131/** NE2000 kernel interrupt code.
[3c106e88]132 *
[21580dd]133 */
[3c106e88]134static irq_code_t ne2k_code = {
135 sizeof(ne2k_cmds) / sizeof(irq_cmd_t),
136 ne2k_cmds
137};
[21580dd]138
[3c106e88]139/** Handle the interrupt notification.
140 *
[7300c37]141 * This is the interrupt notification function. It is quarantied
142 * that there is only a single instance of this notification
143 * function running at one time until the return from the
144 * ne2k_interrupt() function (where the interrupts are unmasked
145 * again).
[3c106e88]146 *
147 * @param[in] iid Interrupt notification identifier.
148 * @param[in] call Interrupt notification.
149 *
150 */
151static void irq_handler(ipc_callid_t iid, ipc_call_t *call)
[21580dd]152{
[3c106e88]153 device_id_t device_id = IRQ_GET_DEVICE(*call);
154 netif_device_t *device;
155 int nil_phone;
156 ne2k_t *ne2k;
[d3c9b60]157
[3c106e88]158 fibril_rwlock_read_lock(&netif_globals.lock);
[d3c9b60]159
[3c106e88]160 if (find_device(device_id, &device) == EOK) {
161 nil_phone = device->nil_phone;
162 ne2k = (ne2k_t *) device->specific;
163 } else
164 ne2k = NULL;
[d3c9b60]165
[3c106e88]166 fibril_rwlock_read_unlock(&netif_globals.lock);
[d3c9b60]167
[7300c37]168 if (ne2k != NULL) {
169 link_t *frames =
170 ne2k_interrupt(ne2k, IRQ_GET_ISR(*call), IRQ_GET_TSR(*call));
171
172 if (frames != NULL) {
173 while (!list_empty(frames)) {
174 frame_t *frame =
175 list_get_instance(frames->next, frame_t, link);
176
177 list_remove(&frame->link);
178 nil_received_msg(nil_phone, device_id, frame->packet,
179 SERVICE_NONE);
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->nil_phone = -1;
280 device->specific = (void *) ne2k;
281 device->state = NETIF_STOPPED;
282
283 rc = ne2k_probe(ne2k, port, irq);
284 if (rc != EOK) {
285 printf("%s: No ethernet card found at I/O address %p\n",
286 NAME, port);
287 free(ne2k);
288 free(device);
289 return rc;
[21580dd]290 }
[506a805]291
[3c106e88]292 rc = netif_device_map_add(&netif_globals.device_map, device->device_id, device);
293 if (rc != EOK) {
294 free(ne2k);
295 free(device);
296 return rc;
[21580dd]297 }
[506a805]298
[3c106e88]299 printf("%s: Ethernet card at I/O address %p, IRQ %d, MAC ",
300 NAME, port, irq);
[506a805]301
[3c106e88]302 unsigned int i;
303 for (i = 0; i < ETH_ADDR; i++)
304 printf("%02x%c", ne2k->mac[i], i < 5 ? ':' : '\n');
[506a805]305
[3c106e88]306 return EOK;
[21580dd]307}
308
[3c106e88]309int netif_start_message(netif_device_t *device)
[21580dd]310{
[3c106e88]311 if (device->state != NETIF_ACTIVE) {
312 ne2k_t *ne2k = (ne2k_t *) device->specific;
313
314 ne2k_cmds[0].addr = ne2k->port + DP_ISR;
[abe95c9]315 ne2k_cmds[3].addr = ne2k->port + DP_IMR;
316 ne2k_cmds[4].addr = ne2k_cmds[0].addr;
[6b22c97]317 ne2k_cmds[5].addr = ne2k->port + DP_TSR;
[3c106e88]318
319 int rc = ipc_register_irq(ne2k->irq, device->device_id,
320 device->device_id, &ne2k_code);
321 if (rc != EOK)
322 return rc;
323
324 rc = ne2k_up(ne2k);
325 if (rc != EOK) {
326 ipc_unregister_irq(ne2k->irq, device->device_id);
327 return rc;
328 }
329
[43b4314]330 change_state(device, NETIF_ACTIVE);
331
[3c106e88]332 if (irc_service)
333 async_msg_1(irc_phone, IRC_ENABLE_INTERRUPT, ne2k->irq);
334 }
[506a805]335
[3c106e88]336 return device->state;
337}
338
339int netif_stop_message(netif_device_t *device)
340{
341 if (device->state != NETIF_STOPPED) {
342 ne2k_t *ne2k = (ne2k_t *) device->specific;
343
344 ne2k_down(ne2k);
345 ipc_unregister_irq(ne2k->irq, device->device_id);
346 change_state(device, NETIF_STOPPED);
347 }
[506a805]348
[fe8dfa6]349 return device->state;
[3c106e88]350}
351
352int netif_send_message(device_id_t device_id, packet_t *packet,
353 services_t sender)
354{
355 netif_device_t *device;
356 int rc = find_device(device_id, &device);
357 if (rc != EOK)
358 return rc;
[506a805]359
[3c106e88]360 if (device->state != NETIF_ACTIVE) {
361 netif_pq_release(packet_get_id(packet));
362 return EFORWARD;
[21580dd]363 }
[506a805]364
[3c106e88]365 ne2k_t *ne2k = (ne2k_t *) device->specific;
[506a805]366
[3c106e88]367 /*
368 * Process the packet queue
369 */
[506a805]370
[3c106e88]371 do {
372 packet_t *next = pq_detach(packet);
373 ne2k_send(ne2k, packet);
374 netif_pq_release(packet_get_id(packet));
375 packet = next;
376 } while (packet);
[506a805]377
[3c106e88]378 return EOK;
[21580dd]379}
380
[3c106e88]381int netif_initialize(void)
382{
383 sysarg_t apic;
384 sysarg_t i8259;
385
386 if ((sysinfo_get_value("apic", &apic) == EOK) && (apic))
387 irc_service = SERVICE_APIC;
388 else if ((sysinfo_get_value("i8259", &i8259) == EOK) && (i8259))
389 irc_service = SERVICE_I8259;
390
391 if (irc_service) {
[007e6efa]392 while (irc_phone < 0)
393 irc_phone = service_connect_blocking(irc_service, 0, 0);
[3c106e88]394 }
395
396 async_set_interrupt_received(irq_handler);
397
[124c061]398 return ipc_connect_to_me(PHONE_NS, SERVICE_NE2000, 0, 0, NULL, NULL);
[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.