1ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/* -----------------------------------------------------------------------------
2ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Copyright (c) 2011 Ozmo Inc
3ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Released under the GNU General Public License Version 2 (GPLv2).
4ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly *
5ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * This file provides the implementation of a USB host controller device that
6ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * does not have any associated hardware. Instead the virtual device is
7ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * connected to the WiFi network and emulates the operation of a USB hcd by
8ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * receiving and sending network frames.
9ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Note:
10ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * We take great pains to reduce the amount of code where interrupts need to be
11ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * disabled and in this respect we are different from standard HCD's. In
12ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * particular we don't want in_irq() code bleeding over to the protocol side of
13ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * the driver.
14ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * The troublesome functions are the urb enqueue and dequeue functions both of
15ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * which can be called in_irq(). So for these functions we put the urbs into a
16ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * queue and request a tasklet to process them. This means that a spinlock with
17ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * interrupts disabled must be held for insertion and removal but most code is
18ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * is in tasklet or soft irq context. The lock that protects this list is called
19ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * the tasklet lock and serves the purpose of the 'HCD lock' which must be held
20ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * when calling the following functions.
21ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly *   usb_hcd_link_urb_to_ep()
22ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly *   usb_hcd_unlink_urb_from_ep()
23ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly *   usb_hcd_flush_endpoint()
24ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly *   usb_hcd_check_unlink_urb()
25ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * -----------------------------------------------------------------------------
26ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
27ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly#include <linux/platform_device.h>
28ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly#include <linux/usb.h>
29ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly#include <linux/jiffies.h>
30ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly#include <linux/slab.h>
31ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly#include <linux/export.h>
32ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly#include "linux/usb/hcd.h"
33ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly#include <asm/unaligned.h>
34ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly#include "ozconfig.h"
35ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly#include "ozusbif.h"
36ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly#include "oztrace.h"
37ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly#include "ozurbparanoia.h"
38ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly#include "ozevent.h"
39ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
40ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Number of units of buffering to capture for an isochronous IN endpoint before
41ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * allowing data to be indicated up.
42ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
43ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly#define OZ_IN_BUFFERING_UNITS	50
44ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/* Name of our platform device.
45ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
46ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly#define OZ_PLAT_DEV_NAME	"ozwpan"
47ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/* Maximum number of free urb links that can be kept in the pool.
48ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
49ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly#define OZ_MAX_LINK_POOL_SIZE	16
50ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/* Get endpoint object from the containing link.
51ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
52ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly#define ep_from_link(__e) container_of((__e), struct oz_endpoint, link)
53ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
54ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Used to link urbs together and also store some status information for each
55ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * urb.
56ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * A cache of these are kept in a pool to reduce number of calls to kmalloc.
57ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
58ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystruct oz_urb_link {
59ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct list_head link;
60ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct urb *urb;
61ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct oz_port *port;
62ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	u8 req_id;
63ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	u8 ep_num;
64ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	unsigned long submit_jiffies;
65ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly};
66ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly
67ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/* Holds state information about a USB endpoint.
68ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
69ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystruct oz_endpoint {
70ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct list_head urb_list;	/* List of oz_urb_link items. */
71ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct list_head link;		/* For isoc ep, links in to isoc
72ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly					   lists of oz_port. */
73ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	unsigned long last_jiffies;
74ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	int credit;
75ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	int credit_ceiling;
76ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	u8 ep_num;
77ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	u8 attrib;
78ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	u8 *buffer;
79ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	int buffer_size;
80ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	int in_ix;
81ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	int out_ix;
82ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	int buffered_units;
83ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	unsigned flags;
84ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	int start_frame;
85ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly};
86ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/* Bits in the flags field. */
87ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly#define OZ_F_EP_BUFFERING	0x1
88ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly#define OZ_F_EP_HAVE_STREAM	0x2
89ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly
90ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/* Holds state information about a USB interface.
91ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
92ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystruct oz_interface {
93ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	unsigned ep_mask;
94ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	u8 alt;
95ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly};
96ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly
97ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/* Holds state information about an hcd port.
98ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
99ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly#define OZ_NB_ENDPOINTS	16
100ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystruct oz_port {
101ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	unsigned flags;
102ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	unsigned status;
103ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	void *hpd;
104ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct oz_hcd *ozhcd;
105ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	spinlock_t port_lock;
106ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	u8 bus_addr;
107ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	u8 next_req_id;
108ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	u8 config_num;
109ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	int num_iface;
110ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct oz_interface *iface;
111ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct oz_endpoint *out_ep[OZ_NB_ENDPOINTS];
112ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct oz_endpoint *in_ep[OZ_NB_ENDPOINTS];
113ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct list_head isoc_out_ep;
114ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct list_head isoc_in_ep;
115ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly};
116ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly#define OZ_PORT_F_PRESENT	0x1
117ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly#define OZ_PORT_F_CHANGED	0x2
118ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly#define OZ_PORT_F_DYING		0x4
119ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly
120ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/* Data structure in the private context area of struct usb_hcd.
121ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
122ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly#define OZ_NB_PORTS	8
123ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystruct oz_hcd {
124ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	spinlock_t hcd_lock;
125ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct list_head urb_pending_list;
126ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct list_head urb_cancel_list;
127ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct list_head orphanage;
128ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	int conn_port; /* Port that is currently connecting, -1 if none.*/
129ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct oz_port ports[OZ_NB_PORTS];
130ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	uint flags;
131ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct usb_hcd *hcd;
132ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly};
133ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/* Bits in flags field.
134ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
135ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly#define OZ_HDC_F_SUSPENDED	0x1
136ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly
137ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
138ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Static function prototypes.
139ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
140ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic int oz_hcd_start(struct usb_hcd *hcd);
141ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic void oz_hcd_stop(struct usb_hcd *hcd);
142ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic void oz_hcd_shutdown(struct usb_hcd *hcd);
143ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic int oz_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
144ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				gfp_t mem_flags);
145ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic int oz_hcd_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status);
146ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic void oz_hcd_endpoint_disable(struct usb_hcd *hcd,
147ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				struct usb_host_endpoint *ep);
148ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic void oz_hcd_endpoint_reset(struct usb_hcd *hcd,
149ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				struct usb_host_endpoint *ep);
150ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic int oz_hcd_get_frame_number(struct usb_hcd *hcd);
151ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic int oz_hcd_hub_status_data(struct usb_hcd *hcd, char *buf);
152ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic int oz_hcd_hub_control(struct usb_hcd *hcd, u16 req_type, u16 wvalue,
153ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				u16 windex, char *buf, u16 wlength);
154ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic int oz_hcd_bus_suspend(struct usb_hcd *hcd);
155ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic int oz_hcd_bus_resume(struct usb_hcd *hcd);
156ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic int oz_plat_probe(struct platform_device *dev);
157ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic int oz_plat_remove(struct platform_device *dev);
158ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic void oz_plat_shutdown(struct platform_device *dev);
159ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic int oz_plat_suspend(struct platform_device *dev, pm_message_t msg);
160ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic int oz_plat_resume(struct platform_device *dev);
161ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic void oz_urb_process_tasklet(unsigned long unused);
162ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic int oz_build_endpoints_for_config(struct usb_hcd *hcd,
163ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		struct oz_port *port, struct usb_host_config *config,
164ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		gfp_t mem_flags);
165ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic void oz_clean_endpoints_for_config(struct usb_hcd *hcd,
166ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				struct oz_port *port);
167ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic int oz_build_endpoints_for_interface(struct usb_hcd *hcd,
168ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			struct oz_port *port,
169ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			struct usb_host_interface *intf, gfp_t mem_flags);
170ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic void oz_clean_endpoints_for_interface(struct usb_hcd *hcd,
171ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			struct oz_port *port, int if_ix);
172ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic void oz_process_ep0_urb(struct oz_hcd *ozhcd, struct urb *urb,
173ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		gfp_t mem_flags);
174ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic struct oz_urb_link *oz_remove_urb(struct oz_endpoint *ep,
175ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		struct urb *urb);
176ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic void oz_hcd_clear_orphanage(struct oz_hcd *ozhcd, int status);
177ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
178ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Static external variables.
179ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
180ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic struct platform_device *g_plat_dev;
181ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic struct oz_hcd *g_ozhcd;
182ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic DEFINE_SPINLOCK(g_hcdlock);	/* Guards g_ozhcd. */
183ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic const char g_hcd_name[] = "Ozmo WPAN";
184ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic struct list_head *g_link_pool;
185ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic int g_link_pool_size;
186ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic DEFINE_SPINLOCK(g_link_lock);
187ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic DEFINE_SPINLOCK(g_tasklet_lock);
188ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic struct tasklet_struct g_urb_process_tasklet;
189ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic struct tasklet_struct g_urb_cancel_tasklet;
190ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic atomic_t g_pending_urbs = ATOMIC_INIT(0);
191ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic const struct hc_driver g_oz_hc_drv = {
192ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	.description =		g_hcd_name,
193ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	.product_desc =		"Ozmo Devices WPAN",
194ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	.hcd_priv_size =	sizeof(struct oz_hcd),
195ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	.flags =		HCD_USB11,
196ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	.start =		oz_hcd_start,
197ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	.stop =			oz_hcd_stop,
198ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	.shutdown =		oz_hcd_shutdown,
199ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	.urb_enqueue =		oz_hcd_urb_enqueue,
200ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	.urb_dequeue =		oz_hcd_urb_dequeue,
201ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	.endpoint_disable =	oz_hcd_endpoint_disable,
202ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	.endpoint_reset =	oz_hcd_endpoint_reset,
203ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	.get_frame_number =	oz_hcd_get_frame_number,
204ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	.hub_status_data =	oz_hcd_hub_status_data,
205ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	.hub_control =		oz_hcd_hub_control,
206ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	.bus_suspend =		oz_hcd_bus_suspend,
207ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	.bus_resume =		oz_hcd_bus_resume,
208ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly};
209ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly
210ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic struct platform_driver g_oz_plat_drv = {
211ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	.probe = oz_plat_probe,
212ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	.remove = oz_plat_remove,
213ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	.shutdown = oz_plat_shutdown,
214ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	.suspend = oz_plat_suspend,
215ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	.resume = oz_plat_resume,
216ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	.driver = {
217ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		.name = OZ_PLAT_DEV_NAME,
218ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		.owner = THIS_MODULE,
219ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	},
220ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly};
221ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
222ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Gets our private context area (which is of type struct oz_hcd) from the
223ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * usb_hcd structure.
224ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Context: any
225ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
226ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic inline struct oz_hcd *oz_hcd_private(struct usb_hcd *hcd)
227ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly{
228ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	return (struct oz_hcd *)hcd->hcd_priv;
229ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly}
230ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
231ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Searches list of ports to find the index of the one with a specified  USB
232ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * bus address. If none of the ports has the bus address then the connection
233ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * port is returned, if there is one or -1 otherwise.
234ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Context: any
235ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
236ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic int oz_get_port_from_addr(struct oz_hcd *ozhcd, u8 bus_addr)
237ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly{
238ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	int i;
239ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	for (i = 0; i < OZ_NB_PORTS; i++) {
240ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		if (ozhcd->ports[i].bus_addr == bus_addr)
241ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			return i;
242ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
243ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	return ozhcd->conn_port;
244ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly}
245ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
246ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Allocates an urb link, first trying the pool but going to heap if empty.
247ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Context: any
248ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
249ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic struct oz_urb_link *oz_alloc_urb_link(void)
250ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly{
251ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct oz_urb_link *urbl = 0;
252ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	unsigned long irq_state;
253ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	spin_lock_irqsave(&g_link_lock, irq_state);
254ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (g_link_pool) {
255ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		urbl = container_of(g_link_pool, struct oz_urb_link, link);
256ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		g_link_pool = urbl->link.next;
257ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		--g_link_pool_size;
258ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
259ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	spin_unlock_irqrestore(&g_link_lock, irq_state);
260ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (urbl == 0)
2611ec41a31fb695682cab7fc7c1f6ced84d188b6f9Greg Kroah-Hartman		urbl = kmalloc(sizeof(struct oz_urb_link), GFP_ATOMIC);
262ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	return urbl;
263ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly}
264ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
265ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Frees an urb link by putting it in the pool if there is enough space or
266ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * deallocating it to heap otherwise.
267ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Context: any
268ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
269ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic void oz_free_urb_link(struct oz_urb_link *urbl)
270ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly{
271ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (urbl) {
272ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		unsigned long irq_state;
273ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		spin_lock_irqsave(&g_link_lock, irq_state);
274ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		if (g_link_pool_size < OZ_MAX_LINK_POOL_SIZE) {
275ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			urbl->link.next = g_link_pool;
276ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			g_link_pool = &urbl->link;
277ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			urbl = 0;
278ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			g_link_pool_size++;
279ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		}
280ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		spin_unlock_irqrestore(&g_link_lock, irq_state);
281ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		if (urbl)
2821ec41a31fb695682cab7fc7c1f6ced84d188b6f9Greg Kroah-Hartman			kfree(urbl);
283ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
284ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly}
285ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
286ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Deallocates all the urb links in the pool.
287ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Context: unknown
288ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
289ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic void oz_empty_link_pool(void)
290ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly{
291ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct list_head *e;
292ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	unsigned long irq_state;
293ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	spin_lock_irqsave(&g_link_lock, irq_state);
294ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	e = g_link_pool;
295ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	g_link_pool = 0;
296ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	g_link_pool_size = 0;
297ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	spin_unlock_irqrestore(&g_link_lock, irq_state);
298ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	while (e) {
299ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		struct oz_urb_link *urbl =
300ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			container_of(e, struct oz_urb_link, link);
301ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		e = e->next;
3021ec41a31fb695682cab7fc7c1f6ced84d188b6f9Greg Kroah-Hartman		kfree(urbl);
303ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
304ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly}
305ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
306ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Allocates endpoint structure and optionally a buffer. If a buffer is
307ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * allocated it immediately follows the endpoint structure.
308ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Context: softirq
309ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
310ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic struct oz_endpoint *oz_ep_alloc(gfp_t mem_flags, int buffer_size)
311ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly{
312ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct oz_endpoint *ep =
3131ec41a31fb695682cab7fc7c1f6ced84d188b6f9Greg Kroah-Hartman		kzalloc(sizeof(struct oz_endpoint)+buffer_size, mem_flags);
314ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (ep) {
315ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		INIT_LIST_HEAD(&ep->urb_list);
316ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		INIT_LIST_HEAD(&ep->link);
317ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		ep->credit = -1;
318ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		if (buffer_size) {
319ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			ep->buffer_size = buffer_size;
320ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			ep->buffer = (u8 *)(ep+1);
321ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		}
322ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
323ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	return ep;
324ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly}
325ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
326ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Pre-condition: Must be called with g_tasklet_lock held and interrupts
327ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * disabled.
328ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Context: softirq or process
329ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
330ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystruct oz_urb_link *oz_uncancel_urb(struct oz_hcd *ozhcd, struct urb *urb)
331ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly{
332ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct oz_urb_link *urbl;
333ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct list_head *e;
334ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	list_for_each(e, &ozhcd->urb_cancel_list) {
335ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		urbl = container_of(e, struct oz_urb_link, link);
336ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		if (urb == urbl->urb) {
337ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			list_del_init(e);
338ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			return urbl;
339ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		}
340ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
341ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	return 0;
342ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly}
343ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
344ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * This is called when we have finished processing an urb. It unlinks it from
345ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * the ep and returns it to the core.
346ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Context: softirq or process
347ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
348ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic void oz_complete_urb(struct usb_hcd *hcd, struct urb *urb,
349ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		int status, unsigned long submit_jiffies)
350ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly{
351ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct oz_hcd *ozhcd = oz_hcd_private(hcd);
352ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	unsigned long irq_state;
353ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct oz_urb_link *cancel_urbl = 0;
354ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	spin_lock_irqsave(&g_tasklet_lock, irq_state);
355ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	usb_hcd_unlink_urb_from_ep(hcd, urb);
356ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	/* Clear hcpriv which will prevent it being put in the cancel list
357ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	 * in the event that an attempt is made to cancel it.
358ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	 */
359ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	urb->hcpriv = 0;
360ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	/* Walk the cancel list in case the urb is already sitting there.
361ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	 * Since we process the cancel list in a tasklet rather than in
362ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	 * the dequeue function this could happen.
363ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	 */
364ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	cancel_urbl = oz_uncancel_urb(ozhcd, urb);
365ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	/* Note: we release lock but do not enable local irqs.
366ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	 * It appears that usb_hcd_giveback_urb() expects irqs to be disabled,
367ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	 * or at least other host controllers disable interrupts at this point
368ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	 * so we do the same. We must, however, release the lock otherwise a
369ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	 * deadlock will occur if an urb is submitted to our driver in the urb
370ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	 * completion function. Because we disable interrupts it is possible
371ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	 * that the urb_enqueue function can be called with them disabled.
372ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	 */
373ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	spin_unlock(&g_tasklet_lock);
374ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (oz_forget_urb(urb)) {
375ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace("OZWPAN: ERROR Unknown URB %p\n", urb);
376ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	} else {
377ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		static unsigned long last_time;
378ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		atomic_dec(&g_pending_urbs);
379ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace2(OZ_TRACE_URB,
380ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			"%lu: giveback_urb(%p,%x) %lu %lu pending:%d\n",
381ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			jiffies, urb, status, jiffies-submit_jiffies,
382ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			jiffies-last_time, atomic_read(&g_pending_urbs));
383ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		last_time = jiffies;
384ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_event_log(OZ_EVT_URB_DONE, 0, 0, urb, status);
385ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		usb_hcd_giveback_urb(hcd, urb, status);
386ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
387ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	spin_lock(&g_tasklet_lock);
388ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	spin_unlock_irqrestore(&g_tasklet_lock, irq_state);
389ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (cancel_urbl)
390ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_free_urb_link(cancel_urbl);
391ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly}
392ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
393ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Deallocates an endpoint including deallocating any associated stream and
394ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * returning any queued urbs to the core.
395ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Context: softirq
396ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
397ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic void oz_ep_free(struct oz_port *port, struct oz_endpoint *ep)
398ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly{
399ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	oz_trace("oz_ep_free()\n");
400ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (port) {
401ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		struct list_head list;
402ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		struct oz_hcd *ozhcd = port->ozhcd;
403ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		INIT_LIST_HEAD(&list);
404ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		if (ep->flags & OZ_F_EP_HAVE_STREAM)
405ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			oz_usb_stream_delete(port->hpd, ep->ep_num);
406ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		/* Transfer URBs to the orphanage while we hold the lock. */
407ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		spin_lock_bh(&ozhcd->hcd_lock);
408ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		/* Note: this works even if ep->urb_list is empty.*/
409ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		list_replace_init(&ep->urb_list, &list);
410ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		/* Put the URBs in the orphanage. */
411ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		list_splice_tail(&list, &ozhcd->orphanage);
412ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		spin_unlock_bh(&ozhcd->hcd_lock);
413ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
414ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	oz_trace("Freeing endpoint memory\n");
4151ec41a31fb695682cab7fc7c1f6ced84d188b6f9Greg Kroah-Hartman	kfree(ep);
416ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly}
417ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
418ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Context: softirq
419ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
420ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic int oz_enqueue_ep_urb(struct oz_port *port, u8 ep_addr, int in_dir,
421ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			struct urb *urb, u8 req_id)
422ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly{
423ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct oz_urb_link *urbl;
424ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct oz_endpoint *ep;
425ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	int err = 0;
426ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (ep_addr >= OZ_NB_ENDPOINTS) {
427ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace("Invalid endpoint number in oz_enqueue_ep_urb().\n");
428ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		return -EINVAL;
429ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
430ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	urbl = oz_alloc_urb_link();
431ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (!urbl)
432ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		return -ENOMEM;
433ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	urbl->submit_jiffies = jiffies;
434ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	urbl->urb = urb;
435ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	urbl->req_id = req_id;
436ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	urbl->ep_num = ep_addr;
437ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	/* Hold lock while we insert the URB into the list within the
438ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	 * endpoint structure.
439ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	 */
440ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	spin_lock_bh(&port->ozhcd->hcd_lock);
441ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	/* If the urb has been unlinked while out of any list then
442ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	 * complete it now.
443ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	 */
444ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (urb->unlinked) {
445ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		spin_unlock_bh(&port->ozhcd->hcd_lock);
446ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace("urb %p unlinked so complete immediately\n", urb);
447ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_complete_urb(port->ozhcd->hcd, urb, 0, 0);
448ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_free_urb_link(urbl);
449ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		return 0;
450ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
451ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (in_dir)
452ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		ep = port->in_ep[ep_addr];
453ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	else
454ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		ep = port->out_ep[ep_addr];
455ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (ep && port->hpd) {
456ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		list_add_tail(&urbl->link, &ep->urb_list);
457ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		if (!in_dir && ep_addr && (ep->credit < 0)) {
458ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			ep->last_jiffies = jiffies;
459ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			ep->credit = 0;
460ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			oz_event_log(OZ_EVT_EP_CREDIT, ep->ep_num,
461ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly					0, 0, ep->credit);
462ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		}
463ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	} else {
464ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		err = -EPIPE;
465ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
466ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	spin_unlock_bh(&port->ozhcd->hcd_lock);
467ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (err)
468ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_free_urb_link(urbl);
469ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	return err;
470ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly}
471ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
472ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Removes an urb from the queue in the endpoint.
473ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Returns 0 if it is found and -EIDRM otherwise.
474ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Context: softirq
475ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
476ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic int oz_dequeue_ep_urb(struct oz_port *port, u8 ep_addr, int in_dir,
477ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			struct urb *urb)
478ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly{
479ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct oz_urb_link *urbl = 0;
480ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct oz_endpoint *ep;
481ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	spin_lock_bh(&port->ozhcd->hcd_lock);
482ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (in_dir)
483ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		ep = port->in_ep[ep_addr];
484ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	else
485ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		ep = port->out_ep[ep_addr];
486ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (ep) {
487ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		struct list_head *e;
488ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		list_for_each(e, &ep->urb_list) {
489ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			urbl = container_of(e, struct oz_urb_link, link);
490ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			if (urbl->urb == urb) {
491ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				list_del_init(e);
492ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				break;
493ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			}
494ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			urbl = 0;
495ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		}
496ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
497ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	spin_unlock_bh(&port->ozhcd->hcd_lock);
498ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (urbl)
499ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_free_urb_link(urbl);
500ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	return urbl ? 0 : -EIDRM;
501ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly}
502ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
503ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Finds an urb given its request id.
504ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Context: softirq
505ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
506ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic struct urb *oz_find_urb_by_id(struct oz_port *port, int ep_ix,
507ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		u8 req_id)
508ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly{
509ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct oz_hcd *ozhcd = port->ozhcd;
510ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct urb *urb = 0;
511ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct oz_urb_link *urbl = 0;
512ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct oz_endpoint *ep;
513ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly
514ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	spin_lock_bh(&ozhcd->hcd_lock);
515ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	ep = port->out_ep[ep_ix];
516ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (ep) {
517ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		struct list_head *e;
518ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		list_for_each(e, &ep->urb_list) {
519ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			urbl = container_of(e, struct oz_urb_link, link);
520ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			if (urbl->req_id == req_id) {
521ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				urb = urbl->urb;
522ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				list_del_init(e);
523ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				break;
524ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			}
525ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		}
526ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
527ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	spin_unlock_bh(&ozhcd->hcd_lock);
528ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	/* If urb is non-zero then we we must have an urb link to delete.
529ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	 */
530ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (urb)
531ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_free_urb_link(urbl);
532ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	return urb;
533ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly}
534ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
535ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Pre-condition: Port lock must be held.
536ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Context: softirq
537ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
538ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic void oz_acquire_port(struct oz_port *port, void *hpd)
539ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly{
540ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	INIT_LIST_HEAD(&port->isoc_out_ep);
541ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	INIT_LIST_HEAD(&port->isoc_in_ep);
542ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	port->flags |= OZ_PORT_F_PRESENT | OZ_PORT_F_CHANGED;
543ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	port->status |= USB_PORT_STAT_CONNECTION |
544ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			(USB_PORT_STAT_C_CONNECTION << 16);
545ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	oz_usb_get(hpd);
546ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	port->hpd = hpd;
547ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly}
548ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
549ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Context: softirq
550ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
551ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic struct oz_hcd *oz_hcd_claim(void)
552ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly{
553ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct oz_hcd *ozhcd;
554ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	spin_lock_bh(&g_hcdlock);
555ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	ozhcd = g_ozhcd;
556ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (ozhcd)
557ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		usb_get_hcd(ozhcd->hcd);
558ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	spin_unlock_bh(&g_hcdlock);
559ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	return ozhcd;
560ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly}
561ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
562ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Context: softirq
563ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
564ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic inline void oz_hcd_put(struct oz_hcd *ozhcd)
565ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly{
566ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (ozhcd)
567ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		usb_put_hcd(ozhcd->hcd);
568ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly}
569ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
570ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * This is called by the protocol handler to notify that a PD has arrived.
571ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * We allocate a port to associate with the PD and create a structure for
572ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * endpoint 0. This port is made the connection port.
573ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * In the event that one of the other port is already a connection port then
574ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * we fail.
575ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * TODO We should be able to do better than fail and should be able remember
576ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * that this port needs configuring and make it the connection port once the
577ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * current connection port has been assigned an address. Collisions here are
578ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * probably very rare indeed.
579ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Context: softirq
580ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
581ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellyvoid *oz_hcd_pd_arrived(void *hpd)
582ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly{
583ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	int i;
584ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	void *hport = 0;
585ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct oz_hcd *ozhcd = 0;
586ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct oz_endpoint *ep;
587ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	oz_trace("oz_hcd_pd_arrived()\n");
588ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	ozhcd = oz_hcd_claim();
589ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (ozhcd == 0)
590ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		return 0;
591ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	/* Allocate an endpoint object in advance (before holding hcd lock) to
592ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	 * use for out endpoint 0.
593ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	 */
594ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	ep = oz_ep_alloc(GFP_ATOMIC, 0);
595ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	spin_lock_bh(&ozhcd->hcd_lock);
596ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (ozhcd->conn_port >= 0) {
597ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		spin_unlock_bh(&ozhcd->hcd_lock);
598ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace("conn_port >= 0\n");
599ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		goto out;
600ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
601ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	for (i = 0; i < OZ_NB_PORTS; i++) {
602ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		struct oz_port *port = &ozhcd->ports[i];
603ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		spin_lock(&port->port_lock);
604ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		if ((port->flags & OZ_PORT_F_PRESENT) == 0) {
605ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			oz_acquire_port(port, hpd);
606ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			spin_unlock(&port->port_lock);
607ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			break;
608ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		}
609ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		spin_unlock(&port->port_lock);
610ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
611ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (i < OZ_NB_PORTS) {
612ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace("Setting conn_port = %d\n", i);
613ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		ozhcd->conn_port = i;
614ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		/* Attach out endpoint 0.
615ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		 */
616ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		ozhcd->ports[i].out_ep[0] = ep;
617ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		ep = 0;
618ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		hport = &ozhcd->ports[i];
619ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		spin_unlock_bh(&ozhcd->hcd_lock);
620ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		if (ozhcd->flags & OZ_HDC_F_SUSPENDED) {
621ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			oz_trace("Resuming root hub\n");
622ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			usb_hcd_resume_root_hub(ozhcd->hcd);
623ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		}
624ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		usb_hcd_poll_rh_status(ozhcd->hcd);
625ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	} else {
626ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		spin_unlock_bh(&ozhcd->hcd_lock);
627ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
628ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellyout:
629ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (ep) /* ep is non-null if not used. */
630ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_ep_free(0, ep);
631ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	oz_hcd_put(ozhcd);
632ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	return hport;
633ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly}
634ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
635ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * This is called by the protocol handler to notify that the PD has gone away.
636ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * We need to deallocate all resources and then request that the root hub is
637ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * polled. We release the reference we hold on the PD.
638ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Context: softirq
639ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
640ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellyvoid oz_hcd_pd_departed(void *hport)
641ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly{
642ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct oz_port *port = (struct oz_port *)hport;
643ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct oz_hcd *ozhcd;
644ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	void *hpd;
645ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct oz_endpoint *ep = 0;
646ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly
647ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	oz_trace("oz_hcd_pd_departed()\n");
648ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (port == 0) {
649ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace("oz_hcd_pd_departed() port = 0\n");
650ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		return;
651ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
652ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	ozhcd = port->ozhcd;
653ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (ozhcd == 0)
654ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		return;
655ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	/* Check if this is the connection port - if so clear it.
656ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	 */
657ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	spin_lock_bh(&ozhcd->hcd_lock);
658ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if ((ozhcd->conn_port >= 0) &&
659ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		(port == &ozhcd->ports[ozhcd->conn_port])) {
660ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace("Clearing conn_port\n");
661ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		ozhcd->conn_port = -1;
662ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
663ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	spin_lock(&port->port_lock);
664ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	port->flags |= OZ_PORT_F_DYING;
665ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	spin_unlock(&port->port_lock);
666ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	spin_unlock_bh(&ozhcd->hcd_lock);
667ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly
668ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	oz_clean_endpoints_for_config(ozhcd->hcd, port);
669ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	spin_lock_bh(&port->port_lock);
670ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	hpd = port->hpd;
671ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	port->hpd = 0;
672ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	port->bus_addr = 0xff;
673ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	port->flags &= ~(OZ_PORT_F_PRESENT | OZ_PORT_F_DYING);
674ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	port->flags |= OZ_PORT_F_CHANGED;
675ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	port->status &= ~USB_PORT_STAT_CONNECTION;
676ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	port->status |= (USB_PORT_STAT_C_CONNECTION << 16);
677ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	/* If there is an endpont 0 then clear the pointer while we hold
678ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	 * the spinlock be we deallocate it after releasing the lock.
679ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	 */
680ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (port->out_ep[0]) {
681ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		ep = port->out_ep[0];
682ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		port->out_ep[0] = 0;
683ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
684ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	spin_unlock_bh(&port->port_lock);
685ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (ep)
686ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_ep_free(port, ep);
687ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	usb_hcd_poll_rh_status(ozhcd->hcd);
688ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	oz_usb_put(hpd);
689ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly}
690ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
691ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Context: softirq
692ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
693ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellyvoid oz_hcd_pd_reset(void *hpd, void *hport)
694ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly{
695ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	/* Cleanup the current configuration and report reset to the core.
696ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	 */
697ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct oz_port *port = (struct oz_port *)hport;
698ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct oz_hcd *ozhcd = port->ozhcd;
699ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	oz_trace("PD Reset\n");
700ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	spin_lock_bh(&port->port_lock);
701ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	port->flags |= OZ_PORT_F_CHANGED;
702ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	port->status |= USB_PORT_STAT_RESET;
703ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	port->status |= (USB_PORT_STAT_C_RESET << 16);
704ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	spin_unlock_bh(&port->port_lock);
705ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	oz_clean_endpoints_for_config(ozhcd->hcd, port);
706ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	usb_hcd_poll_rh_status(ozhcd->hcd);
707ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly}
708ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
709ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Context: softirq
710ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
711ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellyvoid oz_hcd_get_desc_cnf(void *hport, u8 req_id, int status, u8 *desc,
712ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			int length, int offset, int total_size)
713ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly{
714ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct oz_port *port = (struct oz_port *)hport;
715ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct urb *urb;
716ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	int err = 0;
717ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly
718ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	oz_event_log(OZ_EVT_CTRL_CNF, 0, req_id, 0, status);
719ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	oz_trace("oz_hcd_get_desc_cnf length = %d offs = %d tot_size = %d\n",
720ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			length, offset, total_size);
721ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	urb = oz_find_urb_by_id(port, 0, req_id);
722ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (!urb)
723ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		return;
724ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (status == 0) {
725ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		int copy_len;
726ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		int required_size = urb->transfer_buffer_length;
727ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		if (required_size > total_size)
728ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			required_size = total_size;
729ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		copy_len = required_size-offset;
730ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		if (length <= copy_len)
731ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			copy_len = length;
732ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		memcpy(urb->transfer_buffer+offset, desc, copy_len);
733ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		offset += copy_len;
734ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		if (offset < required_size) {
735ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			struct usb_ctrlrequest *setup =
736ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				(struct usb_ctrlrequest *)urb->setup_packet;
737ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			unsigned wvalue = le16_to_cpu(setup->wValue);
738ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			if (oz_enqueue_ep_urb(port, 0, 0, urb, req_id))
739ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				err = -ENOMEM;
740ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			else if (oz_usb_get_desc_req(port->hpd, req_id,
741ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly					setup->bRequestType, (u8)(wvalue>>8),
742ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly					(u8)wvalue, setup->wIndex, offset,
743ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly					required_size-offset)) {
744ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				oz_dequeue_ep_urb(port, 0, 0, urb);
745ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				err = -ENOMEM;
746ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			}
747ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			if (err == 0)
748ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				return;
749ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		}
750ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
751ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	urb->actual_length = total_size;
752ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	oz_complete_urb(port->ozhcd->hcd, urb, 0, 0);
753ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly}
754ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
755ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Context: softirq
756ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
757ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly#ifdef WANT_TRACE
758ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic void oz_display_conf_type(u8 t)
759ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly{
760ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	switch (t) {
761ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	case USB_REQ_GET_STATUS:
762ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace("USB_REQ_GET_STATUS - cnf\n");
763ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		break;
764ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	case USB_REQ_CLEAR_FEATURE:
765ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace("USB_REQ_CLEAR_FEATURE - cnf\n");
766ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		break;
767ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	case USB_REQ_SET_FEATURE:
768ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace("USB_REQ_SET_FEATURE - cnf\n");
769ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		break;
770ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	case USB_REQ_SET_ADDRESS:
771ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace("USB_REQ_SET_ADDRESS - cnf\n");
772ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		break;
773ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	case USB_REQ_GET_DESCRIPTOR:
774ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace("USB_REQ_GET_DESCRIPTOR - cnf\n");
775ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		break;
776ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	case USB_REQ_SET_DESCRIPTOR:
777ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace("USB_REQ_SET_DESCRIPTOR - cnf\n");
778ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		break;
779ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	case USB_REQ_GET_CONFIGURATION:
780ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace("USB_REQ_GET_CONFIGURATION - cnf\n");
781ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		break;
782ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	case USB_REQ_SET_CONFIGURATION:
783ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace("USB_REQ_SET_CONFIGURATION - cnf\n");
784ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		break;
785ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	case USB_REQ_GET_INTERFACE:
786ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace("USB_REQ_GET_INTERFACE - cnf\n");
787ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		break;
788ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	case USB_REQ_SET_INTERFACE:
789ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace("USB_REQ_SET_INTERFACE - cnf\n");
790ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		break;
791ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	case USB_REQ_SYNCH_FRAME:
792ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace("USB_REQ_SYNCH_FRAME - cnf\n");
793ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		break;
794ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
795ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly}
796ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly#else
797ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly#define oz_display_conf_type(__x)
798ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly#endif /* WANT_TRACE */
799ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
800ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Context: softirq
801ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
802ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic void oz_hcd_complete_set_config(struct oz_port *port, struct urb *urb,
803ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		u8 rcode, u8 config_num)
804ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly{
805ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	int rc = 0;
806ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct usb_hcd *hcd = port->ozhcd->hcd;
807ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (rcode == 0) {
808ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		port->config_num = config_num;
809ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_clean_endpoints_for_config(hcd, port);
810ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		if (oz_build_endpoints_for_config(hcd, port,
811ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			&urb->dev->config[port->config_num-1], GFP_ATOMIC)) {
812ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			rc = -ENOMEM;
813ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		}
814ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	} else {
815ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		rc = -ENOMEM;
816ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
817ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	oz_complete_urb(hcd, urb, rc, 0);
818ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly}
819ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
820ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Context: softirq
821ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
822ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic void oz_hcd_complete_set_interface(struct oz_port *port, struct urb *urb,
823ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		u8 rcode, u8 if_num, u8 alt)
824ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly{
825ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct usb_hcd *hcd = port->ozhcd->hcd;
826ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	int rc = 0;
827ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (rcode == 0) {
828ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		struct usb_host_config *config;
829ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		struct usb_host_interface *intf;
830ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace("Set interface %d alt %d\n", if_num, alt);
831ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_clean_endpoints_for_interface(hcd, port, if_num);
832ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		config = &urb->dev->config[port->config_num-1];
833ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		intf = &config->intf_cache[if_num]->altsetting[alt];
834ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		if (oz_build_endpoints_for_interface(hcd, port, intf,
835ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			GFP_ATOMIC))
836ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			rc = -ENOMEM;
837ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		else
838ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			port->iface[if_num].alt = alt;
839ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	} else {
840ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		rc = -ENOMEM;
841ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
842ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	oz_complete_urb(hcd, urb, rc, 0);
843ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly}
844ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
845ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Context: softirq
846ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
847ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellyvoid oz_hcd_control_cnf(void *hport, u8 req_id, u8 rcode, u8 *data,
848ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	int data_len)
849ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly{
850ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct oz_port *port = (struct oz_port *)hport;
851ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct urb *urb;
852ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct usb_ctrlrequest *setup;
853ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct usb_hcd *hcd = port->ozhcd->hcd;
854ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	unsigned windex;
855ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	unsigned wvalue;
856ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly
857ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	oz_event_log(OZ_EVT_CTRL_CNF, 0, req_id, 0, rcode);
858ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	oz_trace("oz_hcd_control_cnf rcode=%u len=%d\n", rcode, data_len);
859ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	urb = oz_find_urb_by_id(port, 0, req_id);
860ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (!urb) {
861ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace("URB not found\n");
862ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		return;
863ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
864ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	setup = (struct usb_ctrlrequest *)urb->setup_packet;
865ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	windex = le16_to_cpu(setup->wIndex);
866ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	wvalue = le16_to_cpu(setup->wValue);
867ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if ((setup->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
868ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		/* Standard requests */
869ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_display_conf_type(setup->bRequest);
870ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		switch (setup->bRequest) {
871ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		case USB_REQ_SET_CONFIGURATION:
872ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			oz_hcd_complete_set_config(port, urb, rcode,
873ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				(u8)wvalue);
874ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			break;
875ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		case USB_REQ_SET_INTERFACE:
876ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			oz_hcd_complete_set_interface(port, urb, rcode,
877ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				(u8)windex, (u8)wvalue);
878ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			break;
879ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		default:
880ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			oz_complete_urb(hcd, urb, 0, 0);
881ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		}
882ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly
883ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	} else {
884ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		int copy_len;
885ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace("VENDOR-CLASS - cnf\n");
886ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		if (data_len <= urb->transfer_buffer_length)
887ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			copy_len = data_len;
888ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		else
889ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			copy_len = urb->transfer_buffer_length;
890ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		if (copy_len)
891ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			memcpy(urb->transfer_buffer, data, copy_len);
892ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		urb->actual_length = copy_len;
893ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_complete_urb(hcd, urb, 0, 0);
894ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
895ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly}
896ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
897ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Context: softirq-serialized
898ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
899ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic int oz_hcd_buffer_data(struct oz_endpoint *ep, u8 *data, int data_len)
900ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly{
901ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	int space;
902ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	int copy_len;
903ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (!ep->buffer)
904ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		return -1;
905ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	space = ep->out_ix-ep->in_ix-1;
906ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (space < 0)
907ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		space += ep->buffer_size;
908ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (space < (data_len+1)) {
909ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace("Buffer full\n");
910ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		return -1;
911ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
912ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	ep->buffer[ep->in_ix] = (u8)data_len;
913ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (++ep->in_ix == ep->buffer_size)
914ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		ep->in_ix = 0;
915ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	copy_len = ep->buffer_size - ep->in_ix;
916ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (copy_len > data_len)
917ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		copy_len = data_len;
918ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	memcpy(&ep->buffer[ep->in_ix], data, copy_len);
919ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly
920ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (copy_len < data_len) {
921ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		memcpy(ep->buffer, data+copy_len, data_len-copy_len);
922ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		ep->in_ix = data_len-copy_len;
923ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	} else {
924ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		ep->in_ix += copy_len;
925ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
926ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (ep->in_ix == ep->buffer_size)
927ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		ep->in_ix = 0;
928ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	ep->buffered_units++;
929ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	return 0;
930ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly}
931ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
932ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Context: softirq-serialized
933ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
934ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellyvoid oz_hcd_data_ind(void *hport, u8 endpoint, u8 *data, int data_len)
935ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly{
936ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct oz_port *port = (struct oz_port *)hport;
937ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct oz_endpoint *ep;
938ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct oz_hcd *ozhcd = port->ozhcd;
939ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	spin_lock_bh(&ozhcd->hcd_lock);
940ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	ep = port->in_ep[endpoint & USB_ENDPOINT_NUMBER_MASK];
941ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (ep == 0)
942ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		goto done;
943ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	switch (ep->attrib & USB_ENDPOINT_XFERTYPE_MASK) {
944ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	case USB_ENDPOINT_XFER_INT:
945ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	case USB_ENDPOINT_XFER_BULK:
946ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		if (!list_empty(&ep->urb_list)) {
947ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			struct oz_urb_link *urbl =
948ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				list_first_entry(&ep->urb_list,
949ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly					struct oz_urb_link, link);
950ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			struct urb *urb;
951ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			int copy_len;
952ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			list_del_init(&urbl->link);
953ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			spin_unlock_bh(&ozhcd->hcd_lock);
954ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			urb = urbl->urb;
955ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			oz_free_urb_link(urbl);
956ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			if (data_len <= urb->transfer_buffer_length)
957ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				copy_len = data_len;
958ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			else
959ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				copy_len = urb->transfer_buffer_length;
960ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			memcpy(urb->transfer_buffer, data, copy_len);
961ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			urb->actual_length = copy_len;
962ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			oz_complete_urb(port->ozhcd->hcd, urb, 0, 0);
963ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			return;
964ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		}
965ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		break;
966ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	case USB_ENDPOINT_XFER_ISOC:
967ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_hcd_buffer_data(ep, data, data_len);
968ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		break;
969ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
970ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellydone:
971ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	spin_unlock_bh(&ozhcd->hcd_lock);
972ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly}
973ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
974ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Context: unknown
975ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
976ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic inline int oz_usb_get_frame_number(void)
977ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly{
978ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	return jiffies_to_msecs(get_jiffies_64());
979ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly}
980ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
981ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Context: softirq
982ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
983ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellyint oz_hcd_heartbeat(void *hport)
984ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly{
985ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	int rc = 0;
986ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct oz_port *port = (struct oz_port *)hport;
987ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct oz_hcd *ozhcd = port->ozhcd;
988ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct oz_urb_link *urbl;
989ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct list_head xfr_list;
990ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct list_head *e;
991ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct list_head *n;
992ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct urb *urb;
993ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct oz_endpoint *ep;
994ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	unsigned long now = jiffies;
995ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	INIT_LIST_HEAD(&xfr_list);
996ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	/* Check the OUT isoc endpoints to see if any URB data can be sent.
997ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	 */
998ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	spin_lock_bh(&ozhcd->hcd_lock);
999ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	list_for_each(e, &port->isoc_out_ep) {
1000ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		ep = ep_from_link(e);
1001ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		if (ep->credit < 0)
1002ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			continue;
1003ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		ep->credit += (now - ep->last_jiffies);
1004ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		if (ep->credit > ep->credit_ceiling)
1005ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			ep->credit = ep->credit_ceiling;
1006ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_event_log(OZ_EVT_EP_CREDIT, ep->ep_num, 0, 0, ep->credit);
1007ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		ep->last_jiffies = now;
1008ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		while (ep->credit && !list_empty(&ep->urb_list)) {
1009ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			urbl = list_first_entry(&ep->urb_list,
1010ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				struct oz_urb_link, link);
1011ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			urb = urbl->urb;
1012ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			if (ep->credit < urb->number_of_packets)
1013ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				break;
1014ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			ep->credit -= urb->number_of_packets;
1015ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			oz_event_log(OZ_EVT_EP_CREDIT, ep->ep_num, 0, 0,
1016ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				ep->credit);
1017ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			list_del(&urbl->link);
1018ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			list_add_tail(&urbl->link, &xfr_list);
1019ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		}
1020ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
1021ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	spin_unlock_bh(&ozhcd->hcd_lock);
1022ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	/* Send to PD and complete URBs.
1023ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	 */
1024ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	list_for_each_safe(e, n, &xfr_list) {
1025ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		unsigned long t;
1026ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		urbl = container_of(e, struct oz_urb_link, link);
1027ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		urb = urbl->urb;
1028ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		t = urbl->submit_jiffies;
1029ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		list_del_init(e);
1030ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		urb->error_count = 0;
1031ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		urb->start_frame = oz_usb_get_frame_number();
1032ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_usb_send_isoc(port->hpd, urbl->ep_num, urb);
1033ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_free_urb_link(urbl);
1034ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_complete_urb(port->ozhcd->hcd, urb, 0, t);
1035ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
1036ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	/* Check the IN isoc endpoints to see if any URBs can be completed.
1037ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	 */
1038ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	spin_lock_bh(&ozhcd->hcd_lock);
1039ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	list_for_each(e, &port->isoc_in_ep) {
1040ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		struct oz_endpoint *ep = ep_from_link(e);
1041ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		if (ep->flags & OZ_F_EP_BUFFERING) {
1042ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			if (ep->buffered_units * OZ_IN_BUFFERING_UNITS) {
1043ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				ep->flags &= ~OZ_F_EP_BUFFERING;
1044ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				ep->credit = 0;
1045ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				oz_event_log(OZ_EVT_EP_CREDIT,
1046ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly					ep->ep_num | USB_DIR_IN,
1047ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly					0, 0, ep->credit);
1048ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				ep->last_jiffies = now;
1049ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				ep->start_frame = 0;
1050ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				oz_event_log(OZ_EVT_EP_BUFFERING,
1051ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly					ep->ep_num | USB_DIR_IN, 0, 0, 0);
1052ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			}
1053ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			continue;
1054ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		}
1055ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		ep->credit += (now - ep->last_jiffies);
1056ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_event_log(OZ_EVT_EP_CREDIT, ep->ep_num | USB_DIR_IN,
1057ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			0, 0, ep->credit);
1058ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		ep->last_jiffies = now;
1059ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		while (!list_empty(&ep->urb_list)) {
1060ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			struct oz_urb_link *urbl =
1061ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				list_first_entry(&ep->urb_list,
1062ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly					struct oz_urb_link, link);
1063ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			struct urb *urb = urbl->urb;
1064ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			int len = 0;
1065ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			int copy_len;
1066ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			int i;
1067ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			if (ep->credit < urb->number_of_packets)
1068ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				break;
1069ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			if (ep->buffered_units < urb->number_of_packets)
1070ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				break;
1071ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			urb->actual_length = 0;
1072ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			for (i = 0; i < urb->number_of_packets; i++) {
1073ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				len = ep->buffer[ep->out_ix];
1074ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				if (++ep->out_ix == ep->buffer_size)
1075ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly					ep->out_ix = 0;
1076ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				copy_len = ep->buffer_size - ep->out_ix;
1077ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				if (copy_len > len)
1078ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly					copy_len = len;
1079ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				memcpy(urb->transfer_buffer,
1080ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly					&ep->buffer[ep->out_ix], copy_len);
1081ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				if (copy_len < len) {
1082ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly					memcpy(urb->transfer_buffer+copy_len,
1083ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly						ep->buffer, len-copy_len);
1084ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly					ep->out_ix = len-copy_len;
1085ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				} else
1086ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly					ep->out_ix += copy_len;
1087ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				if (ep->out_ix == ep->buffer_size)
1088ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly					ep->out_ix = 0;
1089ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				urb->iso_frame_desc[i].offset =
1090ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly					urb->actual_length;
1091ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				urb->actual_length += len;
1092ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				urb->iso_frame_desc[i].actual_length = len;
1093ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				urb->iso_frame_desc[i].status = 0;
1094ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			}
1095ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			ep->buffered_units -= urb->number_of_packets;
1096ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			urb->error_count = 0;
1097ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			urb->start_frame = ep->start_frame;
1098ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			ep->start_frame += urb->number_of_packets;
1099ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			list_del(&urbl->link);
1100ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			list_add_tail(&urbl->link, &xfr_list);
1101ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			ep->credit -= urb->number_of_packets;
1102ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			oz_event_log(OZ_EVT_EP_CREDIT, ep->ep_num | USB_DIR_IN,
1103ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				0, 0, ep->credit);
1104ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		}
1105ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
1106ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (!list_empty(&port->isoc_out_ep) || !list_empty(&port->isoc_in_ep))
1107ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		rc = 1;
1108ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	spin_unlock_bh(&ozhcd->hcd_lock);
1109ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	/* Complete the filled URBs.
1110ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	 */
1111ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	list_for_each_safe(e, n, &xfr_list) {
1112ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		urbl = container_of(e, struct oz_urb_link, link);
1113ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		urb = urbl->urb;
1114ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		list_del_init(e);
1115ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_free_urb_link(urbl);
1116ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_complete_urb(port->ozhcd->hcd, urb, 0, 0);
1117ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
1118ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	/* Check if there are any ep0 requests that have timed out.
1119ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	 * If so resent to PD.
1120ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	 */
1121ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	ep = port->out_ep[0];
1122ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (ep) {
1123ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		struct list_head *e;
1124ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		struct list_head *n;
1125ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		spin_lock_bh(&ozhcd->hcd_lock);
1126ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		list_for_each_safe(e, n, &ep->urb_list) {
1127ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			urbl = container_of(e, struct oz_urb_link, link);
1128ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			if (time_after(now, urbl->submit_jiffies+HZ/2)) {
1129ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				oz_trace("%ld: Request 0x%p timeout\n",
1130ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly						now, urbl->urb);
1131ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				urbl->submit_jiffies = now;
1132ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				list_del(e);
1133ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				list_add_tail(e, &xfr_list);
1134ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			}
1135ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		}
1136ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		if (!list_empty(&ep->urb_list))
1137ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			rc = 1;
1138ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		spin_unlock_bh(&ozhcd->hcd_lock);
1139ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		e = xfr_list.next;
1140ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		while (e != &xfr_list) {
1141ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			urbl = container_of(e, struct oz_urb_link, link);
1142ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			e = e->next;
1143ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			oz_trace("Resending request to PD.\n");
1144ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			oz_process_ep0_urb(ozhcd, urbl->urb, GFP_ATOMIC);
1145ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			oz_free_urb_link(urbl);
1146ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		}
1147ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
1148ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	return rc;
1149ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly}
1150ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
1151ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Context: softirq
1152ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
1153ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic int oz_build_endpoints_for_interface(struct usb_hcd *hcd,
1154ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		struct oz_port *port,
1155ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		struct usb_host_interface *intf, gfp_t mem_flags)
1156ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly{
1157ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct oz_hcd *ozhcd = port->ozhcd;
1158ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	int i;
1159ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	int if_ix = intf->desc.bInterfaceNumber;
1160ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	int request_heartbeat = 0;
1161ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	oz_trace("interface[%d] = %p\n", if_ix, intf);
1162ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	for (i = 0; i < intf->desc.bNumEndpoints; i++) {
1163ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		struct usb_host_endpoint *hep = &intf->endpoint[i];
1164ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		u8 ep_addr = hep->desc.bEndpointAddress;
1165ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		u8 ep_num = ep_addr & USB_ENDPOINT_NUMBER_MASK;
1166ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		struct oz_endpoint *ep;
1167ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		int buffer_size = 0;
1168ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly
1169ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace("%d bEndpointAddress = %x\n", i, ep_addr);
1170ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		if ((ep_addr & USB_ENDPOINT_DIR_MASK) &&
1171ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			((hep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
1172ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			== USB_ENDPOINT_XFER_ISOC)) {
1173ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			buffer_size = 24*1024;
1174ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		}
1175ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly
1176ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		ep = oz_ep_alloc(mem_flags, buffer_size);
1177ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		if (!ep) {
1178ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			oz_clean_endpoints_for_interface(hcd, port, if_ix);
1179ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			return -ENOMEM;
1180ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		}
1181ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		ep->attrib = hep->desc.bmAttributes;
1182ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		ep->ep_num = ep_num;
1183ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		if ((ep->attrib & USB_ENDPOINT_XFERTYPE_MASK)
1184ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			== USB_ENDPOINT_XFER_ISOC) {
1185ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			oz_trace("wMaxPacketSize = %d\n",
1186ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				hep->desc.wMaxPacketSize);
1187ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			ep->credit_ceiling = 200;
1188ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			if (ep_addr & USB_ENDPOINT_DIR_MASK) {
1189ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				ep->flags |= OZ_F_EP_BUFFERING;
1190ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				oz_event_log(OZ_EVT_EP_BUFFERING,
1191ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly					ep->ep_num | USB_DIR_IN, 1, 0, 0);
1192ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			} else {
1193ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				ep->flags |= OZ_F_EP_HAVE_STREAM;
1194ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				if (oz_usb_stream_create(port->hpd, ep_num))
1195ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly					ep->flags &= ~OZ_F_EP_HAVE_STREAM;
1196ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			}
1197ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		}
1198ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		spin_lock_bh(&ozhcd->hcd_lock);
1199ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		if (ep_addr & USB_ENDPOINT_DIR_MASK) {
1200ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			port->in_ep[ep_num] = ep;
1201ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			port->iface[if_ix].ep_mask |=
1202ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				(1<<(ep_num+OZ_NB_ENDPOINTS));
1203ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			if ((ep->attrib & USB_ENDPOINT_XFERTYPE_MASK)
1204ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				 == USB_ENDPOINT_XFER_ISOC) {
1205ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				list_add_tail(&ep->link, &port->isoc_in_ep);
1206ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				request_heartbeat = 1;
1207ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			}
1208ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		} else {
1209ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			port->out_ep[ep_num] = ep;
1210ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			port->iface[if_ix].ep_mask |= (1<<ep_num);
1211ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			if ((ep->attrib & USB_ENDPOINT_XFERTYPE_MASK)
1212ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				== USB_ENDPOINT_XFER_ISOC) {
1213ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				list_add_tail(&ep->link, &port->isoc_out_ep);
1214ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				request_heartbeat = 1;
1215ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			}
1216ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		}
1217ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		spin_unlock_bh(&ozhcd->hcd_lock);
1218ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		if (request_heartbeat && port->hpd)
1219ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			oz_usb_request_heartbeat(port->hpd);
1220ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
1221ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	return 0;
1222ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly}
1223ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
1224ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Context: softirq
1225ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
1226ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic void oz_clean_endpoints_for_interface(struct usb_hcd *hcd,
1227ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			struct oz_port *port, int if_ix)
1228ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly{
1229ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct oz_hcd *ozhcd = port->ozhcd;
1230ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	unsigned mask;
1231ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	int i;
1232ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct list_head ep_list;
1233ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly
1234ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	oz_trace("Deleting endpoints for interface %d\n", if_ix);
1235ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (if_ix >= port->num_iface)
1236ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		return;
1237ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	INIT_LIST_HEAD(&ep_list);
1238ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	spin_lock_bh(&ozhcd->hcd_lock);
1239ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	mask = port->iface[if_ix].ep_mask;
1240ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	port->iface[if_ix].ep_mask = 0;
1241ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	for (i = 0; i < OZ_NB_ENDPOINTS; i++) {
1242ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		struct list_head *e;
1243ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		/* Gather OUT endpoints.
1244ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		 */
1245ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		if ((mask & (1<<i)) && port->out_ep[i]) {
1246ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			e = &port->out_ep[i]->link;
1247ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			port->out_ep[i] = 0;
1248ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			/* Remove from isoc list if present.
1249ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			 */
1250ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			list_del(e);
1251ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			list_add_tail(e, &ep_list);
1252ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		}
1253ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		/* Gather IN endpoints.
1254ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		 */
1255ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		if ((mask & (1<<(i+OZ_NB_ENDPOINTS))) && port->in_ep[i]) {
1256ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			e = &port->in_ep[i]->link;
1257ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			port->in_ep[i] = 0;
1258ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			list_del(e);
1259ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			list_add_tail(e, &ep_list);
1260ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		}
1261ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
1262ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	spin_unlock_bh(&ozhcd->hcd_lock);
1263ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	while (!list_empty(&ep_list)) {
1264ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		struct oz_endpoint *ep =
1265ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			list_first_entry(&ep_list, struct oz_endpoint, link);
1266ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		list_del_init(&ep->link);
1267ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_ep_free(port, ep);
1268ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
1269ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly}
1270ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
1271ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Context: softirq
1272ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
1273ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic int oz_build_endpoints_for_config(struct usb_hcd *hcd,
1274ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		struct oz_port *port, struct usb_host_config *config,
1275ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		gfp_t mem_flags)
1276ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly{
1277ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct oz_hcd *ozhcd = port->ozhcd;
1278ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	int i;
1279ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	int num_iface = config->desc.bNumInterfaces;
1280ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (num_iface) {
12811ec41a31fb695682cab7fc7c1f6ced84d188b6f9Greg Kroah-Hartman		struct oz_interface *iface;
12821ec41a31fb695682cab7fc7c1f6ced84d188b6f9Greg Kroah-Hartman
12831ec41a31fb695682cab7fc7c1f6ced84d188b6f9Greg Kroah-Hartman		iface = kmalloc(num_iface*sizeof(struct oz_interface),
1284ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				mem_flags | __GFP_ZERO);
1285ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		if (!iface)
1286ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			return -ENOMEM;
1287ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		spin_lock_bh(&ozhcd->hcd_lock);
1288ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		port->iface = iface;
1289ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		port->num_iface = num_iface;
1290ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		spin_unlock_bh(&ozhcd->hcd_lock);
1291ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
1292ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	for (i = 0; i < num_iface; i++) {
1293ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		struct usb_host_interface *intf =
1294ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			&config->intf_cache[i]->altsetting[0];
1295ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		if (oz_build_endpoints_for_interface(hcd, port, intf,
1296ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			mem_flags))
1297ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			goto fail;
1298ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
1299ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	return 0;
1300ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellyfail:
1301ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	oz_clean_endpoints_for_config(hcd, port);
1302ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	return -1;
1303ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly}
1304ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
1305ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Context: softirq
1306ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
1307ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic void oz_clean_endpoints_for_config(struct usb_hcd *hcd,
1308ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			struct oz_port *port)
1309ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly{
1310ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct oz_hcd *ozhcd = port->ozhcd;
1311ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	int i;
1312ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	oz_trace("Deleting endpoints for configuration.\n");
1313ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	for (i = 0; i < port->num_iface; i++)
1314ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_clean_endpoints_for_interface(hcd, port, i);
1315ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	spin_lock_bh(&ozhcd->hcd_lock);
1316ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (port->iface) {
1317ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace("Freeing interfaces object.\n");
13181ec41a31fb695682cab7fc7c1f6ced84d188b6f9Greg Kroah-Hartman		kfree(port->iface);
1319ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		port->iface = 0;
1320ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
1321ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	port->num_iface = 0;
1322ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	spin_unlock_bh(&ozhcd->hcd_lock);
1323ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly}
1324ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
1325ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Context: tasklet
1326ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
1327ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic void *oz_claim_hpd(struct oz_port *port)
1328ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly{
1329ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	void *hpd = 0;
1330ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct oz_hcd *ozhcd = port->ozhcd;
1331ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	spin_lock_bh(&ozhcd->hcd_lock);
1332ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	hpd = port->hpd;
1333ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (hpd)
1334ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_usb_get(hpd);
1335ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	spin_unlock_bh(&ozhcd->hcd_lock);
1336ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	return hpd;
1337ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly}
1338ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
1339ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Context: tasklet
1340ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
1341ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic void oz_process_ep0_urb(struct oz_hcd *ozhcd, struct urb *urb,
1342ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		gfp_t mem_flags)
1343ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly{
1344ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct usb_ctrlrequest *setup;
1345ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	unsigned windex;
1346ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	unsigned wvalue;
1347ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	unsigned wlength;
1348ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	void *hpd = 0;
1349ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	u8 req_id;
1350ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	int rc = 0;
1351ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	unsigned complete = 0;
1352ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly
1353ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	int port_ix = -1;
1354ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct oz_port *port = 0;
1355ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly
1356ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	oz_trace2(OZ_TRACE_URB, "%lu: oz_process_ep0_urb(%p)\n", jiffies, urb);
1357ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	port_ix = oz_get_port_from_addr(ozhcd, urb->dev->devnum);
1358ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (port_ix < 0) {
1359ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		rc = -EPIPE;
1360ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		goto out;
1361ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
1362ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	port =  &ozhcd->ports[port_ix];
1363ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (((port->flags & OZ_PORT_F_PRESENT) == 0)
1364ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		|| (port->flags & OZ_PORT_F_DYING)) {
1365ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace("Refusing URB port_ix = %d devnum = %d\n",
1366ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			port_ix, urb->dev->devnum);
1367ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		rc = -EPIPE;
1368ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		goto out;
1369ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
1370ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	/* Store port in private context data.
1371ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	 */
1372ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	urb->hcpriv = port;
1373ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	setup = (struct usb_ctrlrequest *)urb->setup_packet;
1374ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	windex = le16_to_cpu(setup->wIndex);
1375ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	wvalue = le16_to_cpu(setup->wValue);
1376ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	wlength = le16_to_cpu(setup->wLength);
1377ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	oz_trace2(OZ_TRACE_CTRL_DETAIL, "bRequestType = %x\n",
1378ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		setup->bRequestType);
1379ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	oz_trace2(OZ_TRACE_CTRL_DETAIL, "bRequest = %x\n", setup->bRequest);
1380ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	oz_trace2(OZ_TRACE_CTRL_DETAIL, "wValue = %x\n", wvalue);
1381ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	oz_trace2(OZ_TRACE_CTRL_DETAIL, "wIndex = %x\n", windex);
1382ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	oz_trace2(OZ_TRACE_CTRL_DETAIL, "wLength = %x\n", wlength);
1383ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly
1384ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	req_id = port->next_req_id++;
1385ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	hpd = oz_claim_hpd(port);
1386ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (hpd == 0) {
1387ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace("Cannot claim port\n");
1388ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		rc = -EPIPE;
1389ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		goto out;
1390ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
1391ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly
1392ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if ((setup->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
1393ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		/* Standard requests
1394ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		 */
1395ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		switch (setup->bRequest) {
1396ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		case USB_REQ_GET_DESCRIPTOR:
1397ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			oz_trace("USB_REQ_GET_DESCRIPTOR - req\n");
1398ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			break;
1399ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		case USB_REQ_SET_ADDRESS:
1400ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			oz_event_log(OZ_EVT_CTRL_LOCAL, setup->bRequest,
1401ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				0, 0, setup->bRequestType);
1402ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			oz_trace("USB_REQ_SET_ADDRESS - req\n");
1403ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			oz_trace("Port %d address is 0x%x\n", ozhcd->conn_port,
1404ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				(u8)le16_to_cpu(setup->wValue));
1405ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			spin_lock_bh(&ozhcd->hcd_lock);
1406ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			if (ozhcd->conn_port >= 0) {
1407ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				ozhcd->ports[ozhcd->conn_port].bus_addr =
1408ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly					(u8)le16_to_cpu(setup->wValue);
1409ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				oz_trace("Clearing conn_port\n");
1410ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				ozhcd->conn_port = -1;
1411ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			}
1412ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			spin_unlock_bh(&ozhcd->hcd_lock);
1413ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			complete = 1;
1414ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			break;
1415ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		case USB_REQ_SET_CONFIGURATION:
1416ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			oz_trace("USB_REQ_SET_CONFIGURATION - req\n");
1417ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			break;
1418ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		case USB_REQ_GET_CONFIGURATION:
1419ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			/* We short curcuit this case and reply directly since
1420ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			 * we have the selected configuration number cached.
1421ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			 */
1422ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			oz_event_log(OZ_EVT_CTRL_LOCAL, setup->bRequest, 0, 0,
1423ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				setup->bRequestType);
1424ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			oz_trace("USB_REQ_GET_CONFIGURATION - reply now\n");
1425ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			if (urb->transfer_buffer_length >= 1) {
1426ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				urb->actual_length = 1;
1427ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				*((u8 *)urb->transfer_buffer) =
1428ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly					port->config_num;
1429ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				complete = 1;
1430ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			} else {
1431ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				rc = -EPIPE;
1432ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			}
1433ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			break;
1434ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		case USB_REQ_GET_INTERFACE:
1435ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			/* We short curcuit this case and reply directly since
1436ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			 * we have the selected interface alternative cached.
1437ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			 */
1438ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			oz_event_log(OZ_EVT_CTRL_LOCAL, setup->bRequest, 0, 0,
1439ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				setup->bRequestType);
1440ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			oz_trace("USB_REQ_GET_INTERFACE - reply now\n");
1441ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			if (urb->transfer_buffer_length >= 1) {
1442ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				urb->actual_length = 1;
1443ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				*((u8 *)urb->transfer_buffer) =
1444ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly					port->iface[(u8)windex].alt;
1445ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				oz_trace("interface = %d alt = %d\n",
1446ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly					windex, port->iface[(u8)windex].alt);
1447ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				complete = 1;
1448ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			} else {
1449ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				rc = -EPIPE;
1450ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			}
1451ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			break;
1452ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		case USB_REQ_SET_INTERFACE:
1453ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			oz_trace("USB_REQ_SET_INTERFACE - req\n");
1454ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			break;
1455ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		}
1456ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
1457ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (!rc && !complete) {
1458ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		int data_len = 0;
1459ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		if ((setup->bRequestType & USB_DIR_IN) == 0)
1460ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			data_len = wlength;
1461ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		if (oz_usb_control_req(port->hpd, req_id, setup,
1462ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				urb->transfer_buffer, data_len)) {
1463ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			rc = -ENOMEM;
1464ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		} else {
1465ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			/* Note: we are queuing the request after we have
1466ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			 * submitted it to be tranmitted. If the request were
1467ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			 * to complete before we queued it then it would not
1468ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			 * be found in the queue. It seems impossible for
1469ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			 * this to happen but if it did the request would
1470ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			 * be resubmitted so the problem would hopefully
1471ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			 * resolve itself. Putting the request into the
1472ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			 * queue before it has been sent is worse since the
1473ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			 * urb could be cancelled while we are using it
1474ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			 * to build the request.
1475ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			 */
1476ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			if (oz_enqueue_ep_urb(port, 0, 0, urb, req_id))
1477ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				rc = -ENOMEM;
1478ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		}
1479ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
1480ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	oz_usb_put(hpd);
1481ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellyout:
1482ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (rc || complete) {
1483ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace("Completing request locally\n");
1484ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_complete_urb(ozhcd->hcd, urb, rc, 0);
1485ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	} else {
1486ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_usb_request_heartbeat(port->hpd);
1487ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
1488ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly}
1489ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
1490ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Context: tasklet
1491ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
1492ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic int oz_urb_process(struct oz_hcd *ozhcd, struct urb *urb)
1493ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly{
1494ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	int rc = 0;
1495ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct oz_port *port = urb->hcpriv;
1496ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	u8 ep_addr;
1497ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	/* When we are paranoid we keep a list of urbs which we check against
1498ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	 * before handing one back. This is just for debugging during
1499ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	 * development and should be turned off in the released driver.
1500ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	 */
1501ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	oz_remember_urb(urb);
1502ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	/* Check buffer is valid.
1503ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	 */
1504ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (!urb->transfer_buffer && urb->transfer_buffer_length)
1505ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		return -EINVAL;
1506ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	/* Check if there is a device at the port - refuse if not.
1507ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	 */
1508ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if ((port->flags & OZ_PORT_F_PRESENT) == 0)
1509ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		return -EPIPE;
1510ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	ep_addr = usb_pipeendpoint(urb->pipe);
1511ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (ep_addr) {
1512ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		/* If the request is not for EP0 then queue it.
1513ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		 */
1514ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		if (oz_enqueue_ep_urb(port, ep_addr, usb_pipein(urb->pipe),
1515ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			urb, 0))
1516ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			rc = -EPIPE;
1517ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	} else {
1518ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_process_ep0_urb(ozhcd, urb, GFP_ATOMIC);
1519ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
1520ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	return rc;
1521ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly}
1522ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
1523ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Context: tasklet
1524ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
1525ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic void oz_urb_process_tasklet(unsigned long unused)
1526ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly{
1527ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	unsigned long irq_state;
1528ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct urb *urb;
1529ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct oz_hcd *ozhcd = oz_hcd_claim();
1530ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	int rc = 0;
1531ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (ozhcd == 0)
1532ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		return;
1533ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	/* This is called from a tasklet so is in softirq context but the urb
1534ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	 * list is filled from any context so we need to lock
1535ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	 * appropriately while removing urbs.
1536ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	 */
1537ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	spin_lock_irqsave(&g_tasklet_lock, irq_state);
1538ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	while (!list_empty(&ozhcd->urb_pending_list)) {
1539ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		struct oz_urb_link *urbl =
1540ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			list_first_entry(&ozhcd->urb_pending_list,
1541ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				struct oz_urb_link, link);
1542ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		list_del_init(&urbl->link);
1543ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		spin_unlock_irqrestore(&g_tasklet_lock, irq_state);
1544ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		urb = urbl->urb;
1545ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_free_urb_link(urbl);
1546ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		rc = oz_urb_process(ozhcd, urb);
1547ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		if (rc)
1548ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			oz_complete_urb(ozhcd->hcd, urb, rc, 0);
1549ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		spin_lock_irqsave(&g_tasklet_lock, irq_state);
1550ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
1551ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	spin_unlock_irqrestore(&g_tasklet_lock, irq_state);
1552ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	oz_hcd_put(ozhcd);
1553ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly}
1554ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
1555ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * This function searches for the urb in any of the lists it could be in.
1556ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * If it is found it is removed from the list and completed. If the urb is
1557ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * being processed then it won't be in a list so won't be found. However, the
1558ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * call to usb_hcd_check_unlink_urb() will set the value of the unlinked field
1559ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * to a non-zero value. When an attempt is made to put the urb back in a list
1560ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * the unlinked field will be checked and the urb will then be completed.
1561ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Context: tasklet
1562ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
1563ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic void oz_urb_cancel(struct oz_port *port, u8 ep_num, struct urb *urb)
1564ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly{
1565ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct oz_urb_link *urbl = 0;
1566ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct list_head *e;
1567ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct oz_hcd *ozhcd;
1568ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	unsigned long irq_state;
1569ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	u8 ix;
1570ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (port == 0) {
1571ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace("ERRORERROR: oz_urb_cancel(%p) port is null\n", urb);
1572ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		return;
1573ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
1574ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	ozhcd = port->ozhcd;
1575ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (ozhcd == 0) {
1576ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace("ERRORERROR: oz_urb_cancel(%p) ozhcd is null\n", urb);
1577ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		return;
1578ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
1579ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly
1580ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	/* Look in the tasklet queue.
1581ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	 */
1582ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	spin_lock_irqsave(&g_tasklet_lock, irq_state);
1583ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	list_for_each(e, &ozhcd->urb_cancel_list) {
1584ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		urbl = container_of(e, struct oz_urb_link, link);
1585ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		if (urb == urbl->urb) {
1586ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			list_del_init(e);
1587ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			spin_unlock_irqrestore(&g_tasklet_lock, irq_state);
1588ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			goto out2;
1589ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		}
1590ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
1591ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	spin_unlock_irqrestore(&g_tasklet_lock, irq_state);
1592ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	urbl = 0;
1593ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly
1594ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	/* Look in the orphanage.
1595ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	 */
1596ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	spin_lock_irqsave(&ozhcd->hcd_lock, irq_state);
1597ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	list_for_each(e, &ozhcd->orphanage) {
1598ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		urbl = container_of(e, struct oz_urb_link, link);
1599ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		if (urbl->urb == urb) {
1600ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			list_del(e);
1601ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			oz_trace("Found urb in orphanage\n");
1602ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			goto out;
1603ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		}
1604ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
1605ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	ix = (ep_num & 0xf);
1606ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	urbl = 0;
1607ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if ((ep_num & USB_DIR_IN) && ix)
1608ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		urbl = oz_remove_urb(port->in_ep[ix], urb);
1609ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	else
1610ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		urbl = oz_remove_urb(port->out_ep[ix], urb);
1611ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellyout:
1612ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	spin_unlock_irqrestore(&ozhcd->hcd_lock, irq_state);
1613ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellyout2:
1614ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (urbl) {
1615ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		urb->actual_length = 0;
1616ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_free_urb_link(urbl);
1617ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_complete_urb(ozhcd->hcd, urb, -EPIPE, 0);
1618ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
1619ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly}
1620ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
1621ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Context: tasklet
1622ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
1623ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic void oz_urb_cancel_tasklet(unsigned long unused)
1624ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly{
1625ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	unsigned long irq_state;
1626ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct urb *urb;
1627ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct oz_hcd *ozhcd = oz_hcd_claim();
1628ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (ozhcd == 0)
1629ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		return;
1630ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	spin_lock_irqsave(&g_tasklet_lock, irq_state);
1631ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	while (!list_empty(&ozhcd->urb_cancel_list)) {
1632ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		struct oz_urb_link *urbl =
1633ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			list_first_entry(&ozhcd->urb_cancel_list,
1634ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				struct oz_urb_link, link);
1635ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		list_del_init(&urbl->link);
1636ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		spin_unlock_irqrestore(&g_tasklet_lock, irq_state);
1637ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		urb = urbl->urb;
1638ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		if (urb->unlinked)
1639ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			oz_urb_cancel(urbl->port, urbl->ep_num, urb);
1640ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_free_urb_link(urbl);
1641ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		spin_lock_irqsave(&g_tasklet_lock, irq_state);
1642ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
1643ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	spin_unlock_irqrestore(&g_tasklet_lock, irq_state);
1644ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	oz_hcd_put(ozhcd);
1645ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly}
1646ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
1647ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Context: unknown
1648ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
1649ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic void oz_hcd_clear_orphanage(struct oz_hcd *ozhcd, int status)
1650ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly{
1651ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (ozhcd) {
1652ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		struct oz_urb_link *urbl;
1653ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		while (!list_empty(&ozhcd->orphanage)) {
1654ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			urbl = list_first_entry(&ozhcd->orphanage,
1655ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				struct oz_urb_link, link);
1656ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			list_del(&urbl->link);
1657ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			oz_complete_urb(ozhcd->hcd, urbl->urb, status, 0);
1658ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			oz_free_urb_link(urbl);
1659ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		}
1660ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
1661ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly}
1662ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
1663ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Context: unknown
1664ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
1665ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic int oz_hcd_start(struct usb_hcd *hcd)
1666ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly{
1667ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	oz_trace("oz_hcd_start()\n");
1668ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	hcd->power_budget = 200;
1669ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	hcd->state = HC_STATE_RUNNING;
1670ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	hcd->uses_new_polling = 1;
1671ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	return 0;
1672ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly}
1673ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
1674ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Context: unknown
1675ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
1676ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic void oz_hcd_stop(struct usb_hcd *hcd)
1677ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly{
1678ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	oz_trace("oz_hcd_stop()\n");
1679ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly}
1680ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
1681ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Context: unknown
1682ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
1683ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic void oz_hcd_shutdown(struct usb_hcd *hcd)
1684ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly{
1685ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	oz_trace("oz_hcd_shutdown()\n");
1686ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly}
1687ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
1688ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Context: any
1689ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
1690ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly#ifdef WANT_EVENT_TRACE
1691ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic u8 oz_get_irq_ctx(void)
1692ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly{
1693ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	u8 irq_info = 0;
1694ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (in_interrupt())
1695ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		irq_info |= 1;
1696ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (in_irq())
1697ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		irq_info |= 2;
1698ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	return irq_info;
1699ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly}
1700ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly#endif /* WANT_EVENT_TRACE */
1701ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
1702ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Called to queue an urb for the device.
1703ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * This function should return a non-zero error code if it fails the urb but
1704ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * should not call usb_hcd_giveback_urb().
1705ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Context: any
1706ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
1707ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic int oz_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
1708ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				gfp_t mem_flags)
1709ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly{
1710ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct oz_hcd *ozhcd = oz_hcd_private(hcd);
1711ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	int rc = 0;
1712ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	int port_ix;
1713ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct oz_port *port;
1714ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	unsigned long irq_state;
1715ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct oz_urb_link *urbl;
1716ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	oz_trace2(OZ_TRACE_URB, "%lu: oz_hcd_urb_enqueue(%p)\n",
1717ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		jiffies, urb);
1718ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	oz_event_log(OZ_EVT_URB_SUBMIT, oz_get_irq_ctx(),
1719ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		(u16)urb->number_of_packets, urb, urb->pipe);
1720ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (unlikely(ozhcd == 0)) {
1721ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace2(OZ_TRACE_URB, "%lu: Refused urb(%p) not ozhcd.\n",
1722ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			jiffies, urb);
1723ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		return -EPIPE;
1724ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
1725ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (unlikely(hcd->state != HC_STATE_RUNNING)) {
1726ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace2(OZ_TRACE_URB, "%lu: Refused urb(%p) not running.\n",
1727ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			jiffies, urb);
1728ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		return -EPIPE;
1729ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
1730ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	port_ix = oz_get_port_from_addr(ozhcd, urb->dev->devnum);
1731ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (port_ix < 0)
1732ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		return -EPIPE;
1733ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	port =  &ozhcd->ports[port_ix];
1734ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (port == 0)
1735ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		return -EPIPE;
1736ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if ((port->flags & OZ_PORT_F_PRESENT) == 0) {
1737ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace("Refusing URB port_ix = %d devnum = %d\n",
1738ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			port_ix, urb->dev->devnum);
1739ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		return -EPIPE;
1740ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
1741ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	urb->hcpriv = port;
1742ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	/* Put request in queue for processing by tasklet.
1743ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	 */
1744ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	urbl = oz_alloc_urb_link();
1745ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (unlikely(urbl == 0))
1746ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		return -ENOMEM;
1747ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	urbl->urb = urb;
1748ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	spin_lock_irqsave(&g_tasklet_lock, irq_state);
1749ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	rc = usb_hcd_link_urb_to_ep(hcd, urb);
1750ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (unlikely(rc)) {
1751ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		spin_unlock_irqrestore(&g_tasklet_lock, irq_state);
1752ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_free_urb_link(urbl);
1753ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		return rc;
1754ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
1755ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	list_add_tail(&urbl->link, &ozhcd->urb_pending_list);
1756ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	spin_unlock_irqrestore(&g_tasklet_lock, irq_state);
1757ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	tasklet_schedule(&g_urb_process_tasklet);
1758ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	atomic_inc(&g_pending_urbs);
1759ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	return 0;
1760ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly}
1761ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
1762ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Context: tasklet
1763ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
1764ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic struct oz_urb_link *oz_remove_urb(struct oz_endpoint *ep,
1765ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				struct urb *urb)
1766ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly{
1767ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct oz_urb_link *urbl = 0;
1768ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct list_head *e;
1769ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (unlikely(ep == 0))
1770ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		return 0;
1771ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	list_for_each(e, &ep->urb_list) {
1772ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		urbl = container_of(e, struct oz_urb_link, link);
1773ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		if (urbl->urb == urb) {
1774ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			list_del_init(e);
1775ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			if (usb_pipeisoc(urb->pipe)) {
1776ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				ep->credit -= urb->number_of_packets;
1777ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				if (ep->credit < 0)
1778ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly					ep->credit = 0;
1779ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				oz_event_log(OZ_EVT_EP_CREDIT,
1780ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly					usb_pipein(urb->pipe) ?
1781ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly					(ep->ep_num | USB_DIR_IN) : ep->ep_num,
1782ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly					0, 0, ep->credit);
1783ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			}
1784ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			return urbl;
1785ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		}
1786ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
1787ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	return 0;
1788ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly}
1789ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
1790ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Called to dequeue a previously submitted urb for the device.
1791ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Context: any
1792ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
1793ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic int oz_hcd_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
1794ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly{
1795ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct oz_hcd *ozhcd = oz_hcd_private(hcd);
1796ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct oz_urb_link *urbl = 0;
1797ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	int rc;
1798ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	unsigned long irq_state;
1799ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	oz_trace2(OZ_TRACE_URB, "%lu: oz_hcd_urb_dequeue(%p)\n", jiffies, urb);
1800ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	urbl = oz_alloc_urb_link();
1801ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (unlikely(urbl == 0))
1802ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		return -ENOMEM;
1803ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	spin_lock_irqsave(&g_tasklet_lock, irq_state);
1804ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	/* The following function checks the urb is still in the queue
1805ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	 * maintained by the core and that the unlinked field is zero.
1806ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	 * If both are true the function sets the unlinked field and returns
1807ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	 * zero. Otherwise it returns an error.
1808ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	 */
1809ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	rc = usb_hcd_check_unlink_urb(hcd, urb, status);
1810ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	/* We have to check we haven't completed the urb or are about
1811ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	 * to complete it. When we do we set hcpriv to 0 so if this has
1812ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	 * already happened we don't put the urb in the cancel queue.
1813ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	 */
1814ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if ((rc == 0) && urb->hcpriv) {
1815ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		urbl->urb = urb;
1816ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		urbl->port = (struct oz_port *)urb->hcpriv;
1817ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		urbl->ep_num = usb_pipeendpoint(urb->pipe);
1818ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		if (usb_pipein(urb->pipe))
1819ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			urbl->ep_num |= USB_DIR_IN;
1820ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		list_add_tail(&urbl->link, &ozhcd->urb_cancel_list);
1821ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		spin_unlock_irqrestore(&g_tasklet_lock, irq_state);
1822ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		tasklet_schedule(&g_urb_cancel_tasklet);
1823ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	} else {
1824ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		spin_unlock_irqrestore(&g_tasklet_lock, irq_state);
1825ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_free_urb_link(urbl);
1826ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
1827ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	return rc;
1828ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly}
1829ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
1830ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Context: unknown
1831ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
1832ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic void oz_hcd_endpoint_disable(struct usb_hcd *hcd,
1833ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				struct usb_host_endpoint *ep)
1834ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly{
1835ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	oz_trace("oz_hcd_endpoint_disable\n");
1836ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly}
1837ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
1838ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Context: unknown
1839ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
1840ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic void oz_hcd_endpoint_reset(struct usb_hcd *hcd,
1841ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				struct usb_host_endpoint *ep)
1842ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly{
1843ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	oz_trace("oz_hcd_endpoint_reset\n");
1844ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly}
1845ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
1846ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Context: unknown
1847ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
1848ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic int oz_hcd_get_frame_number(struct usb_hcd *hcd)
1849ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly{
1850ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	oz_trace("oz_hcd_get_frame_number\n");
1851ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	return oz_usb_get_frame_number();
1852ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly}
1853ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
1854ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Context: softirq
1855ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * This is called as a consquence of us calling usb_hcd_poll_rh_status() and we
1856ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * always do that in softirq context.
1857ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
1858ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic int oz_hcd_hub_status_data(struct usb_hcd *hcd, char *buf)
1859ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly{
1860ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct oz_hcd *ozhcd = oz_hcd_private(hcd);
1861ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	int i;
1862ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly
1863ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	oz_trace2(OZ_TRACE_HUB, "oz_hcd_hub_status_data()\n");
1864ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	buf[0] = 0;
1865ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly
1866ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	spin_lock_bh(&ozhcd->hcd_lock);
1867ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	for (i = 0; i < OZ_NB_PORTS; i++) {
1868ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		if (ozhcd->ports[i].flags & OZ_PORT_F_CHANGED) {
1869ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			oz_trace2(OZ_TRACE_HUB, "Port %d changed\n", i);
1870ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			ozhcd->ports[i].flags &= ~OZ_PORT_F_CHANGED;
1871ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			buf[0] |= 1<<(i+1);
1872ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		}
1873ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
1874ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	spin_unlock_bh(&ozhcd->hcd_lock);
1875ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	return buf[0] ? 1 : 0;
1876ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly}
1877ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
1878ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Context: process
1879ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
1880ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic void oz_get_hub_descriptor(struct usb_hcd *hcd,
1881ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				struct usb_hub_descriptor *desc)
1882ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly{
1883ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	oz_trace2(OZ_TRACE_HUB, "GetHubDescriptor\n");
1884ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	memset(desc, 0, sizeof(*desc));
1885ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	desc->bDescriptorType = 0x29;
1886ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	desc->bDescLength = 9;
1887ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	desc->wHubCharacteristics = (__force __u16)
1888ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			__constant_cpu_to_le16(0x0001);
1889ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	desc->bNbrPorts = OZ_NB_PORTS;
1890ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly}
1891ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
1892ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Context: process
1893ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
1894ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic int oz_set_port_feature(struct usb_hcd *hcd, u16 wvalue, u16 windex)
1895ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly{
1896ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct oz_port *port;
1897ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	int err = 0;
1898ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	u8 port_id = (u8)windex;
1899ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct oz_hcd *ozhcd = oz_hcd_private(hcd);
1900ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	unsigned set_bits = 0;
1901ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	unsigned clear_bits = 0;
1902ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	oz_trace2(OZ_TRACE_HUB, "SetPortFeature\n");
1903ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if ((port_id < 1) || (port_id > OZ_NB_PORTS))
1904ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		return -EPIPE;
1905ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	port = &ozhcd->ports[port_id-1];
1906ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	switch (wvalue) {
1907ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	case USB_PORT_FEAT_CONNECTION:
1908ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_CONNECTION\n");
1909ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		break;
1910ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	case USB_PORT_FEAT_ENABLE:
1911ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_ENABLE\n");
1912ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		break;
1913ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	case USB_PORT_FEAT_SUSPEND:
1914ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_SUSPEND\n");
1915ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		break;
1916ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	case USB_PORT_FEAT_OVER_CURRENT:
1917ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_OVER_CURRENT\n");
1918ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		break;
1919ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	case USB_PORT_FEAT_RESET:
1920ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_RESET\n");
1921ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		set_bits = USB_PORT_STAT_ENABLE | (USB_PORT_STAT_C_RESET<<16);
1922ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		clear_bits = USB_PORT_STAT_RESET;
1923ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		ozhcd->ports[port_id-1].bus_addr = 0;
1924ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		break;
1925ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	case USB_PORT_FEAT_POWER:
1926ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_POWER\n");
1927ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		set_bits |= USB_PORT_STAT_POWER;
1928ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		break;
1929ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	case USB_PORT_FEAT_LOWSPEED:
1930ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_LOWSPEED\n");
1931ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		break;
1932ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	case USB_PORT_FEAT_C_CONNECTION:
1933ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_C_CONNECTION\n");
1934ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		break;
1935ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	case USB_PORT_FEAT_C_ENABLE:
1936ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_C_ENABLE\n");
1937ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		break;
1938ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	case USB_PORT_FEAT_C_SUSPEND:
1939ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_C_SUSPEND\n");
1940ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		break;
1941ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	case USB_PORT_FEAT_C_OVER_CURRENT:
1942ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_C_OVER_CURRENT\n");
1943ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		break;
1944ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	case USB_PORT_FEAT_C_RESET:
1945ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_C_RESET\n");
1946ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		break;
1947ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	case USB_PORT_FEAT_TEST:
1948ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_TEST\n");
1949ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		break;
1950ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	case USB_PORT_FEAT_INDICATOR:
1951ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_INDICATOR\n");
1952ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		break;
1953ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	default:
1954ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace2(OZ_TRACE_HUB, "Other %d\n", wvalue);
1955ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		break;
1956ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
1957ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (set_bits || clear_bits) {
1958ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		spin_lock_bh(&port->port_lock);
1959ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		port->status &= ~clear_bits;
1960ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		port->status |= set_bits;
1961ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		spin_unlock_bh(&port->port_lock);
1962ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
1963ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	oz_trace2(OZ_TRACE_HUB, "Port[%d] status = 0x%x\n", port_id,
1964ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		port->status);
1965ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	return err;
1966ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly}
1967ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
1968ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Context: process
1969ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
1970ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic int oz_clear_port_feature(struct usb_hcd *hcd, u16 wvalue, u16 windex)
1971ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly{
1972ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct oz_port *port;
1973ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	int err = 0;
1974ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	u8 port_id = (u8)windex;
1975ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct oz_hcd *ozhcd = oz_hcd_private(hcd);
1976ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	unsigned clear_bits = 0;
1977ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	oz_trace2(OZ_TRACE_HUB, "ClearPortFeature\n");
1978ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if ((port_id < 1) || (port_id > OZ_NB_PORTS))
1979ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		return -EPIPE;
1980ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	port = &ozhcd->ports[port_id-1];
1981ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	switch (wvalue) {
1982ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	case USB_PORT_FEAT_CONNECTION:
1983ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_CONNECTION\n");
1984ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		break;
1985ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	case USB_PORT_FEAT_ENABLE:
1986ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_ENABLE\n");
1987ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		clear_bits = USB_PORT_STAT_ENABLE;
1988ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		break;
1989ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	case USB_PORT_FEAT_SUSPEND:
1990ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_SUSPEND\n");
1991ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		break;
1992ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	case USB_PORT_FEAT_OVER_CURRENT:
1993ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_OVER_CURRENT\n");
1994ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		break;
1995ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	case USB_PORT_FEAT_RESET:
1996ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_RESET\n");
1997ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		break;
1998ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	case USB_PORT_FEAT_POWER:
1999ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_POWER\n");
2000ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		clear_bits |= USB_PORT_STAT_POWER;
2001ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		break;
2002ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	case USB_PORT_FEAT_LOWSPEED:
2003ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_LOWSPEED\n");
2004ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		break;
2005ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	case USB_PORT_FEAT_C_CONNECTION:
2006ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_C_CONNECTION\n");
2007ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		clear_bits = (USB_PORT_STAT_C_CONNECTION << 16);
2008ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		break;
2009ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	case USB_PORT_FEAT_C_ENABLE:
2010ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_C_ENABLE\n");
2011ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		clear_bits = (USB_PORT_STAT_C_ENABLE << 16);
2012ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		break;
2013ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	case USB_PORT_FEAT_C_SUSPEND:
2014ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_C_SUSPEND\n");
2015ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		break;
2016ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	case USB_PORT_FEAT_C_OVER_CURRENT:
2017ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_C_OVER_CURRENT\n");
2018ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		break;
2019ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	case USB_PORT_FEAT_C_RESET:
2020ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_C_RESET\n");
2021ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		clear_bits = (USB_PORT_FEAT_C_RESET << 16);
2022ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		break;
2023ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	case USB_PORT_FEAT_TEST:
2024ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_TEST\n");
2025ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		break;
2026ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	case USB_PORT_FEAT_INDICATOR:
2027ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_INDICATOR\n");
2028ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		break;
2029ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	default:
2030ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace2(OZ_TRACE_HUB, "Other %d\n", wvalue);
2031ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		break;
2032ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
2033ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (clear_bits) {
2034ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		spin_lock_bh(&port->port_lock);
2035ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		port->status &= ~clear_bits;
2036ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		spin_unlock_bh(&port->port_lock);
2037ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
2038ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	oz_trace2(OZ_TRACE_HUB, "Port[%d] status = 0x%x\n", port_id,
2039ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		ozhcd->ports[port_id-1].status);
2040ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	return err;
2041ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly}
2042ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
2043ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Context: process
2044ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
2045ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic int oz_get_port_status(struct usb_hcd *hcd, u16 windex, char *buf)
2046ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly{
2047ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct oz_hcd *ozhcd;
2048ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	u32 status = 0;
2049ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if ((windex < 1) || (windex > OZ_NB_PORTS))
2050ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		return -EPIPE;
2051ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	ozhcd = oz_hcd_private(hcd);
2052ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	oz_trace2(OZ_TRACE_HUB, "GetPortStatus windex = %d\n", windex);
2053ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	status = ozhcd->ports[windex-1].status;
2054ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	put_unaligned(cpu_to_le32(status), (__le32 *)buf);
2055ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	oz_trace2(OZ_TRACE_HUB, "Port[%d] status = %x\n", windex, status);
2056ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	return 0;
2057ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly}
2058ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
2059ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Context: process
2060ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
2061ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic int oz_hcd_hub_control(struct usb_hcd *hcd, u16 req_type, u16 wvalue,
2062ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly				u16 windex, char *buf, u16 wlength)
2063ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly{
2064ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	int err = 0;
2065ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	oz_trace2(OZ_TRACE_HUB, "oz_hcd_hub_control()\n");
2066ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	switch (req_type) {
2067ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	case ClearHubFeature:
2068ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace2(OZ_TRACE_HUB, "ClearHubFeature: %d\n", req_type);
2069ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		break;
2070ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	case ClearPortFeature:
2071ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		err = oz_clear_port_feature(hcd, wvalue, windex);
2072ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		break;
2073ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	case GetHubDescriptor:
2074ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_get_hub_descriptor(hcd, (struct usb_hub_descriptor *)buf);
2075ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		break;
2076ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	case GetHubStatus:
2077ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace2(OZ_TRACE_HUB, "GetHubStatus: req_type = 0x%x\n",
2078ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly			req_type);
2079ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		put_unaligned(__constant_cpu_to_le32(0), (__le32 *)buf);
2080ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		break;
2081ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	case GetPortStatus:
2082ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		err = oz_get_port_status(hcd, windex, buf);
2083ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		break;
2084ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	case SetHubFeature:
2085ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace2(OZ_TRACE_HUB, "SetHubFeature: %d\n", req_type);
2086ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		break;
2087ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	case SetPortFeature:
2088ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		err = oz_set_port_feature(hcd, wvalue, windex);
2089ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		break;
2090ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	default:
2091ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace2(OZ_TRACE_HUB, "Other: %d\n", req_type);
2092ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		break;
2093ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
2094ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	return err;
2095ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly}
2096ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
2097ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Context: process
2098ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
2099ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic int oz_hcd_bus_suspend(struct usb_hcd *hcd)
2100ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly{
2101ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct oz_hcd *ozhcd;
2102ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	oz_trace2(OZ_TRACE_HUB, "oz_hcd_hub_suspend()\n");
2103ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	ozhcd = oz_hcd_private(hcd);
2104ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	spin_lock_bh(&ozhcd->hcd_lock);
2105ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	hcd->state = HC_STATE_SUSPENDED;
2106ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	ozhcd->flags |= OZ_HDC_F_SUSPENDED;
2107ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	spin_unlock_bh(&ozhcd->hcd_lock);
2108ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	return 0;
2109ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly}
2110ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
2111ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Context: process
2112ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
2113ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic int oz_hcd_bus_resume(struct usb_hcd *hcd)
2114ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly{
2115ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct oz_hcd *ozhcd;
2116ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	oz_trace2(OZ_TRACE_HUB, "oz_hcd_hub_resume()\n");
2117ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	ozhcd = oz_hcd_private(hcd);
2118ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	spin_lock_bh(&ozhcd->hcd_lock);
2119ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	ozhcd->flags &= ~OZ_HDC_F_SUSPENDED;
2120ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	hcd->state = HC_STATE_RUNNING;
2121ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	spin_unlock_bh(&ozhcd->hcd_lock);
2122ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	return 0;
2123ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly}
2124ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
2125ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
2126ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic void oz_plat_shutdown(struct platform_device *dev)
2127ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly{
2128ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	oz_trace("oz_plat_shutdown()\n");
2129ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly}
2130ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
2131ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Context: process
2132ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
2133ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic int oz_plat_probe(struct platform_device *dev)
2134ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly{
2135ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	int i;
2136ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	int err;
2137ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct usb_hcd *hcd;
2138ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct oz_hcd *ozhcd;
2139ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	oz_trace("oz_plat_probe()\n");
2140ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	hcd = usb_create_hcd(&g_oz_hc_drv, &dev->dev, dev_name(&dev->dev));
2141ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (hcd == 0) {
2142ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace("Failed to created hcd object OK\n");
2143ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		return -ENOMEM;
2144ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
2145ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	ozhcd = oz_hcd_private(hcd);
2146ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	memset(ozhcd, 0, sizeof(*ozhcd));
2147ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	INIT_LIST_HEAD(&ozhcd->urb_pending_list);
2148ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	INIT_LIST_HEAD(&ozhcd->urb_cancel_list);
2149ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	INIT_LIST_HEAD(&ozhcd->orphanage);
2150ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	ozhcd->hcd = hcd;
2151ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	ozhcd->conn_port = -1;
2152ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	spin_lock_init(&ozhcd->hcd_lock);
2153ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	for (i = 0; i < OZ_NB_PORTS; i++) {
2154ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		struct oz_port *port = &ozhcd->ports[i];
2155ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		port->ozhcd = ozhcd;
2156ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		port->flags = 0;
2157ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		port->status = 0;
2158ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		port->bus_addr = 0xff;
2159ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		spin_lock_init(&port->port_lock);
2160ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
2161ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	err = usb_add_hcd(hcd, 0, 0);
2162ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (err) {
2163ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		oz_trace("Failed to add hcd object OK\n");
2164ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		usb_put_hcd(hcd);
2165ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		return -1;
2166ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
2167ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	spin_lock_bh(&g_hcdlock);
2168ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	g_ozhcd = ozhcd;
2169ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	spin_unlock_bh(&g_hcdlock);
2170ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	return 0;
2171ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly}
2172ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
2173ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Context: unknown
2174ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
2175ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic int oz_plat_remove(struct platform_device *dev)
2176ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly{
2177ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct usb_hcd *hcd = platform_get_drvdata(dev);
2178ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	struct oz_hcd *ozhcd;
2179ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	oz_trace("oz_plat_remove()\n");
2180ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (hcd == 0)
2181ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		return -1;
2182ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	ozhcd = oz_hcd_private(hcd);
2183ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	spin_lock_bh(&g_hcdlock);
2184ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (ozhcd == g_ozhcd)
2185ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		g_ozhcd = 0;
2186ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	spin_unlock_bh(&g_hcdlock);
2187ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	oz_trace("Clearing orphanage\n");
2188ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	oz_hcd_clear_orphanage(ozhcd, -EPIPE);
2189ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	oz_trace("Removing hcd\n");
2190ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	usb_remove_hcd(hcd);
2191ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	usb_put_hcd(hcd);
2192ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	oz_empty_link_pool();
2193ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	return 0;
2194ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly}
2195ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
2196ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Context: unknown
2197ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
2198ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic int oz_plat_suspend(struct platform_device *dev, pm_message_t msg)
2199ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly{
2200ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	oz_trace("oz_plat_suspend()\n");
2201ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	return 0;
2202ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly}
2203ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
2204ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Context: unknown
2205ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
2206ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellystatic int oz_plat_resume(struct platform_device *dev)
2207ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly{
2208ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	oz_trace("oz_plat_resume()\n");
2209ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	return 0;
2210ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly}
2211ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
2212ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Context: process
2213ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
2214ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellyint oz_hcd_init(void)
2215ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly{
2216ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	int err;
2217ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (usb_disabled())
2218ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		return -ENODEV;
2219ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	tasklet_init(&g_urb_process_tasklet, oz_urb_process_tasklet, 0);
2220ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	tasklet_init(&g_urb_cancel_tasklet, oz_urb_cancel_tasklet, 0);
2221ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	err = platform_driver_register(&g_oz_plat_drv);
2222ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	oz_trace("platform_driver_register() returned %d\n", err);
2223ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (err)
2224ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		goto error;
2225ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	g_plat_dev = platform_device_alloc(OZ_PLAT_DEV_NAME, -1);
2226ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (g_plat_dev == 0) {
2227ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		err = -ENOMEM;
2228ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		goto error1;
2229ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	}
2230ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	oz_trace("platform_device_alloc() succeeded\n");
2231ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	err = platform_device_add(g_plat_dev);
2232ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	if (err)
2233ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly		goto error2;
2234ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	oz_trace("platform_device_add() succeeded\n");
2235ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	return 0;
2236ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellyerror2:
2237ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	platform_device_put(g_plat_dev);
2238ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellyerror1:
2239ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	platform_driver_unregister(&g_oz_plat_drv);
2240ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellyerror:
2241ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	tasklet_disable(&g_urb_process_tasklet);
2242ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	tasklet_disable(&g_urb_cancel_tasklet);
2243ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	oz_trace("oz_hcd_init() failed %d\n", err);
2244ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	return err;
2245ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly}
2246ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly/*------------------------------------------------------------------------------
2247ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly * Context: process
2248ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly */
2249ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kellyvoid oz_hcd_term(void)
2250ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly{
2251ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	tasklet_disable(&g_urb_process_tasklet);
2252ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	tasklet_disable(&g_urb_cancel_tasklet);
2253ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	platform_device_unregister(g_plat_dev);
2254ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	platform_driver_unregister(&g_oz_plat_drv);
2255ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly	oz_trace("Pending urbs:%d\n", atomic_read(&g_pending_urbs));
2256ae926051d7eb8f80dba9513db70d2e2fc8385d3aChris Kelly}
2257