func: static void uhci_async_complete_packet(USBPacket * packet, void *opaque)
  
  {
  
      UHCIState *s = opaque;
  
      UHCI_QH qh;
  
      UHCI_TD td;
  
      uint32_t link;
  
      uint32_t old_td_ctrl;
  
      uint32_t val;
  
      uint32_t frame_addr;
  
      int ret;
  
  
  
      /* Handle async isochronous packet completion */
  
      frame_addr = s->async_frame_addr;
  
      if (frame_addr) {
  
          cpu_physical_memory_read(frame_addr, (uint8_t *)&link, 4);
  
          le32_to_cpus(&link);
  
  
  
          cpu_physical_memory_read(link & ~0xf, (uint8_t *)&td, sizeof(td));
  
          le32_to_cpus(&td.link);
  
          le32_to_cpus(&td.ctrl);
  
          le32_to_cpus(&td.token);
  
          le32_to_cpus(&td.buffer);
  
          old_td_ctrl = td.ctrl;
  
          ret = uhci_handle_td(s, &td, &s->pending_int_mask, 1);
  
  
  
          /* update the status bits of the TD */
  
          if (old_td_ctrl != td.ctrl) {
  
              val = cpu_to_le32(td.ctrl);
  
              cpu_physical_memory_write((link & ~0xf) + 4,
  
                                        (const uint8_t *)&val,
  
                                        sizeof(val));
  
          }
  
          if (ret == 2) {
  
              s->async_frame_addr = frame_addr;
  
          } else if (ret == 0) {
  
              /* update qh element link */
  
              val = cpu_to_le32(td.link);
  
              cpu_physical_memory_write(frame_addr,
  
                                        (const uint8_t *)&val,
  
                                        sizeof(val));
  
          }
  
          return;
  
      }
  
  
  
      link = s->async_qh;
  
      if (!link) {
  
          /* This should never happen. It means a TD somehow got removed
  
             without cancelling the associated async IO request.  */
  
          return;
  
      }
  
      cpu_physical_memory_read(link & ~0xf, (uint8_t *)&qh, sizeof(qh));
  
      le32_to_cpus(&qh.link);
  
      le32_to_cpus(&qh.el_link);
  
      /* Re-process the queue containing the async packet.  */
  
      while (1) {
  
          cpu_physical_memory_read(qh.el_link & ~0xf,
  
                                   (uint8_t *)&td, sizeof(td));
  
          le32_to_cpus(&td.link);
  
          le32_to_cpus(&td.ctrl);
  
          le32_to_cpus(&td.token);
  
          le32_to_cpus(&td.buffer);
  
          old_td_ctrl = td.ctrl;
  
          ret = uhci_handle_td(s, &td, &s->pending_int_mask, 1);
  
  
  
          /* update the status bits of the TD */
  
          if (old_td_ctrl != td.ctrl) {
  
              val = cpu_to_le32(td.ctrl);
  
              cpu_physical_memory_write((qh.el_link & ~0xf) + 4,
  
                                        (const uint8_t *)&val,
  
                                        sizeof(val));
  
          }
  
          if (ret < 0)
  
              break; /* interrupted frame */
  
          if (ret == 2) {
  
              s->async_qh = link;
  
              break;
  
          } else if (ret == 0) {
  
              /* update qh element link */
  
              qh.el_link = td.link;
  
              val = cpu_to_le32(qh.el_link);
  
              cpu_physical_memory_write((link & ~0xf) + 4,
  
                                        (const uint8_t *)&val,
  
                                        sizeof(val));
  
              if (!(qh.el_link & 4))
  
                  break;
  
          }
  
          break;
  
      }
  
  }
  