/*
* Renesas USB driver
*
* Copyright (C) 2011 Renesas Solutions Corp.
* Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include <linux/io.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/usb.h>
#include <linux/usb/hcd.h>
#include "common.h"
/*
*** HARDWARE LIMITATION ***
*
* 1) renesas_usbhs has a limited number of controllable devices.
* it can control only 9 devices in generally.
* see DEVADDn / DCPMAXP / PIPEMAXP.
*
* 2) renesas_usbhs pipe number is limited.
* the pipe will be re-used for each devices.
* so, software should control DATA0/1 sequence of each devices.
*/
/*
* image of mod_host
*
* +--------+
* | udev 0 | --> it is used when set address
* +--------+
*
* +--------+ pipes are reused for each uep.
* | udev 1 |-+- [uep 0 (dcp) ] --+ pipe will be switched when
* +--------+ | | other device requested
* +- [uep 1 (bulk)] --|---+ +--------------+
* | +--------------> | pipe0 (dcp) |
* +- [uep 2 (bulk)] -@ | +--------------+
* | | pipe1 (isoc) |
* +--------+ | +--------------+
* | udev 2 |-+- [uep 0 (dcp) ] -@ +----------> | pipe2 (bulk) |
* +--------+ | +--------------+
* +- [uep 1 (int) ] ----+ +------> | pipe3 (bulk) |
* | | +--------------+
* +--------+ +-----|------> | pipe4 (int) |
* | udev 3 |-+- [uep 0 (dcp) ] -@ | +--------------+
* +--------+ | | | .... |
* +- [uep 1 (bulk)] -@ | | .... |
* | |
* +- [uep 2 (bulk)]-----------+
*
* @ : uep requested free pipe, but all have been used.
* now it is waiting for free pipe
*/
/*
* struct
*/
struct usbhsh_request {
struct urb *urb;
struct usbhs_pkt pkt;
};
struct usbhsh_device {
struct usb_device *usbv;
struct list_head ep_list_head; /* list of usbhsh_ep */
};
struct usbhsh_ep {
struct usbhs_pipe *pipe; /* attached pipe */
struct usbhsh_device *udev; /* attached udev */
struct usb_host_endpoint *ep;
struct list_head ep_list; /* list to usbhsh_device */
unsigned int counter; /* pipe attach counter */
};
#define USBHSH_DEVICE_MAX 10 /* see DEVADDn / DCPMAXP / PIPEMAXP */
#define USBHSH_PORT_MAX 7 /* see DEVADDn :: HUBPORT */
struct usbhsh_hpriv {
struct usbhs_mod mod;
struct usbhs_pipe *dcp;
struct usbhsh_device udev[USBHSH_DEVICE_MAX];
u32 port_stat; /* USB_PORT_STAT_xxx */
struct completion setup_ack_done;
};
static const char usbhsh_hcd_name[] = "renesas_usbhs host";
/*
* macro
*/
#define usbhsh_priv_to_hpriv(priv) \
container_of(usbhs_mod_get(priv, USBHS_HOST), struct usbhsh_hpriv, mod)
#define __usbhsh_for_each_udev(start, pos, h, i) \
for ((i) = start; \
((i) < USBHSH_DEVICE_MAX) && ((pos) = (h)->udev + (i)); \
(i)++)
#define usbhsh_for_each_udev(pos, hpriv, i) \
__usbhsh_for_each_udev(1, pos, hpriv, i)
#define usbhsh_for_each_udev_with_dev0(pos, hpriv, i) \
__usbhsh_for_each_udev(0, pos, hpriv, i)
#define usbhsh_hcd_to_hpriv(h) (struct usbhsh_hpriv *)((h)->hcd_priv)
#define usbhsh_hcd_to_dev(h) ((h)->self.controller)
#define usbhsh_hpriv_to_priv(h) ((h)->mod.priv)
#define usbhsh_hpriv_to_dcp(h) ((h)->dcp)
#define usbhsh_hpriv_to_hcd(h) \
container_of((void *)h, struct usb_hcd, hcd_priv)
#define usbhsh_ep_to_uep(u) ((u)->hcpriv)
#define usbhsh_uep_to_pipe(u) ((u)->pipe)
#define usbhsh_uep_to_udev(u) ((u)->udev)
#define usbhsh_uep_to_ep(u) ((u)->ep)
#define usbhsh_urb_to_ureq(u) ((u)->hcpriv)
#define usbhsh_urb_to_usbv(u) ((u)->dev)
#define usbhsh_usbv_to_udev(d) dev_get_drvdata(&(d)->dev)
#define usbhsh_udev_to_usbv(h) ((h)->usbv)
#define usbhsh_udev_is_used(h) usbhsh_udev_to_usbv(h)
#define usbhsh_pipe_to_uep(p) ((p)->mod_private)
#define usbhsh_device_parent(d) (usbhsh_usbv_to_udev((d)->usbv->parent))
#define usbhsh_device_hubport(d) ((d)->usbv->portnum)
#define usbhsh_device_number(h, d) ((int)((d) - (h)->udev))
#define usbhsh_device_nth(h, d) ((h)->udev + d)
#define usbhsh_device0(h) usbhsh_device_nth(h, 0)
#define usbhsh_port_stat_init(h) ((h)->port_stat = 0)
#define usbhsh_port_stat_set(h, s) ((h)->port_stat |= (s))
#define usbhsh_port_stat_clear(h, s) ((h)->port_stat &= ~(s))
#define usbhsh_port_stat_get(h) ((h)->port_stat)
#define usbhsh_pkt_to_ureq(p) \
container_of((void *)p, struct usbhsh_request, pkt)
/*
* req alloc/free
*/
static struct usbhsh_request *usbhsh_ureq_alloc(struct usbhsh_hpriv *hpriv,
struct urb *urb,
gfp_t mem_flags)
{
struct usbhsh_request *ureq;
ureq = kzalloc(sizeof(struct usbhsh_request), mem_flags);
if (!ureq)
return NULL;
usbhs_pkt_init(&ureq->pkt);
ureq->urb = urb;
usbhsh_urb_to_ureq(urb) = ureq;
retu
|