Re: [PATCH] PXA27x UDC driver.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, 28 Jun 2007 16:12:07 +0200
Rodolfo Giometti <[email protected]> wrote:

> On Thu, Jun 28, 2007 at 07:15:06PM +0800, Li Yang-r58472 wrote:
> 
> > You should probably also cc: [email protected] and
> > David Brownell for UDC matters.
> 
> As suggest by Leo let me propose to you my new patch for PXA27x UDC
> support.
> 
> Please, let me know what I have to do for kernel inclusion. :)
> 

Please feed it through the current version of scripts/checkpatch.pl and
think about fixing the large amount of trivia spew which ensues.

> diff --git a/arch/arm/mach-pxa/generic.c b/arch/arm/mach-pxa/generic.c
> index 64b08b7..7f390fd 100644
> --- a/arch/arm/mach-pxa/generic.c
> +++ b/arch/arm/mach-pxa/generic.c
> @@ -282,7 +282,11 @@ static struct resource pxa2xx_udc_resources[] = {
>  static u64 udc_dma_mask = ~(u32)0;
>  
>  static struct platform_device udc_device = {
> +#ifdef CONFIG_PXA27x
> +	.name		= "pxa27x-udc",
> +#else
>  	.name		= "pxa2xx-udc",
> +#endif

This looks odd.  The same driver presents itself under a different name
according to a config option?

> @@ -0,0 +1,2395 @@
> +/*
> + * linux/drivers/usb/gadget/pxa27x_udc.c
> + * Intel PXA2xx and IXP4xx on-chip full speed USB device controllers
> + *
> + * Copyright (C) 2002 Intrinsyc, Inc. (Frank Becker)
> + * Copyright (C) 2003 Robert Schwebel, Pengutronix
> + * Copyright (C) 2003 Benedikt Spranger, Pengutronix
> + * Copyright (C) 2003 David Brownell
> + * Copyright (C) 2003 Joshua Wise
> + * Copyright (C) 2004 Intel Corporation
> + * Copyright (C) 2007 Rodolfo Giometti <[email protected]> 
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
> + *
> + */
> +
> +#undef DEBUG

Why?  -DDEBUG is normally provided on the command line.  If the user _did_
go and set DEBUG, he presumably wants DEBUG.

> +/* #define	VERBOSE	DBG_VERBOSE */
> +
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/ioport.h>
> +#include <linux/types.h>
> +#include <linux/version.h>
> +#include <linux/errno.h>
> +#include <linux/delay.h>
> +#include <linux/sched.h>
> +#include <linux/slab.h>
> +#include <linux/init.h>
> +#include <linux/timer.h>
> +#include <linux/list.h>
> +#include <linux/interrupt.h>
> +#include <linux/proc_fs.h>
> +#include <linux/mm.h>
> +#include <linux/device.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/platform_device.h>
> +
> +#include <asm/byteorder.h>
> +#include <asm/dma.h>
> +#include <asm/io.h>
> +#include <asm/irq.h>
> +#include <asm/system.h>
> +#include <asm/mach-types.h>
> +#include <asm/unaligned.h>
> +#include <asm/hardware.h>
> +#include <asm/arch/pxa-regs.h>
> +
> +#include <linux/usb/ch9.h>
> +#include <linux/usb_gadget.h>
> +
> +#include <asm/arch/udc.h>
> +
> +/*
> + * This driver handles the USB Device Controller (UDC) in Intel's PXA 27x
> + * series processors.  
> + * Such controller drivers work with a gadget driver.  The gadget driver
> + * returns descriptors, implements configuration and data protocols used
> + * by the host to interact with this device, and allocates endpoints to
> + * the different protocol interfaces.  The controller driver virtualizes
> + * usb hardware so that the gadget drivers will be more portable.
> + * 
> + * This UDC hardware wants to implement a bit too much USB protocol, so
> + * it constrains the sorts of USB configuration change events that work.
> + * The errata for these chips are misleading; some "fixed" bugs from
> + * pxa250 a0/a1 b0/b1/b2 sure act like they're still there.
> + */
> +
> +#define	DRIVER_VERSION	"28-Jun-2007"
> +#define	DRIVER_DESC	"PXA 27x USB Device Controller driver"
> +
> +static const char driver_name[] = "pxa27x_udc";
> +
> +static const char ep0name[] = "ep0";
> +
> +#undef	USE_DMA

So DMA is busted?

> +#undef	DISABLE_TEST_MODE

enabling DISABLE_TEST_MODE seens to enable test mode.  Confused.

> +#ifdef CONFIG_PROC_FS
> +#define	UDC_PROC_FILE
> +#endif
> +
> +#include "pxa27x_udc.h"
> +
> +#ifdef CONFIG_EMBEDDED
> +/* few strings, and little code to use them */
> +#undef	DEBUG
> +#undef	UDC_PROC_FILE
> +#endif

gag, this looks like a mess.  Thise sort of logic should be implemented in
Kconfig, not in .c.

> +#ifdef	USE_DMA
> +static int use_dma = 1;
> +module_param(use_dma, bool, 0);
> +MODULE_PARM_DESC(use_dma, "true to use dma");
> +
> +static void dma_nodesc_handler(int dmach, void *_ep);
> +static void kick_dma(struct pxa27x_ep *ep, struct pxa27x_request *req);
> +
> +#define	DMASTR " (dma support)"
> +
> +#else				/* !USE_DMA */
> +#define	DMASTR " (pio only)"
> +#endif
> +
> +#ifdef	CONFIG_USB_PXA27X_SMALL
> +#define SIZE_STR	" (small)"
> +#else
> +#define SIZE_STR	""
> +#endif
> +
> +#ifdef DISABLE_TEST_MODE
> +/* (mode == 0) == no undocumented chip tweaks
> + * (mode & 1)  == double buffer bulk IN
> + * (mode & 2)  == double buffer bulk OUT
> + * ... so mode = 3 (or 7, 15, etc) does it for both
> + */
> +static ushort fifo_mode = 0;

Unneeded initialisation (checkpatch should catch this)

Use u16, not ushort.  Or just "int".

> +module_param(fifo_mode, ushort, 0);
> +MODULE_PARM_DESC(fifo_mode, "pxa27x udc fifo mode");
> +#endif
> +
> +#define UDCISR0_IR0	 0x3
> +#define UDCISR_INT_MASK	 (UDC_INT_FIFOERROR | UDC_INT_PACKETCMP)
> +#define UDCICR_INT_MASK	 UDCISR_INT_MASK
> +
> +#define UDCCSR_MASK	(UDCCSR_FST | UDCCSR_DME)
> +/* ---------------------------------------------------------------------------
> + * 	endpoint related parts of the api to the usb controller hardware,
> + *	used by gadget driver; and the inner talker-to-hardware core.
> + * ---------------------------------------------------------------------------
> + */

kernel comments normally look like

/*
 * endpoint related parts of the api to the usb controller hardware,
 * used by gadget driver; and the inner talker-to-hardware core.
 *
 */

> +
> +static void pxa27x_ep_fifo_flush(struct usb_ep *ep);
> +static void nuke(struct pxa27x_ep *, int status);
> +
> +/* one GPIO should control a D+ pullup, so host sees this device (or not) */
> +static void pullup_off(void)
> +{
> +	struct pxa2xx_udc_mach_info *mach = the_controller->mach;
> +
> +	if (mach->gpio_pullup)
> +		udc_gpio_set(mach->gpio_pullup, 0);
> +	else if (mach->udc_command)
> +		mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT);
> +}
> +
> +static void pullup_on(void)
> +{
> +	struct pxa2xx_udc_mach_info *mach = the_controller->mach;
> +
> +	if (mach->gpio_pullup)
> +		udc_gpio_set(mach->gpio_pullup, 1);
> +	else if (mach->udc_command)
> +		mach->udc_command(PXA2XX_UDC_CMD_CONNECT);
> +}
> +
> +static void pio_irq_enable(int ep_num)
> +{
> +	if (ep_num < 16)
> +		UDCICR0 |= 3 << (ep_num * 2);
> +	else {
> +		ep_num -= 16;
> +		UDCICR1 |= 3 << (ep_num * 2);
> +	}
> +}

We'd normally put braces around the "if" clause if there are braces around
the "else" clause.  What you have there looks a bit funny.

> +static void pio_irq_disable(int ep_num)
> +{
> +	ep_num &= 0xf;
> +	if (ep_num < 16)
> +		UDCICR0 &= ~(3 << (ep_num * 2));
> +	else {
> +		ep_num -= 16;
> +		UDCICR1 &= ~(3 << (ep_num * 2));
> +	}
> +}

Ditto

> +	if (ep->ep_type != USB_ENDPOINT_XFER_BULK
> +	    && desc->bmAttributes != USB_ENDPOINT_XFER_INT) {

We'd normally lay this out as

	if (ep->ep_type != USB_ENDPOINT_XFER_BULK &&
	    desc->bmAttributes != USB_ENDPOINT_XFER_INT) {

but what you have there is pretty common.

> +		DMSG("%s, %s type mismatch\n", __FUNCTION__, _ep->name);
> +		return -EINVAL;
> +	}
> +
> +	/* hardware _could_ do smaller, but driver doesn't */
> +	if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK
> +	     && le16_to_cpu(desc->wMaxPacketSize)
> +	     != BULK_FIFO_SIZE)
> +	    || !desc->wMaxPacketSize) {

that expression is quite hard to read.

	/* hardware _could_ do smaller, but driver doesn't */
	if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK &&
		le16_to_cpu(desc->wMaxPacketSize) != BULK_FIFO_SIZE) ||
	    !desc->wMaxPacketSize) {

or something like that?

> +		DMSG("%s, bad %s maxpacket\n", __FUNCTION__, _ep->name);
> +		return -ERANGE;
> +	}
> +
> +	dev = ep->dev;
> +	if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) {
> +		DMSG("%s, bogus device state\n", __FUNCTION__);
> +		return -ESHUTDOWN;
> +	}
> +
> +	ep->desc = desc;
> +	ep->dma = -1;
> +	ep->stopped = 0;
> +	ep->pio_irqs = ep->dma_irqs = 0;
> +	ep->ep.maxpacket = le16_to_cpu(desc->wMaxPacketSize);
> +
> +	/* flush fifo (mostly for OUT buffers) */
> +	pxa27x_ep_fifo_flush(_ep);
> +
> +	/* ... reset halt state too, if we could ... */
> +
> +#ifdef USE_DMA
> +	/* for (some) bulk and ISO endpoints, try to get a DMA channel and
> +	 * bind it to the endpoint.  otherwise use PIO. 
> +	 */
> +	DMSG("%s: called attributes=%d\n", __FUNCTION__, ep->ep_type);
> +	switch (ep->ep_type) {
> +	case USB_ENDPOINT_XFER_ISOC:
> +		if (le16_to_cpu(desc->wMaxPacketSize) % 32)
> +			break;
> +		/* fall through */
> +	case USB_ENDPOINT_XFER_BULK:
> +		if (!use_dma || !ep->reg_drcmr)
> +			break;
> +		ep->dma = pxa_request_dma((char *)_ep->name,
> +				  (le16_to_cpu(desc->wMaxPacketSize) > 64)
> +					  ? DMA_PRIO_MEDIUM	/* some iso */
> +					  : DMA_PRIO_LOW,
> +					  dma_nodesc_handler, ep);
> +		if (ep->dma >= 0) {
> +			*ep->reg_drcmr = DRCMR_MAPVLD | ep->dma;
> +			DMSG("%s using dma%d\n", _ep->name, ep->dma);
> +		}
> +	default:
> +		break;
> +	}
> +#endif
> +	DBG(DBG_VERBOSE, "enabled %s\n", _ep->name);
> +	return 0;
> +}
> +
> +/*-------------------------------------------------------------------------*/
> +
> +/* for the pxa27x, these can just wrap kmalloc/kfree.  gadget drivers
> + * must still pass correctly initialized endpoints, since other controller
> + * drivers may care about how it's currently set up (dma issues etc).
> + */
> +
> +/*
> + * 	pxa27x_ep_alloc_request - allocate a request data structure
> + */
> +static struct usb_request *pxa27x_ep_alloc_request(struct usb_ep *_ep,
> +						   unsigned int gfp_flags)
> +{
> +	struct pxa27x_request *req;
> +
> +	req = kmalloc(sizeof *req, gfp_flags);
> +	if (!req)
> +		return 0;
> +
> +	memset(req, 0, sizeof *req);

use kzalloc()

> +	INIT_LIST_HEAD(&req->queue);
> +	return &req->req;
> +}
> +
>
>
> +
> +static int
> +write_packet(volatile u32 * uddr, struct pxa27x_request *req, unsigned max)

