示例#1
0
文件: ata-main.c 项目: vladsor/chaos
static void create_hard_drive_service (ata_drive_type *ata_drive)
{
  /* Create the service. */

  if (ipc_service_create ("block", &ipc_structure, &empty_tag) != 
      IPC_RETURN_SUCCESS)
  {
    log_print (&log_structure, LOG_URGENCY_EMERGENCY,
               "Couldn't create block service.");
    return -1;
  }

  /* Main loop. */

  system_thread_name_set ("Service handler");
  while (TRUE)
  {
    mailbox_id_type reply_mailbox_id;

    ipc_service_connection_wait (&ipc_structure);
    reply_mailbox_id = ipc_structure.output_mailbox_id;

    if (system_thread_create () == SYSTEM_RETURN_THREAD_NEW)
    {
      system_call_thread_name_set ("Handling connection");
      hard_drive_handle_connection (ata_drive, reply_mailbox_id);
    }
  }    
}
示例#2
0
文件: ata-main.c 项目: vladsor/chaos
int main (void)
{
  ipc_structure_type ipc_structure;
  ata_drive_type *ata_drive;
  unsigned int drive_number;

  /* Set the name of the server. */

  system_process_name_set (PACKAGE_NAME);
  system_thread_name_set ("Initialising");

  log_init (&log_structure, PACKAGE_NAME, &empty_tag);

  for ( drive_number = 0 ; drive_number < number_of_probe ; drive_number++ )
  {
    if (!register_ports (ata_probe_drives[drive_number]))
    {
      continue;
    }

    ata_drive = ata_probe (ata_probe_drives[drive_number]);

    if (ata_drive != NULL)
    {
      switch (ata_drive->type)
      {
	case ATA_HARD_DRIVE :
        {
	  create_hard_drive_service (ata_drive);
          break;
        }

	case ATA_CDROM :
        {
	  create_cdrom_service (ata_drive);
          break;
        }
        /* FIXME: what we must do there ? */
        default :
        {
        }
      }
      ata_drivers[number_of_drives] = ata_drive;
      number_of_drives++;
    }
    else
    {
      unregister_ports (ata_probe_drives[drive_number]);
    }
  }

  system_call_process_parent_unblock ();
  return 0;
}
示例#3
0
int main (void)
{
  pci_device_info_type *device_info;
  unsigned int number_of_devices;
  unsigned int counter;
  unsigned int probe_counter;
  
  system_process_name_set (PACKAGE_NAME);
  system_thread_name_set ("Initialising");
  
  if (log_init (&log_structure, PACKAGE_NAME, &empty_tag) !=
      LOG_RETURN_SUCCESS)
  {
    return -1;
  }
  
  if (pci_init (&pci_structure, &empty_tag) != PCI_RETURN_SUCCESS)
  {
    log_print (&log_structure, LOG_URGENCY_EMERGENCY, 
               "Couldn't create connection to PCI service.");
    return -1;
  }

  system_call_process_parent_unblock ();

  for (probe_counter = 0; pci_device_probe[probe_counter].vendor_id !=
         0xFFFF; probe_counter++)
  {
    pci_device_exists (&pci_structure, &pci_device_probe[probe_counter],
                       &device_info, &number_of_devices);
    
    if (number_of_devices != 0)
    {
      for (counter = 0; counter < number_of_devices; counter++)
      {
        if (system_thread_create () == SYSTEM_RETURN_THREAD_NEW)
        {
          handle_8139 (&device_info[counter]);
        }
      }
    }
  }

  return 0;
}
示例#4
0
int main (void)
{
  ipc_structure_type ipc_structure;
  mailbox_id_type mailbox_id[10];
  unsigned int services = 10;

  system_process_name_set (PACKAGE_NAME);
  system_thread_name_set ("Initialising");
  
  if (log_init (&log_structure, PACKAGE_NAME, &empty_tag) !=
      LOG_RETURN_SUCCESS)
  {
    return -1;
  }
    
  /* Create our service. */

  if (ipc_service_create ("file_system", &ipc_structure, &empty_tag) != 
      STORM_RETURN_SUCCESS)
  {
    log_print (&log_structure, LOG_URGENCY_EMERGENCY,
               "Couldn't create a file system service.");
    return -1;
  }

  system_call_process_parent_unblock ();

  if (ipc_service_resolve ("virtual_file_system", mailbox_id, &services, 0, 
                           &empty_tag) != IPC_RETURN_SUCCESS)
  {
    log_print (&log_structure, LOG_URGENCY_EMERGENCY, 
               "Couldn't resolve VFS service.");
    return -1;
  }

  ipc_structure.output_mailbox_id = mailbox_id[0];
  ipc_service_connection_request (&ipc_structure);
  handle_connection (&ipc_structure);

  return 0;
}
示例#5
0
void handle_connection(mailbox_id_type *reply_mailbox_id)
{
    system_thread_name_set("Handling connection");

    message_parameter_type message_parameter;
    bool done = FALSE;
    bool mounted = FALSE;
    fat_info_type fat_info;
    ipc_structure_type ipc_structure;
    uint8_t *data;
    uint8_t **data_pointer = &data;
    unsigned int data_size = 16384;

    memory_allocate((void **) data_pointer, data_size);

    // Accept the connection.
    ipc_structure.output_mailbox_id = *reply_mailbox_id;
    if (ipc_connection_establish(&ipc_structure) != IPC_RETURN_SUCCESS)
    {
        return;
    }

    message_parameter.block = TRUE;

    while (!done)
    {
        message_parameter.data = data;
        message_parameter.protocol = IPC_PROTOCOL_FILE;
        message_parameter.message_class = IPC_CLASS_NONE;
        message_parameter.length = data_size;

        if (ipc_receive(ipc_structure.input_mailbox_id, &message_parameter, &data_size) != IPC_RETURN_SUCCESS)
        {
            continue;
        }

        switch (message_parameter.message_class)
        {
            // Read one or more directory entries.
            case IPC_FILE_DIRECTORY_ENTRY_READ:
            {
                if (mounted)
                {
                    file_directory_entry_read_type *directory_entry_read = (file_directory_entry_read_type *) data;

                    if (!fat_directory_entry_read(directory_entry_read, &fat_info))
                    {
                        directory_entry_read->entries = 0;
                    }
                    message_parameter.length =
                        sizeof(file_directory_entry_read_type) +
                        sizeof(file_directory_entry_type) *
                        directory_entry_read->entries ;
                    //          log_print_formatted (0, PACKAGE, "Successfully read %u entries",
                    //                               directory_entry_read->entries);
                    //          log_print_formatted (0, PACKAGE, "max: %u\n", directory_entry_read->entries);
                    ipc_send(ipc_structure.output_mailbox_id, &message_parameter);
                }
                break;
            }

            case IPC_FILE_GET_INFO:
            {
                if (mounted)
                {
                    file_verbose_directory_entry_type *directory_entry = (file_verbose_directory_entry_type *) data;

                    if (!fat_file_get_info(&fat_info, directory_entry))
                    {
                        return_type return_value = FILE_RETURN_FILE_ABSENT;

                        log_print_formatted(&log_structure, LOG_URGENCY_ERROR, "IPC_FILE_GET_INFO failed");
                        message_parameter.message_class = IPC_FILE_RETURN_VALUE;
                        message_parameter.data = &return_value;
                        message_parameter.length = sizeof(return_type);
                    }

                    ipc_send(ipc_structure.output_mailbox_id, &message_parameter);
                }
                break;
            }

            case IPC_FILE_MOUNT_VOLUME:
            {
                mailbox_id_type *mailbox = (mailbox_id_type *) data;

                fat_info.block_structure.output_mailbox_id = *mailbox;
                if (ipc_service_connection_request(&fat_info.block_structure) != IPC_RETURN_SUCCESS)
                {
                    break;
                }

                // Check if we have a FAT file system at this location.
                if (!detect_fat(&fat_info))
                {
                    log_print(&log_structure, LOG_URGENCY_ERROR, "No FAT filesystem detected.");
                    break;
                }

                mounted = TRUE;

                break;
            }

            case IPC_FILE_OPEN:
            {
                ipc_file_open_type *open = (ipc_file_open_type *) data;

                if (!fat_file_open(&fat_info, open))
                {
                    log_print(&log_structure, LOG_URGENCY_ERROR, "Failed to open file.");
                }

                ipc_send(ipc_structure.output_mailbox_id, &message_parameter);

                break;
            }

            case IPC_FILE_READ:
            {
                file_read_type *read = (file_read_type *) data;
                uint8_t *read_buffer;
                uint8_t **read_buffer_pointer = &read_buffer;

                memory_allocate((void **) read_buffer_pointer, read->bytes);

                if (!fat_file_read(&fat_info, read->file_handle, read_buffer, read->bytes))
                {
                    log_print(&log_structure, LOG_URGENCY_ERROR, "Failed to read from file.");
                }

                message_parameter.data = read_buffer;
                message_parameter.length = read->bytes;
#ifdef DEBUG
                log_print_formatted(&log_structure, LOG_URGENCY_DEBUG, "Sending %lu", read->bytes);
#endif
                ipc_send(ipc_structure.output_mailbox_id, &message_parameter);
                memory_deallocate((void **) read_buffer_pointer);
                break;
            }

            // Unsupported functions.
            case IPC_FILE_CLOSE:
            case IPC_FILE_SEEK:
            case IPC_FILE_WRITE:
            case IPC_FILE_ACL_READ:
            case IPC_FILE_ACL_WRITE:
            case IPC_FILE_UNMOUNT_VOLUME:
            default:
            {
                return_type return_value = IPC_RETURN_FILE_FUNCTION_UNSUPPORTED;

                message_parameter.data = &return_value;
                message_parameter.length = sizeof(return_type);

                ipc_send(ipc_structure.output_mailbox_id, &message_parameter);
                break;
            }
        }
    }
}
示例#6
0
文件: boot.c 项目: vladsor/chaos
int main (void)
{
#if FALSE
  virtual_file_system_mount_type mount;
  mailbox_id_type mailbox_id[10];
  ipc_structure_type vfs_structure;
  message_parameter_type message_parameter;
  file_read_type read;
  file_handle_type handle;
  file_verbose_directory_entry_type directory_entry;
  u8 *buffer;
  u8 *server_name_buffer;
  char *server[MAX_SERVERS];
  unsigned int where, number_of_servers = 0, server_number;
  process_id_type process_id;
  unsigned int bytes_read;
  unsigned int services = 10;
#endif

  /* Set our name. */

  system_process_name_set (PACKAGE_NAME);
  system_thread_name_set ("Initialising");

  if (log_init (&log_structure, PACKAGE_NAME, &empty_tag) !=
      LOG_RETURN_SUCCESS)
  {
    return -1;
  }

#if FALSE

  /* Mount the initial ramdisk as //ramdisk. To do this, we must first
     hook up a connection to the VFS service and resolve the first
     block service. */
    
  if (ipc_service_resolve ("virtual_file_system", mailbox_id, &services, 5, 
                           &empty_tag) != IPC_RETURN_SUCCESS)
  {
    log_print (&log_structure, LOG_URGENCY_EMERGENCY,
               "Couldn't resolve the VFS service.");
    return -1;
  }

  vfs_structure.output_mailbox_id = mailbox_id[0];

  if (ipc_service_connection_request (&vfs_structure) != IPC_RETURN_SUCCESS)
  {
    log_print (&log_structure, LOG_URGENCY_EMERGENCY,
               "Couldn't connect to the VFS service.");
    return -1;
  }

  services = 1;

  if (ipc_service_resolve ("block", mailbox_id, &services, 5, &empty_tag) !=
      IPC_RETURN_SUCCESS)
  {
    log_print (&log_structure, LOG_URGENCY_EMERGENCY, 
               "No block services found.");
    return -1;
  }

  mount.mailbox_id = mailbox_id[0];
  string_copy (mount.location, "ramdisk");

  /* That's it. Send the message. */

  message_parameter.protocol = IPC_PROTOCOL_VIRTUAL_FILE_SYSTEM;
  message_parameter.message_class = IPC_VIRTUAL_FILE_SYSTEM_MOUNT;
  message_parameter.data = &mount;
  message_parameter.length = sizeof (virtual_file_system_mount_type);
  message_parameter.block = TRUE;
  ipc_send (vfs_structure.output_mailbox_id, &message_parameter);

  log_print (&log_structure, LOG_URGENCY_DEBUG,
             "Mounted the first available block service as //ramdisk.");

  /* Now, read the list of servers to start from here. */

  log_print (&log_structure, LOG_URGENCY_DEBUG, "Reading startup script...");
  string_copy (directory_entry.path_name, STARTUP_FILE);
  if (file_get_info (&vfs_structure, &directory_entry) != FILE_RETURN_SUCCESS)
  {
    log_print (&log_structure, LOG_URGENCY_ERROR,
               STARTUP_FILE " not found.");
    return -1;
  }

  memory_allocate ((void **) &server_name_buffer, directory_entry.size);

  file_open (&vfs_structure, STARTUP_FILE, FILE_MODE_READ, &handle);
  file_read (&vfs_structure, handle, directory_entry.size,
             &server_name_buffer);

  /* Parse the file. */

  server[0] = &server_name_buffer[0];
  number_of_servers++;

  for (where = 1; where < directory_entry.size; where++)
  {

    if (server_name_buffer[where] == '\n')
    {
      server_name_buffer[where] = '\0';
      if (where + 1 < directory_entry.size)
      {
        server[number_of_servers] = &server_name_buffer[where + 1];
        number_of_servers++;
      }
    }
  }

  log_print_formatted (&log_structure, LOG_URGENCY_DEBUG,
                       "Starting %u servers.", number_of_servers);

  for (server_number = 0; server_number < number_of_servers; server_number++)
  {
    log_print_formatted (&log_structure, LOG_URGENCY_INFORMATIVE, 
                         "Starting %s.", server[server_number]);

    string_copy (directory_entry.path_name, server[server_number]);
    if (file_get_info (&vfs_structure, &directory_entry) !=
        FILE_RETURN_SUCCESS)
    {
      log_print_formatted (&log_structure, LOG_URGENCY_ERROR,
                           "'%s' could not be accessed!",
                           server[server_number]);
      continue;
    }

    /* Open the file. */

    file_open (&vfs_structure, server[server_number], FILE_MODE_READ, &handle);
    read.file_handle = handle;
    
    bytes_read = 0;

    log_print_formatted (&log_structure, LOG_URGENCY_DEBUG,
                         "Allocating %lu bytes for %s.",
                         directory_entry.size, server[server_number]);

    memory_allocate ((void **) &buffer, directory_entry.size);

    log_print_formatted (&log_structure, LOG_URGENCY_DEBUG,
                         "Buffer is at %p.", buffer);
    
    while (bytes_read < directory_entry.size)
    {
      unsigned int bytes;

      /* Read the file. */
    
      bytes = directory_entry.size - bytes_read;
      if (bytes > 32 * KB)
      {
        bytes = 32 * KB;
      }
      file_read (&vfs_structure, handle, bytes, &buffer[bytes_read]);
      bytes_read += bytes;
    }
    
    switch (execute_elf ((elf_header_type *) buffer, "", &process_id))
    {
      case EXECUTE_ELF_RETURN_SUCCESS:
      {
        log_print_formatted (&log_structure, LOG_URGENCY_INFORMATIVE,
                             "New process ID %lu.",
                              process_id);
        break;
      }
      
      case EXECUTE_ELF_RETURN_IMAGE_INVALID:
      {
        log_print (&log_structure, LOG_URGENCY_ERROR,
                   "Invalid ELF image.");
        break;
      }
      
      case EXECUTE_ELF_RETURN_ELF_UNSUPPORTED:
      {
        log_print (&log_structure, LOG_URGENCY_ERROR,
                   "Unsupported ELF.");
        break;
      }
      
      case EXECUTE_ELF_RETURN_FAILED:
      {
        log_print (&log_structure, LOG_URGENCY_ERROR,
                   "system_process_create failed.");
        break;
      }
    }

    memory_deallocate ((void **) &buffer);
  }

#endif

  system_call_process_parent_unblock ();

  log_print (&log_structure, LOG_URGENCY_DEBUG, "surf");

  return 0;
}
示例#7
0
static void handle_8139 (pci_device_info_type *device_info)
{
  unsigned int counter;
  u16 port_base = MAX_U16;
  u16 ports = 0;
  realtek_device_type *device;
  unsigned int physical, physical_index;
  ipc_structure_type ipc_structure;

  system_thread_name_set ("Initialising");
  
  for (counter = 0; counter < PCI_NUMBER_OF_RESOURCES; counter++)
  {
    if ((device_info->resource[counter].flags & PCI_RESOURCE_IO) != 0)
    {
      port_base = device_info->resource[counter].start;
      ports = (device_info->resource[counter].end -
               device_info->resource[counter].start + 1);
    }
  }

  if (port_base == MAX_U16)
  {
    log_print_formatted (&log_structure, LOG_URGENCY_ERROR, 
                         "No port range found -- hardware possibly broken or incompatible?");
    return;
  }

  system_call_port_range_register (port_base, ports, "Realtek 8139");

  memory_allocate ((void **) &device, sizeof (realtek_device_type));

  device->port_base = port_base;
  device->irq = device_info->irq;

  /* Initialise the adapter. */

  system_port_out_u8 (port_base + Config1, 0x00);
  
  if (read_eeprom (port_base, 0) != 0xFFFF) 
  {
    for (counter = 0; counter < 3; counter++) 
    {
      ((u16 *)(device->ethernet_address))[counter] =
        system_little_endian_to_native_u16 (read_eeprom (port_base, 
                                                        counter + 7));
    }
  }
  else 
  {
    for (counter = 0; counter < 6; counter++)
    {
      device->ethernet_address[counter] = 
        system_port_in_u8 (port_base + MAC0 + counter);
    }
  }

  log_print_formatted 
    (&log_structure, LOG_URGENCY_INFORMATIVE,
     "Realtek 8139 at 0x%X, IRQ %d, ethernet address: %02X:%02X:%02X:%02X:%02X:%02X",
     port_base, device_info->irq, device->ethernet_address[0], 
     device->ethernet_address[1], device->ethernet_address[2], 
     device->ethernet_address[3], device->ethernet_address[4],
     device->ethernet_address[5]);

  /* Find the connected MII transceivers. */

  for (physical = 0, physical_index = 0; physical < 32 &&
         physical_index < sizeof (device->mii_address); physical++)
  {
    int mii_status = mdio_read (port_base, physical, 1);

    if (mii_status != 0xFFFF && mii_status != 0x0000) 
    {
      device->mii_address[physical_index] = physical;
      physical_index++;

      log_print_formatted (&log_structure, LOG_URGENCY_INFORMATIVE,
                           "MII transceiver found at address %d.",
                           physical);
    }
  }

  if (physical_index == 0) 
  {
    if (realtek_debug > 1)
    {
      log_print_formatted (&log_structure, LOG_URGENCY_INFORMATIVE,
                           "No MII transceivers found! Assuming SYM "
                           "transceiver.");
    }

    device->mii_address[0] = -1;
  }

  /* Soft reset the chip. */

  system_port_out_u8 (port_base + ChipCommand, CommandReset);

  pci_allocate_buffer ((void **) &device->tx_buffers_dma,
                       (void **) &device->tx_buffers,
                       TX_BUFFER_SIZE * NUMBER_OF_TX_DESCRIPTORS);
  pci_allocate_buffer ((void **) &device->rx_ring_dma,
                       (void **) &device->rx_ring,
                       RX_BUFFER_LENGTH + 16);

  device->tx_full = FALSE;
  device->current_rx = 0;
  device->dirty_tx = device->current_tx = 0;

  for (counter = 0; counter < NUMBER_OF_TX_DESCRIPTORS; counter++) 
  {
    device->tx_buffer[counter] = &device->tx_buffers[counter * TX_BUFFER_SIZE];
  }
  
  /* Check that the chip has finished the reset. */

  for (counter = 0; counter < 1000; counter++)
  {
    if ((system_port_in_u8 (port_base + ChipCommand) & CommandReset) == 0)
    {
      break;
    }
  }

  /* Must enable Tx/Rx before setting transfer thresholds! */

  system_port_out_u8 (port_base + ChipCommand, 
                      CommandRxEnable | CommandTxEnable);
  system_port_out_u32 (port_base + RxConfig, 
                       (RX_FIFO_THRESHOLD << 13) | 
                       (RX_BUFFER_LENGTH_INDEX << 11) | 
                       (RX_DMA_BURST << 8));

  system_port_out_u32 (port_base + TxConfig, (TX_DMA_BURST << 8) | 0x03000000);

  if (device->mii_address[0] >= 0) 
  {
    u16 mii_reg5 = mdio_read (port_base, device->mii_address[0], 5);

    if (mii_reg5 == 0xffff)
    {
    }
    else if ((mii_reg5 & 0x0100) == 0x0100 || (mii_reg5 & 0x00C0) == 0x0040)
    {
      device->full_duplex = TRUE;
    }

    log_print_formatted (&log_structure, LOG_URGENCY_INFORMATIVE,
                         "Setting %s%s-duplex based on"
                         " auto-negotiated partner ability %4.4x.\n",
                         mii_reg5 == 0 ? "" :
                         ((mii_reg5 & 0x0180) != 0) ? "100 Mbps " : 
                         "10 Mbps ",
                         device->full_duplex ? "full" : "half", mii_reg5);
  }
  
  system_port_out_u8 (port_base + Config9346, 0xC0);
  system_port_out_u8 (port_base + Config1, device->full_duplex ? 0x60 : 0x20);
  system_port_out_u8 (port_base + Config9346, 0x00);

  system_port_out_u32 (port_base + RxBuffer, (u32) device->rx_ring_dma);
  
  /* Start the chip's Tx and Rx process. */
  
  system_port_out_u32 (port_base + RxMissed, 0);
  set_rx_mode (device);
  
  system_port_out_u8 (port_base + ChipCommand,
                      CommandRxEnable | CommandTxEnable);
  
  /* Enable all known interrupts by setting the interrupt mask. */
  
  system_port_out_u16 (port_base + InterruptMask,
                       PCIError | PCSTimeout | RxUnderrun | RxOverflow | 
                       RxFIFOOverrun | TxError | TxOK | RxError | RxOK);


  if (system_thread_create () == SYSTEM_RETURN_THREAD_NEW)
  {
    system_thread_name_set ("IRQ handler");

    if (system_call_irq_register (device_info->irq, "Realtek 8139") != 
        SYSTEM_RETURN_SUCCESS)
    {
      log_print_formatted (&log_structure, LOG_URGENCY_EMERGENCY, 
                           "Couldn't set up IRQ handler");
      return;
    }

    /* Loop and handle interrupts. */
    
    while (TRUE)
    {
      int bogus_count = max_interrupt_work;
      unsigned status, link_changed = 0;
      
      system_call_irq_wait (device->irq);
      
      do 
      {
        status = system_port_in_u16 (port_base + InterruptStatus);
        
        /* Acknowledge all of the current interrupt sources ASAP, but
           an first get an additional status bit from CSCR. */
        
        if ((status & RxUnderrun) && 
            system_port_in_u16 (port_base + CSCR) & CSCR_LinkChangeBit)
        {
          link_changed = 1;
        }
        
        system_port_out_u16 (port_base + InterruptStatus, status);
        
        if ((status & (PCIError | PCSTimeout | RxUnderrun | RxOverflow | 
                       RxFIFOOverrun | TxError | TxOK | RxError | RxOK)) == 0)
        {
          break;
        }
        
        /* Rx interrupt. */
        
        if ((status & (RxOK | RxUnderrun | RxOverflow | RxFIFOOverrun)) != 0)
        {
          realtek_receive (device);
        }
        
        if ((status & (TxOK | TxError)) != 0) 
        {
          unsigned int dirty_tx = device->dirty_tx;
          
          while (device->current_tx - dirty_tx > 0) 
          {
            int entry = dirty_tx % NUMBER_OF_TX_DESCRIPTORS;
            int txstatus = system_port_in_u32 (port_base + TxStatus0 +
                                               entry * 4);
            
            if ((txstatus & (TxStatusOK | TxUnderrun | TxAborted)) == 0)
            {
              /* It still hasn't been transmitted. */
              
              break;
            }
            
            /* Note: TxCarrierLost is always asserted at 100 Mbps. */
            
            if ((txstatus & (TxOutOfWindow | TxAborted)) != 0)
            {
              /* There was an major error, log it. */
              
              // device->stats.tx_errors++;

              if ((txstatus & TxAborted) != 0)
              {
                // tp->stats.tx_aborted_errors++;

                system_port_out_u32 (port_base + TxConfig, 
                                     (TX_DMA_BURST << 8) | 0x03000001);
              }
              
              if ((txstatus & TxCarrierLost) != 0)
              {
                // tp->stats.tx_carrier_errors++;
              }
              
              if ((txstatus & TxOutOfWindow) != 0)
              {
                // tp->stats.tx_window_errors++;
              }
            }
            else 
            {
              if ((txstatus & TxUnderrun) != 0)
              {
                /* Add 64 to the Tx FIFO threshold. */
                
                if (device->tx_flag < 0x00300000)
                {
                  device->tx_flag += 0x00020000;
                }
                
                // tp->stats.tx_fifo_errors++;
              }
              
              // tp->stats.collisions += (txstatus >> 24) & 15;
              // tp->stats.tx_bytes += txstatus & 0x7ff;
              // tp->stats.tx_packets++;
            }
            
            // if (tp->tx_info[entry].mapping != 0)
            // {
            //   pci_unmap_single (tp->pdev,
            //                     tp->tx_info[entry].mapping,
            //                     tp->tx_info[entry].skb->len,
            //                     PCI_DMA_TODEVICE);
            // tp->tx_info[entry].mapping = 0;
            // }
          
            /* Free the original skb. */
            
            // dev_kfree_skb_irq (tp->tx_info[entry].skb);
            //          tp->tx_info[entry].skb = NULL;
            
            if (device->tx_full) 
            {
              /* The ring is no longer full, wake the queue. */
              
              device->tx_full = FALSE;
              
              // netif_wake_queue(dev);
            }
            
            dirty_tx++;
          }
          
          device->dirty_tx = dirty_tx;
        }
        
        /* Check uncommon events with one test. */
        
        if ((status & (PCIError | PCSTimeout | RxUnderrun | RxOverflow | 
                       RxFIFOOverrun | TxError | RxError)) != 0)
        {
          if (realtek_debug > 2)
          {
            log_print_formatted (&log_structure, LOG_URGENCY_WARNING,
                                 "Abnormal interrupt, status %8.8x.\n",
                                 status);
          }
          
          if (status == 0xFFFFFFFF)
          {
            break;
          }
          
          /* Update the error count. */
          
          // tp->stats.rx_missed_errors += inl(port_base + RxMissed);
          system_port_out_u32 (port_base + RxMissed, 0);
          
          if ((status & RxUnderrun) != 0 && link_changed)
          {
            /* Really link-change on new chips. */
            
            int lpar = system_port_in_u16 (port_base + NWayLPAR);
            int duplex = (lpar & 0x0100) || (lpar & 0x01C0) == 0x0040; 
            
            if (device->full_duplex != duplex) 
            {
              device->full_duplex = duplex;
              
              system_port_out_u8 (port_base + Config9346, 0xC0);
              system_port_out_u8 (port_base + Config1, 
                                  device->full_duplex ? 0x60 : 0x20);
              system_port_out_u8 (port_base + Config9346, 0x00);
            }
            status &= ~RxUnderrun;
          }
          
          if ((status & (RxUnderrun | RxOverflow | RxError |
                         RxFIFOOverrun)) != 0)
          {
            // tp->stats.rx_errors++;
          }
          
          if ((status & (PCSTimeout)) != 0)
          {
            // tp->stats.rx_length_errors++;
          }
          
          if ((status & (RxUnderrun | RxFIFOOverrun)) != 0)
          {
            //  tp->stats.rx_fifo_errors++;
          }
          
          if ((status & RxOverflow) != 0)
          {
            // tp->stats.rx_over_errors++;
            device->current_rx =
              (system_port_in_u16 (port_base + RxBufferAddress) % 
               RX_BUFFER_LENGTH);
            system_port_out_u16 (port_base + RxBufferPointer, device->current_rx - 16);
          }
          
          if ((status & PCIError) != 0) 
          {
            log_print (&log_structure, LOG_URGENCY_WARNING, "PCI Bus error.");
          }
        }
        
        if (--bogus_count < 0) 
        {
          log_print_formatted (&log_structure, LOG_URGENCY_WARNING,
                               "Too much work at interrupt, "
                               "InterruptStatus = 0x%4.4x.",
                               status);
          
          /* Clear all interrupt sources. */
          
          system_port_out_u16 (port_base + InterruptStatus, 0xFFFF);
          break;
        }
      } while (TRUE);
      
      system_call_irq_acknowledge (device->irq);
    }
  }

  /* Now, use the remaining thread for the service handler. */

  system_thread_name_set ("Service handler");

  /* Create the service. */

  if (ipc_service_create ("ethernet", &ipc_structure, &empty_tag) !=
      IPC_RETURN_SUCCESS)
  {
    log_print (&log_structure, LOG_URGENCY_EMERGENCY,
               "Couldn't create ethernet service.");
    return;
  }

  while (TRUE)
  {
    mailbox_id_type reply_mailbox_id;

    ipc_service_connection_wait (&ipc_structure);
    reply_mailbox_id = ipc_structure.output_mailbox_id;

    if (system_thread_create () == SYSTEM_RETURN_THREAD_NEW)
    {
      system_call_thread_name_set ("Handling connection");
      handle_connection (reply_mailbox_id, device);
    }
  }    
}