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
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 <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>
47#include <ipc/ns.h>
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>
54#include <nil_remote.h>
55#include "dp8390.h"
56
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))
63
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))
70
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
78static int irc_service = 0;
79static int irc_phone = -1;
80
81/** NE2000 kernel interrupt command sequence.
82 *
83 */
84static irq_cmd_t ne2k_cmds[] = {
85 {
86 /* Read Interrupt Status Register */
87 .cmd = CMD_PIO_READ_8,
88 .addr = NULL,
89 .dstarg = 2
90 },
91 {
92 /* Mask supported interrupt causes */
93 .cmd = CMD_BTEST,
94 .value = (ISR_PRX | ISR_PTX | ISR_RXE | ISR_TXE | ISR_OVW |
95 ISR_CNT | ISR_RDC),
96 .srcarg = 2,
97 .dstarg = 3,
98 },
99 {
100 /* Predicate for accepting the interrupt */
101 .cmd = CMD_PREDICATE,
102 .value = 4,
103 .srcarg = 3
104 },
105 {
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 */
116 .cmd = CMD_PIO_WRITE_A_8,
117 .addr = NULL,
118 .srcarg = 3
119 },
120 {
121 /* Read Transmit Status Register */
122 .cmd = CMD_PIO_READ_8,
123 .addr = NULL,
124 .dstarg = 3
125 },
126 {
127 .cmd = CMD_ACCEPT
128 }
129};
130
131/** NE2000 kernel interrupt code.
132 *
133 */
134static irq_code_t ne2k_code = {
135 sizeof(ne2k_cmds) / sizeof(irq_cmd_t),
136 ne2k_cmds
137};
138
139/** Handle the interrupt notification.
140 *
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).
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)
152{
153 device_id_t device_id = IRQ_GET_DEVICE(*call);
154 netif_device_t *device;
155 int nil_phone;
156 ne2k_t *ne2k;
157
158 fibril_rwlock_read_lock(&netif_globals.lock);
159
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;
165
166 fibril_rwlock_read_unlock(&netif_globals.lock);
167
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 }
186}
187
188/** Change the network interface state.
189 *
190 * @param[in,out] device Network interface.
191 * @param[in] state New state.
192 *
193 */
194static void change_state(netif_device_t *device, device_state_t state)
195{
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);
212 }
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;
225
226 netif_device_t *device;
227 int rc = find_device(device_id, &device);
228 if (rc != EOK)
229 return rc;
230
231 ne2k_t *ne2k = (ne2k_t *) device->specific;
232
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;
241
242 netif_device_t *device;
243 int rc = find_device(device_id, &device);
244 if (rc != EOK)
245 return rc;
246
247 ne2k_t *ne2k = (ne2k_t *) device->specific;
248
249 address->value = ne2k->mac;
250 address->length = ETH_ADDR;
251 return EOK;
252}
253
254int netif_probe_message(device_id_t device_id, int irq, void *io)
255{
256 netif_device_t *device =
257 (netif_device_t *) malloc(sizeof(netif_device_t));
258 if (!device)
259 return ENOMEM;
260
261 ne2k_t *ne2k = (ne2k_t *) malloc(sizeof(ne2k_t));
262 if (!ne2k) {
263 free(device);
264 return ENOMEM;
265 }
266
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 }
274
275 bzero(device, sizeof(netif_device_t));
276 bzero(ne2k, sizeof(ne2k_t));
277
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;
290 }
291
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;
297 }
298
299 printf("%s: Ethernet card at I/O address %p, IRQ %d, MAC ",
300 NAME, port, irq);
301
302 unsigned int i;
303 for (i = 0; i < ETH_ADDR; i++)
304 printf("%02x%c", ne2k->mac[i], i < 5 ? ':' : '\n');
305
306 return EOK;
307}
308
309int netif_start_message(netif_device_t *device)
310{
311 if (device->state != NETIF_ACTIVE) {
312 ne2k_t *ne2k = (ne2k_t *) device->specific;
313
314 ne2k_cmds[0].addr = ne2k->port + DP_ISR;
315 ne2k_cmds[3].addr = ne2k->port + DP_IMR;
316 ne2k_cmds[4].addr = ne2k_cmds[0].addr;
317 ne2k_cmds[5].addr = ne2k->port + DP_TSR;
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
330 change_state(device, NETIF_ACTIVE);
331
332 if (irc_service)
333 async_msg_1(irc_phone, IRC_ENABLE_INTERRUPT, ne2k->irq);
334 }
335
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 }
348
349 return device->state;
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;
359
360 if (device->state != NETIF_ACTIVE) {
361 netif_pq_release(packet_get_id(packet));
362 return EFORWARD;
363 }
364
365 ne2k_t *ne2k = (ne2k_t *) device->specific;
366
367 /*
368 * Process the packet queue
369 */
370
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);
377
378 return EOK;
379}
380
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) {
392 while (irc_phone < 0)
393 irc_phone = service_connect_blocking(irc_service, 0, 0);
394 }
395
396 async_set_interrupt_received(irq_handler);
397
398 return ipc_connect_to_me(PHONE_NS, SERVICE_NE2000, 0, 0, NULL, NULL);
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.