cregit-Linux how code gets into the kernel

Release 4.11 drivers/usb/renesas_usbhs/mod_gadget.c

/*
 * 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/delay.h>
#include <linux/dma-mapping.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include <linux/usb/otg.h>
#include "common.h"

/*
 *              struct
 */

struct usbhsg_request {
	
struct usb_request	req;
	
struct usbhs_pkt	pkt;
};


#define EP_NAME_SIZE 8
struct usbhsg_gpriv;

struct usbhsg_uep {
	
struct usb_ep		 ep;
	
struct usbhs_pipe	*pipe;

	
char ep_name[EP_NAME_SIZE];

	
struct usbhsg_gpriv *gpriv;
};


struct usbhsg_gpriv {
	
struct usb_gadget	 gadget;
	
struct usbhs_mod	 mod;

	
struct usbhsg_uep	*uep;
	
int			 uep_size;

	
struct usb_gadget_driver	*driver;
	
struct usb_phy		*transceiver;
	
bool			 vbus_active;

	
u32	status;

#define USBHSG_STATUS_STARTED		(1 << 0)

#define USBHSG_STATUS_REGISTERD		(1 << 1)

#define USBHSG_STATUS_WEDGE		(1 << 2)

#define USBHSG_STATUS_SELF_POWERED	(1 << 3)

#define USBHSG_STATUS_SOFT_CONNECT	(1 << 4)
};


struct usbhsg_recip_handle {
	
char *name;
	
int (*device)(struct usbhs_priv *priv, struct usbhsg_uep *uep,
		      struct usb_ctrlrequest *ctrl);
	
int (*interface)(struct usbhs_priv *priv, struct usbhsg_uep *uep,
			 struct usb_ctrlrequest *ctrl);
	
int (*endpoint)(struct usbhs_priv *priv, struct usbhsg_uep *uep,
			struct usb_ctrlrequest *ctrl);
};

/*
 *              macro
 */

#define usbhsg_priv_to_gpriv(priv)			\
	container_of(                                   \
                usbhs_mod_get(priv, USBHS_GADGET),      \
                struct usbhsg_gpriv, mod)


#define __usbhsg_for_each_uep(start, pos, g, i)	\
	for ((i) = start;                                       \
             ((i) < (g)->uep_size) && ((pos) = (g)->uep + (i)); \
             (i)++)


#define usbhsg_for_each_uep(pos, gpriv, i)	\
	__usbhsg_for_each_uep(1, pos, gpriv, i)


#define usbhsg_for_each_uep_with_dcp(pos, gpriv, i)	\
	__usbhsg_for_each_uep(0, pos, gpriv, i)


#define usbhsg_gadget_to_gpriv(g)\
	container_of(g, struct usbhsg_gpriv, gadget)


#define usbhsg_req_to_ureq(r)\
	container_of(r, struct usbhsg_request, req)


#define usbhsg_ep_to_uep(e)		container_of(e, struct usbhsg_uep, ep)

#define usbhsg_gpriv_to_dev(gp)		usbhs_priv_to_dev((gp)->mod.priv)

#define usbhsg_gpriv_to_priv(gp)	((gp)->mod.priv)

#define usbhsg_gpriv_to_dcp(gp)		((gp)->uep)

#define usbhsg_gpriv_to_nth_uep(gp, i)	((gp)->uep + i)

#define usbhsg_uep_to_gpriv(u)		((u)->gpriv)

#define usbhsg_uep_to_pipe(u)		((u)->pipe)

#define usbhsg_pipe_to_uep(p)		((p)->mod_private)

#define usbhsg_is_dcp(u)		((u) == usbhsg_gpriv_to_dcp((u)->gpriv))


#define usbhsg_ureq_to_pkt(u)		(&(u)->pkt)

#define usbhsg_pkt_to_ureq(i)	\
	container_of(i, struct usbhsg_request, pkt)


#define usbhsg_is_not_connected(gp) ((gp)->gadget.speed == USB_SPEED_UNKNOWN)

/* status */

#define usbhsg_status_init(gp)   do {(gp)->status = 0; } while (0)

#define usbhsg_status_set(gp, b) (gp->status |=  b)

#define usbhsg_status_clr(gp, b) (gp->status &= ~b)

#define usbhsg_status_has(gp, b) (gp->status &   b)

/*
 *              queue push/pop
 */

static void __usbhsg_queue_pop(struct usbhsg_uep *uep, struct usbhsg_request *ureq, int status) { struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep); struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep); struct device *dev = usbhsg_gpriv_to_dev(gpriv); struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv); if (pipe) dev_dbg(dev, "pipe %d : queue pop\n", usbhs_pipe_number(pipe)); ureq->req.status = status; spin_unlock(usbhs_priv_to_lock(priv)); usb_gadget_giveback_request(&uep->ep, &ureq->req); spin_lock(usbhs_priv_to_lock(priv)); }

Contributors

PersonTokensPropCommitsCommitProp
Kuninori Morimoto7970.54%125.00%
Yoshihiro Shimoda3228.57%250.00%
Michal Sojka10.89%125.00%
Total112100.00%4100.00%