Please review Documentation/volatile-considered-harmful.txt

> +{
> +	u32 *buf;
> +	int length, count, remain;
> +
> +	buf = (u32 *) (req->req.buf + req->req.actual);
> +	prefetch(buf);
> +
> +	/* how big will this packet be? */
> +	length = min(req->req.length - req->req.actual, max);
> +	req->req.actual += length;
> +
> +	remain = length & 0x3;
> +	count = length & ~(0x3);
> +
> +	while (likely(count)) {
> +		*uddr = *buf++;
> +		count -= 4;
> +	}
> +
> +	if (remain) {
> +		volatile u8 *reg = (u8 *) uddr;
> +		char *rd = (u8 *) buf;
> +
> +		while (remain--) {
> +			*reg = *rd++;
> +		}
> +	}
> +
> +	return length;
> +}
> +
>
> ...
>
> +
> +static void dma_nodesc_handler(int dmach, void *_ep, struct pt_regs *r)
> +{
> +	struct pxa27x_ep *ep = _ep;
> +	struct pxa27x_request *req, *req_next;
> +	u32 dcsr, tmp, completed;
> +
> +	local_irq_disable();

this looks fishy.  local_irq_disable() only provides cpu-local protection. 
Is this code SMP-correct?  What's happening here?  A comment is needed
explaining this, at least.

> +static inline void validate_fifo_size(struct pxa27x_ep *pxa_ep, u8 bmAttributes)
> +{
> +	switch (bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
> +	case USB_ENDPOINT_XFER_CONTROL:
> +		pxa_ep->fifo_size = EP0_FIFO_SIZE;
> +		break;
> +	case USB_ENDPOINT_XFER_ISOC:
> +		pxa_ep->fifo_size = ISO_FIFO_SIZE;
> +		break;
> +	case USB_ENDPOINT_XFER_BULK:
> +		pxa_ep->fifo_size = BULK_FIFO_SIZE;
> +		break;
> +	case USB_ENDPOINT_XFER_INT:
> +		pxa_ep->fifo_size = INT_FIFO_SIZE;
> +		break;
> +	default:
> +		break;
> +	}
> +}

There's no point in inlining this.  With only one callsite the compiler
will inline it anyway.  If we grow a second callsite, this fucntion is too
large to inline.

This is general truth, so please generally avoid inline.

> +	ep->maxpacket = min((ushort) pxa_ep->fifo_size, desc->wMaxPacketSize);

Use min_t, not an open-coded cast.

Use u16.

> +#ifdef UDC_PROC_FILE
> +
> +static const char proc_node_name[] = "driver/udc";

/proc is for process-related things.  Driver-related things go in /sys

> +
> +#define create_proc_files() \
> +	create_proc_read_entry(proc_node_name, 0, NULL, udc_proc_read, dev)
> +#define remove_proc_files() \
> +	remove_proc_entry(proc_node_name, NULL)
> +
> +#else				/* !UDC_PROC_FILE */
> +#define create_proc_files() do {} while (0)
> +#define remove_proc_files() do {} while (0)

Please only use macros when you *must* use macros.  When for some reason
you cannot use C.  This is not such a case.  IOW, convert to static
inlines.

> +#endif				/* UDC_PROC_FILE */
> +
> +	DMSG("registered gadget driver '%s'\n", driver->driver.name);
> +	udc_enable(dev);
> +	dump_state(dev);
> +
> +	return 0;
> +
> +      create_file_error:
> +	driver->unbind(&dev->gadget);
> +
> +      device_bind_error:
> +	device_del(&dev->gadget.dev);
> +
> +      device_add_error:
> +	dev->driver = 0;
> +	dev->gadget.dev.driver = 0;
> +
> +	return retval;
> +}

