dwc_otg_hcd_queue.c

Go to the documentation of this file.
00001 /* ==========================================================================
00002  * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_queue.c $
00003  * $Revision: #39 $
00004  * $Date: 2009/04/21 $
00005  * $Change: 1237477 $
00006  *
00007  * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
00008  * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
00009  * otherwise expressly agreed to in writing between Synopsys and you.
00010  * 
00011  * The Software IS NOT an item of Licensed Software or Licensed Product under
00012  * any End User Software License Agreement or Agreement for Licensed Product
00013  * with Synopsys or any supplement thereto. You are permitted to use and
00014  * redistribute this Software in source and binary forms, with or without
00015  * modification, provided that redistributions of source code must retain this
00016  * notice. You may not view, use, disclose, copy or distribute this file or
00017  * any information contained herein except pursuant to this license grant from
00018  * Synopsys. If you do not agree with this notice, including the disclaimer
00019  * below, then you are not authorized to use the Software.
00020  * 
00021  * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
00022  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00023  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00024  * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
00025  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00026  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
00027  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00028  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00029  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00030  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
00031  * DAMAGE.
00032  * ========================================================================== */
00033 #ifndef DWC_DEVICE_ONLY
00034 
00042 #include "dwc_otg_hcd.h"
00043 #include "dwc_otg_regs.h"
00044 
00053 void dwc_otg_hcd_qh_free(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
00054 {
00055         dwc_otg_qtd_t *qtd, *qtd_tmp;
00056         uint64_t flags;
00057 
00058         /* Free each QTD in the QTD list */
00059         DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
00060         DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &qh->qtd_list, qtd_list_entry) {
00061                 DWC_CIRCLEQ_REMOVE(&qh->qtd_list, qtd, qtd_list_entry);
00062                 dwc_otg_hcd_qtd_free(qtd);
00063         }
00064         DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
00065 
00066         if (hcd->core_if->dma_desc_enable) {
00067                 dwc_otg_hcd_qh_free_ddma(hcd, qh);
00068         }
00069         else if (qh->dw_align_buf) {
00070                 uint32_t buf_size;
00071                 if(qh->ep_type == UE_ISOCHRONOUS) {
00072                         buf_size = 4096;
00073                 } else {
00074                         buf_size = hcd->core_if->core_params->max_transfer_size;
00075                 }
00076                 dwc_dma_free(buf_size, qh->dw_align_buf, qh->dw_align_buf_dma);
00077         }
00078         
00079         
00080         
00081         dwc_free(qh);
00082         return;
00083 }
00084 
00085 #define BitStuffTime(bytecount)  ((8 * 7* bytecount) / 6)
00086 #define HS_HOST_DELAY           5       /* nanoseconds */
00087 #define FS_LS_HOST_DELAY        1000    /* nanoseconds */
00088 #define HUB_LS_SETUP            333     /* nanoseconds */
00089 #define NS_TO_US(ns)            ((ns + 500) / 1000)
00090                                 /* convert & round nanoseconds to microseconds */
00091 
00092 static uint32_t calc_bus_time(int speed, int is_in, int is_isoc,
00093                                           int bytecount)
00094 {
00095         unsigned long retval;
00096 
00097         switch (speed) {
00098         case USB_SPEED_HIGH:
00099                 if (is_isoc) {
00100                         retval =
00101                             ((38 * 8 * 2083) +
00102                              (2083 * (3 + BitStuffTime(bytecount)))) / 1000 +
00103                             HS_HOST_DELAY;
00104                 } else {
00105                         retval =
00106                             ((55 * 8 * 2083) +
00107                              (2083 * (3 + BitStuffTime(bytecount)))) / 1000 +
00108                             HS_HOST_DELAY;
00109                 }
00110                 break;
00111         case USB_SPEED_FULL:
00112                 if (is_isoc) {
00113                         retval =
00114                             (8354 * (31 + 10 * BitStuffTime(bytecount))) / 1000;
00115                         if (is_in) {
00116                                 retval = 7268 + FS_LS_HOST_DELAY + retval;
00117                         } else {
00118                                 retval = 6265 + FS_LS_HOST_DELAY + retval;
00119                         }
00120                 } else {
00121                         retval =
00122                             (8354 * (31 + 10 * BitStuffTime(bytecount))) / 1000;
00123                         retval = 9107 + FS_LS_HOST_DELAY + retval;
00124                 }
00125                 break;
00126         case USB_SPEED_LOW:
00127                 if (is_in) {
00128                         retval =
00129                             (67667 * (31 + 10 * BitStuffTime(bytecount))) /
00130                             1000;
00131                         retval =
00132                             64060 + (2 * HUB_LS_SETUP) + FS_LS_HOST_DELAY +
00133                             retval;
00134                 } else {
00135                         retval =
00136                             (66700 * (31 + 10 * BitStuffTime(bytecount))) /
00137                             1000;
00138                         retval =
00139                             64107 + (2 * HUB_LS_SETUP) + FS_LS_HOST_DELAY +
00140                             retval;
00141                 }
00142                 break;
00143         default:
00144                 DWC_WARN("Unknown device speed\n");
00145                 retval = -1;
00146         }
00147         
00148         return NS_TO_US(retval);
00149 }
00150 
00159 #define SCHEDULE_SLOP 10
00160 void qh_init(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh,
00161                          dwc_otg_hcd_urb_t * urb)
00162 {
00163         char *speed, *type;
00164         int dev_speed;
00165         uint32_t hub_addr, hub_port;
00166 
00167         dwc_memset(qh, 0, sizeof(dwc_otg_qh_t));
00168         
00169         /* Initialize QH */
00170         qh->ep_type = dwc_otg_hcd_get_pipe_type(&urb->pipe_info);
00171 
00172         qh->ep_is_in = dwc_otg_hcd_is_pipe_in(&urb->pipe_info) ? 1 : 0;
00173 
00174         qh->data_toggle = DWC_OTG_HC_PID_DATA0;
00175         qh->maxp = dwc_otg_hcd_get_mps(&urb->pipe_info);
00176         DWC_CIRCLEQ_INIT(&qh->qtd_list);
00177         DWC_LIST_INIT(&qh->qh_list_entry);
00178         qh->channel = NULL;
00179 
00180         /* FS/LS Enpoint on HS Hub 
00181          * NOT virtual root hub */
00182         dev_speed = hcd->fops->speed(hcd, urb->priv);
00183         hcd->fops->hub_info(hcd, urb->priv, &hub_addr, &hub_port);
00184         qh->do_split = 0;
00185         if (((dev_speed == USB_SPEED_LOW) ||
00186              (dev_speed == USB_SPEED_FULL)) &&
00187             (hub_addr != 0 && hub_addr != 1)) {
00188                 
00189                 DWC_DEBUGPL(DBG_HCD,
00190                             "QH init: EP %d: TT found at hub addr %d, for port %d\n",
00191                             dwc_otg_hcd_get_ep_num(&urb->pipe_info), hub_addr,
00192                             hub_port);
00193                 
00194                 qh->do_split = 1;
00195         }
00196 
00197         if (qh->ep_type == UE_INTERRUPT || qh->ep_type == UE_ISOCHRONOUS) {
00198                 /* Compute scheduling parameters once and save them. */
00199                 hprt0_data_t hprt;
00200 
00202                 int bytecount =
00203                     dwc_hb_mult(qh->maxp) * dwc_max_packet(qh->maxp);
00204 
00205                 qh->usecs = calc_bus_time((qh->do_split ? USB_SPEED_HIGH : dev_speed),
00206                                           qh->ep_is_in,
00207                                           (qh->ep_type == UE_ISOCHRONOUS),
00208                                           bytecount);
00209                 /* Start in a slightly future (micro)frame. */
00210                 qh->sched_frame = dwc_frame_num_inc(hcd->frame_number,
00211                                                     SCHEDULE_SLOP);
00212                 qh->interval = urb->interval;
00213                 
00214 #if 0
00215                 /* Increase interrupt polling rate for debugging. */
00216                 if (qh->ep_type == UE_INTERRUPT) {
00217                         qh->interval = 8;
00218                 }
00219 #endif
00220                 hprt.d32 = dwc_read_reg32(hcd->core_if->host_if->hprt0);
00221                 if ((hprt.b.prtspd == DWC_HPRT0_PRTSPD_HIGH_SPEED) &&
00222                     ((dev_speed == USB_SPEED_LOW) ||
00223                      (dev_speed == USB_SPEED_FULL))) {
00224                         qh->interval *= 8;
00225                         qh->sched_frame |= 0x7;
00226                         qh->start_split_frame = qh->sched_frame;
00227                 }
00228 
00229         }
00230 
00231         DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD QH Initialized\n");
00232         DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH  - qh = %p\n", qh);
00233         DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH  - Device Address = %d\n",
00234                     dwc_otg_hcd_get_dev_addr(&urb->pipe_info));
00235         DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH  - Endpoint %d, %s\n",
00236                     dwc_otg_hcd_get_ep_num(&urb->pipe_info),
00237                     dwc_otg_hcd_is_pipe_in(&urb->pipe_info) ? "IN" : "OUT");
00238         switch (dev_speed) {
00239         case USB_SPEED_LOW:
00240                 qh->dev_speed = DWC_OTG_EP_SPEED_LOW;
00241                 speed = "low";
00242                 break;
00243         case USB_SPEED_FULL:
00244                 qh->dev_speed = DWC_OTG_EP_SPEED_FULL;
00245                 speed = "full";
00246                 break;
00247         case USB_SPEED_HIGH:
00248                 qh->dev_speed = DWC_OTG_EP_SPEED_HIGH;
00249                 speed = "high";
00250                 break;
00251         default:
00252                 speed = "?";
00253                 break;
00254         }
00255         DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH  - Speed = %s\n", speed);
00256 
00257         switch (qh->ep_type) {
00258         case UE_ISOCHRONOUS:
00259                 type = "isochronous";
00260                 break;
00261         case UE_INTERRUPT:
00262                 type = "interrupt";
00263                 break;
00264         case UE_CONTROL:
00265                 type = "control";
00266                 break;
00267         case UE_BULK:
00268                 type = "bulk";
00269                 break;
00270         default:
00271                 type = "?";
00272                 break;
00273         }
00274         
00275         DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH  - Type = %s\n", type);
00276 
00277 #ifdef DEBUG
00278         if (qh->ep_type == UE_INTERRUPT) {
00279                 DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - usecs = %d\n",
00280                             qh->usecs);
00281                 DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - interval = %d\n",
00282                             qh->interval);
00283         }
00284 #endif
00285 
00286 }
00287 
00296 dwc_otg_qh_t *dwc_otg_hcd_qh_create(dwc_otg_hcd_t * hcd,
00297                                     dwc_otg_hcd_urb_t * urb)
00298 {
00299         dwc_otg_qh_t *qh;
00300 
00301         /* Allocate memory */
00303         qh = dwc_otg_hcd_qh_alloc();
00304         if (qh == NULL) {
00305                 return NULL;
00306         }
00307 
00308         qh_init(hcd, qh, urb);
00309         
00310         if (hcd->core_if->dma_desc_enable && (dwc_otg_hcd_qh_init_ddma(hcd, qh) < 0)) {
00311                 dwc_otg_hcd_qh_free(hcd, qh);   
00312                 return NULL;
00313         }
00314         
00315         return qh;
00316 }
00317 
00323 static int periodic_channel_available(dwc_otg_hcd_t * hcd)
00324 {
00325         /*
00326          * Currently assuming that there is a dedicated host channnel for each
00327          * periodic transaction plus at least one host channel for
00328          * non-periodic transactions.
00329          */
00330         int status;
00331         int num_channels;
00332 
00333         num_channels = hcd->core_if->core_params->host_channels;
00334         if ((hcd->periodic_channels + hcd->non_periodic_channels < num_channels) &&
00335             (hcd->periodic_channels < num_channels - 1)) {
00336                 status = 0;
00337         } else {
00338                 DWC_INFO("%s: Total channels: %d, Periodic: %d, Non-periodic: %d\n",
00339                         __func__, num_channels, hcd->periodic_channels, hcd->non_periodic_channels);    //NOTICE
00340                 status = -DWC_E_NO_SPACE;
00341         }
00342 
00343         return status;
00344 }
00345 
00356 static int check_periodic_bandwidth(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
00357 {
00358         int status;
00359         int16_t max_claimed_usecs;
00360 
00361         status = 0;
00362 
00363         if ((qh->dev_speed == DWC_OTG_EP_SPEED_HIGH) || qh->do_split) {
00364                 /*
00365                  * High speed mode.
00366                  * Max periodic usecs is 80% x 125 usec = 100 usec.
00367                  */
00368 
00369                 max_claimed_usecs = 100 - qh->usecs;
00370         } else {
00371                 /*
00372                  * Full speed mode.
00373                  * Max periodic usecs is 90% x 1000 usec = 900 usec.
00374                  */
00375                 max_claimed_usecs = 900 - qh->usecs;
00376         }
00377 
00378         if (hcd->periodic_usecs > max_claimed_usecs) {
00379                 DWC_INFO("%s: already claimed usecs %d, required usecs %d\n", __func__, hcd->periodic_usecs, qh->usecs);        //NOTICE
00380                 status = -DWC_E_NO_SPACE;
00381         }
00382 
00383         return status;
00384 }
00385 
00396 static int check_max_xfer_size(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
00397 {
00398         int status;
00399         uint32_t max_xfer_size;
00400         uint32_t max_channel_xfer_size;
00401 
00402         status = 0;
00403 
00404         max_xfer_size = dwc_max_packet(qh->maxp) * dwc_hb_mult(qh->maxp);
00405         max_channel_xfer_size = hcd->core_if->core_params->max_transfer_size;
00406 
00407         if (max_xfer_size > max_channel_xfer_size) {
00408                 DWC_INFO("%s: Periodic xfer length %d > " "max xfer length for channel %d\n",
00409                                 __func__, max_xfer_size, max_channel_xfer_size);        //NOTICE
00410                 status = -DWC_E_NO_SPACE;
00411         }
00412 
00413         return status;
00414 }
00415 
00425 static int schedule_periodic(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
00426 {
00427         int status = 0;
00428 
00429         status = periodic_channel_available(hcd);
00430         if (status) {
00431                 DWC_INFO("%s: No host channel available for periodic " "transfer.\n", __func__);        //NOTICE
00432                 return status;
00433         }
00434 
00435         status = check_periodic_bandwidth(hcd, qh);
00436         if (status) {
00437                 DWC_INFO("%s: Insufficient periodic bandwidth for " "periodic transfer.\n", __func__);  //NOTICE
00438                 return status;
00439         }
00440 
00441         status = check_max_xfer_size(hcd, qh);
00442         if (status) {
00443                 DWC_INFO("%s: Channel max transfer size too small " "for periodic transfer.\n", __func__);      //NOTICE
00444                 return status;
00445         }
00446 
00447         if (hcd->core_if->dma_desc_enable) {
00448                 /* Don't rely on SOF and start in ready schedule */
00449                 DWC_LIST_INSERT_TAIL(&hcd->periodic_sched_ready, &qh->qh_list_entry);
00450         }
00451         else {
00452         /* Always start in the inactive schedule. */
00453         DWC_LIST_INSERT_TAIL(&hcd->periodic_sched_inactive, &qh->qh_list_entry);
00454         }
00455 
00456         /* Reserve the periodic channel. */
00457         hcd->periodic_channels++;
00458 
00459         /* Update claimed usecs per (micro)frame. */
00460         hcd->periodic_usecs += qh->usecs;
00461 
00462         return status;
00463 }
00464 
00472 int dwc_otg_hcd_qh_add(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
00473 {
00474         int status = 0;
00475         uint64_t flags;
00476 
00477         DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
00478 
00479         if (!DWC_LIST_EMPTY(&qh->qh_list_entry)) {
00480                 /* QH already in a schedule. */
00481                 goto done;
00482         }
00483 
00484         /* Add the new QH to the appropriate schedule */
00485         if (dwc_qh_is_non_per(qh)) {
00486                 /* Always start in the inactive schedule. */
00487                 DWC_LIST_INSERT_TAIL(&hcd->non_periodic_sched_inactive,
00488                                      &qh->qh_list_entry);
00489         } else {
00490                 status = schedule_periodic(hcd, qh);
00491         }
00492 
00493       done:
00494         DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
00495 
00496         return status;
00497 }
00498 
00505 static void deschedule_periodic(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
00506 {
00507         DWC_LIST_REMOVE_INIT(&qh->qh_list_entry);
00508 
00509         /* Release the periodic channel reservation. */
00510         hcd->periodic_channels--;
00511 
00512         /* Update claimed usecs per (micro)frame. */
00513         hcd->periodic_usecs -= qh->usecs;
00514 }
00515 
00522 void dwc_otg_hcd_qh_remove(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
00523 {
00524         uint64_t flags;
00525         DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
00526 
00527         if (DWC_LIST_EMPTY(&qh->qh_list_entry)) {
00528                 /* QH is not in a schedule. */
00529                 goto done;
00530         }
00531 
00532         if (dwc_qh_is_non_per(qh)) {
00533                 if (hcd->non_periodic_qh_ptr == &qh->qh_list_entry) {
00534                         hcd->non_periodic_qh_ptr =
00535                             hcd->non_periodic_qh_ptr->next;
00536                 }
00537                 DWC_LIST_REMOVE_INIT(&qh->qh_list_entry);
00538         } else {
00539                 deschedule_periodic(hcd, qh);
00540         }
00541 
00542       done:
00543         DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
00544 }
00545 
00559 void dwc_otg_hcd_qh_deactivate(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh,
00560                                int sched_next_periodic_split)
00561 {
00562         uint64_t flags;
00563         DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
00564 
00565         if (dwc_qh_is_non_per(qh)) {
00566                 dwc_otg_hcd_qh_remove(hcd, qh);
00567                 if (!DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
00568                         /* Add back to inactive non-periodic schedule. */
00569                         dwc_otg_hcd_qh_add(hcd, qh);
00570                 }
00571         } else {
00572                 uint16_t frame_number = dwc_otg_hcd_get_frame_number(hcd);
00573 
00574                 if (qh->do_split) {
00575                         /* Schedule the next continuing periodic split transfer */
00576                         if (sched_next_periodic_split) {
00577 
00578                                 qh->sched_frame = frame_number;
00579                                 if (dwc_frame_num_le(frame_number,
00580                                                      dwc_frame_num_inc(qh->
00581                                                                        start_split_frame,
00582                                                                        1))) {
00583                                         /*
00584                                          * Allow one frame to elapse after start
00585                                          * split microframe before scheduling
00586                                          * complete split, but DONT if we are
00587                                          * doing the next start split in the
00588                                          * same frame for an ISOC out.
00589                                          */
00590                                         if ((qh->ep_type != UE_ISOCHRONOUS) ||
00591                                             (qh->ep_is_in != 0)) {
00592                                                 qh->sched_frame =
00593                                                     dwc_frame_num_inc(qh->sched_frame, 1);
00594                                         }
00595                                 }
00596                         } else {
00597                                 qh->sched_frame =
00598                                     dwc_frame_num_inc(qh->start_split_frame,
00599                                                       qh->interval);
00600                                 if (dwc_frame_num_le
00601                                     (qh->sched_frame, frame_number)) {
00602                                         qh->sched_frame = frame_number;
00603                                 }
00604                                 qh->sched_frame |= 0x7;
00605                                 qh->start_split_frame = qh->sched_frame;
00606                         }
00607                 } else {
00608                         qh->sched_frame =
00609                             dwc_frame_num_inc(qh->sched_frame, qh->interval);
00610                         if (dwc_frame_num_le(qh->sched_frame, frame_number)) {
00611                                 qh->sched_frame = frame_number;
00612                         }
00613                 }
00614 
00615                 if (DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
00616                         dwc_otg_hcd_qh_remove(hcd, qh);
00617                 } else {
00618                         /*
00619                          * Remove from periodic_sched_queued and move to
00620                          * appropriate queue.
00621                          */
00622                         if (qh->sched_frame == frame_number) {
00623                                 DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_ready,
00624                                                    &qh->qh_list_entry);
00625                         } else {
00626                                 DWC_LIST_MOVE_HEAD(&hcd->
00627                                                    periodic_sched_inactive,
00628                                                    &qh->qh_list_entry);
00629                         }
00630                 }
00631         }
00632 
00633         DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
00634 }
00635 
00643 dwc_otg_qtd_t *dwc_otg_hcd_qtd_create(dwc_otg_hcd_urb_t * urb)
00644 {
00645         dwc_otg_qtd_t *qtd;
00646 
00647         qtd = dwc_otg_hcd_qtd_alloc();
00648         if (qtd == NULL) {
00649                 return NULL;
00650         }
00651 
00652         dwc_otg_hcd_qtd_init(qtd, urb);
00653         return qtd;
00654 }
00655 
00661 void dwc_otg_hcd_qtd_init(dwc_otg_qtd_t * qtd, dwc_otg_hcd_urb_t * urb)
00662 {
00663         dwc_memset(qtd, 0, sizeof(dwc_otg_qtd_t));
00664         qtd->urb = urb;
00665         if (dwc_otg_hcd_get_pipe_type(&urb->pipe_info) == UE_CONTROL) {
00666                 /*
00667                  * The only time the QTD data toggle is used is on the data
00668                  * phase of control transfers. This phase always starts with
00669                  * DATA1.
00670                  */
00671                 qtd->data_toggle = DWC_OTG_HC_PID_DATA1;
00672                 qtd->control_phase = DWC_OTG_CONTROL_SETUP;
00673         }
00674 
00675         /* start split */
00676         qtd->complete_split = 0;
00677         qtd->isoc_split_pos = DWC_HCSPLIT_XACTPOS_ALL;
00678         qtd->isoc_split_offset = 0;
00679         qtd->in_process = 0;
00680 
00681         /* Store the qtd ptr in the urb to reference what QTD. */
00682         urb->qtd = qtd;
00683         return;
00684 }
00685 
00698 int dwc_otg_hcd_qtd_add(dwc_otg_qtd_t * qtd,
00699                         dwc_otg_hcd_t * hcd, dwc_otg_qh_t ** qh)
00700 {
00701         int retval = 0;
00702         uint64_t flags;
00703 
00704         dwc_otg_hcd_urb_t *urb = qtd->urb;
00705 
00706         DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
00707 
00708         /*
00709          * Get the QH which holds the QTD-list to insert to. Create QH if it
00710          * doesn't exist.
00711          */
00712         if (*qh == NULL) {
00713                 *qh = dwc_otg_hcd_qh_create(hcd, urb);
00714                 if (*qh == NULL) {
00715                         retval = -1;
00716                         goto done;
00717                 }
00718         }
00719 
00720         retval = dwc_otg_hcd_qh_add(hcd, *qh);
00721         if (retval == 0) {
00722                 DWC_CIRCLEQ_INSERT_TAIL(&((*qh)->qtd_list), qtd,
00723                                         qtd_list_entry);
00724         }
00725 
00726       done:
00727         DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
00728 
00729         return retval;
00730 }
00731 
00732 #endif                          /* DWC_DEVICE_ONLY */

Generated on Tue May 5 02:22:48 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  doxygen 1.4.7