⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 usb_ohci.c

📁 看到最近大家都关心 usbhost 的实现, 论坛上能找到的代码仅是一些简单的 demo , 完整的源码级的协议层是找不到的 我就贡献一把, 将我前一段时间移植成功的 USBHost 代码奉上 注
💻 C
📖 第 1 页 / 共 4 页
字号:
  
  if (!maxsize) {
    /* submit_common_message: pipesize for pipe %lx is zero", pipe); */
    urb_free_priv (urb);
    return -1;
  }

  if (sohci_submit_job(urb, setup) < 0) {
    err("sohci_submit_job failed");
    return -1;
  }

#if 0
  os_dly_waitms(10);
  /* ohci_dump_status(&gohci); */
#endif

  /* allow more time for a BULK device to react - some are slow */
#define BULK_TO   5000  /* timeout in milliseconds */
  if (usb_pipetype (pipe) == PIPE_BULK)
    timeout = BULK_TO;
  else
    timeout = 100;

  /* wait for it to complete */
  for (;;) {
    /* check whether the controller is done */
    stat = hc_interrupt();
    if (stat < 0) {
      stat = USB_ST_CRC_ERR;
      break;
    }

    /* NOTE: since we are not interrupt driven in U-Boot and always
     * handle only one URB at a time, we cannot assume the
     * transaction finished on the first successful return from
     * hc_interrupt().. unless the flag for current URB is set,
     * meaning that all TD's to/from device got actually
     * transferred and processed. If the current URB is not
     * finished we need to re-iterate this loop so as
     * hc_interrupt() gets called again as there needs to be some
     * more TD's to process still */
    if ((stat >= 0) && (stat != 0xff) && (urb->finished)) {
      /* 0xff is returned for an SF-interrupt */
      break;
    }

    if (--timeout) {
      os_dly_waitms(1);
      if (!urb->finished)
        dbg("\%");

    } else {
      err("CTL:TIMEOUT ");
      dbg("submit_common_msg: TO status %x\n", stat);
      urb->finished = 1;
      stat = USB_ST_CRC_ERR;
      break;
    }
  }

  dev->status = stat;
  dev->act_len = transfer_len;

  os_dly_waitms(1);

  /* free TDs in urb_priv */
  if (usb_pipetype (pipe) != PIPE_INTERRUPT)
  { urb_free_priv (urb);  }
  return 0;
}

/* submit routines called from usb.c */
int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer, int transfer_len)
{
  info("submit_bulk_msg");
  return submit_common_msg(dev, pipe, buffer, transfer_len, NULL, 0);
}

int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
    int transfer_len, struct devrequest *setup)
{
  int maxsize = usb_maxpacket(dev, pipe);

  info("submit_control_msg");
  
  os_dly_waitms(1);

  if (!maxsize) {
    err("submit_control_message: pipesize for pipe %lx is zero",
      pipe);
    return -1;
  }
  if (((pipe >> 8) & 0x7f) == gohci.rh.devnum) {
    gohci.rh.dev = dev;
    /* root hub - redirect */
    return ohci_submit_rh_msg(dev, pipe, buffer, transfer_len,
      setup);
  }

  return submit_common_msg(dev, pipe, buffer, transfer_len, setup, 0);
}

int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
    int transfer_len, int interval)
{
  info("submit_int_msg");
  return submit_common_msg(dev, pipe, buffer, transfer_len, NULL,
      interval);
}

/*-------------------------------------------------------------------------*
 * HC functions
 *-------------------------------------------------------------------------*/

/* reset the HC and BUS */

static int hc_reset (ohci_t *ohci)
{
  int timeout = 30;
  int smm_timeout = 50; /* 0,5 sec */

  dbg("%s\n", __FUNCTION__);

  if (readl (&ohci->regs->control) & OHCI_CTRL_IR) { /* SMM owns the HC */
    writel (OHCI_OCR, &ohci->regs->cmdstatus); /* request ownership */
    info("USB HC TakeOver from SMM");
    while (readl (&ohci->regs->control) & OHCI_CTRL_IR) {
      os_dly_waitms (10);
      if (--smm_timeout == 0) {
        err("USB HC TakeOver failed!");
        return -1;
      }
    }
  }

  /* Disable HC interrupts */
  writel (OHCI_INTR_MIE, &ohci->regs->intrdisable);

  dbg("USB HC reset_hc usb-%s: ctrl = 0x%X ;\n",
    ohci->slot_name,
    readl(&ohci->regs->control));

  /* Reset USB (needed by some controllers) */
  ohci->hc_control = 0;
  writel (ohci->hc_control, &ohci->regs->control);

  /* HC Reset requires max 10 us delay */
  writel (OHCI_HCR,  &ohci->regs->cmdstatus);
  while ((readl (&ohci->regs->cmdstatus) & OHCI_HCR) != 0) {
    if (--timeout == 0) {
      err("USB HC reset timed out!");
      return -1;
    }
    os_dly_waitms(1);
  }
  return 0;
}

