1b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly/* -----------------------------------------------------------------------------
2b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly * Copyright (c) 2011 Ozmo Inc
3b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly * Released under the GNU General Public License Version 2 (GPLv2).
4b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly *
5b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly * This file provides protocol independent part of the implementation of the USB
6b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly * service for a PD.
7b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly * The implementation of this service is split into two parts the first of which
8b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly * is protocol independent and the second contains protocol specific details.
9b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly * This split is to allow alternative protocols to be defined.
10b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly * The implemenation of this service uses ozhcd.c to implement a USB HCD.
11b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly * -----------------------------------------------------------------------------
12b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly */
13b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly#include <linux/init.h>
14b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly#include <linux/module.h>
15b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly#include <linux/timer.h>
16b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly#include <linux/sched.h>
17b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly#include <linux/netdevice.h>
18b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly#include <linux/errno.h>
19b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly#include <linux/input.h>
20b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly#include <asm/unaligned.h>
21b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly#include "ozconfig.h"
22b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly#include "ozprotocol.h"
23b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly#include "ozeltbuf.h"
24b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly#include "ozpd.h"
25b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly#include "ozproto.h"
26b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly#include "ozusbif.h"
27b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly#include "ozhcd.h"
28b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly#include "oztrace.h"
29b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly#include "ozusbsvc.h"
30b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly#include "ozevent.h"
31b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly/*------------------------------------------------------------------------------
32b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly * This is called once when the driver is loaded to initialise the USB service.
33b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly * Context: process
34b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly */
35b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kellyint oz_usb_init(void)
36b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly{
37b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	oz_event_log(OZ_EVT_SERVICE, 1, OZ_APPID_USB, 0, 0);
38b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	return oz_hcd_init();
39b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly}
40b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly/*------------------------------------------------------------------------------
41b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly * This is called once when the driver is unloaded to terminate the USB service.
42b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly * Context: process
43b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly */
44b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kellyvoid oz_usb_term(void)
45b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly{
46b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	oz_event_log(OZ_EVT_SERVICE, 2, OZ_APPID_USB, 0, 0);
47b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	oz_hcd_term();
48b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly}
49b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly/*------------------------------------------------------------------------------
50b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly * This is called when the USB service is started or resumed for a PD.
51b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly * Context: softirq
52b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly */
53b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kellyint oz_usb_start(struct oz_pd *pd, int resume)
54b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly{
55b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	int rc = 0;
56b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	struct oz_usb_ctx *usb_ctx;
57b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	struct oz_usb_ctx *old_ctx = 0;
58b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	oz_event_log(OZ_EVT_SERVICE, 3, OZ_APPID_USB, 0, resume);
59b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	if (resume) {
60b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly		oz_trace("USB service resumed.\n");
61b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly		return 0;
62b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	}
63b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	oz_trace("USB service started.\n");
64b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	/* Create a USB context in case we need one. If we find the PD already
65b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	 * has a USB context then we will destroy it.
66b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	 */
671ec41a31fb695682cab7fc7c1f6ced84d188b6f9Greg Kroah-Hartman	usb_ctx = kzalloc(sizeof(struct oz_usb_ctx), GFP_ATOMIC);
68b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	if (usb_ctx == 0)
691ec41a31fb695682cab7fc7c1f6ced84d188b6f9Greg Kroah-Hartman		return -ENOMEM;
70b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	atomic_set(&usb_ctx->ref_count, 1);
71b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	usb_ctx->pd = pd;
72b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	usb_ctx->stopped = 0;
73b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	/* Install the USB context if the PD doesn't already have one.
74b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	 * If it does already have one then destroy the one we have just
75b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	 * created.
76b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	 */
77b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	spin_lock_bh(&pd->app_lock[OZ_APPID_USB-1]);
78b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	old_ctx = pd->app_ctx[OZ_APPID_USB-1];
79b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	if (old_ctx == 0)
80b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly		pd->app_ctx[OZ_APPID_USB-1] = usb_ctx;
81b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	oz_usb_get(pd->app_ctx[OZ_APPID_USB-1]);
82b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	spin_unlock_bh(&pd->app_lock[OZ_APPID_USB-1]);
83b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	if (old_ctx) {
84b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly		oz_trace("Already have USB context.\n");
851ec41a31fb695682cab7fc7c1f6ced84d188b6f9Greg Kroah-Hartman		kfree(usb_ctx);
86b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly		usb_ctx = old_ctx;
87b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	} else if (usb_ctx) {
88b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly		/* Take a reference to the PD. This will be released when
89b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly		 * the USB context is destroyed.
90b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly		 */
91b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly		oz_pd_get(pd);
92b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	}
93b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	/* If we already had a USB context and had obtained a port from
94b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	 * the USB HCD then just reset the port. If we didn't have a port
95b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	 * then report the arrival to the USB HCD so we get one.
96b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	 */
97b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	if (usb_ctx->hport) {
98b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly		oz_hcd_pd_reset(usb_ctx, usb_ctx->hport);
99b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	} else {
100b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly		usb_ctx->hport = oz_hcd_pd_arrived(usb_ctx);
101b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly		if (usb_ctx->hport == 0) {
102b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly			oz_trace("USB hub returned null port.\n");
103b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly			spin_lock_bh(&pd->app_lock[OZ_APPID_USB-1]);
104b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly			pd->app_ctx[OZ_APPID_USB-1] = 0;
105b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly			spin_unlock_bh(&pd->app_lock[OZ_APPID_USB-1]);
106b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly			oz_usb_put(usb_ctx);
107b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly			rc = -1;
108b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly		}
109b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	}
110b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	oz_usb_put(usb_ctx);
111b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	return rc;
112b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly}
113b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly/*------------------------------------------------------------------------------
114b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly * This is called when the USB service is stopped or paused for a PD.
115b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly * Context: softirq or process
116b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly */
117b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kellyvoid oz_usb_stop(struct oz_pd *pd, int pause)
118b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly{
119b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	struct oz_usb_ctx *usb_ctx;
120b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	oz_event_log(OZ_EVT_SERVICE, 4, OZ_APPID_USB, 0, pause);
121b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	if (pause) {
122b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly		oz_trace("USB service paused.\n");
123b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly		return;
124b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	}
125b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	spin_lock_bh(&pd->app_lock[OZ_APPID_USB-1]);
126b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	usb_ctx = (struct oz_usb_ctx *)pd->app_ctx[OZ_APPID_USB-1];
127b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	pd->app_ctx[OZ_APPID_USB-1] = 0;
128b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	spin_unlock_bh(&pd->app_lock[OZ_APPID_USB-1]);
129b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	if (usb_ctx) {
130b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly		unsigned long tout = jiffies + HZ;
131b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly		oz_trace("USB service stopping...\n");
132b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly		usb_ctx->stopped = 1;
133b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly		/* At this point the reference count on the usb context should
134b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly		 * be 2 - one from when we created it and one from the hcd
135b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly		 * which claims a reference. Since stopped = 1 no one else
136b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly		 * should get in but someone may already be in. So wait
137b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly		 * until they leave but timeout after 1 second.
138b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly		 */
139b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly		while ((atomic_read(&usb_ctx->ref_count) > 2) &&
140b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly			time_before(jiffies, tout))
141b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly			;
142b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly		oz_trace("USB service stopped.\n");
143b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly		oz_hcd_pd_departed(usb_ctx->hport);
144b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly		/* Release the reference taken in oz_usb_start.
145b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly		 */
146b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly		oz_usb_put(usb_ctx);
147b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	}
148b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly}
149b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly/*------------------------------------------------------------------------------
150b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly * This increments the reference count of the context area for a specific PD.
151b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly * This ensures this context area does not disappear while still in use.
152b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly * Context: softirq
153b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly */
154b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kellyvoid oz_usb_get(void *hpd)
155b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly{
156b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	struct oz_usb_ctx *usb_ctx = (struct oz_usb_ctx *)hpd;
157b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	atomic_inc(&usb_ctx->ref_count);
158b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly}
159b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly/*------------------------------------------------------------------------------
160b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly * This decrements the reference count of the context area for a specific PD
161b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly * and destroys the context area if the reference count becomes zero.
162b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly * Context: softirq or process
163b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly */
164b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kellyvoid oz_usb_put(void *hpd)
165b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly{
166b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	struct oz_usb_ctx *usb_ctx = (struct oz_usb_ctx *)hpd;
167b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	if (atomic_dec_and_test(&usb_ctx->ref_count)) {
168b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly		oz_trace("Dealloc USB context.\n");
169b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly		oz_pd_put(usb_ctx->pd);
1701ec41a31fb695682cab7fc7c1f6ced84d188b6f9Greg Kroah-Hartman		kfree(usb_ctx);
171b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	}
172b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly}
173b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly/*------------------------------------------------------------------------------
174b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly * Context: softirq
175b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly */
176b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kellyint oz_usb_heartbeat(struct oz_pd *pd)
177b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly{
178b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	struct oz_usb_ctx *usb_ctx;
179b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	int rc = 0;
180b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	spin_lock_bh(&pd->app_lock[OZ_APPID_USB-1]);
181b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	usb_ctx = (struct oz_usb_ctx *)pd->app_ctx[OZ_APPID_USB-1];
182b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	if (usb_ctx)
183b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly		oz_usb_get(usb_ctx);
184b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	spin_unlock_bh(&pd->app_lock[OZ_APPID_USB-1]);
185b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	if (usb_ctx == 0)
186b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly		return rc;
187b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	if (usb_ctx->stopped)
188b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly		goto done;
189b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	if (usb_ctx->hport)
190b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly		if (oz_hcd_heartbeat(usb_ctx->hport))
191b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly			rc = 1;
192b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kellydone:
193b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	oz_usb_put(usb_ctx);
194b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	return rc;
195b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly}
196b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly/*------------------------------------------------------------------------------
197b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly * Context: softirq
198b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly */
199b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kellyint oz_usb_stream_create(void *hpd, u8 ep_num)
200b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly{
201b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	struct oz_usb_ctx *usb_ctx = (struct oz_usb_ctx *)hpd;
202b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	struct oz_pd *pd = usb_ctx->pd;
203b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	oz_trace("oz_usb_stream_create(0x%x)\n", ep_num);
204b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	if (pd->mode & OZ_F_ISOC_NO_ELTS) {
205b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly		oz_isoc_stream_create(pd, ep_num);
206b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	} else {
207b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly		oz_pd_get(pd);
208b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly		if (oz_elt_stream_create(&pd->elt_buff, ep_num,
209b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly			4*pd->max_tx_size)) {
210b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly			oz_pd_put(pd);
211b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly			return -1;
212b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly		}
213b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	}
214b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	return 0;
215b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly}
216b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly/*------------------------------------------------------------------------------
217b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly * Context: softirq
218b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly */
219b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kellyint oz_usb_stream_delete(void *hpd, u8 ep_num)
220b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly{
221b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	struct oz_usb_ctx *usb_ctx = (struct oz_usb_ctx *)hpd;
222b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	if (usb_ctx) {
223b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly		struct oz_pd *pd = usb_ctx->pd;
224b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly		if (pd) {
225b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly			oz_trace("oz_usb_stream_delete(0x%x)\n", ep_num);
226b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly			if (pd->mode & OZ_F_ISOC_NO_ELTS) {
227b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly				oz_isoc_stream_delete(pd, ep_num);
228b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly			} else {
229b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly				if (oz_elt_stream_delete(&pd->elt_buff, ep_num))
230b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly					return -1;
231b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly				oz_pd_put(pd);
232b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly			}
233b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly		}
234b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	}
235b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	return 0;
236b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly}
237b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly/*------------------------------------------------------------------------------
238b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly * Context: softirq or process
239b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly */
240b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kellyvoid oz_usb_request_heartbeat(void *hpd)
241b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly{
242b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	struct oz_usb_ctx *usb_ctx = (struct oz_usb_ctx *)hpd;
243b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly	if (usb_ctx && usb_ctx->pd)
244b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly		oz_pd_request_heartbeat(usb_ctx->pd);
245b3147863b523912633bfd4876d242cd5ae7d8e7aChris Kelly}
246