static void usbhsg_queue_pop(struct usbhsg_uep *uep, struct usbhsg_request *ureq, int status) { struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep); struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv); unsigned long flags; usbhs_lock(priv, flags); __usbhsg_queue_pop(uep, ureq, status); usbhs_unlock(priv, flags); }

Contributors

PersonTokensPropCommitsCommitProp
Yoshihiro Shimoda6598.48%150.00%
Kuninori Morimoto11.52%150.00%
Total66100.00%2100.00%


static void usbhsg_queue_done(struct usbhs_priv *priv, struct usbhs_pkt *pkt) { struct usbhs_pipe *pipe = pkt->pipe; struct usbhsg_uep *uep = usbhsg_pipe_to_uep(pipe); struct usbhsg_request *ureq = usbhsg_pkt_to_ureq(pkt); unsigned long flags; ureq->req.actual = pkt->actual; usbhs_lock(priv, flags); if (uep) __usbhsg_queue_pop(uep, ureq, 0); usbhs_unlock(priv, flags); }

Contributors

PersonTokensPropCommitsCommitProp
Kuninori Morimoto6373.26%583.33%
Yoshihiro Shimoda2326.74%116.67%
Total86100.00%6100.00%


static void usbhsg_queue_push(struct usbhsg_uep *uep, struct usbhsg_request *ureq) { struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep); struct device *dev = usbhsg_gpriv_to_dev(gpriv); struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep); struct usbhs_pkt *pkt = usbhsg_ureq_to_pkt(ureq); struct usb_request *req = &ureq->req; req->actual = 0; req->status = -EINPROGRESS; usbhs_pkt_push(pipe, pkt, usbhsg_queue_done, req->buf, req->length, req->zero, -1); usbhs_pkt_start(pipe); dev_dbg(dev, "pipe %d : queue push (%d)\n", usbhs_pipe_number(pipe), req->length); }

Contributors

PersonTokensPropCommitsCommitProp
Kuninori Morimoto124100.00%3100.00%
Total124100.00%3100.00%

/* * dma map/unmap */
static int usbhsg_dma_map_ctrl(struct device *dma_dev, struct usbhs_pkt *pkt, int map) { struct usbhsg_request *ureq = usbhsg_pkt_to_ureq(pkt); struct usb_request *req = &ureq->req; struct usbhs_pipe *pipe = pkt->pipe; enum dma_data_direction dir; int ret = 0; dir = usbhs_pipe_is_dir_host(pipe); if (map) { /* it can not use scatter/gather */ WARN_ON(req->num_sgs); ret = usb_gadget_map_request_by_dev(dma_dev, req, dir); if (ret < 0) return ret; pkt->dma = req->dma; } else { usb_gadget_unmap_request_by_dev(dma_dev, req, dir); } return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Kuninori Morimoto6856.20%125.00%
Felipe Balbi4436.36%125.00%
Yoshihiro Shimoda97.44%250.00%
Total121100.00%4100.00%

/* * USB_TYPE_STANDARD / clear feature functions */
static int usbhsg_recip_handler_std_control_done(struct usbhs_priv *priv, struct usbhsg_uep *uep, struct usb_ctrlrequest *ctrl) { struct usbhsg_gpriv *gpriv = usbhsg_priv_to_gpriv(priv); struct usbhsg_uep *dcp = usbhsg_gpriv_to_dcp(gpriv); struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(dcp); usbhs_dcp_control_transfer_done(pipe); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Kuninori Morimoto59100.00%3100.00%
Total59100.00%3100.00%


static int usbhsg_recip_handler_std_clear_endpoint(struct usbhs_priv *priv, struct usbhsg_uep *uep, struct usb_ctrlrequest *ctrl) { struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep); struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep); if (!usbhsg_status_has(gpriv, USBHSG_STATUS_WEDGE)) { usbhs_pipe_disable(pipe); usbhs_pipe_sequence_data0(pipe); usbhs_pipe_enable(pipe); } usbhsg_recip_handler_std_control_done(priv, uep, ctrl); usbhs_pkt_start(pipe); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Kuninori Morimoto85100.00%5100.00%
Total85100.00%5100.00%

static struct usbhsg_recip_handle req_clear_feature = { .name = "clear feature", .device = usbhsg_recip_handler_std_control_done, .interface = usbhsg_recip_handler_std_control_done, .endpoint = usbhsg_recip_handler_std_clear_endpoint, }; /* * USB_TYPE_STANDARD / set feature functions */
static int usbhsg_recip_handler_std_set_device(struct usbhs_priv *priv, struct usbhsg_uep *uep, struct usb_ctrlrequest *ctrl) { switch (le16_to_cpu(ctrl->wValue)) { case USB_DEVICE_TEST_MODE: usbhsg_recip_handler_std_control_done(priv, uep, ctrl); udelay(100); usbhs_sys_set_test_mode(priv, le16_to_cpu(ctrl->wIndex >> 8)); break; default: usbhsg_recip_handler_std_control_done(priv, uep, ctrl); break; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Kuninori Morimoto78100.00%1100.00%
Total78100.00%1100.00%


static int usbhsg_recip_handler_std_set_endpoint(struct usbhs_priv *priv, struct usbhsg_uep *uep, struct usb_ctrlrequest *ctrl) { struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep); usbhs_pipe_stall(pipe); usbhsg_recip_handler_std_control_done(priv, uep, ctrl); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Kuninori Morimoto48100.00%1100.00%
Total48100.00%1100.00%

static struct usbhsg_recip_handle req_set_feature = { .name = "set feature", .device = usbhsg_recip_handler_std_set_device, .interface = usbhsg_recip_handler_std_control_done, .endpoint = usbhsg_recip_handler_std_set_endpoint, }; /* * USB_TYPE_STANDARD / get status functions */
static void __usbhsg_recip_send_complete(struct usb_ep *ep, struct usb_request *req) { struct usbhsg_request *ureq = usbhsg_req_to_ureq(req); /* free allocated recip-buffer/usb_request */ kfree(ureq->pkt.buf); usb_ep_free_request(ep, req); }

Contributors

PersonTokensPropCommitsCommitProp
Kuninori Morimoto43100.00%1100.00%
Total43100.00%1100.00%


static void __usbhsg_recip_send_status(struct usbhsg_gpriv *gpriv, unsigned short status) { struct usbhsg_uep *dcp = usbhsg_gpriv_to_dcp(gpriv); struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(dcp); struct device *dev = usbhsg_gpriv_to_dev(gpriv); struct usb_request *req; unsigned short *buf; /* alloc new usb_request for recip */ req = usb_ep_alloc_request(&dcp->ep, GFP_ATOMIC); if (!req) { dev_err(dev, "recip request allocation fail\n"); return; } /* alloc recip data buffer */ buf = kmalloc(sizeof(*buf), GFP_ATOMIC); if (!buf) { usb_ep_free_request(&dcp->ep, req); return; } /* recip data is status */ *buf = cpu_to_le16(status); /* allocated usb_request/buffer will be freed */ req->complete = __usbhsg_recip_send_complete; req->buf = buf; req->length = sizeof(*buf); req->zero = 0; /* push packet */ pipe->handler = &usbhs_fifo_pio_push_handler; usbhsg_queue_push(dcp, usbhsg_req_to_ureq(req)); }

Contributors

PersonTokensPropCommitsCommitProp
Kuninori Morimoto171100.00%1100.00%
Total171100.00%1100.00%


static int usbhsg_recip_handler_std_get_device(struct usbhs_priv *priv, struct usbhsg_uep *uep, struct usb_ctrlrequest *ctrl) { struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep); unsigned short status = 0; if (usbhsg_status_has(gpriv, USBHSG_STATUS_SELF_POWERED)) status = 1 << USB_DEVICE_SELF_POWERED; __usbhsg_recip_send_status(gpriv, status); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Kuninori Morimoto4877.42%150.00%
Yoshihiro Shimoda1422.58%150.00%
Total62100.00%2100.00%


static int usbhsg_recip_handler_std_get_interface(struct usbhs_priv *priv, struct usbhsg_uep *uep, struct usb_ctrlrequest *ctrl) { struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep); unsigned short status = 0; __usbhsg_recip_send_status(gpriv, status); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Kuninori Morimoto47100.00%1100.00%
Total47100.00%1100.00%


static int usbhsg_recip_handler_std_get_endpoint(struct usbhs_priv *priv, struct usbhsg_uep *uep, struct usb_ctrlrequest *ctrl) { struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep); struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep); unsigned short status = 0; if (usbhs_pipe_is_stall(pipe)) status = 1 << USB_ENDPOINT_HALT; __usbhsg_recip_send_status(gpriv, status); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Kuninori Morimoto70100.00%1100.00%
Total70100.00%1100.00%

static struct usbhsg_recip_handle req_get_status = { .name = "get status", .device = usbhsg_recip_handler_std_get_device, .interface = usbhsg_recip_handler_std_get_interface, .endpoint = usbhsg_recip_handler_std_get_endpoint, }; /* * USB_TYPE handler */
static int usbhsg_recip_run_handle(struct usbhs_priv *priv, struct usbhsg_recip_handle *handler, struct usb_ctrlrequest *ctrl) { struct usbhsg_gpriv *gpriv = usbhsg_priv_to_gpriv(priv); struct device *dev = usbhsg_gpriv_to_dev(gpriv); struct usbhsg_uep *uep; struct usbhs_pipe *pipe; int recip = ctrl->bRequestType & USB_RECIP_MASK; int nth = le16_to_cpu(ctrl->wIndex) & USB_ENDPOINT_NUMBER_MASK; int ret = 0; int (*func)(struct usbhs_priv *priv, struct usbhsg_uep *uep, struct usb_ctrlrequest *ctrl); char *msg; uep = usbhsg_gpriv_to_nth_uep(gpriv, nth); pipe = usbhsg_uep_to_pipe(uep); if (!pipe) { dev_err(dev, "wrong recip request\n"); return -EINVAL; } switch (recip) { case USB_RECIP_DEVICE: msg = "DEVICE"; func = handler->device; break; case USB_RECIP_INTERFACE: msg = "INTERFACE"; func = handler->interface; break; case USB_RECIP_ENDPOINT: msg = "ENDPOINT"; func = handler->endpoint; break; default: dev_warn(dev, "unsupported RECIP(%d)\n", recip); func = NULL; ret = -EINVAL; } if (func) { dev_dbg(dev, "%s (pipe %d :%s)\n", handler->name, nth, msg); ret = func(priv, uep, ctrl); } return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Kuninori Morimoto23799.16%583.33%
Jesper Juhl20.84%116.67%
Total239100.00%6100.00%

/* * irq functions * * it will be called from usbhs_interrupt */
static int usbhsg_irq_dev_state(struct usbhs_priv *priv, struct usbhs_irq_state *irq_state) { struct usbhsg_gpriv *gpriv = usbhsg_priv_to_gpriv(priv); struct device *dev = usbhsg_gpriv_to_dev(gpriv); gpriv->gadget.speed = usbhs_bus_get_speed(priv); dev_dbg(dev, "state = %x : speed : %d\n", usbhs_status_get_device_state(irq_state), gpriv->gadget.speed); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Kuninori Morimoto68100.00%3100.00%
Total68100.00%3100.00%


static int usbhsg_irq_ctrl_stage(struct usbhs_priv *priv, struct usbhs_irq_state *irq_state) { struct usbhsg_gpriv *gpriv = usbhsg_priv_to_gpriv(priv); struct usbhsg_uep *dcp = usbhsg_gpriv_to_dcp(gpriv); struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(dcp); struct device *dev = usbhsg_gpriv_to_dev(gpriv); struct usb_ctrlrequest ctrl; struct usbhsg_recip_handle *recip_handler = NULL; int stage = usbhs_status_get_ctrl_stage(irq_state); int ret = 0; dev_dbg(dev, "stage = %d\n", stage); /* * see Manual * * "Operation" * - "Interrupt Function" * - "Control Transfer Stage Transition Interrupt" * - Fig. "Control Transfer Stage Transitions" */ switch (stage) { case READ_DATA_STAGE: pipe->handler = &usbhs_fifo_pio_push_handler; break; case WRITE_DATA_STAGE: pipe->handler = &usbhs_fifo_pio_pop_handler; break; case NODATA_STATUS_STAGE: pipe->handler = &usbhs_ctrl_stage_end_handler; break; case READ_STATUS_STAGE: case WRITE_STATUS_STAGE: usbhs_dcp_control_transfer_done(pipe); default: return ret; } /* * get usb request */ usbhs_usbreq_get_val(priv, &ctrl); switch (ctrl.bRequestType & USB_TYPE_MASK) { case USB_TYPE_STANDARD: switch (ctrl.bRequest) { case USB_REQ_CLEAR_FEATURE: recip_handler = &req_clear_feature; break; case USB_REQ_SET_FEATURE: recip_handler = &req_set_feature; break; case USB_REQ_GET_STATUS: recip_handler = &req_get_status; break; } } /* * setup stage / run recip */ if (recip_handler) ret = usbhsg_recip_run_handle(priv, recip_handler, &ctrl); else ret = gpriv->driver->setup(&gpriv->gadget, &ctrl); if (ret < 0) usbhs_pipe_stall(pipe); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Kuninori Morimoto23995.60%685.71%
Yoshihiro Shimoda114.40%114.29%
Total250100.00%7100.00%

/* * * usb_dcp_ops * */
static int usbhsg_pipe_disable(struct usbhsg_uep *uep) { struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep); struct usbhs_pkt *pkt; while (1) { pkt = usbhs_pkt_pop(pipe, NULL); if (!pkt) break; usbhsg_queue_pop(uep, usbhsg_pkt_to_ureq(pkt), -ESHUTDOWN); } usbhs_pipe_disable(pipe); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Kuninori Morimoto6798.53%583.33%
Yoshihiro Shimoda11.47%116.67%
Total68100.00%6100.00%

/* * * usb_ep_ops * */
static int usbhsg_ep_enable(struct usb_ep *ep, const struct usb_endpoint_descriptor *desc) { struct usbhsg_uep *uep = usbhsg_ep_to_uep(ep); struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep); struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv); struct usbhs_pipe *pipe; int ret = -EIO; unsigned long flags; usbhs_lock(priv, flags); /* * if it already have pipe, * nothing to do */ if (uep->pipe) { usbhs_pipe_clear(uep->pipe); usbhs_pipe_sequence_data0(uep->pipe); ret = 0; goto usbhsg_ep_enable_end; } pipe = usbhs_pipe_malloc(priv, usb_endpoint_type(desc), usb_endpoint_dir_in(desc)); if (pipe) { uep->pipe = pipe; pipe->mod_private = uep; /* set epnum / maxp */ usbhs_pipe_config_update(pipe, 0, usb_endpoint_num(desc), usb_endpoint_maxp(desc)); /* * usbhs_fifo_dma_push/pop_handler try to * use dmaengine if possible. * It will use pio handler if impossible. */ if (usb_endpoint_dir_in(desc)) { pipe->handler = &usbhs_fifo_dma_push_handler; } else { pipe->handler = &usbhs_fifo_dma_pop_handler; usbhs_xxxsts_clear(priv, BRDYSTS, usbhs_pipe_number(pipe)); } ret = 0; } usbhsg_ep_enable_end: usbhs_unlock(priv, flags); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Kuninori Morimoto16579.71%981.82%
Yoshihiro Shimoda4220.29%218.18%
Total207100.00%11100.00%


static int usbhsg_ep_disable(struct usb_ep *ep) { struct usbhsg_uep *uep = usbhsg_ep_to_uep(ep); struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep); if (!pipe) return -EINVAL; usbhsg_pipe_disable(uep); usbhs_pipe_free(pipe); uep->pipe->mod_private = NULL; uep->pipe = NULL; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Kuninori Morimoto4364.18%250.00%
Yoshihiro Shimoda1522.39%125.00%
Kazuya Mizuguchi913.43%125.00%
Total67100.00%4100.00%


static struct usb_request *usbhsg_ep_alloc_request(struct usb_ep *ep, gfp_t gfp_flags) { struct usbhsg_request *ureq; ureq = kzalloc(sizeof *ureq, gfp_flags); if (!ureq) return NULL; usbhs_pkt_init(usbhsg_ureq_to_pkt(ureq)); return &ureq->req; }

Contributors

PersonTokensPropCommitsCommitProp
Kuninori Morimoto54100.00%2100.00%
Total54100.00%2100.00%


static void usbhsg_ep_free_request(struct usb_ep *ep, struct usb_request *req) { struct usbhsg_request *ureq = usbhsg_req_to_ureq(req); WARN_ON(!list_empty(&ureq->pkt.node)); kfree(ureq); }

Contributors

PersonTokensPropCommitsCommitProp
Kuninori Morimoto45100.00%2100.00%
Total45100.00%2100.00%


static int usbhsg_ep_queue(struct usb_ep *ep, struct usb_request *req, gfp_t gfp_flags) { struct usbhsg_uep *uep = usbhsg_ep_to_uep(ep); struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep); struct usbhsg_request *ureq = usbhsg_req_to_ureq(req); struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep); /* param check */ if (usbhsg_is_not_connected(gpriv) || unlikely(!gpriv->driver) || unlikely(!pipe)) return -ESHUTDOWN; usbhsg_queue_push(uep, ureq); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Kuninori Morimoto95100.00%2100.00%
Total95100.00%2100.00%


static int usbhsg_ep_dequeue(struct usb_ep *ep, struct usb_request *req) { struct usbhsg_uep *uep = usbhsg_ep_to_uep(ep); struct usbhsg_request *ureq = usbhsg_req_to_ureq(req); struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep); if (pipe) usbhs_pkt_pop(pipe, usbhsg_ureq_to_pkt(ureq)); /* * To dequeue a request, this driver should call the usbhsg_queue_pop() * even if the pipe is NULL. */ usbhsg_queue_pop(uep, ureq, -ECONNRESET); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Kuninori Morimoto6993.24%266.67%
Yoshihiro Shimoda56.76%133.33%
Total74100.00%3100.00%


static int __usbhsg_ep_set_halt_wedge(struct usb_ep *ep, int halt, int wedge) { struct usbhsg_uep *uep = usbhsg_ep_to_uep(ep); struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep); struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep); struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv); struct device *dev = usbhsg_gpriv_to_dev(gpriv); unsigned long flags; usbhsg_pipe_disable(uep); dev_dbg(dev, "set halt %d (pipe %d)\n", halt, usbhs_pipe_number(pipe)); /******************** spin lock ********************/ usbhs_lock(priv, flags); if (halt) usbhs_pipe_stall(pipe); else usbhs_pipe_disable(pipe); if (halt && wedge) usbhsg_status_set(gpriv, USBHSG_STATUS_WEDGE); else usbhsg_status_clr(gpriv, USBHSG_STATUS_WEDGE); usbhs_unlock(priv, flags); /******************** spin unlock ******************/ return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Kuninori Morimoto145100.00%3100.00%
Total145100.00%3100.00%


static int usbhsg_ep_set_halt(struct usb_ep *ep, int value) { return __usbhsg_ep_set_halt_wedge(ep, value, 0); }

Contributors

PersonTokensPropCommitsCommitProp
Kuninori Morimoto24100.00%1100.00%
Total24100.00%1100.00%


static int usbhsg_ep_set_wedge(struct usb_ep *ep) { return __usbhsg_ep_set_halt_wedge(ep, 1, 1); }

Contributors

PersonTokensPropCommitsCommitProp
Kuninori Morimoto21100.00%1100.00%
Total21100.00%1100.00%

static struct usb_ep_ops usbhsg_ep_ops = { .enable = usbhsg_ep_enable, .disable = usbhsg_ep_disable, .alloc_request = usbhsg_ep_alloc_request, .free_request = usbhsg_ep_free_request, .queue = usbhsg_ep_queue, .dequeue = usbhsg_ep_dequeue, .set_halt = usbhsg_ep_set_halt, .set_wedge = usbhsg_ep_set_wedge, }; /* * pullup control */
static int usbhsg_can_pullup(struct usbhs_priv *priv) { struct usbhsg_gpriv *gpriv = usbhsg_priv_to_gpriv(priv); return gpriv->driver && usbhsg_status_has(gpriv, USBHSG_STATUS_SOFT_CONNECT); }

Contributors

PersonTokensPropCommitsCommitProp
Takeshi Kihara33100.00%1100.00%
Total33100.00%1100.00%


static void usbhsg_update_pullup(struct usbhs_priv *priv) { if (usbhsg_can_pullup(priv)) usbhs_sys_function_pullup(priv, 1); else usbhs_sys_function_pullup(priv, 0); }

Contributors

PersonTokensPropCommitsCommitProp
Takeshi Kihara33100.00%1100.00%
Total33100.00%1100.00%

/* * usb module start/end */
static int usbhsg_try_start(struct usbhs_priv *priv, u32 status) { struct usbhsg_gpriv *gpriv = usbhsg_priv_to_gpriv(priv); struct usbhsg_uep *dcp = usbhsg_gpriv_to_dcp(gpriv); struct usbhs_mod *mod = usbhs_mod_get_current(priv); struct device *dev = usbhs_priv_to_dev(priv); unsigned long flags; int ret = 0; /******************** spin lock ********************/ usbhs_lock(priv, flags); usbhsg_status_set(gpriv, status); if (!(usbhsg_status_has(gpriv, USBHSG_STATUS_STARTED) && usbhsg_status_has(gpriv, USBHSG_STATUS_REGISTERD))) ret = -1; /* not ready */ usbhs_unlock(priv, flags); /******************** spin unlock ********************/ if (ret < 0) return 0; /* not ready is not error */ /* * enable interrupt and systems if ready */ dev_dbg(dev, "start gadget\n"); /* * pipe initialize and enable DCP */ usbhs_fifo_init(priv); usbhs_pipe_init(priv, usbhsg_dma_map_ctrl); /* dcp init instead of usbhsg_ep_enable() */ dcp->pipe = usbhs_dcp_malloc(priv); dcp->pipe->mod_private = dcp; usbhs_pipe_config_update(dcp->pipe, 0, 0, 64); /* * system config enble * - HI speed * - function * - usb module */ usbhs_sys_function_ctrl(priv, 1); usbhsg_update_pullup(priv); /* * enable irq callback */ mod->irq_dev_state = usbhsg_irq_dev_state; mod->irq_ctrl_stage = usbhsg_irq_ctrl_stage; usbhs_irq_callback_update(priv, mod); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Kuninori Morimoto20095.69%777.78%
Takeshi Kihara52.39%111.11%
Yoshihiro Shimoda41.91%111.11%
Total209100.00%9100.00%


static int usbhsg_try_stop(struct usbhs_priv *priv, u32 status) { struct usbhsg_gpriv *gpriv = usbhsg_priv_to_gpriv(priv); struct usbhs_mod *mod = usbhs_mod_get_current(priv); struct usbhsg_uep *dcp = usbhsg_gpriv_to_dcp(gpriv); struct device *dev = usbhs_priv_to_dev(priv); unsigned long flags; int ret = 0; /******************** spin lock ********************/ usbhs_lock(priv, flags); usbhsg_status_clr(gpriv, status); if (!usbhsg_status_has(gpriv, USBHSG_STATUS_STARTED) && !usbhsg_status_has(gpriv, USBHSG_STATUS_REGISTERD)) ret = -1; /* already done */ usbhs_unlock(priv, flags); /******************** spin unlock ********************/ if (ret < 0) return 0; /* already done is not error */ /* * disable interrupt and systems if 1st try */ usbhs_fifo_quit(priv); /* disable all irq */ mod->irq_dev_state = NULL; mod->irq_ctrl_stage = NULL; usbhs_irq_callback_update(priv, mod); gpriv->gadget.speed = USB_SPEED_UNKNOWN; /* disable sys */ usbhs_sys_set_test_mode(priv, 0); usbhs_sys_function_ctrl(priv, 0); usbhsg_ep_disable(&dcp->ep); dev_dbg(dev, "stop gadget\n"); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Kuninori Morimoto187100.00%6100.00%
Total187100.00%6100.00%

/* * VBUS provided by the PHY */
static int usbhsm_phy_get_vbus(struct platform_device *pdev) { struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev); struct usbhsg_gpriv *gpriv = usbhsg_priv_to_gpriv(priv); return gpriv->vbus_active; }

Contributors

PersonTokensPropCommitsCommitProp
Phil Edworthy36100.00%1100.00%
Total36100.00%1100.00%


static void usbhs_mod_phy_mode(struct usbhs_priv *priv) { struct usbhs_mod_info *info = &priv->mod_info; info->irq_vbus = NULL; priv->pfunc.get_vbus = usbhsm_phy_get_vbus; usbhs_irq_callback_update(priv, NULL); }

Contributors

PersonTokensPropCommitsCommitProp
Phil Edworthy42100.00%1100.00%
Total42100.00%1100.00%

/* * * linux usb function * */
static int usbhsg_gadget_start(struct usb_gadget *gadget, struct usb_gadget_driver *driver) { struct usbhsg_gpriv *gpriv = usbhsg_gadget_to_gpriv(gadget); struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv); struct device *dev = usbhs_priv_to_dev(priv); int ret; if (!driver || !driver->setup || driver->max_speed < USB_SPEED_FULL) return -EINVAL; /* connect to bus through transceiver */ if (!IS_ERR_OR_NULL(gpriv->transceiver)) { ret = otg_set_peripheral(gpriv->transceiver->otg, &gpriv->gadget); if (ret) { dev_err(dev, "%s: can't bind to transceiver\n", gpriv->gadget.name); return ret; } /* get vbus using phy versions */ usbhs_mod_phy_mode(priv); } /* first hook up the driver ... */ gpriv->driver = driver; return usbhsg_try_start(priv, USBHSG_STATUS_REGISTERD); }

Contributors

PersonTokensPropCommitsCommitProp
Phil Edworthy7049.65%114.29%
Kuninori Morimoto5941.84%342.86%
Felipe Balbi96.38%114.29%
Sebastian Andrzej Siewior21.42%114.29%
Michal Nazarewicz10.71%114.29%
Total141100.00%7100.00%


static int usbhsg_gadget_stop(struct usb_gadget *gadget) { struct usbhsg_gpriv *gpriv = usbhsg_gadget_to_gpriv(gadget); struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv); usbhsg_try_stop(priv, USBHSG_STATUS_REGISTERD); if (!IS_ERR_OR_NULL(gpriv->transceiver)) otg_set_peripheral(gpriv->transceiver->otg, NULL); gpriv->driver = NULL; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Kuninori Morimoto3754.41%240.00%
Phil Edworthy2130.88%120.00%
Felipe Balbi811.76%120.00%
Sebastian Andrzej Siewior22.94%120.00%
Total68100.00%5100.00%

/* * usb gadget ops */
static int usbhsg_get_frame(struct usb_gadget *gadget) { struct usbhsg_gpriv *gpriv = usbhsg_gadget_to_gpriv(gadget); struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv); return usbhs_frame_get_num(priv); }

Contributors

PersonTokensPropCommitsCommitProp
Kuninori Morimoto37100.00%1100.00%
Total37100.00%1100.00%


static int usbhsg_pullup(struct usb_gadget *gadget, int is_on) { struct usbhsg_gpriv *gpriv = usbhsg_gadget_to_gpriv(gadget); struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv); unsigned long flags; usbhs_lock(priv, flags); if (is_on) usbhsg_status_set(gpriv, USBHSG_STATUS_SOFT_CONNECT); else usbhsg_status_clr(gpriv, USBHSG_STATUS_SOFT_CONNECT); usbhsg_update_pullup(priv); usbhs_unlock(priv, flags); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Kuninori Morimoto4354.43%150.00%
Takeshi Kihara3645.57%150.00%
Total79100.00%2100.00%


static int usbhsg_set_selfpowered(struct usb_gadget *gadget, int is_self) { struct usbhsg_gpriv *gpriv = usbhsg_gadget_to_gpriv(gadget); if (is_self) usbhsg_status_set(gpriv, USBHSG_STATUS_SELF_POWERED); else usbhsg_status_clr(gpriv, USBHSG_STATUS_SELF_POWERED); gadget->is_selfpowered = (is_self != 0); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Yoshihiro Shimoda4682.14%150.00%
Peter Chen1017.86%150.00%
Total56100.00%2100.00%


static int usbhsg_vbus_session(struct usb_gadget *gadget, int is_active) { struct usbhsg_gpriv *gpriv = usbhsg_gadget_to_gpriv(gadget); struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv); struct platform_device *pdev = usbhs_priv_to_pdev(priv); gpriv->vbus_active = !!is_active; renesas_usbhs_call_notify_hotplug(pdev); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Phil Edworthy60100.00%1100.00%
Total60100.00%1100.00%

static const struct usb_gadget_ops usbhsg_gadget_ops = { .get_frame = usbhsg_get_frame, .set_selfpowered = usbhsg_set_selfpowered, .udc_start = usbhsg_gadget_start, .udc_stop = usbhsg_gadget_stop, .pullup = usbhsg_pullup, .vbus_session = usbhsg_vbus_session, };
static int usbhsg_start(struct usbhs_priv *priv) { return usbhsg_try_start(priv, USBHSG_STATUS_STARTED); }

Contributors

PersonTokensPropCommitsCommitProp
Kuninori Morimoto19100.00%1100.00%
Total19100.00%1100.00%


static int usbhsg_stop(struct usbhs_priv *priv) { struct usbhsg_gpriv *gpriv = usbhsg_priv_to_gpriv(priv); /* cable disconnect */ if (gpriv->driver && gpriv->driver->disconnect) gpriv->driver->disconnect(&gpriv->gadget); return usbhsg_try_stop(priv, USBHSG_STATUS_STARTED); }

Contributors

PersonTokensPropCommitsCommitProp
Kuninori Morimoto54100.00%2100.00%
Total54100.00%2100.00%


int usbhs_mod_gadget_probe(struct usbhs_priv *priv) { struct usbhsg_gpriv *gpriv; struct usbhsg_uep *uep; struct device *dev = usbhs_priv_to_dev(priv); struct renesas_usbhs_driver_pipe_config *pipe_configs = usbhs_get_dparam(priv, pipe_configs); int pipe_size = usbhs_get_dparam(priv, pipe_size); int i; int ret; gpriv = kzalloc(sizeof(struct usbhsg_gpriv), GFP_KERNEL); if (!gpriv) return -ENOMEM; uep = kzalloc(sizeof(struct usbhsg_uep) * pipe_size, GFP_KERNEL); if (!uep) { ret = -ENOMEM; goto usbhs_mod_gadget_probe_err_gpriv; } gpriv->transceiver = usb_get_phy(USB_PHY_TYPE_UNDEFINED); dev_info(dev, "%stransceiver found\n", !IS_ERR(gpriv->transceiver) ? "" : "no "); /* * CAUTION * * There is no guarantee that it is possible to access usb module here. * Don't accesses to it. * The accesse will be enable after "usbhsg_start" */ /* * register itself */ usbhs_mod_register(priv, &gpriv->mod, USBHS_GADGET); /* init gpriv */ gpriv->mod.name = "gadget"; gpriv->mod.start = usbhsg_start; gpriv->mod.stop = usbhsg_stop; gpriv->uep = uep; gpriv->uep_size = pipe_size; usbhsg_status_init(gpriv); /* * init gadget */ gpriv->gadget.dev.parent = dev; gpriv->gadget.name = "renesas_usbhs_udc"; gpriv->gadget.ops = &usbhsg_gadget_ops; gpriv->gadget.max_speed = USB_SPEED_HIGH; gpriv->gadget.quirk_avoids_skb_reserve = usbhs_get_dparam(priv, has_usb_dmac); INIT_LIST_HEAD(&gpriv->gadget.ep_list); /* * init usb_ep */ usbhsg_for_each_uep_with_dcp(uep, gpriv, i) { uep->gpriv = gpriv; uep->pipe = NULL; snprintf(uep->ep_name, EP_NAME_SIZE, "ep%d", i); uep->ep.name = uep->ep_name; uep->ep.ops = &usbhsg_ep_ops; INIT_LIST_HEAD(&uep->ep.ep_list); /* init DCP */ if (usbhsg_is_dcp(uep)) { gpriv->gadget.ep0 = &uep->ep; usb_ep_set_maxpacket_limit(&uep->ep, 64); uep->ep.caps.type_control = true; } else { /* init normal pipe */ if (pipe_configs[i].type == USB_ENDPOINT_XFER_ISOC) uep->ep.caps.type_iso = true; if (pipe_configs[i].type == USB_ENDPOINT_XFER_BULK) uep->ep.caps.type_bulk = true; if (pipe_configs[i].type == USB_ENDPOINT_XFER_INT) uep->ep.caps.type_int = true; usb_ep_set_maxpacket_limit(&uep->ep, pipe_configs[i].bufsize); list_add_tail(&uep->ep.ep_list, &gpriv->gadget.ep_list); } uep->ep.caps.dir_in = true; uep->ep.caps.dir_out = true; } ret = usb_add_gadget_udc(dev, &gpriv->gadget); if (ret) goto err_add_udc; dev_info(dev, "gadget probed\n"); return 0; err_add_udc: kfree(gpriv->uep); usbhs_mod_gadget_probe_err_gpriv: kfree(gpriv); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Kuninori Morimoto32060.84%218.18%
Yoshihiro Shimoda7414.07%218.18%
Robert Baldyga6512.36%218.18%
Sebastian Andrzej Siewior366.84%19.09%
Phil Edworthy244.56%19.09%
Wei Yongjun40.76%19.09%
Michal Nazarewicz20.38%19.09%
Felipe Balbi10.19%19.09%
Total526100.00%11100.00%


void usbhs_mod_gadget_remove(struct usbhs_priv *priv) { struct usbhsg_gpriv *gpriv = usbhsg_priv_to_gpriv(priv); usb_del_gadget_udc(&gpriv->gadget); kfree(gpriv->uep); kfree(gpriv); }

Contributors

PersonTokensPropCommitsCommitProp
Kuninori Morimoto2562.50%133.33%
Sebastian Andrzej Siewior1537.50%266.67%
Total40100.00%3100.00%


Overall Contributors

PersonTokensPropCommitsCommitProp
Kuninori Morimoto376679.79%4056.34%
Yoshihiro Shimoda3507.42%1419.72%
Phil Edworthy2705.72%11.41%
Takeshi Kihara1122.37%11.41%
Felipe Balbi651.38%45.63%
Robert Baldyga651.38%22.82%
Sebastian Andrzej Siewior631.33%22.82%
Peter Chen100.21%11.41%
Kazuya Mizuguchi90.19%11.41%
Wei Yongjun40.08%11.41%
Michal Nazarewicz30.06%22.82%
Jesper Juhl20.04%11.41%
Michal Sojka10.02%11.41%
Total4720100.00%71100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.