/*-------------------------------------------------------------------------*/

/* Start an OHCI controller, set the BUS operational
 * enable interrupts
 * connect the virtual root hub */

static int hc_start (ohci_t * ohci)
{
  unsigned int mask;
  unsigned int fminterval;

  ohci->disabled = 1;

  /* Tell the controller where the control and bulk lists are
   * The lists are empty now. */

  writel (0, &ohci->regs->ed_controlhead);
  writel (0, &ohci->regs->ed_bulkhead);

  writel ((unsigned int)ohci->hcca, &ohci->regs->hcca); /* a reset clears this */

  fminterval = 0x2edf;
  writel ((fminterval * 9) / 10, &ohci->regs->periodicstart);
  fminterval |= ((((fminterval - 210) * 6) / 7) << 16);
  writel (fminterval, &ohci->regs->fminterval);
  writel (0x628, &ohci->regs->lsthresh);

  /* start controller operations */
  ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER;
  ohci->disabled = 0;
  writel (ohci->hc_control, &ohci->regs->control);

  /* disable all interrupts */
  mask = (OHCI_INTR_SO | OHCI_INTR_WDH | OHCI_INTR_SF | OHCI_INTR_RD |
      OHCI_INTR_UE | OHCI_INTR_FNO | OHCI_INTR_RHSC |
      OHCI_INTR_OC | OHCI_INTR_MIE);
  writel (mask, &ohci->regs->intrdisable);
  /* clear all interrupts */
  mask &= ~OHCI_INTR_MIE;
  writel (mask, &ohci->regs->intrstatus);
  /* Choose the interrupts we care about now  - but w/o MIE */
  mask = OHCI_INTR_RHSC | OHCI_INTR_UE | OHCI_INTR_WDH | OHCI_INTR_SO;
  writel (mask, &ohci->regs->intrenable);

#ifdef  OHCI_USE_NPS
  /* required for AMD-756 and some Mac platforms */
  writel ((roothub_a (ohci) | RH_A_NPS) & ~RH_A_PSM,
    &ohci->regs->roothub.a);
  writel (RH_HS_LPSC, &ohci->regs->roothub.status);
#endif  /* OHCI_USE_NPS */

  /* POTPGT delay is bits 24-31, in 2 ms units. */
  os_dly_wait(((roothub_a (ohci) >> 23) & 0x1fe)/10);

  /* connect the virtual root hub */
  ohci->rh.devnum = 0;

  return 0;
}

/*-------------------------------------------------------------------------*/

/* Poll USB interrupt. */
void usb_event_poll(void)
{
  hc_interrupt();
}

/* an interrupt happens */

