static void fd_seek(void)
{
	unsigned long flags;
	DPRINT(("fd_seek() to track %d (unit[SelectedDrive].track=%d)\n", ReqTrack,
		unit[SelectedDrive].track));
	if (unit[SelectedDrive].track == ReqTrack <<
	    unit[SelectedDrive].disktype->stretch) {
		fd_seek_done(0);
		return;
	}
	FDC1772_WRITE(FDC1772REG_DATA, ReqTrack <<
		      unit[SelectedDrive].disktype->stretch);
	udelay(25);
	save_flags(flags);
	clf();
	SET_IRQ_HANDLER(fd_seek_done);
	FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_SEEK | unit[SelectedDrive].steprate |
		/* DAG */
		(MotorOn?FDC1772CMDADD_H:0));

	restore_flags(flags);
	MotorOn = 1;
	set_head_settle_flag();
	START_TIMEOUT();
	/* wait for IRQ */
}
OggPlayErrorCode
oggplay_connect_to_host(SOCKET socket, struct sockaddr *addr) {

  ogg_int64_t           time_ref;

  START_TIMEOUT(time_ref);

  while (connect(socket, addr, sizeof(struct sockaddr_in)) < 0) {
    if (
        CHECK_ERROR(EINPROGRESS) || CHECK_ERROR(EALREADY)
#ifdef WIN32
          /* see http://msdn2.microsoft.com/en-us/library/ms737625.aspx */
        || CHECK_ERROR(EWOULDBLOCK) || CHECK_ERROR(EINVAL)
#endif
    ) {
      RETURN_ON_TIMEOUT_OR_CONTINUE(time_ref);
    }
    else if CHECK_ERROR(EISCONN)
    {
      break;
    }
    printf("Could not connect to host; error code is %d\n", errno);
    return CHECK_ERROR(ETIMEDOUT) ? E_OGGPLAY_TIMEOUT :
                                              E_OGGPLAY_SOCKET_ERROR;
  }

  return E_OGGPLAY_OK;

}
static void fd_calibrate(void)
{
	DPRINT(("fd_calibrate\n"));
	if (unit[SelectedDrive].track >= 0) {
		fd_calibrate_done(0);
		return;
	}
	DPRINT(("fd_calibrate (after track compare)\n"));
	SET_IRQ_HANDLER(fd_calibrate_done);
	/* we can't verify, since the speed may be incorrect */
	FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_RESTORE | unit[SelectedDrive].steprate);

	NeedSeek = 1;
	MotorOn = 1;
	START_TIMEOUT();
	/* wait for IRQ */
}
OggPlayErrorCode
oggplay_tcp_reader_initialise(OggPlayReader * opr, int block) {

  OggPlayTCPReader    * me = (OggPlayTCPReader *)opr;
  struct hostent      * he;
  struct sockaddr_in    addr;
  char                * host;
  char                * path;
  int                   port;
  int                   nbytes;
  int                   remaining;
  char                  http_request_header[1024];
  ogg_int64_t           time_ref;
  int                   r;

  char                * pos;
  size_t                len;

  if (me == NULL) {
    return E_OGGPLAY_BAD_READER;
  }
  if (me->state == OTRS_INIT_COMPLETE) {
    return E_OGGPLAY_OK;
  }

  /*
   * Create the socket.
   */
  if (me->state == OTRS_UNINITIALISED) {
    assert(me->socket == INVALID_SOCKET);

    me->socket = oggplay_create_socket();
    if (me->socket == INVALID_SOCKET) {
      return E_OGGPLAY_SOCKET_ERROR;
    }

    me->state = OTRS_SOCKET_CREATED;
  }

  /*
   * If required, set the socket to non-blocking mode so we can
   * timeout and return control to the caller.
   */
  if (!block) {
    if (!oggplay_set_socket_blocking_state(me->socket, 0)) {
      return E_OGGPLAY_SOCKET_ERROR;
    }
  }

  /*
   * Extract the host name and the path from the location.
   */
  if (oggplay_hostname_and_path(me->location, me->proxy, me->proxy_port,
                              &host, &port, &path) != 0)
    return E_OGGPLAY_OUT_OF_MEMORY;


  /*
   * Prepare the HTTP request header now, so we can free all our
   * allocated memory before returning on any errors.
   */
  snprintf(http_request_header, 1024,
    "GET %s HTTP/1.0\n"
    "Host: %s\n"
    "User-Agent: AnnodexFirefoxPlugin/0.1\n"
    "Accept: */*\n"
    "Connection: Keep-Alive\n\n", path, host);

  he = gethostbyname(host);

  oggplay_free(host);
  oggplay_free(path);

  if (he == NULL) {
    printf("Host not found\n");
    return E_OGGPLAY_BAD_INPUT;
  }
  /* 
   * currently we only support IPv4
   * TODO: switch to getaddrinfo and support IPv6!
   */
  if (sizeof(addr.sin_addr.s_addr) != he->h_length) {
    printf("No IPv6 support, yet!\n");
    return E_OGGPLAY_BAD_INPUT;
  }
  
  memcpy(&addr.sin_addr.s_addr, he->h_addr, he->h_length);
  addr.sin_family = AF_INET;
  addr.sin_port = htons(port);

  /*
   * Connect to the host.
   */
  if (me->state == OTRS_SOCKET_CREATED) {
    r = oggplay_connect_to_host(me->socket, (struct sockaddr *)&addr);
    if (r != E_OGGPLAY_OK) {
      return r;
    }

    me->state = OTRS_CONNECTED;
  }

  /*
   * Send the HTTP request header.
   *
   * If this times out after sending some, but not all, of the request header,
   * we'll end up sending the entire header string again. This is probably not
   * the best idea, so we may want to rework it at some time...
   */
  if (me->state == OTRS_CONNECTED) {
    oggplay_set_socket_blocking_state(me->socket, 1);
    pos = http_request_header;
    len = strlen(http_request_header);
#ifdef WIN32
    nbytes = send(me->socket, pos, len, 0);
#else
    nbytes = write(me->socket, pos, len);
#endif
    assert(nbytes == len);
    if (nbytes < 0) {
      return E_OGGPLAY_SOCKET_ERROR;
    }
    me->state = OTRS_SENT_HEADER;
  }

  /*
   * Strip out the HTTP response by finding the first Ogg packet.
   */
  if (me->state == OTRS_SENT_HEADER) {
    int offset;
    int found_http_response = 0;

    if (me->buffer == NULL) {
      me->buffer = (unsigned char*)oggplay_malloc(TCP_READER_MAX_IN_MEMORY);
      if (me->buffer == NULL)
        return E_OGGPLAY_OUT_OF_MEMORY;

      me->buffer_size = TCP_READER_MAX_IN_MEMORY;
      me->amount_in_memory = 0;
    }

    while (1) {
      char *dpos;

      remaining = TCP_READER_MAX_IN_MEMORY - me->amount_in_memory - 1;
#ifdef WIN32
      nbytes = recv(me->socket, (char*)(me->buffer + me->amount_in_memory),
              remaining, 0);
#else
      nbytes = read(me->socket, (char*)(me->buffer + me->amount_in_memory),
              remaining);
#endif
      if (nbytes < 0) {
        return E_OGGPLAY_SOCKET_ERROR;
      } else if (nbytes == 0) {
        /*
         * End-of-file is an error here, because we should at least be able
         * to read a complete HTTP response header.
         */
        return E_OGGPLAY_END_OF_FILE;
      }

      me->amount_in_memory += nbytes;
      me->buffer[me->amount_in_memory] = '\0';

      if (me->amount_in_memory < 15) {
        continue;
      }

      if
      (
        (!found_http_response)
        &&
        strncmp((char *)me->buffer, "HTTP/1.1 200 ", 13) != 0
        &&
        strncmp((char *)me->buffer, "HTTP/1.0 200 ", 13) != 0
      )
      {
        return E_OGGPLAY_BAD_INPUT;
      } else {
        found_http_response = 1;
      }

      dpos = strstr((char *)me->buffer, "X-Content-Duration:");
      if (dpos != NULL) {
        me->duration = (int)(strtod(dpos + 20, NULL) * 1000);
      }

      pos = strstr((char *)(me->buffer), "OggS");
      if (pos != NULL) {
        break;
      }
    }

    offset = pos - (char *)(me->buffer);
    memmove(me->buffer, pos, me->amount_in_memory - offset);
    me->amount_in_memory -= offset;
    me->backing_store = tmpfile();
    fwrite(me->buffer, 1, me->amount_in_memory, me->backing_store);
    me->current_position = 0;
    me->stored_offset = me->amount_in_memory;
    me->amount_in_memory = 0;
    me->state = OTRS_HTTP_RESPONDED;
  }



  /*
   * Read in enough data to fill the buffer.
   */
  if (!block) {
    oggplay_set_socket_blocking_state(me->socket, 0);
  }

  if (me->state == OTRS_HTTP_RESPONDED) {
    remaining = TCP_READER_MAX_IN_MEMORY - me->amount_in_memory;
    START_TIMEOUT(time_ref);
    while (remaining > 0) {
#ifdef WIN32
      nbytes = recv(me->socket, (char*)(me->buffer + me->amount_in_memory),
              remaining, 0);
#else
      nbytes = read(me->socket, me->buffer + me->amount_in_memory, remaining);
#endif
      if (nbytes < 0) {
#ifdef WIN32
        if CHECK_ERROR(EWOULDBLOCK) {
#else
        if CHECK_ERROR(EAGAIN) {
#endif
          RETURN_ON_TIMEOUT_OR_CONTINUE(time_ref);
        }
        return E_OGGPLAY_SOCKET_ERROR;
      } else if (nbytes == 0) {
        /*
         * End-of-file is *not* an error here, it's just a really small file.
         */
        break;
      }
      me->amount_in_memory += nbytes;
      remaining -= nbytes;
    }
    fwrite(me->buffer, 1, me->amount_in_memory, me->backing_store);
    me->stored_offset += me->amount_in_memory;
    me->amount_in_memory = 0;
    me->state = OTRS_INIT_COMPLETE;
  }