We normally indent labels with zero or one spaces, not six.

> +}
> +
> +EXPORT_SYMBOL(usb_gadget_unregister_driver);

We normally leave zero blank lines between the } and the EXPORT_SYMBOL
(checkpatch should report this)

> +#ifndef	enable_disconnect_irq
> +#define	enable_disconnect_irq()		do {} while (0)
> +#define	disable_disconnect_irq()	do {} while (0)
> +#endif

hm, OK, I guess this is somewhere where a macro is appropriate.

> +/*-------------------------------------------------------------------------*/
> +
> +static inline void clear_ep_state(struct pxa27x_udc *dev)
> +{
> +	unsigned i;
> +
> +	/* hardware SET_{CONFIGURATION,INTERFACE} automagic resets endpoint
> +	 * fifos, and pending transactions mustn't be continued in any case.
> +	 */
> +	for (i = 1; i < UDC_EP_NUM; i++)
> +		nuke(&dev->ep[i], -ECONNABORTED);
> +}

Probably too big to inline.

Has no callers.

> +			if (i < 0) {
> +				/* hardware automagic preventing STALL... */
> +				if (dev->req_config) {
> +					/* hardware sometimes neglects to tell
> +					 * tell us about config change events,
> +					 * so later ones may fail...
> +					 */
> +					WARN("config change %02x fail %d?\n",
> +					     u.r.bRequest, i);
> +					return;
> +					/* TODO experiment:  if has_cfr,
> +					 * hardware didn't ACK; maybe we
> +					 * could actually STALL!
> +					 */
> +				}
> +				DBG(DBG_VERBOSE, "protocol STALL, "
> +				    "%02x err %d\n", UDCCSR0, i);
> +			      stall:

what's that label doing all the way over there.  It makes it rather hard to
find.

> +				/* the watchdog timer helps deal with cases
> +				 * where udc seems to clear FST wrongly, and
> +				 * then NAKs instead of STALLing.
> +				 */
> +				ep0start(dev, UDCCSR0_FST | UDCCSR0_FTF,
> +					 "stall");
> +				start_watchdog(dev);
> +				dev->ep0state = EP0_STALL;
> +				LED_EP0_OFF;
> +
> +				/* deferred i/o == no response yet */
> +			} else if (dev->req_pending) {
> +				if (likely(dev->ep0state == EP0_IN_DATA_PHASE
> +					   || dev->req_std || u.r.wLength))
> +					ep0start(dev, 0, "defer");
> +				else
> +					ep0start(dev, UDCCSR0_IPR, "defer/IPR");
> +			}
> +
> +			/* expect at least one data or status stage irq */
> +			return;

Burying returns deep inside large functions is unpopular: it can easily
lead to resource leaks and locking errors as the code evolves.  It makes
review and auditing harder.

> +		} else {
> +			/* some random early IRQ:
> +			 * - we acked FST
> +			 * - IPR cleared
> +			 * - OPC got set, without SA (likely status stage)
> +			 */
> +			UDCCSR0 = udccsr0 & (UDCCSR0_SA | UDCCSR0_OPC);
> +		}
> +		break;
> +	case EP0_IN_DATA_PHASE:	/* GET_DESCRIPTOR etc */
> +		if (udccsr0 & UDCCSR0_OPC) {
> +			UDCCSR0 = UDCCSR0_OPC | UDCCSR0_FTF;
> +			DBG(DBG_VERBOSE, "ep0in premature status\n");
> +			if (req)
> +				done(ep, req, 0);
> +			ep0_idle(dev);
> +		} else {	/* irq was IPR clearing */
> +
> +			if (req) {
> +				/* this IN packet might finish the request */
> +				(void)write_ep0_fifo(ep, req);
> +			}	/* else IN token before response was written */
> +		}
> +		break;
> +	case EP0_OUT_DATA_PHASE:	/* SET_DESCRIPTOR etc */
> +		if (udccsr0 & UDCCSR0_OPC) {
> +			if (req) {
> +				/* this OUT packet might finish the request */
> +				if (read_ep0_fifo(ep, req))
> +					done(ep, req, 0);
> +				/* else more OUT packets expected */
> +			}	/* else OUT token before read was issued */
> +		} else {	/* irq was IPR clearing */
> +
> +			DBG(DBG_VERBOSE, "ep0out premature status\n");
> +			if (req)
> +				done(ep, req, 0);
> +			ep0_idle(dev);
> +		}
> +		break;
> +	case EP0_STALL:
> +		UDCCSR0 = UDCCSR0_FST;
> +		break;
> +	}
> +	UDCISR0 = UDCISR_INT(0, UDCISR_INT_MASK);
> +}
> +
>
> ...
>
> +static void udc_init_ep(struct pxa27x_udc *dev)
> +{
> +	int i;
> +
> +	INIT_LIST_HEAD(&dev->gadget.ep_list);
> +	INIT_LIST_HEAD(&dev->gadget.ep0->ep_list);
> +
> +	for (i = 0; i < UDC_EP_NUM; i++) {
> +		struct pxa27x_ep *ep = &dev->ep[i];
> +
> +		ep->dma = -1;
> +		if (i != 0) {
> +			memset(ep, 0, sizeof(*ep));
> +		}

unneeded braces

> +		INIT_LIST_HEAD(&ep->queue);
> +	}
> +}
> +
> +/*-------------------------------------------------------------------------*/
> +
> +static void nop_release(struct device *dev)
> +{
> +	DMSG("%s %s\n", __FUNCTION__, dev->bus_id);
> +}
> +
> +/* this uses load-time allocation and initialization (instead of
> + * doing it at run-time) to save code, eliminate fault paths, and
> + * be more obviously correct.
> + */
> +static struct pxa27x_udc memory = {
> +	.gadget = {
> +		   .ops = &pxa27x_udc_ops,
> +		   .ep0 = &memory.ep[0].ep,
> +		   .name = driver_name,
> +		   .dev = {
> +			   .bus_id = "gadget",
> +			   .release = nop_release,
> +			   },
> +		   },
> +
> +	/* control endpoint */
> +	.ep[0] = {
> +		  .ep = {
> +			 .name = ep0name,
> +			 .ops = &pxa27x_ep_ops,
> +			 .maxpacket = EP0_FIFO_SIZE,
> +			 },
> +		  .dev = &memory,
> +		  .reg_udccsr = &UDCCSR0,
> +		  .reg_udcdr = &UDCDR0,

whitespace broke

> +		  }
> +};
> +
> +#define CP15R0_VENDOR_MASK	0xffffe000
> +
> +#define CP15R0_XSCALE_VALUE	0x69054000	/* intel/arm/xscale */
> +
> +/*
> + * 	probe - binds to the platform device
> + */
> +static int __init pxa27x_udc_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct pxa27x_udc *udc = &memory;
> +	int irq, retval;
> +	u32 chiprev;
> +
> +	/* insist on Intel/ARM/XScale */
> +      asm("mrc%? p15, 0, %0, c0, c0":"=r"(chiprev));

whitespace

> +	if ((chiprev & CP15R0_VENDOR_MASK) != CP15R0_XSCALE_VALUE) {
> +		printk(KERN_ERR "%s: not XScale!\n", driver_name);
> +		return -ENODEV;
> +	}
> +
> +	irq = platform_get_irq(pdev, 0);
> +	if (irq < 0)
> +		return -ENODEV;
> +	pr_debug("%s: IRQ %d\n", driver_name, irq);
> +
> +	/* other non-static parts of init */
> +	udc->dev = dev;
> +	udc->mach = dev->platform_data;
> +
> +	/* Disable irq, erase old events and disable the pull up on the bus */
> +	UDCICR0 = 0x00000000;
> +	UDCICR1 = 0x00000000;
> +	UDCISR0 = 0xffffffff;
> +	UDCISR1 = 0xffffffff;
> +	if (udc->mach->gpio_pullup)
> +		udc_gpio_init_pullup(udc->mach->gpio_pullup);
> +
> +	init_timer(&udc->timer);
> +	udc->timer.function = udc_watchdog;
> +	udc->timer.data = (unsigned long)udc;
> +
> +	device_initialize(&udc->gadget.dev);
> +	udc->gadget.dev.parent = dev;
> +	udc->gadget.dev.dma_mask = dev->dma_mask;
> +
> +	the_controller = udc;
> +	dev_set_drvdata(dev, udc);
> +
> +	udc_disable(udc);
> +	udc_init_ep(udc);
> +	udc_reinit(udc);
> +
> +	/* irq setup after old hardware state is cleaned up */
> +	retval = request_irq(irq, pxa27x_udc_irq, 0, driver_name, udc);
> +	if (retval != 0) {
> +		printk(KERN_ERR "%s: can't get irq %i, err %d\n",
> +		       driver_name, irq, retval);
> +		return -EBUSY;
> +	}
> +	udc->got_irq = 1;
> +
> +	create_proc_files();
> +
> +	return 0;
> +}
> +
>
> ...
>
> +	/* UDCCSR = UDC Control/Status Register for this EP
> +	 * UBCR = UDC Byte Count Remaining (contents of OUT fifo)
> +	 * UDCDR = UDC Endpoint Data Register (the fifo)
> +	 * UDCCR = UDC Endpoint Configuration Registers
> +	 * DRCM = DMA Request Channel Map
> +	 */
> +	volatile u32				*reg_udccsr;
> +	volatile u32				*reg_udcbcr;
> +	volatile u32				*reg_udcdr;
> +	volatile u32				*reg_udccr;

more volatiles

> +#ifdef USE_DMA
> +	volatile u32				*reg_drcmr;
> +#define	drcmr(n)  .reg_drcmr = & DRCMR ## n ,
> +#else
> +#define	drcmr(n)  
> +#endif
> +
> +#ifdef CONFIG_PM
> +	unsigned				udccsr_value;
> +	unsigned				udccr_value;
> +#endif
> +};
> +
>
> ...
>
> +
> +#define EP0_FIFO_SIZE	((unsigned)16)
> +#define BULK_FIFO_SIZE	((unsigned)64)
> +#define ISO_FIFO_SIZE	((unsigned)256)
> +#define INT_FIFO_SIZE	((unsigned)8)

#define INT_FIFO_SIZE	8U

would be nicer.

> +struct pxa27x_udc {
> +	struct usb_gadget			gadget;
> +	struct usb_gadget_driver		*driver;
> +
> +	enum ep0_state				ep0state;
> +	struct udc_stats			stats;
> +	unsigned				got_irq : 1,
> +						got_disc : 1,
> +						has_cfr : 1,
> +						req_pending : 1,
> +						req_std : 1,
> +						req_config : 1;
> +
> +#define start_watchdog(dev) mod_timer(&dev->timer, jiffies + (HZ/200))

write it in C or, better, just open-code it at the callsite.

> +	struct timer_list			timer;
> +
> +	struct device				*dev;
> +	struct pxa2xx_udc_mach_info		*mach;
> +	u64					dma_mask;
> +	struct pxa27x_ep			ep [UDC_EP_NUM];
> +
> +	unsigned				configuration, 
> +						interface, 
> +						alternate;
> +#ifdef CONFIG_PM
> +	unsigned				udccsr0;
> +#endif
> +};
>
> ...
>
> +#define HEX_DISPLAY2(n)	do { \
> +	if (machine_is_mainstone()) \
> +		{ MST_LEDDAT2 = (n); } \
> +	} while(0)

See, this references "n"

> +
> +/* LEDs are only for debug */
> +#ifndef HEX_DISPLAY
> +#define HEX_DISPLAY(n)		do {} while(0)
> +#endif

but this doesn't.  So we risk getting unused-var warnings in callers
depending upon config options.  Writing this in C rather than cpp (the
general rule) will fix this, as well as lots of other stuff.

HEX_DISPLAY2 gets different treatment from HEX_DISPLAY here.

> +#ifndef LED_CONNECTED_ON
> +#define LED_CONNECTED_ON	do {} while(0)
> +#define LED_CONNECTED_OFF	do {} while(0)
> +#endif
> +#ifndef LED_EP0_ON
> +#define LED_EP0_ON		do {} while (0)
> +#define LED_EP0_OFF		do {} while (0)
> +#endif
> +
> +static struct pxa27x_udc *the_controller;

eep, you can't do that!  We'll get separate instances of the_controller in
each C file which includes this header.

> +/*-------------------------------------------------------------------------*/
> +
> +/*
> + * Debugging support vanishes in non-debug builds.  DBG_NORMAL should be
> + * mostly silent during normal use/testing, with no timing side-effects.
> + */
> +#define DBG_NORMAL	1	/* error paths, device state transitions */
> +#define DBG_VERBOSE	2	/* add some success path trace info */
> +#define DBG_NOISY	3	/* ... even more: request level */
> +#define DBG_VERY_NOISY	4	/* ... even more: packet level */
> +
> +#ifdef DEBUG
> +
> +static const char *state_name[] = {
> +	"EP0_IDLE",
> +	"EP0_IN_DATA_PHASE", "EP0_OUT_DATA_PHASE",
> +	"EP0_END_XFER", "EP0_STALL"
> +};
> +
> +#define DMSG(stuff...) printk(KERN_ERR "udc: " stuff)
> +
> +#ifdef VERBOSE
> +#    define UDC_DEBUG DBG_VERBOSE
> +#else
> +#    define UDC_DEBUG DBG_NORMAL
> +#endif
> +
> +static void __attribute__ ((__unused__))

Use __maybe_unused

> +dump_udccr(const char *label)
> +{
> +	u32	udccr = UDCCR;
> +	DMSG("%s 0x%08x =%s%s%s%s%s%s%s%s%s%s, con=%d,inter=%d,altinter=%d\n",
> +		label, udccr,
> +		(udccr & UDCCR_OEN) ? " oen":"",
> +		(udccr & UDCCR_AALTHNP) ? " aalthnp":"",
> +		(udccr & UDCCR_AHNP) ? " rem" : "",
> +		(udccr & UDCCR_BHNP) ? " rstir" : "",
> +		(udccr & UDCCR_DWRE) ? " dwre" : "",
> +		(udccr & UDCCR_SMAC) ? " smac" : "",
> +		(udccr & UDCCR_EMCE) ? " emce" : "",
> +		(udccr & UDCCR_UDR) ? " udr" : "",
> +		(udccr & UDCCR_UDA) ? " uda" : "",
> +		(udccr & UDCCR_UDE) ? " ude" : "",
> +		(udccr & UDCCR_ACN) >> UDCCR_ACN_S,
> +		(udccr & UDCCR_AIN) >> UDCCR_AIN_S,
> +		(udccr & UDCCR_AAISN)>> UDCCR_AAISN_S );
> +}
> +
> +static void __attribute__ ((__unused__))

ditto

> +dump_udccsr0(const char *label)
> +{
> +	u32		udccsr0 = UDCCSR0;
> +
> +	DMSG("%s %s 0x%08x =%s%s%s%s%s%s%s\n",
> +		label, state_name[the_controller->ep0state], udccsr0,
> +		(udccsr0 & UDCCSR0_SA) ? " sa" : "",
> +		(udccsr0 & UDCCSR0_RNE) ? " rne" : "",
> +		(udccsr0 & UDCCSR0_FST) ? " fst" : "",
> +		(udccsr0 & UDCCSR0_SST) ? " sst" : "",
> +		(udccsr0 & UDCCSR0_DME) ? " dme" : "",
> +		(udccsr0 & UDCCSR0_IPR) ? " ipr" : "",
> +		(udccsr0 & UDCCSR0_OPC) ? " opr" : "");
> +}
> +
> +static void __attribute__ ((__unused__))

ditto

> +dump_state(struct pxa27x_udc *dev)
> +{
> +	unsigned	i;
> +
> +	DMSG("%s, udcicr %02X.%02X, udcsir %02X.%02x, udcfnr %02X\n",
> +		state_name[dev->ep0state],
> +		UDCICR1, UDCICR0, UDCISR1, UDCISR0, UDCFNR);
> +	dump_udccr("udccr");
> +
> +	if (!dev->driver) {
> +		DMSG("no gadget driver bound\n");
> +		return;
> +	} else
> +		DMSG("ep0 driver '%s'\n", dev->driver->driver.name);
> +
> +	
> +	dump_udccsr0 ("udccsr0");
> +	DMSG("ep0 IN %lu/%lu, OUT %lu/%lu\n",
> +		dev->stats.write.bytes, dev->stats.write.ops,
> +		dev->stats.read.bytes, dev->stats.read.ops);
> +
> +	for (i = 1; i < UDC_EP_NUM; i++) {
> +		if (dev->ep [i].desc == 0)
> +			continue;
> +		DMSG ("udccs%d = %02x\n", i, *dev->ep->reg_udccsr);
> +	}
> +}
> +
>
> ..
> 
> +
> +#define WARN(stuff...) printk(KERN_WARNING "udc: " stuff)
> +#define INFO(stuff...) printk(KERN_INFO "udc: " stuff)

hrm.  Why does every driver in the tree need to invent its own boilerplate
infrastructure?

can we use dev_warn() here or something?


-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux