162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Freescale QUICC Engine USB Host Controller Driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) Freescale Semicondutor, Inc. 2006. 662306a36Sopenharmony_ci * Shlomi Gridish <gridish@freescale.com> 762306a36Sopenharmony_ci * Jerry Huang <Chang-Ming.Huang@freescale.com> 862306a36Sopenharmony_ci * Copyright (c) Logic Product Development, Inc. 2007 962306a36Sopenharmony_ci * Peter Barada <peterb@logicpd.com> 1062306a36Sopenharmony_ci * Copyright (c) MontaVista Software, Inc. 2008. 1162306a36Sopenharmony_ci * Anton Vorontsov <avorontsov@ru.mvista.com> 1262306a36Sopenharmony_ci */ 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include <linux/kernel.h> 1562306a36Sopenharmony_ci#include <linux/types.h> 1662306a36Sopenharmony_ci#include <linux/delay.h> 1762306a36Sopenharmony_ci#include <linux/slab.h> 1862306a36Sopenharmony_ci#include <linux/list.h> 1962306a36Sopenharmony_ci#include <linux/usb.h> 2062306a36Sopenharmony_ci#include <linux/usb/hcd.h> 2162306a36Sopenharmony_ci#include "fhci.h" 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistatic void init_td(struct td *td) 2462306a36Sopenharmony_ci{ 2562306a36Sopenharmony_ci memset(td, 0, sizeof(*td)); 2662306a36Sopenharmony_ci INIT_LIST_HEAD(&td->node); 2762306a36Sopenharmony_ci INIT_LIST_HEAD(&td->frame_lh); 2862306a36Sopenharmony_ci} 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_cistatic void init_ed(struct ed *ed) 3162306a36Sopenharmony_ci{ 3262306a36Sopenharmony_ci memset(ed, 0, sizeof(*ed)); 3362306a36Sopenharmony_ci INIT_LIST_HEAD(&ed->td_list); 3462306a36Sopenharmony_ci INIT_LIST_HEAD(&ed->node); 3562306a36Sopenharmony_ci} 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_cistatic struct td *get_empty_td(struct fhci_hcd *fhci) 3862306a36Sopenharmony_ci{ 3962306a36Sopenharmony_ci struct td *td; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci if (!list_empty(&fhci->empty_tds)) { 4262306a36Sopenharmony_ci td = list_entry(fhci->empty_tds.next, struct td, node); 4362306a36Sopenharmony_ci list_del(fhci->empty_tds.next); 4462306a36Sopenharmony_ci } else { 4562306a36Sopenharmony_ci td = kmalloc(sizeof(*td), GFP_ATOMIC); 4662306a36Sopenharmony_ci if (!td) 4762306a36Sopenharmony_ci fhci_err(fhci, "No memory to allocate to TD\n"); 4862306a36Sopenharmony_ci else 4962306a36Sopenharmony_ci init_td(td); 5062306a36Sopenharmony_ci } 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci return td; 5362306a36Sopenharmony_ci} 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_civoid fhci_recycle_empty_td(struct fhci_hcd *fhci, struct td *td) 5662306a36Sopenharmony_ci{ 5762306a36Sopenharmony_ci init_td(td); 5862306a36Sopenharmony_ci list_add(&td->node, &fhci->empty_tds); 5962306a36Sopenharmony_ci} 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_cistruct ed *fhci_get_empty_ed(struct fhci_hcd *fhci) 6262306a36Sopenharmony_ci{ 6362306a36Sopenharmony_ci struct ed *ed; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci if (!list_empty(&fhci->empty_eds)) { 6662306a36Sopenharmony_ci ed = list_entry(fhci->empty_eds.next, struct ed, node); 6762306a36Sopenharmony_ci list_del(fhci->empty_eds.next); 6862306a36Sopenharmony_ci } else { 6962306a36Sopenharmony_ci ed = kmalloc(sizeof(*ed), GFP_ATOMIC); 7062306a36Sopenharmony_ci if (!ed) 7162306a36Sopenharmony_ci fhci_err(fhci, "No memory to allocate to ED\n"); 7262306a36Sopenharmony_ci else 7362306a36Sopenharmony_ci init_ed(ed); 7462306a36Sopenharmony_ci } 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci return ed; 7762306a36Sopenharmony_ci} 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_civoid fhci_recycle_empty_ed(struct fhci_hcd *fhci, struct ed *ed) 8062306a36Sopenharmony_ci{ 8162306a36Sopenharmony_ci init_ed(ed); 8262306a36Sopenharmony_ci list_add(&ed->node, &fhci->empty_eds); 8362306a36Sopenharmony_ci} 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_cistruct td *fhci_td_fill(struct fhci_hcd *fhci, struct urb *urb, 8662306a36Sopenharmony_ci struct urb_priv *urb_priv, struct ed *ed, u16 index, 8762306a36Sopenharmony_ci enum fhci_ta_type type, int toggle, u8 *data, u32 len, 8862306a36Sopenharmony_ci u16 interval, u16 start_frame, bool ioc) 8962306a36Sopenharmony_ci{ 9062306a36Sopenharmony_ci struct td *td = get_empty_td(fhci); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci if (!td) 9362306a36Sopenharmony_ci return NULL; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci td->urb = urb; 9662306a36Sopenharmony_ci td->ed = ed; 9762306a36Sopenharmony_ci td->type = type; 9862306a36Sopenharmony_ci td->toggle = toggle; 9962306a36Sopenharmony_ci td->data = data; 10062306a36Sopenharmony_ci td->len = len; 10162306a36Sopenharmony_ci td->iso_index = index; 10262306a36Sopenharmony_ci td->interval = interval; 10362306a36Sopenharmony_ci td->start_frame = start_frame; 10462306a36Sopenharmony_ci td->ioc = ioc; 10562306a36Sopenharmony_ci td->status = USB_TD_OK; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci urb_priv->tds[index] = td; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci return td; 11062306a36Sopenharmony_ci} 111