static int hc_interrupt (void)
{
  ohci_t *ohci = &gohci;
  struct ohci_regs *regs = ohci->regs;
  int ints;
  int stat = -1;

  if ((ohci->hcca->done_head != 0) &&
      !(m32_swap (ohci->hcca->done_head) & 0x01)) {
    ints =  OHCI_INTR_WDH;
  } else if ((ints = readl (&regs->intrstatus)) == ~(unsigned int)0) {
    ohci->disabled++;
    err ("%s device removed!", ohci->slot_name);
    return -1;
  } else if ((ints &= readl (&regs->intrenable)) == 0) {
    dbg("hc_interrupt: returning..\n");
    return 0xff;
  }

  /* dbg("Interrupt: %x frame: %x", ints, le16_to_cpu (ohci->hcca->frame_no)); */

  if (ints & OHCI_INTR_RHSC) {
    got_rhsc = 1;
    stat = 0xff;
  }

  if (ints & OHCI_INTR_UE) {
    ohci->disabled++;
    err ("OHCI Unrecoverable Error, controller usb-%s disabled",
      ohci->slot_name);
    /* e.g. due to PCI Master/Target Abort */

  os_dly_waitms(1);

    /* FIXME: be optimistic, hope that bug won't repeat often. */
    /* Make some non-interrupt context restart the controller. */
    /* Count and limit the retries though; either hardware or */
    /* software errors can go forever... */
    hc_reset (ohci);
    return -1;
  }

  if (ints & OHCI_INTR_WDH) {
    os_dly_waitms(1);
    writel (OHCI_INTR_WDH, &regs->intrdisable);
    (void)readl (&regs->intrdisable); /* flush */
    stat = dl_done_list (&gohci, dl_reverse_done_list (&gohci));
    writel (OHCI_INTR_WDH, &regs->intrenable);
    (void)readl (&regs->intrdisable); /* flush */
  }

  if (ints & OHCI_INTR_SO) {
    dbg("USB Schedule overrun\n");
    writel (OHCI_INTR_SO, &regs->intrenable);
    stat = -1;
  }

  /* FIXME:  this assumes SOF (1/ms) interrupts don't get lost... */
  if (ints & OHCI_INTR_SF) {
    unsigned int frame = m16_swap (ohci->hcca->frame_no) & 1;
    os_dly_waitms(1);
    writel (OHCI_INTR_SF, &regs->intrdisable);
    if (ohci->ed_rm_list[frame] != NULL)
      writel (OHCI_INTR_SF, &regs->intrenable);
    stat = 0xff;
  }

  writel (ints, &regs->intrstatus);
  return stat;
}

/*-------------------------------------------------------------------------*/

/*-------------------------------------------------------------------------*/

/* De-allocate all resources.. */

static void hc_release_ohci (ohci_t *ohci)
{
  dbg ("USB HC release ohci usb-%s", ohci->slot_name);

  if (!ohci->disabled)
    hc_reset (ohci);
}

/*-------------------------------------------------------------------------*/

/*
 * low level initalisation routine, called from usb.c
 */
static char ohci_inited = 0;

int usb_lowlevel_init(void)
{
  memset (&gohci, 0, sizeof (ohci_t));

  /* align the storage */
  if ((unsigned int)&ghcca[0] & 0xff) {
    err("HCCA not aligned!!");
    return -1;
  }
  phcca = &ghcca[0];
  info("aligned ghcca %p", phcca);
  memset(&ohci_dev, 0, sizeof(struct ohci_device));
  if ((unsigned int)&ohci_dev.ed[0] & 0x7) {
    err("EDs not aligned!!");
    return -1;
  }
  memset(gtd, 0, sizeof(td_t) * (NUM_TD + 1));
  if ((unsigned int)gtd & 0x7) {
    err("TDs not aligned!!");
    return -1;
  }
  ptd = gtd;
  gohci.hcca = phcca;
  memset (phcca, 0, sizeof (struct ohci_hcca));

  gohci.disabled = 1;
  gohci.sleeping = 0;
  gohci.irq = -1;

  gohci.regs = (struct ohci_regs *)USBHC_BASE_ADDR;

  gohci.flags = 0;
  gohci.slot_name = "lpc2468";

  if (hc_reset (&gohci) < 0) {
    hc_release_ohci (&gohci);
    return -1;
  }

  /* FIXME this is a second HC reset; why?? */
  /* writel(gohci.hc_control = OHCI_USB_RESET, &gohci.regs->control);
     os_dly_waitms(10); */
  if (hc_start (&gohci) < 0) {
    hc_release_ohci (&gohci);
    return -1;
  }
  os_dly_waitms(1);
  ohci_inited = 1;
  return 0;
}

int usb_lowlevel_stop(void)
{
  /* this gets called really early - before the controller has */
  /* even been initialized! */
  if (!ohci_inited)
    return 0;
  /* TODO release any interrupts, etc. */
  /* call hc_release_ohci() here ? */
  hc_reset (&gohci);

#ifdef CFG_USB_OHCI_BOARD_INIT
  /* board dependant cleanup */
  if(usb_board_stop())
    return -1;
#endif

#ifdef CFG_USB_OHCI_CPU_INIT
  /* cpu dependant cleanup */
  if(usb_cpu_stop())
    return -1;
#endif

  return 0;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -