Main Page | Data Structures | File List | Data Fields | Globals | Related Pages

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: #44 $
00004  * $Date: 2011/10/26 $
00005  * $Change: 1873028 $
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 
00057         /* Free each QTD in the QTD list */
00058         DWC_SPINLOCK(hcd->lock);
00059         DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &qh->qtd_list, qtd_list_entry) {
00060                 DWC_CIRCLEQ_REMOVE(&qh->qtd_list, qtd, qtd_list_entry);
00061                 dwc_otg_hcd_qtd_free(qtd);
00062         }
00063 
00064         if (hcd->core_if->dma_desc_enable) {
00065                 dwc_otg_hcd_qh_free_ddma(hcd, qh);
00066         } else if (qh->dw_align_buf) {
00067                 uint32_t buf_size;
00068                 if (qh->ep_type == UE_ISOCHRONOUS) {
00069                         buf_size = 4096;
00070                 } else {
00071                         buf_size = hcd->core_if->core_params->max_transfer_size;
00072                 }
00073                 DWC_DMA_FREE(buf_size, qh->dw_align_buf, qh->dw_align_buf_dma);
00074         }
00075 
00076         DWC_FREE(qh);
00077         DWC_SPINUNLOCK(hcd->lock);
00078         return;
00079 }
00080 
00081 #define BitStuffTime(bytecount)  ((8 * 7* bytecount) / 6)
00082 #define HS_HOST_DELAY           5       /* nanoseconds */
00083 #define FS_LS_HOST_DELAY        1000    /* nanoseconds */
00084 #define HUB_LS_SETUP            333     /* nanoseconds */
00085 #define NS_TO_US(ns)            ((ns + 500) / 1000)
00086                                 /* convert & round nanoseconds to microseconds */
00087 
00088 static uint32_t calc_bus_time(int speed, int is_in, int is_isoc, int bytecount)
00089 {
00090         unsigned long retval;
00091 
00092         switch (speed) {
00093         case USB_SPEED_HIGH:
00094                 if (is_isoc) {
00095                         retval =
00096                             ((38 * 8 * 2083) +
00097                              (2083 * (3 + BitStuffTime(bytecount)))) / 1000 +
00098                             HS_HOST_DELAY;
00099                 } else {
00100                         retval =
00101                             ((55 * 8 * 2083) +
00102                              (2083 * (3 + BitStuffTime(bytecount)))) / 1000 +
00103                             HS_HOST_DELAY;
00104                 }
00105                 break;
00106         case USB_SPEED_FULL:
00107                 if (is_isoc) {
00108                         retval =
00109                             (8354 * (31 + 10 * BitStuffTime(bytecount))) / 1000;
00110                         if (is_in) {
00111                                 retval = 7268 + FS_LS_HOST_DELAY + retval;
00112                         } else {
00113                                 retval = 6265 + FS_LS_HOST_DELAY + retval;
00114                         }
00115                 } else {
00116                         retval =
00117                             (8354 * (31 + 10 * BitStuffTime(bytecount))) / 1000;
00118                         retval = 9107 + FS_LS_HOST_DELAY + retval;
00119                 }
00120                 break;
00121         case USB_SPEED_LOW:
00122                 if (is_in) {
00123                         retval =
00124                             (67667 * (31 + 10 * BitStuffTime(bytecount))) /
00125                             1000;
00126                         retval =
00127                             64060 + (2 * HUB_LS_SETUP) + FS_LS_HOST_DELAY +
00128                             retval;
00129                 } else {
00130                         retval =
00131                             (66700 * (31 + 10 * BitStuffTime(bytecount))) /
00132                             1000;
00133                         retval =
00134                             64107 + (2 * HUB_LS_SETUP) + FS_LS_HOST_DELAY +
00135                             retval;
00136                 }
00137                 break;
00138         default:
00139                 DWC_WARN("Unknown device speed\n");
00140                 retval = -1;
00141         }
00142 
00143         return NS_TO_US(retval);
00144 }
00145 
00154 #define SCHEDULE_SLOP 10
00155 void qh_init(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, dwc_otg_hcd_urb_t * urb)
00156 {
00157         char *speed, *type;
00158         int dev_speed;
00159         uint32_t hub_addr, hub_port;
00160 
00161         dwc_memset(qh, 0, sizeof(dwc_otg_qh_t));
00162 
00163         /* Initialize QH */
00164         qh->ep_type = dwc_otg_hcd_get_pipe_type(&urb->pipe_info);
00165         qh->ep_is_in = dwc_otg_hcd_is_pipe_in(&urb->pipe_info) ? 1 : 0;
00166 
00167         qh->data_toggle = DWC_OTG_HC_PID_DATA0;
00168         qh->maxp = dwc_otg_hcd_get_mps(&urb->pipe_info);
00169         DWC_CIRCLEQ_INIT(&qh->qtd_list);
00170         DWC_LIST_INIT(&qh->qh_list_entry);
00171         qh->channel = NULL;
00172 
00173         /* FS/LS Enpoint on HS Hub 
00174          * NOT virtual root hub */
00175         dev_speed = hcd->fops->speed(hcd, urb->priv);
00176 
00177         hcd->fops->hub_info(hcd, urb->priv, &hub_addr, &hub_port);
00178         qh->do_split = 0;
00179 
00180         if (((dev_speed == USB_SPEED_LOW) ||
00181              (dev_speed == USB_SPEED_FULL)) &&
00182             (hub_addr != 0 && hub_addr != 1)) {
00183                 DWC_DEBUGPL(DBG_HCD,
00184                             "QH init: EP %d: TT found at hub addr %d, for port %d\n",
00185                             dwc_otg_hcd_get_ep_num(&urb->pipe_info), hub_addr,
00186                             hub_port);
00187                 qh->do_split = 1;
00188         }
00189 
00190         if (qh->ep_type == UE_INTERRUPT || qh->ep_type == UE_ISOCHRONOUS) {
00191                 /* Compute scheduling parameters once and save them. */
00192                 hprt0_data_t hprt;
00193 
00195                 int bytecount =
00196                     dwc_hb_mult(qh->maxp) * dwc_max_packet(qh->maxp);
00197 
00198                 qh->usecs =
00199                     calc_bus_time((qh->do_split ? USB_SPEED_HIGH : dev_speed),
00200                                   qh->ep_is_in, (qh->ep_type == UE_ISOCHRONOUS),
00201                                   bytecount);
00202                 /* Start in a slightly future (micro)frame. */
00203                 qh->sched_frame = dwc_frame_num_inc(hcd->frame_number,
00204                                                     SCHEDULE_SLOP);
00205                 qh->interval = urb->interval;
00206 
00207 #if 0
00208                 /* Increase interrupt polling rate for debugging. */
00209                 if (qh->ep_type == UE_INTERRUPT) {
00210                         qh->interval = 8;
00211                 }
00212 #endif
00213                 hprt.d32 = DWC_READ_REG32(hcd->core_if->host_if->hprt0);
00214                 if ((hprt.b.prtspd == DWC_HPRT0_PRTSPD_HIGH_SPEED) &&
00215                     ((dev_speed == USB_SPEED_LOW) ||
00216                      (dev_speed == USB_SPEED_FULL))) {
00217                         qh->interval *= 8;
00218                         qh->sched_frame |= 0x7;
00219                         qh->start_split_frame = qh->sched_frame;
00220                 }
00221 
00222         }
00223 
00224         DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD QH Initialized\n");
00225         DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH  - qh = %p\n", qh);
00226         DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH  - Device Address = %d\n",
00227                     dwc_otg_hcd_get_dev_addr(&urb->pipe_info));
00228         DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH  - Endpoint %d, %s\n",
00229                     dwc_otg_hcd_get_ep_num(&urb->pipe_info),
00230                     dwc_otg_hcd_is_pipe_in(&urb->pipe_info) ? "IN" : "OUT");
00231         switch (dev_speed) {
00232         case USB_SPEED_LOW:
00233                 qh->dev_speed = DWC_OTG_EP_SPEED_LOW;
00234                 speed = "low";
00235                 break;
00236         case USB_SPEED_FULL:
00237                 qh->dev_speed = DWC_OTG_EP_SPEED_FULL;
00238                 speed = "full";
00239                 break;
00240         case USB_SPEED_HIGH:
00241                 qh->dev_speed = DWC_OTG_EP_SPEED_HIGH;
00242                 speed = "high";
00243                 break;
00244         default:
00245                 speed = "?";
00246                 break;
00247         }
00248         DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH  - Speed = %s\n", speed);
00249 
00250         switch (qh->ep_type) {
00251         case UE_ISOCHRONOUS:
00252                 type = "isochronous";
00253                 break;
00254         case UE_INTERRUPT:
00255                 type = "interrupt";
00256                 break;
00257         case UE_CONTROL:
00258                 type = "control";
00259                 break;
00260         case UE_BULK:
00261                 type = "bulk";
00262                 break;
00263         default:
00264                 type = "?";
00265                 break;
00266         }
00267 
00268         DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH  - Type = %s\n", type);
00269 
00270 #ifdef DEBUG
00271         if (qh->ep_type == UE_INTERRUPT) {
00272                 DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - usecs = %d\n",
00273                             qh->usecs);
00274                 DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - interval = %d\n",
00275                             qh->interval);
00276         }
00277 #endif
00278 
00279 }
00280 
00290 dwc_otg_qh_t *dwc_otg_hcd_qh_create(dwc_otg_hcd_t * hcd,
00291                                     dwc_otg_hcd_urb_t * urb, int atomic_alloc)
00292 {
00293         dwc_otg_qh_t *qh;
00294 
00295         /* Allocate memory */
00297         qh = dwc_otg_hcd_qh_alloc(atomic_alloc);
00298         if (qh == NULL) {
00299                 DWC_ERROR("qh allocation failed");
00300                 return NULL;
00301         }
00302 
00303         qh_init(hcd, qh, urb);
00304 
00305         if (hcd->core_if->dma_desc_enable
00306             && (dwc_otg_hcd_qh_init_ddma(hcd, qh) < 0)) {
00307                 dwc_otg_hcd_qh_free(hcd, qh);
00308                 return NULL;
00309         }
00310 
00311         return qh;
00312 }
00313 
00319 static int periodic_channel_available(dwc_otg_hcd_t * hcd)
00320 {
00321         /*
00322          * Currently assuming that there is a dedicated host channnel for each
00323          * periodic transaction plus at least one host channel for
00324          * non-periodic transactions.
00325          */
00326         int status;
00327         int num_channels;
00328 
00329         num_channels = hcd->core_if->core_params->host_channels;
00330         if ((hcd->periodic_channels + hcd->non_periodic_channels < num_channels)
00331             && (hcd->periodic_channels < num_channels - 1)) {
00332                 status = 0;
00333         } else {
00334                 DWC_INFO("%s: Total channels: %d, Periodic: %d, Non-periodic: %d\n",
00335                         __func__, num_channels, hcd->periodic_channels, hcd->non_periodic_channels);    //NOTICE
00336                 status = -DWC_E_NO_SPACE;
00337         }
00338 
00339         return status;
00340 }
00341 
00352 static int check_periodic_bandwidth(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
00353 {
00354         int status;
00355         int16_t max_claimed_usecs;
00356 
00357         status = 0;
00358 
00359         if ((qh->dev_speed == DWC_OTG_EP_SPEED_HIGH) || qh->do_split) {
00360                 /*
00361                  * High speed mode.
00362                  * Max periodic usecs is 80% x 125 usec = 100 usec.
00363                  */
00364 
00365                 max_claimed_usecs = 100 - qh->usecs;
00366         } else {
00367                 /*
00368                  * Full speed mode.
00369                  * Max periodic usecs is 90% x 1000 usec = 900 usec.
00370                  */
00371                 max_claimed_usecs = 900 - qh->usecs;
00372         }
00373 
00374         if (hcd->periodic_usecs > max_claimed_usecs) {
00375                 DWC_INFO("%s: already claimed usecs %d, required usecs %d\n", __func__, hcd->periodic_usecs, qh->usecs);        //NOTICE
00376                 status = -DWC_E_NO_SPACE;
00377         }
00378 
00379         return status;
00380 }
00381 
00392 static int check_max_xfer_size(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
00393 {
00394         int status;
00395         uint32_t max_xfer_size;
00396         uint32_t max_channel_xfer_size;
00397 
00398         status = 0;
00399 
00400         max_xfer_size = dwc_max_packet(qh->maxp) * dwc_hb_mult(qh->maxp);
00401         max_channel_xfer_size = hcd->core_if->core_params->max_transfer_size;
00402 
00403         if (max_xfer_size > max_channel_xfer_size) {
00404                 DWC_INFO("%s: Periodic xfer length %d > " "max xfer length for channel %d\n",
00405                                 __func__, max_xfer_size, max_channel_xfer_size);        //NOTICE
00406                 status = -DWC_E_NO_SPACE;
00407         }
00408 
00409         return status;
00410 }
00411 
00421 static int schedule_periodic(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
00422 {
00423         int status = 0;
00424 
00425         status = periodic_channel_available(hcd);
00426         if (status) {
00427                 DWC_INFO("%s: No host channel available for periodic " "transfer.\n", __func__);        //NOTICE
00428                 return status;
00429         }
00430 
00431         status = check_periodic_bandwidth(hcd, qh);
00432         if (status) {
00433                 DWC_INFO("%s: Insufficient periodic bandwidth for " "periodic transfer.\n", __func__);  //NOTICE
00434                 return status;
00435         }
00436 
00437         status = check_max_xfer_size(hcd, qh);
00438         if (status) {
00439                 DWC_INFO("%s: Channel max transfer size too small " "for periodic transfer.\n", __func__);      //NOTICE
00440                 return status;
00441         }
00442 
00443         if (hcd->core_if->dma_desc_enable) {
00444                 /* Don't rely on SOF and start in ready schedule */
00445                 DWC_LIST_INSERT_TAIL(&hcd->periodic_sched_ready, &qh->qh_list_entry);
00446         }
00447         else {
00448         /* Always start in the inactive schedule. */
00449         DWC_LIST_INSERT_TAIL(&hcd->periodic_sched_inactive, &qh->qh_list_entry);
00450         }
00451 
00452         /* Reserve the periodic channel. */
00453         hcd->periodic_channels++;
00454 
00455         /* Update claimed usecs per (micro)frame. */
00456         hcd->periodic_usecs += qh->usecs;
00457 
00458         return status;
00459 }
00460 
00468 int dwc_otg_hcd_qh_add(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
00469 {
00470         int status = 0;
00471         gintmsk_data_t intr_mask = {.d32 = 0 };
00472 
00473         if (!DWC_LIST_EMPTY(&qh->qh_list_entry)) {
00474                 /* QH already in a schedule. */
00475                 return status;
00476         }
00477 
00478         /* Add the new QH to the appropriate schedule */
00479         if (dwc_qh_is_non_per(qh)) {
00480                 /* Always start in the inactive schedule. */
00481                 DWC_LIST_INSERT_TAIL(&hcd->non_periodic_sched_inactive,
00482                                      &qh->qh_list_entry);
00483         } else {
00484                 status = schedule_periodic(hcd, qh);
00485                 if ( !hcd->periodic_qh_count ) {
00486                         intr_mask.b.sofintr = 1;
00487                         DWC_MODIFY_REG32(&hcd->core_if->core_global_regs->gintmsk,
00488                                                                 intr_mask.d32, intr_mask.d32);
00489                 }
00490                 hcd->periodic_qh_count++;
00491         }
00492 
00493         return status;
00494 }
00495 
00502 static void deschedule_periodic(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
00503 {
00504         DWC_LIST_REMOVE_INIT(&qh->qh_list_entry);
00505 
00506         /* Release the periodic channel reservation. */
00507         hcd->periodic_channels--;
00508 
00509         /* Update claimed usecs per (micro)frame. */
00510         hcd->periodic_usecs -= qh->usecs;
00511 }
00512 
00519 void dwc_otg_hcd_qh_remove(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
00520 {
00521         gintmsk_data_t intr_mask = {.d32 = 0 };
00522 
00523         if (DWC_LIST_EMPTY(&qh->qh_list_entry)) {
00524                 /* QH is not in a schedule. */
00525                 return;
00526         }
00527 
00528         if (dwc_qh_is_non_per(qh)) {
00529                 if (hcd->non_periodic_qh_ptr == &qh->qh_list_entry) {
00530                         hcd->non_periodic_qh_ptr =
00531                             hcd->non_periodic_qh_ptr->next;
00532                 }
00533                 DWC_LIST_REMOVE_INIT(&qh->qh_list_entry);
00534         } else {
00535                 deschedule_periodic(hcd, qh);
00536                 hcd->periodic_qh_count--;
00537                 if( !hcd->periodic_qh_count ) {
00538                         intr_mask.b.sofintr = 1;
00539                                 DWC_MODIFY_REG32(&hcd->core_if->core_global_regs->gintmsk,
00540                                                                         intr_mask.d32, 0);
00541                 }
00542         }
00543 }
00544 
00558 void dwc_otg_hcd_qh_deactivate(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh,
00559                                int sched_next_periodic_split)
00560 {       
00561         if (dwc_qh_is_non_per(qh)) {
00562                 dwc_otg_hcd_qh_remove(hcd, qh);
00563                 if (!DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
00564                         /* Add back to inactive non-periodic schedule. */
00565                         dwc_otg_hcd_qh_add(hcd, qh);
00566                 }
00567         } else {
00568                 uint16_t frame_number = dwc_otg_hcd_get_frame_number(hcd);
00569 
00570                 if (qh->do_split) {
00571                         /* Schedule the next continuing periodic split transfer */
00572                         if (sched_next_periodic_split) {
00573 
00574                                 qh->sched_frame = frame_number;
00575                                 if (dwc_frame_num_le(frame_number,
00576                                                      dwc_frame_num_inc
00577                                                      (qh->start_split_frame,
00578                                                       1))) {
00579                                         /*
00580                                          * Allow one frame to elapse after start
00581                                          * split microframe before scheduling
00582                                          * complete split, but DONT if we are
00583                                          * doing the next start split in the
00584                                          * same frame for an ISOC out.
00585                                          */
00586                                         if ((qh->ep_type != UE_ISOCHRONOUS) ||
00587                                             (qh->ep_is_in != 0)) {
00588                                                 qh->sched_frame =
00589                                                     dwc_frame_num_inc(qh->sched_frame, 1);
00590                                         }
00591                                 }
00592                         } else {
00593                                 qh->sched_frame =
00594                                     dwc_frame_num_inc(qh->start_split_frame,
00595                                                       qh->interval);
00596                                 if (dwc_frame_num_le
00597                                     (qh->sched_frame, frame_number)) {
00598                                         qh->sched_frame = frame_number;
00599                                 }
00600                                 qh->sched_frame |= 0x7;
00601                                 qh->start_split_frame = qh->sched_frame;
00602                         }
00603                 } else {
00604                         qh->sched_frame =
00605                             dwc_frame_num_inc(qh->sched_frame, qh->interval);
00606                         if (dwc_frame_num_le(qh->sched_frame, frame_number)) {
00607                                 qh->sched_frame = frame_number;
00608                         }
00609                 }
00610 
00611                 if (DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
00612                         dwc_otg_hcd_qh_remove(hcd, qh);
00613                 } else {
00614                         /*
00615                          * Remove from periodic_sched_queued and move to
00616                          * appropriate queue.
00617                          */
00618                         if (qh->sched_frame == frame_number) {
00619                                 DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_ready,
00620                                                    &qh->qh_list_entry);
00621                         } else {
00622                                 DWC_LIST_MOVE_HEAD
00623                                     (&hcd->periodic_sched_inactive,
00624                                      &qh->qh_list_entry);
00625                         }
00626                 }
00627         }
00628 }
00629 
00638 dwc_otg_qtd_t *dwc_otg_hcd_qtd_create(dwc_otg_hcd_urb_t * urb, int atomic_alloc)
00639 {
00640         dwc_otg_qtd_t *qtd;
00641 
00642         qtd = dwc_otg_hcd_qtd_alloc(atomic_alloc);
00643         if (qtd == NULL) {
00644                 return NULL;
00645         }
00646 
00647         dwc_otg_hcd_qtd_init(qtd, urb);
00648         return qtd;
00649 }
00650 
00656 void dwc_otg_hcd_qtd_init(dwc_otg_qtd_t * qtd, dwc_otg_hcd_urb_t * urb)
00657 {
00658         dwc_memset(qtd, 0, sizeof(dwc_otg_qtd_t));
00659         qtd->urb = urb;
00660         if (dwc_otg_hcd_get_pipe_type(&urb->pipe_info) == UE_CONTROL) {
00661                 /*
00662                  * The only time the QTD data toggle is used is on the data
00663                  * phase of control transfers. This phase always starts with
00664                  * DATA1.
00665                  */
00666                 qtd->data_toggle = DWC_OTG_HC_PID_DATA1;
00667                 qtd->control_phase = DWC_OTG_CONTROL_SETUP;
00668         }
00669 
00670         /* start split */
00671         qtd->complete_split = 0;
00672         qtd->isoc_split_pos = DWC_HCSPLIT_XACTPOS_ALL;
00673         qtd->isoc_split_offset = 0;
00674         qtd->in_process = 0;
00675 
00676         /* Store the qtd ptr in the urb to reference what QTD. */
00677         urb->qtd = qtd;
00678         return;
00679 }
00680 
00694 int dwc_otg_hcd_qtd_add(dwc_otg_qtd_t * qtd,
00695                         dwc_otg_hcd_t * hcd, dwc_otg_qh_t ** qh, int atomic_alloc)
00696 {
00697         int retval = 0;
00698         dwc_irqflags_t flags;
00699 
00700         dwc_otg_hcd_urb_t *urb = qtd->urb;
00701 
00702         /*
00703          * Get the QH which holds the QTD-list to insert to. Create QH if it
00704          * doesn't exist.
00705          */
00706         if (*qh == NULL) {
00707                 *qh = dwc_otg_hcd_qh_create(hcd, urb, atomic_alloc);
00708                 if (*qh == NULL) {
00709                         retval = -1;
00710                         goto done;
00711                 }
00712         }
00713         DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
00714         retval = dwc_otg_hcd_qh_add(hcd, *qh);
00715         if (retval == 0) {
00716                 DWC_CIRCLEQ_INSERT_TAIL(&((*qh)->qtd_list), qtd,
00717                                         qtd_list_entry);
00718         }
00719         DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
00720 
00721 done:
00722 
00723         return retval;
00724 }
00725 
00726 #endif /* DWC_DEVICE_ONLY */

Generated on Thu Oct 27 03:56:37 2011 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  doxygen 1.3.9.1