18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-1.0+ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Renesas USB driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2011 Renesas Solutions Corp. 68c2ecf20Sopenharmony_ci * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci#include <linux/io.h> 98c2ecf20Sopenharmony_ci#include <linux/list.h> 108c2ecf20Sopenharmony_ci#include <linux/module.h> 118c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 128c2ecf20Sopenharmony_ci#include <linux/slab.h> 138c2ecf20Sopenharmony_ci#include <linux/usb.h> 148c2ecf20Sopenharmony_ci#include <linux/usb/hcd.h> 158c2ecf20Sopenharmony_ci#include "common.h" 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci/* 188c2ecf20Sopenharmony_ci *** HARDWARE LIMITATION *** 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci * 1) renesas_usbhs has a limited number of controllable devices. 218c2ecf20Sopenharmony_ci * it can control only 9 devices in generally. 228c2ecf20Sopenharmony_ci * see DEVADDn / DCPMAXP / PIPEMAXP. 238c2ecf20Sopenharmony_ci * 248c2ecf20Sopenharmony_ci * 2) renesas_usbhs pipe number is limited. 258c2ecf20Sopenharmony_ci * the pipe will be re-used for each devices. 268c2ecf20Sopenharmony_ci * so, software should control DATA0/1 sequence of each devices. 278c2ecf20Sopenharmony_ci */ 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci/* 318c2ecf20Sopenharmony_ci * image of mod_host 328c2ecf20Sopenharmony_ci * 338c2ecf20Sopenharmony_ci * +--------+ 348c2ecf20Sopenharmony_ci * | udev 0 | --> it is used when set address 358c2ecf20Sopenharmony_ci * +--------+ 368c2ecf20Sopenharmony_ci * 378c2ecf20Sopenharmony_ci * +--------+ pipes are reused for each uep. 388c2ecf20Sopenharmony_ci * | udev 1 |-+- [uep 0 (dcp) ] --+ pipe will be switched when 398c2ecf20Sopenharmony_ci * +--------+ | | other device requested 408c2ecf20Sopenharmony_ci * +- [uep 1 (bulk)] --|---+ +--------------+ 418c2ecf20Sopenharmony_ci * | +--------------> | pipe0 (dcp) | 428c2ecf20Sopenharmony_ci * +- [uep 2 (bulk)] -@ | +--------------+ 438c2ecf20Sopenharmony_ci * | | pipe1 (isoc) | 448c2ecf20Sopenharmony_ci * +--------+ | +--------------+ 458c2ecf20Sopenharmony_ci * | udev 2 |-+- [uep 0 (dcp) ] -@ +----------> | pipe2 (bulk) | 468c2ecf20Sopenharmony_ci * +--------+ | +--------------+ 478c2ecf20Sopenharmony_ci * +- [uep 1 (int) ] ----+ +------> | pipe3 (bulk) | 488c2ecf20Sopenharmony_ci * | | +--------------+ 498c2ecf20Sopenharmony_ci * +--------+ +-----|------> | pipe4 (int) | 508c2ecf20Sopenharmony_ci * | udev 3 |-+- [uep 0 (dcp) ] -@ | +--------------+ 518c2ecf20Sopenharmony_ci * +--------+ | | | .... | 528c2ecf20Sopenharmony_ci * +- [uep 1 (bulk)] -@ | | .... | 538c2ecf20Sopenharmony_ci * | | 548c2ecf20Sopenharmony_ci * +- [uep 2 (bulk)]-----------+ 558c2ecf20Sopenharmony_ci * 568c2ecf20Sopenharmony_ci * @ : uep requested free pipe, but all have been used. 578c2ecf20Sopenharmony_ci * now it is waiting for free pipe 588c2ecf20Sopenharmony_ci */ 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci/* 628c2ecf20Sopenharmony_ci * struct 638c2ecf20Sopenharmony_ci */ 648c2ecf20Sopenharmony_cistruct usbhsh_request { 658c2ecf20Sopenharmony_ci struct urb *urb; 668c2ecf20Sopenharmony_ci struct usbhs_pkt pkt; 678c2ecf20Sopenharmony_ci}; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cistruct usbhsh_device { 708c2ecf20Sopenharmony_ci struct usb_device *usbv; 718c2ecf20Sopenharmony_ci struct list_head ep_list_head; /* list of usbhsh_ep */ 728c2ecf20Sopenharmony_ci}; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistruct usbhsh_ep { 758c2ecf20Sopenharmony_ci struct usbhs_pipe *pipe; /* attached pipe */ 768c2ecf20Sopenharmony_ci struct usbhsh_device *udev; /* attached udev */ 778c2ecf20Sopenharmony_ci struct usb_host_endpoint *ep; 788c2ecf20Sopenharmony_ci struct list_head ep_list; /* list to usbhsh_device */ 798c2ecf20Sopenharmony_ci unsigned int counter; /* pipe attach counter */ 808c2ecf20Sopenharmony_ci}; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci#define USBHSH_DEVICE_MAX 10 /* see DEVADDn / DCPMAXP / PIPEMAXP */ 838c2ecf20Sopenharmony_ci#define USBHSH_PORT_MAX 7 /* see DEVADDn :: HUBPORT */ 848c2ecf20Sopenharmony_cistruct usbhsh_hpriv { 858c2ecf20Sopenharmony_ci struct usbhs_mod mod; 868c2ecf20Sopenharmony_ci struct usbhs_pipe *dcp; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci struct usbhsh_device udev[USBHSH_DEVICE_MAX]; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci u32 port_stat; /* USB_PORT_STAT_xxx */ 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci struct completion setup_ack_done; 938c2ecf20Sopenharmony_ci}; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_cistatic const char usbhsh_hcd_name[] = "renesas_usbhs host"; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci/* 998c2ecf20Sopenharmony_ci * macro 1008c2ecf20Sopenharmony_ci */ 1018c2ecf20Sopenharmony_ci#define usbhsh_priv_to_hpriv(priv) \ 1028c2ecf20Sopenharmony_ci container_of(usbhs_mod_get(priv, USBHS_HOST), struct usbhsh_hpriv, mod) 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci#define __usbhsh_for_each_udev(start, pos, h, i) \ 1058c2ecf20Sopenharmony_ci for ((i) = start; \ 1068c2ecf20Sopenharmony_ci ((i) < USBHSH_DEVICE_MAX) && ((pos) = (h)->udev + (i)); \ 1078c2ecf20Sopenharmony_ci (i)++) 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci#define usbhsh_for_each_udev(pos, hpriv, i) \ 1108c2ecf20Sopenharmony_ci __usbhsh_for_each_udev(1, pos, hpriv, i) 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci#define usbhsh_for_each_udev_with_dev0(pos, hpriv, i) \ 1138c2ecf20Sopenharmony_ci __usbhsh_for_each_udev(0, pos, hpriv, i) 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci#define usbhsh_hcd_to_hpriv(h) (struct usbhsh_hpriv *)((h)->hcd_priv) 1168c2ecf20Sopenharmony_ci#define usbhsh_hcd_to_dev(h) ((h)->self.controller) 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci#define usbhsh_hpriv_to_priv(h) ((h)->mod.priv) 1198c2ecf20Sopenharmony_ci#define usbhsh_hpriv_to_dcp(h) ((h)->dcp) 1208c2ecf20Sopenharmony_ci#define usbhsh_hpriv_to_hcd(h) \ 1218c2ecf20Sopenharmony_ci container_of((void *)h, struct usb_hcd, hcd_priv) 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci#define usbhsh_ep_to_uep(u) ((u)->hcpriv) 1248c2ecf20Sopenharmony_ci#define usbhsh_uep_to_pipe(u) ((u)->pipe) 1258c2ecf20Sopenharmony_ci#define usbhsh_uep_to_udev(u) ((u)->udev) 1268c2ecf20Sopenharmony_ci#define usbhsh_uep_to_ep(u) ((u)->ep) 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci#define usbhsh_urb_to_ureq(u) ((u)->hcpriv) 1298c2ecf20Sopenharmony_ci#define usbhsh_urb_to_usbv(u) ((u)->dev) 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci#define usbhsh_usbv_to_udev(d) dev_get_drvdata(&(d)->dev) 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci#define usbhsh_udev_to_usbv(h) ((h)->usbv) 1348c2ecf20Sopenharmony_ci#define usbhsh_udev_is_used(h) usbhsh_udev_to_usbv(h) 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci#define usbhsh_pipe_to_uep(p) ((p)->mod_private) 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci#define usbhsh_device_parent(d) (usbhsh_usbv_to_udev((d)->usbv->parent)) 1398c2ecf20Sopenharmony_ci#define usbhsh_device_hubport(d) ((d)->usbv->portnum) 1408c2ecf20Sopenharmony_ci#define usbhsh_device_number(h, d) ((int)((d) - (h)->udev)) 1418c2ecf20Sopenharmony_ci#define usbhsh_device_nth(h, d) ((h)->udev + d) 1428c2ecf20Sopenharmony_ci#define usbhsh_device0(h) usbhsh_device_nth(h, 0) 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci#define usbhsh_port_stat_init(h) ((h)->port_stat = 0) 1458c2ecf20Sopenharmony_ci#define usbhsh_port_stat_set(h, s) ((h)->port_stat |= (s)) 1468c2ecf20Sopenharmony_ci#define usbhsh_port_stat_clear(h, s) ((h)->port_stat &= ~(s)) 1478c2ecf20Sopenharmony_ci#define usbhsh_port_stat_get(h) ((h)->port_stat) 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci#define usbhsh_pkt_to_ureq(p) \ 1508c2ecf20Sopenharmony_ci container_of((void *)p, struct usbhsh_request, pkt) 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci/* 1538c2ecf20Sopenharmony_ci * req alloc/free 1548c2ecf20Sopenharmony_ci */ 1558c2ecf20Sopenharmony_cistatic struct usbhsh_request *usbhsh_ureq_alloc(struct usbhsh_hpriv *hpriv, 1568c2ecf20Sopenharmony_ci struct urb *urb, 1578c2ecf20Sopenharmony_ci gfp_t mem_flags) 1588c2ecf20Sopenharmony_ci{ 1598c2ecf20Sopenharmony_ci struct usbhsh_request *ureq; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci ureq = kzalloc(sizeof(struct usbhsh_request), mem_flags); 1628c2ecf20Sopenharmony_ci if (!ureq) 1638c2ecf20Sopenharmony_ci return NULL; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci usbhs_pkt_init(&ureq->pkt); 1668c2ecf20Sopenharmony_ci ureq->urb = urb; 1678c2ecf20Sopenharmony_ci usbhsh_urb_to_ureq(urb) = ureq; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci return ureq; 1708c2ecf20Sopenharmony_ci} 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_cistatic void usbhsh_ureq_free(struct usbhsh_hpriv *hpriv, 1738c2ecf20Sopenharmony_ci struct usbhsh_request *ureq) 1748c2ecf20Sopenharmony_ci{ 1758c2ecf20Sopenharmony_ci usbhsh_urb_to_ureq(ureq->urb) = NULL; 1768c2ecf20Sopenharmony_ci ureq->urb = NULL; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci kfree(ureq); 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci/* 1828c2ecf20Sopenharmony_ci * status 1838c2ecf20Sopenharmony_ci */ 1848c2ecf20Sopenharmony_cistatic int usbhsh_is_running(struct usbhsh_hpriv *hpriv) 1858c2ecf20Sopenharmony_ci{ 1868c2ecf20Sopenharmony_ci /* 1878c2ecf20Sopenharmony_ci * we can decide some device is attached or not 1888c2ecf20Sopenharmony_ci * by checking mod.irq_attch 1898c2ecf20Sopenharmony_ci * see 1908c2ecf20Sopenharmony_ci * usbhsh_irq_attch() 1918c2ecf20Sopenharmony_ci * usbhsh_irq_dtch() 1928c2ecf20Sopenharmony_ci */ 1938c2ecf20Sopenharmony_ci return (hpriv->mod.irq_attch == NULL); 1948c2ecf20Sopenharmony_ci} 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci/* 1978c2ecf20Sopenharmony_ci * pipe control 1988c2ecf20Sopenharmony_ci */ 1998c2ecf20Sopenharmony_cistatic void usbhsh_endpoint_sequence_save(struct usbhsh_hpriv *hpriv, 2008c2ecf20Sopenharmony_ci struct urb *urb, 2018c2ecf20Sopenharmony_ci struct usbhs_pkt *pkt) 2028c2ecf20Sopenharmony_ci{ 2038c2ecf20Sopenharmony_ci int len = urb->actual_length; 2048c2ecf20Sopenharmony_ci int maxp = usb_endpoint_maxp(&urb->ep->desc); 2058c2ecf20Sopenharmony_ci int t = 0; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci /* DCP is out of sequence control */ 2088c2ecf20Sopenharmony_ci if (usb_pipecontrol(urb->pipe)) 2098c2ecf20Sopenharmony_ci return; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci /* 2128c2ecf20Sopenharmony_ci * renesas_usbhs pipe has a limitation in a number. 2138c2ecf20Sopenharmony_ci * So, driver should re-use the limited pipe for each device/endpoint. 2148c2ecf20Sopenharmony_ci * DATA0/1 sequence should be saved for it. 2158c2ecf20Sopenharmony_ci * see [image of mod_host] 2168c2ecf20Sopenharmony_ci * [HARDWARE LIMITATION] 2178c2ecf20Sopenharmony_ci */ 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci /* 2208c2ecf20Sopenharmony_ci * next sequence depends on actual_length 2218c2ecf20Sopenharmony_ci * 2228c2ecf20Sopenharmony_ci * ex) actual_length = 1147, maxp = 512 2238c2ecf20Sopenharmony_ci * data0 : 512 2248c2ecf20Sopenharmony_ci * data1 : 512 2258c2ecf20Sopenharmony_ci * data0 : 123 2268c2ecf20Sopenharmony_ci * data1 is the next sequence 2278c2ecf20Sopenharmony_ci */ 2288c2ecf20Sopenharmony_ci t = len / maxp; 2298c2ecf20Sopenharmony_ci if (len % maxp) 2308c2ecf20Sopenharmony_ci t++; 2318c2ecf20Sopenharmony_ci if (pkt->zero) 2328c2ecf20Sopenharmony_ci t++; 2338c2ecf20Sopenharmony_ci t %= 2; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci if (t) 2368c2ecf20Sopenharmony_ci usb_dotoggle(urb->dev, 2378c2ecf20Sopenharmony_ci usb_pipeendpoint(urb->pipe), 2388c2ecf20Sopenharmony_ci usb_pipeout(urb->pipe)); 2398c2ecf20Sopenharmony_ci} 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_cistatic struct usbhsh_device *usbhsh_device_get(struct usbhsh_hpriv *hpriv, 2428c2ecf20Sopenharmony_ci struct urb *urb); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_cistatic int usbhsh_pipe_attach(struct usbhsh_hpriv *hpriv, 2458c2ecf20Sopenharmony_ci struct urb *urb) 2468c2ecf20Sopenharmony_ci{ 2478c2ecf20Sopenharmony_ci struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); 2488c2ecf20Sopenharmony_ci struct usbhsh_ep *uep = usbhsh_ep_to_uep(urb->ep); 2498c2ecf20Sopenharmony_ci struct usbhsh_device *udev = usbhsh_device_get(hpriv, urb); 2508c2ecf20Sopenharmony_ci struct usbhs_pipe *pipe; 2518c2ecf20Sopenharmony_ci struct usb_endpoint_descriptor *desc = &urb->ep->desc; 2528c2ecf20Sopenharmony_ci struct device *dev = usbhs_priv_to_dev(priv); 2538c2ecf20Sopenharmony_ci unsigned long flags; 2548c2ecf20Sopenharmony_ci int dir_in_req = !!usb_pipein(urb->pipe); 2558c2ecf20Sopenharmony_ci int is_dcp = usb_endpoint_xfer_control(desc); 2568c2ecf20Sopenharmony_ci int i, dir_in; 2578c2ecf20Sopenharmony_ci int ret = -EBUSY; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci /******************** spin lock ********************/ 2608c2ecf20Sopenharmony_ci usbhs_lock(priv, flags); 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci /* 2638c2ecf20Sopenharmony_ci * if uep has been attached to pipe, 2648c2ecf20Sopenharmony_ci * reuse it 2658c2ecf20Sopenharmony_ci */ 2668c2ecf20Sopenharmony_ci if (usbhsh_uep_to_pipe(uep)) { 2678c2ecf20Sopenharmony_ci ret = 0; 2688c2ecf20Sopenharmony_ci goto usbhsh_pipe_attach_done; 2698c2ecf20Sopenharmony_ci } 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci usbhs_for_each_pipe_with_dcp(pipe, priv, i) { 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci /* check pipe type */ 2748c2ecf20Sopenharmony_ci if (!usbhs_pipe_type_is(pipe, usb_endpoint_type(desc))) 2758c2ecf20Sopenharmony_ci continue; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci /* check pipe direction if normal pipe */ 2788c2ecf20Sopenharmony_ci if (!is_dcp) { 2798c2ecf20Sopenharmony_ci dir_in = !!usbhs_pipe_is_dir_in(pipe); 2808c2ecf20Sopenharmony_ci if (0 != (dir_in - dir_in_req)) 2818c2ecf20Sopenharmony_ci continue; 2828c2ecf20Sopenharmony_ci } 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci /* check pipe is free */ 2858c2ecf20Sopenharmony_ci if (usbhsh_pipe_to_uep(pipe)) 2868c2ecf20Sopenharmony_ci continue; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci /* 2898c2ecf20Sopenharmony_ci * attach pipe to uep 2908c2ecf20Sopenharmony_ci * 2918c2ecf20Sopenharmony_ci * usbhs_pipe_config_update() should be called after 2928c2ecf20Sopenharmony_ci * usbhs_set_device_config() 2938c2ecf20Sopenharmony_ci * see 2948c2ecf20Sopenharmony_ci * DCPMAXP/PIPEMAXP 2958c2ecf20Sopenharmony_ci */ 2968c2ecf20Sopenharmony_ci usbhsh_uep_to_pipe(uep) = pipe; 2978c2ecf20Sopenharmony_ci usbhsh_pipe_to_uep(pipe) = uep; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci usbhs_pipe_config_update(pipe, 3008c2ecf20Sopenharmony_ci usbhsh_device_number(hpriv, udev), 3018c2ecf20Sopenharmony_ci usb_endpoint_num(desc), 3028c2ecf20Sopenharmony_ci usb_endpoint_maxp(desc)); 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci dev_dbg(dev, "%s [%d-%d(%s:%s)]\n", __func__, 3058c2ecf20Sopenharmony_ci usbhsh_device_number(hpriv, udev), 3068c2ecf20Sopenharmony_ci usb_endpoint_num(desc), 3078c2ecf20Sopenharmony_ci usbhs_pipe_name(pipe), 3088c2ecf20Sopenharmony_ci dir_in_req ? "in" : "out"); 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci ret = 0; 3118c2ecf20Sopenharmony_ci break; 3128c2ecf20Sopenharmony_ci } 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ciusbhsh_pipe_attach_done: 3158c2ecf20Sopenharmony_ci if (0 == ret) 3168c2ecf20Sopenharmony_ci uep->counter++; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci usbhs_unlock(priv, flags); 3198c2ecf20Sopenharmony_ci /******************** spin unlock ******************/ 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci return ret; 3228c2ecf20Sopenharmony_ci} 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_cistatic void usbhsh_pipe_detach(struct usbhsh_hpriv *hpriv, 3258c2ecf20Sopenharmony_ci struct usbhsh_ep *uep) 3268c2ecf20Sopenharmony_ci{ 3278c2ecf20Sopenharmony_ci struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); 3288c2ecf20Sopenharmony_ci struct usbhs_pipe *pipe; 3298c2ecf20Sopenharmony_ci struct device *dev = usbhs_priv_to_dev(priv); 3308c2ecf20Sopenharmony_ci unsigned long flags; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci if (unlikely(!uep)) { 3338c2ecf20Sopenharmony_ci dev_err(dev, "no uep\n"); 3348c2ecf20Sopenharmony_ci return; 3358c2ecf20Sopenharmony_ci } 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci /******************** spin lock ********************/ 3388c2ecf20Sopenharmony_ci usbhs_lock(priv, flags); 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci pipe = usbhsh_uep_to_pipe(uep); 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci if (unlikely(!pipe)) { 3438c2ecf20Sopenharmony_ci dev_err(dev, "uep doesn't have pipe\n"); 3448c2ecf20Sopenharmony_ci } else if (1 == uep->counter--) { /* last user */ 3458c2ecf20Sopenharmony_ci struct usb_host_endpoint *ep = usbhsh_uep_to_ep(uep); 3468c2ecf20Sopenharmony_ci struct usbhsh_device *udev = usbhsh_uep_to_udev(uep); 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci /* detach pipe from uep */ 3498c2ecf20Sopenharmony_ci usbhsh_uep_to_pipe(uep) = NULL; 3508c2ecf20Sopenharmony_ci usbhsh_pipe_to_uep(pipe) = NULL; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci dev_dbg(dev, "%s [%d-%d(%s)]\n", __func__, 3538c2ecf20Sopenharmony_ci usbhsh_device_number(hpriv, udev), 3548c2ecf20Sopenharmony_ci usb_endpoint_num(&ep->desc), 3558c2ecf20Sopenharmony_ci usbhs_pipe_name(pipe)); 3568c2ecf20Sopenharmony_ci } 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci usbhs_unlock(priv, flags); 3598c2ecf20Sopenharmony_ci /******************** spin unlock ******************/ 3608c2ecf20Sopenharmony_ci} 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci/* 3638c2ecf20Sopenharmony_ci * endpoint control 3648c2ecf20Sopenharmony_ci */ 3658c2ecf20Sopenharmony_cistatic int usbhsh_endpoint_attach(struct usbhsh_hpriv *hpriv, 3668c2ecf20Sopenharmony_ci struct urb *urb, 3678c2ecf20Sopenharmony_ci gfp_t mem_flags) 3688c2ecf20Sopenharmony_ci{ 3698c2ecf20Sopenharmony_ci struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); 3708c2ecf20Sopenharmony_ci struct usbhsh_device *udev = usbhsh_device_get(hpriv, urb); 3718c2ecf20Sopenharmony_ci struct usb_host_endpoint *ep = urb->ep; 3728c2ecf20Sopenharmony_ci struct usbhsh_ep *uep; 3738c2ecf20Sopenharmony_ci struct device *dev = usbhs_priv_to_dev(priv); 3748c2ecf20Sopenharmony_ci struct usb_endpoint_descriptor *desc = &ep->desc; 3758c2ecf20Sopenharmony_ci unsigned long flags; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci uep = kzalloc(sizeof(struct usbhsh_ep), mem_flags); 3788c2ecf20Sopenharmony_ci if (!uep) 3798c2ecf20Sopenharmony_ci return -ENOMEM; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci /******************** spin lock ********************/ 3828c2ecf20Sopenharmony_ci usbhs_lock(priv, flags); 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci /* 3858c2ecf20Sopenharmony_ci * init endpoint 3868c2ecf20Sopenharmony_ci */ 3878c2ecf20Sopenharmony_ci uep->counter = 0; 3888c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&uep->ep_list); 3898c2ecf20Sopenharmony_ci list_add_tail(&uep->ep_list, &udev->ep_list_head); 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci usbhsh_uep_to_udev(uep) = udev; 3928c2ecf20Sopenharmony_ci usbhsh_uep_to_ep(uep) = ep; 3938c2ecf20Sopenharmony_ci usbhsh_ep_to_uep(ep) = uep; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci usbhs_unlock(priv, flags); 3968c2ecf20Sopenharmony_ci /******************** spin unlock ******************/ 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci dev_dbg(dev, "%s [%d-%d]\n", __func__, 3998c2ecf20Sopenharmony_ci usbhsh_device_number(hpriv, udev), 4008c2ecf20Sopenharmony_ci usb_endpoint_num(desc)); 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci return 0; 4038c2ecf20Sopenharmony_ci} 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_cistatic void usbhsh_endpoint_detach(struct usbhsh_hpriv *hpriv, 4068c2ecf20Sopenharmony_ci struct usb_host_endpoint *ep) 4078c2ecf20Sopenharmony_ci{ 4088c2ecf20Sopenharmony_ci struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); 4098c2ecf20Sopenharmony_ci struct device *dev = usbhs_priv_to_dev(priv); 4108c2ecf20Sopenharmony_ci struct usbhsh_ep *uep = usbhsh_ep_to_uep(ep); 4118c2ecf20Sopenharmony_ci unsigned long flags; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci if (!uep) 4148c2ecf20Sopenharmony_ci return; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci dev_dbg(dev, "%s [%d-%d]\n", __func__, 4178c2ecf20Sopenharmony_ci usbhsh_device_number(hpriv, usbhsh_uep_to_udev(uep)), 4188c2ecf20Sopenharmony_ci usb_endpoint_num(&ep->desc)); 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci if (usbhsh_uep_to_pipe(uep)) 4218c2ecf20Sopenharmony_ci usbhsh_pipe_detach(hpriv, uep); 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci /******************** spin lock ********************/ 4248c2ecf20Sopenharmony_ci usbhs_lock(priv, flags); 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci /* remove this endpoint from udev */ 4278c2ecf20Sopenharmony_ci list_del_init(&uep->ep_list); 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci usbhsh_uep_to_udev(uep) = NULL; 4308c2ecf20Sopenharmony_ci usbhsh_uep_to_ep(uep) = NULL; 4318c2ecf20Sopenharmony_ci usbhsh_ep_to_uep(ep) = NULL; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci usbhs_unlock(priv, flags); 4348c2ecf20Sopenharmony_ci /******************** spin unlock ******************/ 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci kfree(uep); 4378c2ecf20Sopenharmony_ci} 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_cistatic void usbhsh_endpoint_detach_all(struct usbhsh_hpriv *hpriv, 4408c2ecf20Sopenharmony_ci struct usbhsh_device *udev) 4418c2ecf20Sopenharmony_ci{ 4428c2ecf20Sopenharmony_ci struct usbhsh_ep *uep, *next; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci list_for_each_entry_safe(uep, next, &udev->ep_list_head, ep_list) 4458c2ecf20Sopenharmony_ci usbhsh_endpoint_detach(hpriv, usbhsh_uep_to_ep(uep)); 4468c2ecf20Sopenharmony_ci} 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci/* 4498c2ecf20Sopenharmony_ci * device control 4508c2ecf20Sopenharmony_ci */ 4518c2ecf20Sopenharmony_cistatic int usbhsh_connected_to_rhdev(struct usb_hcd *hcd, 4528c2ecf20Sopenharmony_ci struct usbhsh_device *udev) 4538c2ecf20Sopenharmony_ci{ 4548c2ecf20Sopenharmony_ci struct usb_device *usbv = usbhsh_udev_to_usbv(udev); 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci return hcd->self.root_hub == usbv->parent; 4578c2ecf20Sopenharmony_ci} 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_cistatic int usbhsh_device_has_endpoint(struct usbhsh_device *udev) 4608c2ecf20Sopenharmony_ci{ 4618c2ecf20Sopenharmony_ci return !list_empty(&udev->ep_list_head); 4628c2ecf20Sopenharmony_ci} 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_cistatic struct usbhsh_device *usbhsh_device_get(struct usbhsh_hpriv *hpriv, 4658c2ecf20Sopenharmony_ci struct urb *urb) 4668c2ecf20Sopenharmony_ci{ 4678c2ecf20Sopenharmony_ci struct usb_device *usbv = usbhsh_urb_to_usbv(urb); 4688c2ecf20Sopenharmony_ci struct usbhsh_device *udev = usbhsh_usbv_to_udev(usbv); 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci /* usbhsh_device_attach() is still not called */ 4718c2ecf20Sopenharmony_ci if (!udev) 4728c2ecf20Sopenharmony_ci return NULL; 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci /* if it is device0, return it */ 4758c2ecf20Sopenharmony_ci if (0 == usb_pipedevice(urb->pipe)) 4768c2ecf20Sopenharmony_ci return usbhsh_device0(hpriv); 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci /* return attached device */ 4798c2ecf20Sopenharmony_ci return udev; 4808c2ecf20Sopenharmony_ci} 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_cistatic struct usbhsh_device *usbhsh_device_attach(struct usbhsh_hpriv *hpriv, 4838c2ecf20Sopenharmony_ci struct urb *urb) 4848c2ecf20Sopenharmony_ci{ 4858c2ecf20Sopenharmony_ci struct usbhsh_device *udev = NULL; 4868c2ecf20Sopenharmony_ci struct usbhsh_device *udev0 = usbhsh_device0(hpriv); 4878c2ecf20Sopenharmony_ci struct usbhsh_device *pos; 4888c2ecf20Sopenharmony_ci struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv); 4898c2ecf20Sopenharmony_ci struct device *dev = usbhsh_hcd_to_dev(hcd); 4908c2ecf20Sopenharmony_ci struct usb_device *usbv = usbhsh_urb_to_usbv(urb); 4918c2ecf20Sopenharmony_ci struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); 4928c2ecf20Sopenharmony_ci unsigned long flags; 4938c2ecf20Sopenharmony_ci u16 upphub, hubport; 4948c2ecf20Sopenharmony_ci int i; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci /* 4978c2ecf20Sopenharmony_ci * This function should be called only while urb is pointing to device0. 4988c2ecf20Sopenharmony_ci * It will attach unused usbhsh_device to urb (usbv), 4998c2ecf20Sopenharmony_ci * and initialize device0. 5008c2ecf20Sopenharmony_ci * You can use usbhsh_device_get() to get "current" udev, 5018c2ecf20Sopenharmony_ci * and usbhsh_usbv_to_udev() is for "attached" udev. 5028c2ecf20Sopenharmony_ci */ 5038c2ecf20Sopenharmony_ci if (0 != usb_pipedevice(urb->pipe)) { 5048c2ecf20Sopenharmony_ci dev_err(dev, "%s fail: urb isn't pointing device0\n", __func__); 5058c2ecf20Sopenharmony_ci return NULL; 5068c2ecf20Sopenharmony_ci } 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci /******************** spin lock ********************/ 5098c2ecf20Sopenharmony_ci usbhs_lock(priv, flags); 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci /* 5128c2ecf20Sopenharmony_ci * find unused device 5138c2ecf20Sopenharmony_ci */ 5148c2ecf20Sopenharmony_ci usbhsh_for_each_udev(pos, hpriv, i) { 5158c2ecf20Sopenharmony_ci if (usbhsh_udev_is_used(pos)) 5168c2ecf20Sopenharmony_ci continue; 5178c2ecf20Sopenharmony_ci udev = pos; 5188c2ecf20Sopenharmony_ci break; 5198c2ecf20Sopenharmony_ci } 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci if (udev) { 5228c2ecf20Sopenharmony_ci /* 5238c2ecf20Sopenharmony_ci * usbhsh_usbv_to_udev() 5248c2ecf20Sopenharmony_ci * usbhsh_udev_to_usbv() 5258c2ecf20Sopenharmony_ci * will be enable 5268c2ecf20Sopenharmony_ci */ 5278c2ecf20Sopenharmony_ci dev_set_drvdata(&usbv->dev, udev); 5288c2ecf20Sopenharmony_ci udev->usbv = usbv; 5298c2ecf20Sopenharmony_ci } 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci usbhs_unlock(priv, flags); 5328c2ecf20Sopenharmony_ci /******************** spin unlock ******************/ 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci if (!udev) { 5358c2ecf20Sopenharmony_ci dev_err(dev, "no free usbhsh_device\n"); 5368c2ecf20Sopenharmony_ci return NULL; 5378c2ecf20Sopenharmony_ci } 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci if (usbhsh_device_has_endpoint(udev)) { 5408c2ecf20Sopenharmony_ci dev_warn(dev, "udev have old endpoint\n"); 5418c2ecf20Sopenharmony_ci usbhsh_endpoint_detach_all(hpriv, udev); 5428c2ecf20Sopenharmony_ci } 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci if (usbhsh_device_has_endpoint(udev0)) { 5458c2ecf20Sopenharmony_ci dev_warn(dev, "udev0 have old endpoint\n"); 5468c2ecf20Sopenharmony_ci usbhsh_endpoint_detach_all(hpriv, udev0); 5478c2ecf20Sopenharmony_ci } 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci /* uep will be attached */ 5508c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&udev0->ep_list_head); 5518c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&udev->ep_list_head); 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci /* 5548c2ecf20Sopenharmony_ci * set device0 config 5558c2ecf20Sopenharmony_ci */ 5568c2ecf20Sopenharmony_ci usbhs_set_device_config(priv, 5578c2ecf20Sopenharmony_ci 0, 0, 0, usbv->speed); 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci /* 5608c2ecf20Sopenharmony_ci * set new device config 5618c2ecf20Sopenharmony_ci */ 5628c2ecf20Sopenharmony_ci upphub = 0; 5638c2ecf20Sopenharmony_ci hubport = 0; 5648c2ecf20Sopenharmony_ci if (!usbhsh_connected_to_rhdev(hcd, udev)) { 5658c2ecf20Sopenharmony_ci /* if udev is not connected to rhdev, it means parent is Hub */ 5668c2ecf20Sopenharmony_ci struct usbhsh_device *parent = usbhsh_device_parent(udev); 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci upphub = usbhsh_device_number(hpriv, parent); 5698c2ecf20Sopenharmony_ci hubport = usbhsh_device_hubport(udev); 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci dev_dbg(dev, "%s connected to Hub [%d:%d](%p)\n", __func__, 5728c2ecf20Sopenharmony_ci upphub, hubport, parent); 5738c2ecf20Sopenharmony_ci } 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci usbhs_set_device_config(priv, 5768c2ecf20Sopenharmony_ci usbhsh_device_number(hpriv, udev), 5778c2ecf20Sopenharmony_ci upphub, hubport, usbv->speed); 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci dev_dbg(dev, "%s [%d](%p)\n", __func__, 5808c2ecf20Sopenharmony_ci usbhsh_device_number(hpriv, udev), udev); 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci return udev; 5838c2ecf20Sopenharmony_ci} 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_cistatic void usbhsh_device_detach(struct usbhsh_hpriv *hpriv, 5868c2ecf20Sopenharmony_ci struct usbhsh_device *udev) 5878c2ecf20Sopenharmony_ci{ 5888c2ecf20Sopenharmony_ci struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv); 5898c2ecf20Sopenharmony_ci struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); 5908c2ecf20Sopenharmony_ci struct device *dev = usbhsh_hcd_to_dev(hcd); 5918c2ecf20Sopenharmony_ci struct usb_device *usbv = usbhsh_udev_to_usbv(udev); 5928c2ecf20Sopenharmony_ci unsigned long flags; 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci dev_dbg(dev, "%s [%d](%p)\n", __func__, 5958c2ecf20Sopenharmony_ci usbhsh_device_number(hpriv, udev), udev); 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci if (usbhsh_device_has_endpoint(udev)) { 5988c2ecf20Sopenharmony_ci dev_warn(dev, "udev still have endpoint\n"); 5998c2ecf20Sopenharmony_ci usbhsh_endpoint_detach_all(hpriv, udev); 6008c2ecf20Sopenharmony_ci } 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci /* 6038c2ecf20Sopenharmony_ci * There is nothing to do if it is device0. 6048c2ecf20Sopenharmony_ci * see 6058c2ecf20Sopenharmony_ci * usbhsh_device_attach() 6068c2ecf20Sopenharmony_ci * usbhsh_device_get() 6078c2ecf20Sopenharmony_ci */ 6088c2ecf20Sopenharmony_ci if (0 == usbhsh_device_number(hpriv, udev)) 6098c2ecf20Sopenharmony_ci return; 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci /******************** spin lock ********************/ 6128c2ecf20Sopenharmony_ci usbhs_lock(priv, flags); 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci /* 6158c2ecf20Sopenharmony_ci * usbhsh_usbv_to_udev() 6168c2ecf20Sopenharmony_ci * usbhsh_udev_to_usbv() 6178c2ecf20Sopenharmony_ci * will be disable 6188c2ecf20Sopenharmony_ci */ 6198c2ecf20Sopenharmony_ci dev_set_drvdata(&usbv->dev, NULL); 6208c2ecf20Sopenharmony_ci udev->usbv = NULL; 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci usbhs_unlock(priv, flags); 6238c2ecf20Sopenharmony_ci /******************** spin unlock ******************/ 6248c2ecf20Sopenharmony_ci} 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci/* 6278c2ecf20Sopenharmony_ci * queue push/pop 6288c2ecf20Sopenharmony_ci */ 6298c2ecf20Sopenharmony_cistatic void usbhsh_queue_done(struct usbhs_priv *priv, struct usbhs_pkt *pkt) 6308c2ecf20Sopenharmony_ci{ 6318c2ecf20Sopenharmony_ci struct usbhsh_request *ureq = usbhsh_pkt_to_ureq(pkt); 6328c2ecf20Sopenharmony_ci struct usbhsh_hpriv *hpriv = usbhsh_priv_to_hpriv(priv); 6338c2ecf20Sopenharmony_ci struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv); 6348c2ecf20Sopenharmony_ci struct urb *urb = ureq->urb; 6358c2ecf20Sopenharmony_ci struct device *dev = usbhs_priv_to_dev(priv); 6368c2ecf20Sopenharmony_ci int status = 0; 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci dev_dbg(dev, "%s\n", __func__); 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci if (!urb) { 6418c2ecf20Sopenharmony_ci dev_warn(dev, "pkt doesn't have urb\n"); 6428c2ecf20Sopenharmony_ci return; 6438c2ecf20Sopenharmony_ci } 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci if (!usbhsh_is_running(hpriv)) 6468c2ecf20Sopenharmony_ci status = -ESHUTDOWN; 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci urb->actual_length = pkt->actual; 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci usbhsh_endpoint_sequence_save(hpriv, urb, pkt); 6518c2ecf20Sopenharmony_ci usbhsh_ureq_free(hpriv, ureq); 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci usbhsh_pipe_detach(hpriv, usbhsh_ep_to_uep(urb->ep)); 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci usb_hcd_unlink_urb_from_ep(hcd, urb); 6568c2ecf20Sopenharmony_ci usb_hcd_giveback_urb(hcd, urb, status); 6578c2ecf20Sopenharmony_ci} 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_cistatic int usbhsh_queue_push(struct usb_hcd *hcd, 6608c2ecf20Sopenharmony_ci struct urb *urb, 6618c2ecf20Sopenharmony_ci gfp_t mem_flags) 6628c2ecf20Sopenharmony_ci{ 6638c2ecf20Sopenharmony_ci struct usbhsh_hpriv *hpriv = usbhsh_hcd_to_hpriv(hcd); 6648c2ecf20Sopenharmony_ci struct usbhsh_ep *uep = usbhsh_ep_to_uep(urb->ep); 6658c2ecf20Sopenharmony_ci struct usbhs_pipe *pipe = usbhsh_uep_to_pipe(uep); 6668c2ecf20Sopenharmony_ci struct device *dev = usbhsh_hcd_to_dev(hcd); 6678c2ecf20Sopenharmony_ci struct usbhsh_request *ureq; 6688c2ecf20Sopenharmony_ci void *buf; 6698c2ecf20Sopenharmony_ci int len, sequence; 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci if (usb_pipeisoc(urb->pipe)) { 6728c2ecf20Sopenharmony_ci dev_err(dev, "pipe iso is not supported now\n"); 6738c2ecf20Sopenharmony_ci return -EIO; 6748c2ecf20Sopenharmony_ci } 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci /* this ureq will be freed on usbhsh_queue_done() */ 6778c2ecf20Sopenharmony_ci ureq = usbhsh_ureq_alloc(hpriv, urb, mem_flags); 6788c2ecf20Sopenharmony_ci if (unlikely(!ureq)) { 6798c2ecf20Sopenharmony_ci dev_err(dev, "ureq alloc fail\n"); 6808c2ecf20Sopenharmony_ci return -ENOMEM; 6818c2ecf20Sopenharmony_ci } 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci if (usb_pipein(urb->pipe)) 6848c2ecf20Sopenharmony_ci pipe->handler = &usbhs_fifo_dma_pop_handler; 6858c2ecf20Sopenharmony_ci else 6868c2ecf20Sopenharmony_ci pipe->handler = &usbhs_fifo_dma_push_handler; 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci buf = (void *)(urb->transfer_buffer + urb->actual_length); 6898c2ecf20Sopenharmony_ci len = urb->transfer_buffer_length - urb->actual_length; 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci sequence = usb_gettoggle(urb->dev, 6928c2ecf20Sopenharmony_ci usb_pipeendpoint(urb->pipe), 6938c2ecf20Sopenharmony_ci usb_pipeout(urb->pipe)); 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci dev_dbg(dev, "%s\n", __func__); 6968c2ecf20Sopenharmony_ci usbhs_pkt_push(pipe, &ureq->pkt, usbhsh_queue_done, 6978c2ecf20Sopenharmony_ci buf, len, (urb->transfer_flags & URB_ZERO_PACKET), 6988c2ecf20Sopenharmony_ci sequence); 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci usbhs_pkt_start(pipe); 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci return 0; 7038c2ecf20Sopenharmony_ci} 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_cistatic void usbhsh_queue_force_pop(struct usbhs_priv *priv, 7068c2ecf20Sopenharmony_ci struct usbhs_pipe *pipe) 7078c2ecf20Sopenharmony_ci{ 7088c2ecf20Sopenharmony_ci struct usbhs_pkt *pkt; 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci while (1) { 7118c2ecf20Sopenharmony_ci pkt = usbhs_pkt_pop(pipe, NULL); 7128c2ecf20Sopenharmony_ci if (!pkt) 7138c2ecf20Sopenharmony_ci break; 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci /* 7168c2ecf20Sopenharmony_ci * if all packet are gone, usbhsh_endpoint_disable() 7178c2ecf20Sopenharmony_ci * will be called. 7188c2ecf20Sopenharmony_ci * then, attached device/endpoint/pipe will be detached 7198c2ecf20Sopenharmony_ci */ 7208c2ecf20Sopenharmony_ci usbhsh_queue_done(priv, pkt); 7218c2ecf20Sopenharmony_ci } 7228c2ecf20Sopenharmony_ci} 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_cistatic void usbhsh_queue_force_pop_all(struct usbhs_priv *priv) 7258c2ecf20Sopenharmony_ci{ 7268c2ecf20Sopenharmony_ci struct usbhs_pipe *pos; 7278c2ecf20Sopenharmony_ci int i; 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci usbhs_for_each_pipe_with_dcp(pos, priv, i) 7308c2ecf20Sopenharmony_ci usbhsh_queue_force_pop(priv, pos); 7318c2ecf20Sopenharmony_ci} 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci/* 7348c2ecf20Sopenharmony_ci * DCP setup stage 7358c2ecf20Sopenharmony_ci */ 7368c2ecf20Sopenharmony_cistatic int usbhsh_is_request_address(struct urb *urb) 7378c2ecf20Sopenharmony_ci{ 7388c2ecf20Sopenharmony_ci struct usb_ctrlrequest *req; 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci req = (struct usb_ctrlrequest *)urb->setup_packet; 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci if ((DeviceOutRequest == req->bRequestType << 8) && 7438c2ecf20Sopenharmony_ci (USB_REQ_SET_ADDRESS == req->bRequest)) 7448c2ecf20Sopenharmony_ci return 1; 7458c2ecf20Sopenharmony_ci else 7468c2ecf20Sopenharmony_ci return 0; 7478c2ecf20Sopenharmony_ci} 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_cistatic void usbhsh_setup_stage_packet_push(struct usbhsh_hpriv *hpriv, 7508c2ecf20Sopenharmony_ci struct urb *urb, 7518c2ecf20Sopenharmony_ci struct usbhs_pipe *pipe) 7528c2ecf20Sopenharmony_ci{ 7538c2ecf20Sopenharmony_ci struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); 7548c2ecf20Sopenharmony_ci struct usb_ctrlrequest req; 7558c2ecf20Sopenharmony_ci struct device *dev = usbhs_priv_to_dev(priv); 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci /* 7588c2ecf20Sopenharmony_ci * wait setup packet ACK 7598c2ecf20Sopenharmony_ci * see 7608c2ecf20Sopenharmony_ci * usbhsh_irq_setup_ack() 7618c2ecf20Sopenharmony_ci * usbhsh_irq_setup_err() 7628c2ecf20Sopenharmony_ci */ 7638c2ecf20Sopenharmony_ci init_completion(&hpriv->setup_ack_done); 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci /* copy original request */ 7668c2ecf20Sopenharmony_ci memcpy(&req, urb->setup_packet, sizeof(struct usb_ctrlrequest)); 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci /* 7698c2ecf20Sopenharmony_ci * renesas_usbhs can not use original usb address. 7708c2ecf20Sopenharmony_ci * see HARDWARE LIMITATION. 7718c2ecf20Sopenharmony_ci * modify usb address here to use attached device. 7728c2ecf20Sopenharmony_ci * see usbhsh_device_attach() 7738c2ecf20Sopenharmony_ci */ 7748c2ecf20Sopenharmony_ci if (usbhsh_is_request_address(urb)) { 7758c2ecf20Sopenharmony_ci struct usb_device *usbv = usbhsh_urb_to_usbv(urb); 7768c2ecf20Sopenharmony_ci struct usbhsh_device *udev = usbhsh_usbv_to_udev(usbv); 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci /* udev is a attached device */ 7798c2ecf20Sopenharmony_ci req.wValue = usbhsh_device_number(hpriv, udev); 7808c2ecf20Sopenharmony_ci dev_dbg(dev, "create new address - %d\n", req.wValue); 7818c2ecf20Sopenharmony_ci } 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci /* set request */ 7848c2ecf20Sopenharmony_ci usbhs_usbreq_set_val(priv, &req); 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci /* 7878c2ecf20Sopenharmony_ci * wait setup packet ACK 7888c2ecf20Sopenharmony_ci */ 7898c2ecf20Sopenharmony_ci wait_for_completion(&hpriv->setup_ack_done); 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci dev_dbg(dev, "%s done\n", __func__); 7928c2ecf20Sopenharmony_ci} 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci/* 7958c2ecf20Sopenharmony_ci * DCP data stage 7968c2ecf20Sopenharmony_ci */ 7978c2ecf20Sopenharmony_cistatic void usbhsh_data_stage_packet_done(struct usbhs_priv *priv, 7988c2ecf20Sopenharmony_ci struct usbhs_pkt *pkt) 7998c2ecf20Sopenharmony_ci{ 8008c2ecf20Sopenharmony_ci struct usbhsh_request *ureq = usbhsh_pkt_to_ureq(pkt); 8018c2ecf20Sopenharmony_ci struct usbhsh_hpriv *hpriv = usbhsh_priv_to_hpriv(priv); 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci /* this ureq was connected to urb when usbhsh_urb_enqueue() */ 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci usbhsh_ureq_free(hpriv, ureq); 8068c2ecf20Sopenharmony_ci} 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_cistatic int usbhsh_data_stage_packet_push(struct usbhsh_hpriv *hpriv, 8098c2ecf20Sopenharmony_ci struct urb *urb, 8108c2ecf20Sopenharmony_ci struct usbhs_pipe *pipe, 8118c2ecf20Sopenharmony_ci gfp_t mem_flags) 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ci{ 8148c2ecf20Sopenharmony_ci struct usbhsh_request *ureq; 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci /* this ureq will be freed on usbhsh_data_stage_packet_done() */ 8178c2ecf20Sopenharmony_ci ureq = usbhsh_ureq_alloc(hpriv, urb, mem_flags); 8188c2ecf20Sopenharmony_ci if (unlikely(!ureq)) 8198c2ecf20Sopenharmony_ci return -ENOMEM; 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci if (usb_pipein(urb->pipe)) 8228c2ecf20Sopenharmony_ci pipe->handler = &usbhs_dcp_data_stage_in_handler; 8238c2ecf20Sopenharmony_ci else 8248c2ecf20Sopenharmony_ci pipe->handler = &usbhs_dcp_data_stage_out_handler; 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci usbhs_pkt_push(pipe, &ureq->pkt, 8278c2ecf20Sopenharmony_ci usbhsh_data_stage_packet_done, 8288c2ecf20Sopenharmony_ci urb->transfer_buffer, 8298c2ecf20Sopenharmony_ci urb->transfer_buffer_length, 8308c2ecf20Sopenharmony_ci (urb->transfer_flags & URB_ZERO_PACKET), 8318c2ecf20Sopenharmony_ci -1); 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci return 0; 8348c2ecf20Sopenharmony_ci} 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci/* 8378c2ecf20Sopenharmony_ci * DCP status stage 8388c2ecf20Sopenharmony_ci */ 8398c2ecf20Sopenharmony_cistatic int usbhsh_status_stage_packet_push(struct usbhsh_hpriv *hpriv, 8408c2ecf20Sopenharmony_ci struct urb *urb, 8418c2ecf20Sopenharmony_ci struct usbhs_pipe *pipe, 8428c2ecf20Sopenharmony_ci gfp_t mem_flags) 8438c2ecf20Sopenharmony_ci{ 8448c2ecf20Sopenharmony_ci struct usbhsh_request *ureq; 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci /* This ureq will be freed on usbhsh_queue_done() */ 8478c2ecf20Sopenharmony_ci ureq = usbhsh_ureq_alloc(hpriv, urb, mem_flags); 8488c2ecf20Sopenharmony_ci if (unlikely(!ureq)) 8498c2ecf20Sopenharmony_ci return -ENOMEM; 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci if (usb_pipein(urb->pipe)) 8528c2ecf20Sopenharmony_ci pipe->handler = &usbhs_dcp_status_stage_in_handler; 8538c2ecf20Sopenharmony_ci else 8548c2ecf20Sopenharmony_ci pipe->handler = &usbhs_dcp_status_stage_out_handler; 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci usbhs_pkt_push(pipe, &ureq->pkt, 8578c2ecf20Sopenharmony_ci usbhsh_queue_done, 8588c2ecf20Sopenharmony_ci NULL, 8598c2ecf20Sopenharmony_ci urb->transfer_buffer_length, 8608c2ecf20Sopenharmony_ci 0, -1); 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci return 0; 8638c2ecf20Sopenharmony_ci} 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_cistatic int usbhsh_dcp_queue_push(struct usb_hcd *hcd, 8668c2ecf20Sopenharmony_ci struct urb *urb, 8678c2ecf20Sopenharmony_ci gfp_t mflags) 8688c2ecf20Sopenharmony_ci{ 8698c2ecf20Sopenharmony_ci struct usbhsh_hpriv *hpriv = usbhsh_hcd_to_hpriv(hcd); 8708c2ecf20Sopenharmony_ci struct usbhsh_ep *uep = usbhsh_ep_to_uep(urb->ep); 8718c2ecf20Sopenharmony_ci struct usbhs_pipe *pipe = usbhsh_uep_to_pipe(uep); 8728c2ecf20Sopenharmony_ci struct device *dev = usbhsh_hcd_to_dev(hcd); 8738c2ecf20Sopenharmony_ci int ret; 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci dev_dbg(dev, "%s\n", __func__); 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci /* 8788c2ecf20Sopenharmony_ci * setup stage 8798c2ecf20Sopenharmony_ci * 8808c2ecf20Sopenharmony_ci * usbhsh_send_setup_stage_packet() wait SACK/SIGN 8818c2ecf20Sopenharmony_ci */ 8828c2ecf20Sopenharmony_ci usbhsh_setup_stage_packet_push(hpriv, urb, pipe); 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci /* 8858c2ecf20Sopenharmony_ci * data stage 8868c2ecf20Sopenharmony_ci * 8878c2ecf20Sopenharmony_ci * It is pushed only when urb has buffer. 8888c2ecf20Sopenharmony_ci */ 8898c2ecf20Sopenharmony_ci if (urb->transfer_buffer_length) { 8908c2ecf20Sopenharmony_ci ret = usbhsh_data_stage_packet_push(hpriv, urb, pipe, mflags); 8918c2ecf20Sopenharmony_ci if (ret < 0) { 8928c2ecf20Sopenharmony_ci dev_err(dev, "data stage failed\n"); 8938c2ecf20Sopenharmony_ci return ret; 8948c2ecf20Sopenharmony_ci } 8958c2ecf20Sopenharmony_ci } 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci /* 8988c2ecf20Sopenharmony_ci * status stage 8998c2ecf20Sopenharmony_ci */ 9008c2ecf20Sopenharmony_ci ret = usbhsh_status_stage_packet_push(hpriv, urb, pipe, mflags); 9018c2ecf20Sopenharmony_ci if (ret < 0) { 9028c2ecf20Sopenharmony_ci dev_err(dev, "status stage failed\n"); 9038c2ecf20Sopenharmony_ci return ret; 9048c2ecf20Sopenharmony_ci } 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci /* 9078c2ecf20Sopenharmony_ci * start pushed packets 9088c2ecf20Sopenharmony_ci */ 9098c2ecf20Sopenharmony_ci usbhs_pkt_start(pipe); 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci return 0; 9128c2ecf20Sopenharmony_ci} 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci/* 9158c2ecf20Sopenharmony_ci * dma map functions 9168c2ecf20Sopenharmony_ci */ 9178c2ecf20Sopenharmony_cistatic int usbhsh_dma_map_ctrl(struct device *dma_dev, struct usbhs_pkt *pkt, 9188c2ecf20Sopenharmony_ci int map) 9198c2ecf20Sopenharmony_ci{ 9208c2ecf20Sopenharmony_ci if (map) { 9218c2ecf20Sopenharmony_ci struct usbhsh_request *ureq = usbhsh_pkt_to_ureq(pkt); 9228c2ecf20Sopenharmony_ci struct urb *urb = ureq->urb; 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci /* it can not use scatter/gather */ 9258c2ecf20Sopenharmony_ci if (urb->num_sgs) 9268c2ecf20Sopenharmony_ci return -EINVAL; 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci pkt->dma = urb->transfer_dma; 9298c2ecf20Sopenharmony_ci if (!pkt->dma) 9308c2ecf20Sopenharmony_ci return -EINVAL; 9318c2ecf20Sopenharmony_ci } 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci return 0; 9348c2ecf20Sopenharmony_ci} 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci/* 9378c2ecf20Sopenharmony_ci * for hc_driver 9388c2ecf20Sopenharmony_ci */ 9398c2ecf20Sopenharmony_cistatic int usbhsh_host_start(struct usb_hcd *hcd) 9408c2ecf20Sopenharmony_ci{ 9418c2ecf20Sopenharmony_ci return 0; 9428c2ecf20Sopenharmony_ci} 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_cistatic void usbhsh_host_stop(struct usb_hcd *hcd) 9458c2ecf20Sopenharmony_ci{ 9468c2ecf20Sopenharmony_ci} 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_cistatic int usbhsh_urb_enqueue(struct usb_hcd *hcd, 9498c2ecf20Sopenharmony_ci struct urb *urb, 9508c2ecf20Sopenharmony_ci gfp_t mem_flags) 9518c2ecf20Sopenharmony_ci{ 9528c2ecf20Sopenharmony_ci struct usbhsh_hpriv *hpriv = usbhsh_hcd_to_hpriv(hcd); 9538c2ecf20Sopenharmony_ci struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); 9548c2ecf20Sopenharmony_ci struct device *dev = usbhs_priv_to_dev(priv); 9558c2ecf20Sopenharmony_ci struct usb_host_endpoint *ep = urb->ep; 9568c2ecf20Sopenharmony_ci struct usbhsh_device *new_udev = NULL; 9578c2ecf20Sopenharmony_ci int is_dir_in = usb_pipein(urb->pipe); 9588c2ecf20Sopenharmony_ci int ret; 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci dev_dbg(dev, "%s (%s)\n", __func__, is_dir_in ? "in" : "out"); 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci if (!usbhsh_is_running(hpriv)) { 9638c2ecf20Sopenharmony_ci ret = -EIO; 9648c2ecf20Sopenharmony_ci dev_err(dev, "host is not running\n"); 9658c2ecf20Sopenharmony_ci goto usbhsh_urb_enqueue_error_not_linked; 9668c2ecf20Sopenharmony_ci } 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci ret = usb_hcd_link_urb_to_ep(hcd, urb); 9698c2ecf20Sopenharmony_ci if (ret) { 9708c2ecf20Sopenharmony_ci dev_err(dev, "urb link failed\n"); 9718c2ecf20Sopenharmony_ci goto usbhsh_urb_enqueue_error_not_linked; 9728c2ecf20Sopenharmony_ci } 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci /* 9758c2ecf20Sopenharmony_ci * attach udev if needed 9768c2ecf20Sopenharmony_ci * see [image of mod_host] 9778c2ecf20Sopenharmony_ci */ 9788c2ecf20Sopenharmony_ci if (!usbhsh_device_get(hpriv, urb)) { 9798c2ecf20Sopenharmony_ci new_udev = usbhsh_device_attach(hpriv, urb); 9808c2ecf20Sopenharmony_ci if (!new_udev) { 9818c2ecf20Sopenharmony_ci ret = -EIO; 9828c2ecf20Sopenharmony_ci dev_err(dev, "device attach failed\n"); 9838c2ecf20Sopenharmony_ci goto usbhsh_urb_enqueue_error_not_linked; 9848c2ecf20Sopenharmony_ci } 9858c2ecf20Sopenharmony_ci } 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_ci /* 9888c2ecf20Sopenharmony_ci * attach endpoint if needed 9898c2ecf20Sopenharmony_ci * see [image of mod_host] 9908c2ecf20Sopenharmony_ci */ 9918c2ecf20Sopenharmony_ci if (!usbhsh_ep_to_uep(ep)) { 9928c2ecf20Sopenharmony_ci ret = usbhsh_endpoint_attach(hpriv, urb, mem_flags); 9938c2ecf20Sopenharmony_ci if (ret < 0) { 9948c2ecf20Sopenharmony_ci dev_err(dev, "endpoint attach failed\n"); 9958c2ecf20Sopenharmony_ci goto usbhsh_urb_enqueue_error_free_device; 9968c2ecf20Sopenharmony_ci } 9978c2ecf20Sopenharmony_ci } 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci /* 10008c2ecf20Sopenharmony_ci * attach pipe to endpoint 10018c2ecf20Sopenharmony_ci * see [image of mod_host] 10028c2ecf20Sopenharmony_ci */ 10038c2ecf20Sopenharmony_ci ret = usbhsh_pipe_attach(hpriv, urb); 10048c2ecf20Sopenharmony_ci if (ret < 0) { 10058c2ecf20Sopenharmony_ci dev_err(dev, "pipe attach failed\n"); 10068c2ecf20Sopenharmony_ci goto usbhsh_urb_enqueue_error_free_endpoint; 10078c2ecf20Sopenharmony_ci } 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci /* 10108c2ecf20Sopenharmony_ci * push packet 10118c2ecf20Sopenharmony_ci */ 10128c2ecf20Sopenharmony_ci if (usb_pipecontrol(urb->pipe)) 10138c2ecf20Sopenharmony_ci ret = usbhsh_dcp_queue_push(hcd, urb, mem_flags); 10148c2ecf20Sopenharmony_ci else 10158c2ecf20Sopenharmony_ci ret = usbhsh_queue_push(hcd, urb, mem_flags); 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci return ret; 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_ciusbhsh_urb_enqueue_error_free_endpoint: 10208c2ecf20Sopenharmony_ci usbhsh_endpoint_detach(hpriv, ep); 10218c2ecf20Sopenharmony_ciusbhsh_urb_enqueue_error_free_device: 10228c2ecf20Sopenharmony_ci if (new_udev) 10238c2ecf20Sopenharmony_ci usbhsh_device_detach(hpriv, new_udev); 10248c2ecf20Sopenharmony_ciusbhsh_urb_enqueue_error_not_linked: 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci dev_dbg(dev, "%s error\n", __func__); 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci return ret; 10298c2ecf20Sopenharmony_ci} 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_cistatic int usbhsh_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) 10328c2ecf20Sopenharmony_ci{ 10338c2ecf20Sopenharmony_ci struct usbhsh_hpriv *hpriv = usbhsh_hcd_to_hpriv(hcd); 10348c2ecf20Sopenharmony_ci struct usbhsh_request *ureq = usbhsh_urb_to_ureq(urb); 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_ci if (ureq) { 10378c2ecf20Sopenharmony_ci struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); 10388c2ecf20Sopenharmony_ci struct usbhs_pkt *pkt = &ureq->pkt; 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_ci usbhs_pkt_pop(pkt->pipe, pkt); 10418c2ecf20Sopenharmony_ci usbhsh_queue_done(priv, pkt); 10428c2ecf20Sopenharmony_ci } 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_ci return 0; 10458c2ecf20Sopenharmony_ci} 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_cistatic void usbhsh_endpoint_disable(struct usb_hcd *hcd, 10488c2ecf20Sopenharmony_ci struct usb_host_endpoint *ep) 10498c2ecf20Sopenharmony_ci{ 10508c2ecf20Sopenharmony_ci struct usbhsh_ep *uep = usbhsh_ep_to_uep(ep); 10518c2ecf20Sopenharmony_ci struct usbhsh_device *udev; 10528c2ecf20Sopenharmony_ci struct usbhsh_hpriv *hpriv; 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_ci /* 10558c2ecf20Sopenharmony_ci * this function might be called manytimes by same hcd/ep 10568c2ecf20Sopenharmony_ci * in-endpoint == out-endpoint if ep == dcp. 10578c2ecf20Sopenharmony_ci */ 10588c2ecf20Sopenharmony_ci if (!uep) 10598c2ecf20Sopenharmony_ci return; 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ci udev = usbhsh_uep_to_udev(uep); 10628c2ecf20Sopenharmony_ci hpriv = usbhsh_hcd_to_hpriv(hcd); 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci usbhsh_endpoint_detach(hpriv, ep); 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci /* 10678c2ecf20Sopenharmony_ci * if there is no endpoint, 10688c2ecf20Sopenharmony_ci * free device 10698c2ecf20Sopenharmony_ci */ 10708c2ecf20Sopenharmony_ci if (!usbhsh_device_has_endpoint(udev)) 10718c2ecf20Sopenharmony_ci usbhsh_device_detach(hpriv, udev); 10728c2ecf20Sopenharmony_ci} 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_cistatic int usbhsh_hub_status_data(struct usb_hcd *hcd, char *buf) 10758c2ecf20Sopenharmony_ci{ 10768c2ecf20Sopenharmony_ci struct usbhsh_hpriv *hpriv = usbhsh_hcd_to_hpriv(hcd); 10778c2ecf20Sopenharmony_ci int roothub_id = 1; /* only 1 root hub */ 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci /* 10808c2ecf20Sopenharmony_ci * does port stat was changed ? 10818c2ecf20Sopenharmony_ci * check USB_PORT_STAT_C_xxx << 16 10828c2ecf20Sopenharmony_ci */ 10838c2ecf20Sopenharmony_ci if (usbhsh_port_stat_get(hpriv) & 0xFFFF0000) 10848c2ecf20Sopenharmony_ci *buf = (1 << roothub_id); 10858c2ecf20Sopenharmony_ci else 10868c2ecf20Sopenharmony_ci *buf = 0; 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_ci return !!(*buf); 10898c2ecf20Sopenharmony_ci} 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_cistatic int __usbhsh_hub_hub_feature(struct usbhsh_hpriv *hpriv, 10928c2ecf20Sopenharmony_ci u16 typeReq, u16 wValue, 10938c2ecf20Sopenharmony_ci u16 wIndex, char *buf, u16 wLength) 10948c2ecf20Sopenharmony_ci{ 10958c2ecf20Sopenharmony_ci struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); 10968c2ecf20Sopenharmony_ci struct device *dev = usbhs_priv_to_dev(priv); 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci switch (wValue) { 10998c2ecf20Sopenharmony_ci case C_HUB_OVER_CURRENT: 11008c2ecf20Sopenharmony_ci case C_HUB_LOCAL_POWER: 11018c2ecf20Sopenharmony_ci dev_dbg(dev, "%s :: C_HUB_xx\n", __func__); 11028c2ecf20Sopenharmony_ci return 0; 11038c2ecf20Sopenharmony_ci } 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci return -EPIPE; 11068c2ecf20Sopenharmony_ci} 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_cistatic int __usbhsh_hub_port_feature(struct usbhsh_hpriv *hpriv, 11098c2ecf20Sopenharmony_ci u16 typeReq, u16 wValue, 11108c2ecf20Sopenharmony_ci u16 wIndex, char *buf, u16 wLength) 11118c2ecf20Sopenharmony_ci{ 11128c2ecf20Sopenharmony_ci struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); 11138c2ecf20Sopenharmony_ci struct device *dev = usbhs_priv_to_dev(priv); 11148c2ecf20Sopenharmony_ci int enable = (typeReq == SetPortFeature); 11158c2ecf20Sopenharmony_ci int speed, i, timeout = 128; 11168c2ecf20Sopenharmony_ci int roothub_id = 1; /* only 1 root hub */ 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ci /* common error */ 11198c2ecf20Sopenharmony_ci if (wIndex > roothub_id || wLength != 0) 11208c2ecf20Sopenharmony_ci return -EPIPE; 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_ci /* check wValue */ 11238c2ecf20Sopenharmony_ci switch (wValue) { 11248c2ecf20Sopenharmony_ci case USB_PORT_FEAT_POWER: 11258c2ecf20Sopenharmony_ci usbhs_vbus_ctrl(priv, enable); 11268c2ecf20Sopenharmony_ci dev_dbg(dev, "%s :: USB_PORT_FEAT_POWER\n", __func__); 11278c2ecf20Sopenharmony_ci break; 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci case USB_PORT_FEAT_ENABLE: 11308c2ecf20Sopenharmony_ci case USB_PORT_FEAT_SUSPEND: 11318c2ecf20Sopenharmony_ci case USB_PORT_FEAT_C_ENABLE: 11328c2ecf20Sopenharmony_ci case USB_PORT_FEAT_C_SUSPEND: 11338c2ecf20Sopenharmony_ci case USB_PORT_FEAT_C_CONNECTION: 11348c2ecf20Sopenharmony_ci case USB_PORT_FEAT_C_OVER_CURRENT: 11358c2ecf20Sopenharmony_ci case USB_PORT_FEAT_C_RESET: 11368c2ecf20Sopenharmony_ci dev_dbg(dev, "%s :: USB_PORT_FEAT_xxx\n", __func__); 11378c2ecf20Sopenharmony_ci break; 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci case USB_PORT_FEAT_RESET: 11408c2ecf20Sopenharmony_ci if (!enable) 11418c2ecf20Sopenharmony_ci break; 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci usbhsh_port_stat_clear(hpriv, 11448c2ecf20Sopenharmony_ci USB_PORT_STAT_HIGH_SPEED | 11458c2ecf20Sopenharmony_ci USB_PORT_STAT_LOW_SPEED); 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci usbhsh_queue_force_pop_all(priv); 11488c2ecf20Sopenharmony_ci 11498c2ecf20Sopenharmony_ci usbhs_bus_send_reset(priv); 11508c2ecf20Sopenharmony_ci msleep(20); 11518c2ecf20Sopenharmony_ci usbhs_bus_send_sof_enable(priv); 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_ci for (i = 0; i < timeout ; i++) { 11548c2ecf20Sopenharmony_ci switch (usbhs_bus_get_speed(priv)) { 11558c2ecf20Sopenharmony_ci case USB_SPEED_LOW: 11568c2ecf20Sopenharmony_ci speed = USB_PORT_STAT_LOW_SPEED; 11578c2ecf20Sopenharmony_ci goto got_usb_bus_speed; 11588c2ecf20Sopenharmony_ci case USB_SPEED_HIGH: 11598c2ecf20Sopenharmony_ci speed = USB_PORT_STAT_HIGH_SPEED; 11608c2ecf20Sopenharmony_ci goto got_usb_bus_speed; 11618c2ecf20Sopenharmony_ci case USB_SPEED_FULL: 11628c2ecf20Sopenharmony_ci speed = 0; 11638c2ecf20Sopenharmony_ci goto got_usb_bus_speed; 11648c2ecf20Sopenharmony_ci } 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_ci msleep(20); 11678c2ecf20Sopenharmony_ci } 11688c2ecf20Sopenharmony_ci return -EPIPE; 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_cigot_usb_bus_speed: 11718c2ecf20Sopenharmony_ci usbhsh_port_stat_set(hpriv, speed); 11728c2ecf20Sopenharmony_ci usbhsh_port_stat_set(hpriv, USB_PORT_STAT_ENABLE); 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_ci dev_dbg(dev, "%s :: USB_PORT_FEAT_RESET (speed = %d)\n", 11758c2ecf20Sopenharmony_ci __func__, speed); 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_ci /* status change is not needed */ 11788c2ecf20Sopenharmony_ci return 0; 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_ci default: 11818c2ecf20Sopenharmony_ci return -EPIPE; 11828c2ecf20Sopenharmony_ci } 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_ci /* set/clear status */ 11858c2ecf20Sopenharmony_ci if (enable) 11868c2ecf20Sopenharmony_ci usbhsh_port_stat_set(hpriv, (1 << wValue)); 11878c2ecf20Sopenharmony_ci else 11888c2ecf20Sopenharmony_ci usbhsh_port_stat_clear(hpriv, (1 << wValue)); 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_ci return 0; 11918c2ecf20Sopenharmony_ci} 11928c2ecf20Sopenharmony_ci 11938c2ecf20Sopenharmony_cistatic int __usbhsh_hub_get_status(struct usbhsh_hpriv *hpriv, 11948c2ecf20Sopenharmony_ci u16 typeReq, u16 wValue, 11958c2ecf20Sopenharmony_ci u16 wIndex, char *buf, u16 wLength) 11968c2ecf20Sopenharmony_ci{ 11978c2ecf20Sopenharmony_ci struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); 11988c2ecf20Sopenharmony_ci struct usb_hub_descriptor *desc = (struct usb_hub_descriptor *)buf; 11998c2ecf20Sopenharmony_ci struct device *dev = usbhs_priv_to_dev(priv); 12008c2ecf20Sopenharmony_ci int roothub_id = 1; /* only 1 root hub */ 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_ci switch (typeReq) { 12038c2ecf20Sopenharmony_ci case GetHubStatus: 12048c2ecf20Sopenharmony_ci dev_dbg(dev, "%s :: GetHubStatus\n", __func__); 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci *buf = 0x00; 12078c2ecf20Sopenharmony_ci break; 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_ci case GetPortStatus: 12108c2ecf20Sopenharmony_ci if (wIndex != roothub_id) 12118c2ecf20Sopenharmony_ci return -EPIPE; 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_ci dev_dbg(dev, "%s :: GetPortStatus\n", __func__); 12148c2ecf20Sopenharmony_ci *(__le32 *)buf = cpu_to_le32(usbhsh_port_stat_get(hpriv)); 12158c2ecf20Sopenharmony_ci break; 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_ci case GetHubDescriptor: 12188c2ecf20Sopenharmony_ci desc->bDescriptorType = USB_DT_HUB; 12198c2ecf20Sopenharmony_ci desc->bHubContrCurrent = 0; 12208c2ecf20Sopenharmony_ci desc->bNbrPorts = roothub_id; 12218c2ecf20Sopenharmony_ci desc->bDescLength = 9; 12228c2ecf20Sopenharmony_ci desc->bPwrOn2PwrGood = 0; 12238c2ecf20Sopenharmony_ci desc->wHubCharacteristics = 12248c2ecf20Sopenharmony_ci cpu_to_le16(HUB_CHAR_INDV_PORT_LPSM | HUB_CHAR_NO_OCPM); 12258c2ecf20Sopenharmony_ci desc->u.hs.DeviceRemovable[0] = (roothub_id << 1); 12268c2ecf20Sopenharmony_ci desc->u.hs.DeviceRemovable[1] = ~0; 12278c2ecf20Sopenharmony_ci dev_dbg(dev, "%s :: GetHubDescriptor\n", __func__); 12288c2ecf20Sopenharmony_ci break; 12298c2ecf20Sopenharmony_ci } 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ci return 0; 12328c2ecf20Sopenharmony_ci} 12338c2ecf20Sopenharmony_ci 12348c2ecf20Sopenharmony_cistatic int usbhsh_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, 12358c2ecf20Sopenharmony_ci u16 wIndex, char *buf, u16 wLength) 12368c2ecf20Sopenharmony_ci{ 12378c2ecf20Sopenharmony_ci struct usbhsh_hpriv *hpriv = usbhsh_hcd_to_hpriv(hcd); 12388c2ecf20Sopenharmony_ci struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); 12398c2ecf20Sopenharmony_ci struct device *dev = usbhs_priv_to_dev(priv); 12408c2ecf20Sopenharmony_ci int ret = -EPIPE; 12418c2ecf20Sopenharmony_ci 12428c2ecf20Sopenharmony_ci switch (typeReq) { 12438c2ecf20Sopenharmony_ci 12448c2ecf20Sopenharmony_ci /* Hub Feature */ 12458c2ecf20Sopenharmony_ci case ClearHubFeature: 12468c2ecf20Sopenharmony_ci case SetHubFeature: 12478c2ecf20Sopenharmony_ci ret = __usbhsh_hub_hub_feature(hpriv, typeReq, 12488c2ecf20Sopenharmony_ci wValue, wIndex, buf, wLength); 12498c2ecf20Sopenharmony_ci break; 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_ci /* Port Feature */ 12528c2ecf20Sopenharmony_ci case SetPortFeature: 12538c2ecf20Sopenharmony_ci case ClearPortFeature: 12548c2ecf20Sopenharmony_ci ret = __usbhsh_hub_port_feature(hpriv, typeReq, 12558c2ecf20Sopenharmony_ci wValue, wIndex, buf, wLength); 12568c2ecf20Sopenharmony_ci break; 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_ci /* Get status */ 12598c2ecf20Sopenharmony_ci case GetHubStatus: 12608c2ecf20Sopenharmony_ci case GetPortStatus: 12618c2ecf20Sopenharmony_ci case GetHubDescriptor: 12628c2ecf20Sopenharmony_ci ret = __usbhsh_hub_get_status(hpriv, typeReq, 12638c2ecf20Sopenharmony_ci wValue, wIndex, buf, wLength); 12648c2ecf20Sopenharmony_ci break; 12658c2ecf20Sopenharmony_ci } 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci dev_dbg(dev, "typeReq = %x, ret = %d, port_stat = %x\n", 12688c2ecf20Sopenharmony_ci typeReq, ret, usbhsh_port_stat_get(hpriv)); 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_ci return ret; 12718c2ecf20Sopenharmony_ci} 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_cistatic int usbhsh_bus_nop(struct usb_hcd *hcd) 12748c2ecf20Sopenharmony_ci{ 12758c2ecf20Sopenharmony_ci /* nothing to do */ 12768c2ecf20Sopenharmony_ci return 0; 12778c2ecf20Sopenharmony_ci} 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_cistatic const struct hc_driver usbhsh_driver = { 12808c2ecf20Sopenharmony_ci .description = usbhsh_hcd_name, 12818c2ecf20Sopenharmony_ci .hcd_priv_size = sizeof(struct usbhsh_hpriv), 12828c2ecf20Sopenharmony_ci 12838c2ecf20Sopenharmony_ci /* 12848c2ecf20Sopenharmony_ci * generic hardware linkage 12858c2ecf20Sopenharmony_ci */ 12868c2ecf20Sopenharmony_ci .flags = HCD_DMA | HCD_USB2, 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_ci .start = usbhsh_host_start, 12898c2ecf20Sopenharmony_ci .stop = usbhsh_host_stop, 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_ci /* 12928c2ecf20Sopenharmony_ci * managing i/o requests and associated device resources 12938c2ecf20Sopenharmony_ci */ 12948c2ecf20Sopenharmony_ci .urb_enqueue = usbhsh_urb_enqueue, 12958c2ecf20Sopenharmony_ci .urb_dequeue = usbhsh_urb_dequeue, 12968c2ecf20Sopenharmony_ci .endpoint_disable = usbhsh_endpoint_disable, 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_ci /* 12998c2ecf20Sopenharmony_ci * root hub 13008c2ecf20Sopenharmony_ci */ 13018c2ecf20Sopenharmony_ci .hub_status_data = usbhsh_hub_status_data, 13028c2ecf20Sopenharmony_ci .hub_control = usbhsh_hub_control, 13038c2ecf20Sopenharmony_ci .bus_suspend = usbhsh_bus_nop, 13048c2ecf20Sopenharmony_ci .bus_resume = usbhsh_bus_nop, 13058c2ecf20Sopenharmony_ci}; 13068c2ecf20Sopenharmony_ci 13078c2ecf20Sopenharmony_ci/* 13088c2ecf20Sopenharmony_ci * interrupt functions 13098c2ecf20Sopenharmony_ci */ 13108c2ecf20Sopenharmony_cistatic int usbhsh_irq_attch(struct usbhs_priv *priv, 13118c2ecf20Sopenharmony_ci struct usbhs_irq_state *irq_state) 13128c2ecf20Sopenharmony_ci{ 13138c2ecf20Sopenharmony_ci struct usbhsh_hpriv *hpriv = usbhsh_priv_to_hpriv(priv); 13148c2ecf20Sopenharmony_ci struct device *dev = usbhs_priv_to_dev(priv); 13158c2ecf20Sopenharmony_ci 13168c2ecf20Sopenharmony_ci dev_dbg(dev, "device attached\n"); 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_ci usbhsh_port_stat_set(hpriv, USB_PORT_STAT_CONNECTION); 13198c2ecf20Sopenharmony_ci usbhsh_port_stat_set(hpriv, USB_PORT_STAT_C_CONNECTION << 16); 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_ci /* 13228c2ecf20Sopenharmony_ci * attch interrupt might happen infinitely on some device 13238c2ecf20Sopenharmony_ci * (on self power USB hub ?) 13248c2ecf20Sopenharmony_ci * disable it here. 13258c2ecf20Sopenharmony_ci * 13268c2ecf20Sopenharmony_ci * usbhsh_is_running() becomes effective 13278c2ecf20Sopenharmony_ci * according to this process. 13288c2ecf20Sopenharmony_ci * see 13298c2ecf20Sopenharmony_ci * usbhsh_is_running() 13308c2ecf20Sopenharmony_ci * usbhsh_urb_enqueue() 13318c2ecf20Sopenharmony_ci */ 13328c2ecf20Sopenharmony_ci hpriv->mod.irq_attch = NULL; 13338c2ecf20Sopenharmony_ci usbhs_irq_callback_update(priv, &hpriv->mod); 13348c2ecf20Sopenharmony_ci 13358c2ecf20Sopenharmony_ci return 0; 13368c2ecf20Sopenharmony_ci} 13378c2ecf20Sopenharmony_ci 13388c2ecf20Sopenharmony_cistatic int usbhsh_irq_dtch(struct usbhs_priv *priv, 13398c2ecf20Sopenharmony_ci struct usbhs_irq_state *irq_state) 13408c2ecf20Sopenharmony_ci{ 13418c2ecf20Sopenharmony_ci struct usbhsh_hpriv *hpriv = usbhsh_priv_to_hpriv(priv); 13428c2ecf20Sopenharmony_ci struct device *dev = usbhs_priv_to_dev(priv); 13438c2ecf20Sopenharmony_ci 13448c2ecf20Sopenharmony_ci dev_dbg(dev, "device detached\n"); 13458c2ecf20Sopenharmony_ci 13468c2ecf20Sopenharmony_ci usbhsh_port_stat_clear(hpriv, USB_PORT_STAT_CONNECTION); 13478c2ecf20Sopenharmony_ci usbhsh_port_stat_set(hpriv, USB_PORT_STAT_C_CONNECTION << 16); 13488c2ecf20Sopenharmony_ci 13498c2ecf20Sopenharmony_ci /* 13508c2ecf20Sopenharmony_ci * enable attch interrupt again 13518c2ecf20Sopenharmony_ci * 13528c2ecf20Sopenharmony_ci * usbhsh_is_running() becomes invalid 13538c2ecf20Sopenharmony_ci * according to this process. 13548c2ecf20Sopenharmony_ci * see 13558c2ecf20Sopenharmony_ci * usbhsh_is_running() 13568c2ecf20Sopenharmony_ci * usbhsh_urb_enqueue() 13578c2ecf20Sopenharmony_ci */ 13588c2ecf20Sopenharmony_ci hpriv->mod.irq_attch = usbhsh_irq_attch; 13598c2ecf20Sopenharmony_ci usbhs_irq_callback_update(priv, &hpriv->mod); 13608c2ecf20Sopenharmony_ci 13618c2ecf20Sopenharmony_ci /* 13628c2ecf20Sopenharmony_ci * usbhsh_queue_force_pop_all() should be called 13638c2ecf20Sopenharmony_ci * after usbhsh_is_running() becomes invalid. 13648c2ecf20Sopenharmony_ci */ 13658c2ecf20Sopenharmony_ci usbhsh_queue_force_pop_all(priv); 13668c2ecf20Sopenharmony_ci 13678c2ecf20Sopenharmony_ci return 0; 13688c2ecf20Sopenharmony_ci} 13698c2ecf20Sopenharmony_ci 13708c2ecf20Sopenharmony_cistatic int usbhsh_irq_setup_ack(struct usbhs_priv *priv, 13718c2ecf20Sopenharmony_ci struct usbhs_irq_state *irq_state) 13728c2ecf20Sopenharmony_ci{ 13738c2ecf20Sopenharmony_ci struct usbhsh_hpriv *hpriv = usbhsh_priv_to_hpriv(priv); 13748c2ecf20Sopenharmony_ci struct device *dev = usbhs_priv_to_dev(priv); 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_ci dev_dbg(dev, "setup packet OK\n"); 13778c2ecf20Sopenharmony_ci 13788c2ecf20Sopenharmony_ci complete(&hpriv->setup_ack_done); /* see usbhsh_urb_enqueue() */ 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_ci return 0; 13818c2ecf20Sopenharmony_ci} 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_cistatic int usbhsh_irq_setup_err(struct usbhs_priv *priv, 13848c2ecf20Sopenharmony_ci struct usbhs_irq_state *irq_state) 13858c2ecf20Sopenharmony_ci{ 13868c2ecf20Sopenharmony_ci struct usbhsh_hpriv *hpriv = usbhsh_priv_to_hpriv(priv); 13878c2ecf20Sopenharmony_ci struct device *dev = usbhs_priv_to_dev(priv); 13888c2ecf20Sopenharmony_ci 13898c2ecf20Sopenharmony_ci dev_dbg(dev, "setup packet Err\n"); 13908c2ecf20Sopenharmony_ci 13918c2ecf20Sopenharmony_ci complete(&hpriv->setup_ack_done); /* see usbhsh_urb_enqueue() */ 13928c2ecf20Sopenharmony_ci 13938c2ecf20Sopenharmony_ci return 0; 13948c2ecf20Sopenharmony_ci} 13958c2ecf20Sopenharmony_ci 13968c2ecf20Sopenharmony_ci/* 13978c2ecf20Sopenharmony_ci * module start/stop 13988c2ecf20Sopenharmony_ci */ 13998c2ecf20Sopenharmony_cistatic void usbhsh_pipe_init_for_host(struct usbhs_priv *priv) 14008c2ecf20Sopenharmony_ci{ 14018c2ecf20Sopenharmony_ci struct usbhsh_hpriv *hpriv = usbhsh_priv_to_hpriv(priv); 14028c2ecf20Sopenharmony_ci struct usbhs_pipe *pipe; 14038c2ecf20Sopenharmony_ci struct renesas_usbhs_driver_pipe_config *pipe_configs = 14048c2ecf20Sopenharmony_ci usbhs_get_dparam(priv, pipe_configs); 14058c2ecf20Sopenharmony_ci int pipe_size = usbhs_get_dparam(priv, pipe_size); 14068c2ecf20Sopenharmony_ci int old_type, dir_in, i; 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_ci /* init all pipe */ 14098c2ecf20Sopenharmony_ci old_type = USB_ENDPOINT_XFER_CONTROL; 14108c2ecf20Sopenharmony_ci for (i = 0; i < pipe_size; i++) { 14118c2ecf20Sopenharmony_ci 14128c2ecf20Sopenharmony_ci /* 14138c2ecf20Sopenharmony_ci * data "output" will be finished as soon as possible, 14148c2ecf20Sopenharmony_ci * but there is no guaranty at data "input" case. 14158c2ecf20Sopenharmony_ci * 14168c2ecf20Sopenharmony_ci * "input" needs "standby" pipe. 14178c2ecf20Sopenharmony_ci * So, "input" direction pipe > "output" direction pipe 14188c2ecf20Sopenharmony_ci * is good idea. 14198c2ecf20Sopenharmony_ci * 14208c2ecf20Sopenharmony_ci * 1st USB_ENDPOINT_XFER_xxx will be output direction, 14218c2ecf20Sopenharmony_ci * and the other will be input direction here. 14228c2ecf20Sopenharmony_ci * 14238c2ecf20Sopenharmony_ci * ex) 14248c2ecf20Sopenharmony_ci * ... 14258c2ecf20Sopenharmony_ci * USB_ENDPOINT_XFER_ISOC -> dir out 14268c2ecf20Sopenharmony_ci * USB_ENDPOINT_XFER_ISOC -> dir in 14278c2ecf20Sopenharmony_ci * USB_ENDPOINT_XFER_BULK -> dir out 14288c2ecf20Sopenharmony_ci * USB_ENDPOINT_XFER_BULK -> dir in 14298c2ecf20Sopenharmony_ci * USB_ENDPOINT_XFER_BULK -> dir in 14308c2ecf20Sopenharmony_ci * ... 14318c2ecf20Sopenharmony_ci */ 14328c2ecf20Sopenharmony_ci dir_in = (pipe_configs[i].type == old_type); 14338c2ecf20Sopenharmony_ci old_type = pipe_configs[i].type; 14348c2ecf20Sopenharmony_ci 14358c2ecf20Sopenharmony_ci if (USB_ENDPOINT_XFER_CONTROL == pipe_configs[i].type) { 14368c2ecf20Sopenharmony_ci pipe = usbhs_dcp_malloc(priv); 14378c2ecf20Sopenharmony_ci usbhsh_hpriv_to_dcp(hpriv) = pipe; 14388c2ecf20Sopenharmony_ci } else { 14398c2ecf20Sopenharmony_ci pipe = usbhs_pipe_malloc(priv, 14408c2ecf20Sopenharmony_ci pipe_configs[i].type, 14418c2ecf20Sopenharmony_ci dir_in); 14428c2ecf20Sopenharmony_ci } 14438c2ecf20Sopenharmony_ci 14448c2ecf20Sopenharmony_ci pipe->mod_private = NULL; 14458c2ecf20Sopenharmony_ci } 14468c2ecf20Sopenharmony_ci} 14478c2ecf20Sopenharmony_ci 14488c2ecf20Sopenharmony_cistatic int usbhsh_start(struct usbhs_priv *priv) 14498c2ecf20Sopenharmony_ci{ 14508c2ecf20Sopenharmony_ci struct usbhsh_hpriv *hpriv = usbhsh_priv_to_hpriv(priv); 14518c2ecf20Sopenharmony_ci struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv); 14528c2ecf20Sopenharmony_ci struct usbhs_mod *mod = usbhs_mod_get_current(priv); 14538c2ecf20Sopenharmony_ci struct device *dev = usbhs_priv_to_dev(priv); 14548c2ecf20Sopenharmony_ci int ret; 14558c2ecf20Sopenharmony_ci 14568c2ecf20Sopenharmony_ci /* add hcd */ 14578c2ecf20Sopenharmony_ci ret = usb_add_hcd(hcd, 0, 0); 14588c2ecf20Sopenharmony_ci if (ret < 0) 14598c2ecf20Sopenharmony_ci return 0; 14608c2ecf20Sopenharmony_ci device_wakeup_enable(hcd->self.controller); 14618c2ecf20Sopenharmony_ci 14628c2ecf20Sopenharmony_ci /* 14638c2ecf20Sopenharmony_ci * pipe initialize and enable DCP 14648c2ecf20Sopenharmony_ci */ 14658c2ecf20Sopenharmony_ci usbhs_fifo_init(priv); 14668c2ecf20Sopenharmony_ci usbhs_pipe_init(priv, 14678c2ecf20Sopenharmony_ci usbhsh_dma_map_ctrl); 14688c2ecf20Sopenharmony_ci usbhsh_pipe_init_for_host(priv); 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_ci /* 14718c2ecf20Sopenharmony_ci * system config enble 14728c2ecf20Sopenharmony_ci * - HI speed 14738c2ecf20Sopenharmony_ci * - host 14748c2ecf20Sopenharmony_ci * - usb module 14758c2ecf20Sopenharmony_ci */ 14768c2ecf20Sopenharmony_ci usbhs_sys_host_ctrl(priv, 1); 14778c2ecf20Sopenharmony_ci 14788c2ecf20Sopenharmony_ci /* 14798c2ecf20Sopenharmony_ci * enable irq callback 14808c2ecf20Sopenharmony_ci */ 14818c2ecf20Sopenharmony_ci mod->irq_attch = usbhsh_irq_attch; 14828c2ecf20Sopenharmony_ci mod->irq_dtch = usbhsh_irq_dtch; 14838c2ecf20Sopenharmony_ci mod->irq_sack = usbhsh_irq_setup_ack; 14848c2ecf20Sopenharmony_ci mod->irq_sign = usbhsh_irq_setup_err; 14858c2ecf20Sopenharmony_ci usbhs_irq_callback_update(priv, mod); 14868c2ecf20Sopenharmony_ci 14878c2ecf20Sopenharmony_ci dev_dbg(dev, "start host\n"); 14888c2ecf20Sopenharmony_ci 14898c2ecf20Sopenharmony_ci return ret; 14908c2ecf20Sopenharmony_ci} 14918c2ecf20Sopenharmony_ci 14928c2ecf20Sopenharmony_cistatic int usbhsh_stop(struct usbhs_priv *priv) 14938c2ecf20Sopenharmony_ci{ 14948c2ecf20Sopenharmony_ci struct usbhsh_hpriv *hpriv = usbhsh_priv_to_hpriv(priv); 14958c2ecf20Sopenharmony_ci struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv); 14968c2ecf20Sopenharmony_ci struct usbhs_mod *mod = usbhs_mod_get_current(priv); 14978c2ecf20Sopenharmony_ci struct device *dev = usbhs_priv_to_dev(priv); 14988c2ecf20Sopenharmony_ci 14998c2ecf20Sopenharmony_ci /* 15008c2ecf20Sopenharmony_ci * disable irq callback 15018c2ecf20Sopenharmony_ci */ 15028c2ecf20Sopenharmony_ci mod->irq_attch = NULL; 15038c2ecf20Sopenharmony_ci mod->irq_dtch = NULL; 15048c2ecf20Sopenharmony_ci mod->irq_sack = NULL; 15058c2ecf20Sopenharmony_ci mod->irq_sign = NULL; 15068c2ecf20Sopenharmony_ci usbhs_irq_callback_update(priv, mod); 15078c2ecf20Sopenharmony_ci 15088c2ecf20Sopenharmony_ci usb_remove_hcd(hcd); 15098c2ecf20Sopenharmony_ci 15108c2ecf20Sopenharmony_ci /* disable sys */ 15118c2ecf20Sopenharmony_ci usbhs_sys_host_ctrl(priv, 0); 15128c2ecf20Sopenharmony_ci 15138c2ecf20Sopenharmony_ci dev_dbg(dev, "quit host\n"); 15148c2ecf20Sopenharmony_ci 15158c2ecf20Sopenharmony_ci return 0; 15168c2ecf20Sopenharmony_ci} 15178c2ecf20Sopenharmony_ci 15188c2ecf20Sopenharmony_ciint usbhs_mod_host_probe(struct usbhs_priv *priv) 15198c2ecf20Sopenharmony_ci{ 15208c2ecf20Sopenharmony_ci struct usbhsh_hpriv *hpriv; 15218c2ecf20Sopenharmony_ci struct usb_hcd *hcd; 15228c2ecf20Sopenharmony_ci struct usbhsh_device *udev; 15238c2ecf20Sopenharmony_ci struct device *dev = usbhs_priv_to_dev(priv); 15248c2ecf20Sopenharmony_ci int i; 15258c2ecf20Sopenharmony_ci 15268c2ecf20Sopenharmony_ci /* initialize hcd */ 15278c2ecf20Sopenharmony_ci hcd = usb_create_hcd(&usbhsh_driver, dev, usbhsh_hcd_name); 15288c2ecf20Sopenharmony_ci if (!hcd) { 15298c2ecf20Sopenharmony_ci dev_err(dev, "Failed to create hcd\n"); 15308c2ecf20Sopenharmony_ci return -ENOMEM; 15318c2ecf20Sopenharmony_ci } 15328c2ecf20Sopenharmony_ci hcd->has_tt = 1; /* for low/full speed */ 15338c2ecf20Sopenharmony_ci 15348c2ecf20Sopenharmony_ci /* 15358c2ecf20Sopenharmony_ci * CAUTION 15368c2ecf20Sopenharmony_ci * 15378c2ecf20Sopenharmony_ci * There is no guarantee that it is possible to access usb module here. 15388c2ecf20Sopenharmony_ci * Don't accesses to it. 15398c2ecf20Sopenharmony_ci * The accesse will be enable after "usbhsh_start" 15408c2ecf20Sopenharmony_ci */ 15418c2ecf20Sopenharmony_ci 15428c2ecf20Sopenharmony_ci hpriv = usbhsh_hcd_to_hpriv(hcd); 15438c2ecf20Sopenharmony_ci 15448c2ecf20Sopenharmony_ci /* 15458c2ecf20Sopenharmony_ci * register itself 15468c2ecf20Sopenharmony_ci */ 15478c2ecf20Sopenharmony_ci usbhs_mod_register(priv, &hpriv->mod, USBHS_HOST); 15488c2ecf20Sopenharmony_ci 15498c2ecf20Sopenharmony_ci /* init hpriv */ 15508c2ecf20Sopenharmony_ci hpriv->mod.name = "host"; 15518c2ecf20Sopenharmony_ci hpriv->mod.start = usbhsh_start; 15528c2ecf20Sopenharmony_ci hpriv->mod.stop = usbhsh_stop; 15538c2ecf20Sopenharmony_ci usbhsh_port_stat_init(hpriv); 15548c2ecf20Sopenharmony_ci 15558c2ecf20Sopenharmony_ci /* init all device */ 15568c2ecf20Sopenharmony_ci usbhsh_for_each_udev_with_dev0(udev, hpriv, i) { 15578c2ecf20Sopenharmony_ci udev->usbv = NULL; 15588c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&udev->ep_list_head); 15598c2ecf20Sopenharmony_ci } 15608c2ecf20Sopenharmony_ci 15618c2ecf20Sopenharmony_ci dev_info(dev, "host probed\n"); 15628c2ecf20Sopenharmony_ci 15638c2ecf20Sopenharmony_ci return 0; 15648c2ecf20Sopenharmony_ci} 15658c2ecf20Sopenharmony_ci 15668c2ecf20Sopenharmony_ciint usbhs_mod_host_remove(struct usbhs_priv *priv) 15678c2ecf20Sopenharmony_ci{ 15688c2ecf20Sopenharmony_ci struct usbhsh_hpriv *hpriv = usbhsh_priv_to_hpriv(priv); 15698c2ecf20Sopenharmony_ci struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv); 15708c2ecf20Sopenharmony_ci 15718c2ecf20Sopenharmony_ci usb_put_hcd(hcd); 15728c2ecf20Sopenharmony_ci 15738c2ecf20Sopenharmony_ci return 0; 15748c2ecf20Sopenharmony_ci} 1575