ne2000.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2009 Lukas Mejdrech
00003  * Copyright (c) 2011 Martin Decky
00004  * All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions
00008  * are met:
00009  *
00010  * - Redistributions of source code must retain the above copyright
00011  *   notice, this list of conditions and the following disclaimer.
00012  * - Redistributions in binary form must reproduce the above copyright
00013  *   notice, this list of conditions and the following disclaimer in the
00014  *   documentation and/or other materials provided with the distribution.
00015  * - The name of the author may not be used to endorse or promote products
00016  *   derived from this software without specific prior written permission.
00017  *
00018  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00019  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00020  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00021  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00022  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00023  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00024  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00025  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00026  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00027  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00028  */
00029 
00038 #include <assert.h>
00039 #include <async.h>
00040 #include <ddi.h>
00041 #include <errno.h>
00042 #include <err.h>
00043 #include <malloc.h>
00044 #include <sysinfo.h>
00045 #include <ipc/services.h>
00046 #include <ipc/ns.h>
00047 #include <ipc/irc.h>
00048 #include <net/modules.h>
00049 #include <packet_client.h>
00050 #include <adt/measured_strings.h>
00051 #include <net/device.h>
00052 #include <netif_skel.h>
00053 #include <nil_remote.h>
00054 #include "dp8390.h"
00055 
00061 #define IRQ_GET_DEVICE(call)  ((device_id_t) IPC_GET_IMETHOD(call))
00062 
00068 #define IRQ_GET_ISR(call)  ((int) IPC_GET_ARG2(call))
00069 
00075 #define IRQ_GET_TSR(call)  ((int) IPC_GET_ARG3(call))
00076 
00077 static bool irc_service = false;
00078 static int irc_phone = -1;
00079 
00083 static irq_cmd_t ne2k_cmds[] = {
00084         {
00085                 /* Read Interrupt Status Register */
00086                 .cmd = CMD_PIO_READ_8,
00087                 .addr = NULL,
00088                 .dstarg = 2
00089         },
00090         {
00091                 /* Mask supported interrupt causes */
00092                 .cmd = CMD_BTEST,
00093                 .value = (ISR_PRX | ISR_PTX | ISR_RXE | ISR_TXE | ISR_OVW |
00094                     ISR_CNT | ISR_RDC),
00095                 .srcarg = 2,
00096                 .dstarg = 3,
00097         },
00098         {
00099                 /* Predicate for accepting the interrupt */
00100                 .cmd = CMD_PREDICATE,
00101                 .value = 4,
00102                 .srcarg = 3
00103         },
00104         {
00105                 /*
00106                  * Mask future interrupts via
00107                  * Interrupt Mask Register
00108                  */
00109                 .cmd = CMD_PIO_WRITE_8,
00110                 .addr = NULL,
00111                 .value = 0
00112         },
00113         {
00114                 /* Acknowledge the current interrupt */
00115                 .cmd = CMD_PIO_WRITE_A_8,
00116                 .addr = NULL,
00117                 .srcarg = 3
00118         },
00119         {
00120                 /* Read Transmit Status Register */
00121                 .cmd = CMD_PIO_READ_8,
00122                 .addr = NULL,
00123                 .dstarg = 3
00124         },
00125         {
00126                 .cmd = CMD_ACCEPT
00127         }
00128 };
00129 
00133 static irq_code_t ne2k_code = {
00134         sizeof(ne2k_cmds) / sizeof(irq_cmd_t),
00135         ne2k_cmds
00136 };
00137 
00150 static void irq_handler(ipc_callid_t iid, ipc_call_t *call)
00151 {
00152         device_id_t device_id = IRQ_GET_DEVICE(*call);
00153         netif_device_t *device;
00154         int nil_phone;
00155         ne2k_t *ne2k;
00156         
00157         fibril_rwlock_read_lock(&netif_globals.lock);
00158         
00159         if (find_device(device_id, &device) == EOK) {
00160                 nil_phone = device->nil_phone;
00161                 ne2k = (ne2k_t *) device->specific;
00162         } else
00163                 ne2k = NULL;
00164         
00165         fibril_rwlock_read_unlock(&netif_globals.lock);
00166         
00167         if (ne2k != NULL) {
00168                 link_t *frames =
00169                     ne2k_interrupt(ne2k, IRQ_GET_ISR(*call), IRQ_GET_TSR(*call));
00170                 
00171                 if (frames != NULL) {
00172                         while (!list_empty(frames)) {
00173                                 frame_t *frame =
00174                                     list_get_instance(frames->next, frame_t, link);
00175                                 
00176                                 list_remove(&frame->link);
00177                                 nil_received_msg(nil_phone, device_id, frame->packet,
00178                                     SERVICE_NONE);
00179                                 free(frame);
00180                         }
00181                         
00182                         free(frames);
00183                 }
00184         }
00185 }
00186 
00193 static void change_state(netif_device_t *device, device_state_t state)
00194 {
00195         if (device->state != state) {
00196                 device->state = state;
00197                 
00198                 const char *desc;
00199                 switch (state) {
00200                 case NETIF_ACTIVE:
00201                         desc = "active";
00202                         break;
00203                 case NETIF_STOPPED:
00204                         desc = "stopped";
00205                         break;
00206                 default:
00207                         desc = "unknown";
00208                 }
00209                 
00210                 printf("%s: State changed to %s\n", NAME, desc);
00211         }
00212 }
00213 
00214 int netif_specific_message(ipc_callid_t callid, ipc_call_t *call,
00215     ipc_call_t *answer, size_t *count)
00216 {
00217         return ENOTSUP;
00218 }
00219 
00220 int netif_get_device_stats(device_id_t device_id, device_stats_t *stats)
00221 {
00222         if (!stats)
00223                 return EBADMEM;
00224         
00225         netif_device_t *device;
00226         int rc = find_device(device_id, &device);
00227         if (rc != EOK)
00228                 return rc;
00229         
00230         ne2k_t *ne2k = (ne2k_t *) device->specific;
00231         
00232         memcpy(stats, &ne2k->stats, sizeof(device_stats_t));
00233         return EOK;
00234 }
00235 
00236 int netif_get_addr_message(device_id_t device_id, measured_string_t *address)
00237 {
00238         if (!address)
00239                 return EBADMEM;
00240         
00241         netif_device_t *device;
00242         int rc = find_device(device_id, &device);
00243         if (rc != EOK)
00244                 return rc;
00245         
00246         ne2k_t *ne2k = (ne2k_t *) device->specific;
00247         
00248         address->value = ne2k->mac;
00249         address->length = ETH_ADDR;
00250         return EOK;
00251 }
00252 
00253 int netif_probe_message(device_id_t device_id, int irq, void *io)
00254 {
00255         netif_device_t *device =
00256             (netif_device_t *) malloc(sizeof(netif_device_t));
00257         if (!device)
00258                 return ENOMEM;
00259         
00260         ne2k_t *ne2k = (ne2k_t *) malloc(sizeof(ne2k_t));
00261         if (!ne2k) {
00262                 free(device);
00263                 return ENOMEM;
00264         }
00265         
00266         void *port;
00267         int rc = pio_enable((void *) io, NE2K_IO_SIZE, &port);
00268         if (rc != EOK) {
00269                 free(ne2k);
00270                 free(device);
00271                 return rc;
00272         }
00273         
00274         bzero(device, sizeof(netif_device_t));
00275         bzero(ne2k, sizeof(ne2k_t));
00276         
00277         device->device_id = device_id;
00278         device->nil_phone = -1;
00279         device->specific = (void *) ne2k;
00280         device->state = NETIF_STOPPED;
00281         
00282         rc = ne2k_probe(ne2k, port, irq);
00283         if (rc != EOK) {
00284                 printf("%s: No ethernet card found at I/O address %p\n",
00285                     NAME, port);
00286                 free(ne2k);
00287                 free(device);
00288                 return rc;
00289         }
00290         
00291         rc = netif_device_map_add(&netif_globals.device_map, device->device_id, device);
00292         if (rc != EOK) {
00293                 free(ne2k);
00294                 free(device);
00295                 return rc;
00296         }
00297         
00298         printf("%s: Ethernet card at I/O address %p, IRQ %d, MAC ",
00299             NAME, port, irq);
00300         
00301         unsigned int i;
00302         for (i = 0; i < ETH_ADDR; i++)
00303                 printf("%02x%c", ne2k->mac[i], i < 5 ? ':' : '\n');
00304         
00305         return EOK;
00306 }
00307 
00308 int netif_start_message(netif_device_t *device)
00309 {
00310         if (device->state != NETIF_ACTIVE) {
00311                 ne2k_t *ne2k = (ne2k_t *) device->specific;
00312                 
00313                 ne2k_cmds[0].addr = ne2k->port + DP_ISR;
00314                 ne2k_cmds[3].addr = ne2k->port + DP_IMR;
00315                 ne2k_cmds[4].addr = ne2k_cmds[0].addr;
00316                 ne2k_cmds[5].addr = ne2k->port + DP_TSR;
00317                 
00318                 int rc = register_irq(ne2k->irq, device->device_id,
00319                     device->device_id, &ne2k_code);
00320                 if (rc != EOK)
00321                         return rc;
00322                 
00323                 rc = ne2k_up(ne2k);
00324                 if (rc != EOK) {
00325                         unregister_irq(ne2k->irq, device->device_id);
00326                         return rc;
00327                 }
00328                 
00329                 change_state(device, NETIF_ACTIVE);
00330                 
00331                 if (irc_service)
00332                         async_msg_1(irc_phone, IRC_ENABLE_INTERRUPT, ne2k->irq);
00333         }
00334         
00335         return device->state;
00336 }
00337 
00338 int netif_stop_message(netif_device_t *device)
00339 {
00340         if (device->state != NETIF_STOPPED) {
00341                 ne2k_t *ne2k = (ne2k_t *) device->specific;
00342                 
00343                 ne2k_down(ne2k);
00344                 unregister_irq(ne2k->irq, device->device_id);
00345                 change_state(device, NETIF_STOPPED);
00346         }
00347         
00348         return device->state;
00349 }
00350 
00351 int netif_send_message(device_id_t device_id, packet_t *packet,
00352     services_t sender)
00353 {
00354         netif_device_t *device;
00355         int rc = find_device(device_id, &device);
00356         if (rc != EOK)
00357                 return rc;
00358         
00359         if (device->state != NETIF_ACTIVE) {
00360                 netif_pq_release(packet_get_id(packet));
00361                 return EFORWARD;
00362         }
00363         
00364         ne2k_t *ne2k = (ne2k_t *) device->specific;
00365         
00366         /*
00367          * Process the packet queue
00368          */
00369         
00370         do {
00371                 packet_t *next = pq_detach(packet);
00372                 ne2k_send(ne2k, packet);
00373                 netif_pq_release(packet_get_id(packet));
00374                 packet = next;
00375         } while (packet);
00376         
00377         return EOK;
00378 }
00379 
00380 int netif_initialize(void)
00381 {
00382         sysarg_t apic;
00383         sysarg_t i8259;
00384         
00385         if (((sysinfo_get_value("apic", &apic) == EOK) && (apic))
00386             || ((sysinfo_get_value("i8259", &i8259) == EOK) && (i8259)))
00387                 irc_service = true;
00388         
00389         if (irc_service) {
00390                 while (irc_phone < 0)
00391                         irc_phone = service_connect_blocking(SERVICE_IRC, 0, 0);
00392         }
00393         
00394         async_set_interrupt_received(irq_handler);
00395         
00396         return async_connect_to_me(PHONE_NS, SERVICE_NE2000, 0, 0, NULL);
00397 }
00398 
00399 int main(int argc, char *argv[])
00400 {
00401         /* Start the module */
00402         return netif_module_start();
00403 }
00404 

Generated on Thu Jun 2 07:45:50 2011 for HelenOS/USB by  doxygen 1.4.7