Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6: USB: update Kconfig help text for CONFIG_USB_SUSPEND usb: musb: gadget: restart request on clearing endpoint halt usb: musb: host: Issue a memory barrier before starting DMA usb: musb: gadget: fix dma length in txstate usb: musb: gadget: complete request only if data is transfered over usb: musb: gadget: fix DMA length for OUT transfer usb: musb: gadget: enable autoclear for OUT transfer in both DMA 0 and DMA 1 usb: musb: gadget: fix bulk IN infinit hangs in double buffer case usb: musb: gadget: fix kernel panic if using out ep with FIFO_TXRX style USB: fix bug in initialization of interface minor numbers
This commit is contained in:
commit
cb9cae0395
|
@ -91,12 +91,12 @@ config USB_DYNAMIC_MINORS
|
|||
If you are unsure about this, say N here.
|
||||
|
||||
config USB_SUSPEND
|
||||
bool "USB runtime power management (suspend/resume and wakeup)"
|
||||
bool "USB runtime power management (autosuspend) and wakeup"
|
||||
depends on USB && PM_RUNTIME
|
||||
help
|
||||
If you say Y here, you can use driver calls or the sysfs
|
||||
"power/level" file to suspend or resume individual USB
|
||||
peripherals and to enable or disable autosuspend (see
|
||||
"power/control" file to enable or disable autosuspend for
|
||||
individual USB peripherals (see
|
||||
Documentation/usb/power-management.txt for more details).
|
||||
|
||||
Also, USB "remote wakeup" signaling is supported, whereby some
|
||||
|
|
|
@ -159,9 +159,9 @@ void usb_major_cleanup(void)
|
|||
int usb_register_dev(struct usb_interface *intf,
|
||||
struct usb_class_driver *class_driver)
|
||||
{
|
||||
int retval = -EINVAL;
|
||||
int retval;
|
||||
int minor_base = class_driver->minor_base;
|
||||
int minor = 0;
|
||||
int minor;
|
||||
char name[20];
|
||||
char *temp;
|
||||
|
||||
|
@ -173,12 +173,17 @@ int usb_register_dev(struct usb_interface *intf,
|
|||
*/
|
||||
minor_base = 0;
|
||||
#endif
|
||||
intf->minor = -1;
|
||||
|
||||
dbg ("looking for a minor, starting at %d", minor_base);
|
||||
|
||||
if (class_driver->fops == NULL)
|
||||
goto exit;
|
||||
return -EINVAL;
|
||||
if (intf->minor >= 0)
|
||||
return -EADDRINUSE;
|
||||
|
||||
retval = init_usb_class();
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
dev_dbg(&intf->dev, "looking for a minor, starting at %d", minor_base);
|
||||
|
||||
down_write(&minor_rwsem);
|
||||
for (minor = minor_base; minor < MAX_USB_MINORS; ++minor) {
|
||||
|
@ -186,20 +191,12 @@ int usb_register_dev(struct usb_interface *intf,
|
|||
continue;
|
||||
|
||||
usb_minors[minor] = class_driver->fops;
|
||||
|
||||
retval = 0;
|
||||
intf->minor = minor;
|
||||
break;
|
||||
}
|
||||
up_write(&minor_rwsem);
|
||||
|
||||
if (retval)
|
||||
goto exit;
|
||||
|
||||
retval = init_usb_class();
|
||||
if (retval)
|
||||
goto exit;
|
||||
|
||||
intf->minor = minor;
|
||||
if (intf->minor < 0)
|
||||
return -EXFULL;
|
||||
|
||||
/* create a usb class device for this usb interface */
|
||||
snprintf(name, sizeof(name), class_driver->name, minor - minor_base);
|
||||
|
@ -213,11 +210,11 @@ int usb_register_dev(struct usb_interface *intf,
|
|||
"%s", temp);
|
||||
if (IS_ERR(intf->usb_dev)) {
|
||||
down_write(&minor_rwsem);
|
||||
usb_minors[intf->minor] = NULL;
|
||||
usb_minors[minor] = NULL;
|
||||
intf->minor = -1;
|
||||
up_write(&minor_rwsem);
|
||||
retval = PTR_ERR(intf->usb_dev);
|
||||
}
|
||||
exit:
|
||||
return retval;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_register_dev);
|
||||
|
|
|
@ -1802,6 +1802,7 @@ free_interfaces:
|
|||
intf->dev.groups = usb_interface_groups;
|
||||
intf->dev.dma_mask = dev->dev.dma_mask;
|
||||
INIT_WORK(&intf->reset_ws, __usb_queue_reset_device);
|
||||
intf->minor = -1;
|
||||
device_initialize(&intf->dev);
|
||||
dev_set_name(&intf->dev, "%d-%s:%d.%d",
|
||||
dev->bus->busnum, dev->devpath,
|
||||
|
|
|
@ -322,6 +322,7 @@ cppi_channel_allocate(struct dma_controller *c,
|
|||
index, transmit ? 'T' : 'R', cppi_ch);
|
||||
cppi_ch->hw_ep = ep;
|
||||
cppi_ch->channel.status = MUSB_DMA_STATUS_FREE;
|
||||
cppi_ch->channel.max_len = 0x7fffffff;
|
||||
|
||||
DBG(4, "Allocate CPPI%d %cX\n", index, transmit ? 'T' : 'R');
|
||||
return &cppi_ch->channel;
|
||||
|
|
|
@ -300,6 +300,11 @@ static void txstate(struct musb *musb, struct musb_request *req)
|
|||
#ifndef CONFIG_MUSB_PIO_ONLY
|
||||
if (is_dma_capable() && musb_ep->dma) {
|
||||
struct dma_controller *c = musb->dma_controller;
|
||||
size_t request_size;
|
||||
|
||||
/* setup DMA, then program endpoint CSR */
|
||||
request_size = min_t(size_t, request->length - request->actual,
|
||||
musb_ep->dma->max_len);
|
||||
|
||||
use_dma = (request->dma != DMA_ADDR_INVALID);
|
||||
|
||||
|
@ -307,11 +312,6 @@ static void txstate(struct musb *musb, struct musb_request *req)
|
|||
|
||||
#ifdef CONFIG_USB_INVENTRA_DMA
|
||||
{
|
||||
size_t request_size;
|
||||
|
||||
/* setup DMA, then program endpoint CSR */
|
||||
request_size = min_t(size_t, request->length,
|
||||
musb_ep->dma->max_len);
|
||||
if (request_size < musb_ep->packet_sz)
|
||||
musb_ep->dma->desired_mode = 0;
|
||||
else
|
||||
|
@ -373,8 +373,8 @@ static void txstate(struct musb *musb, struct musb_request *req)
|
|||
use_dma = use_dma && c->channel_program(
|
||||
musb_ep->dma, musb_ep->packet_sz,
|
||||
0,
|
||||
request->dma,
|
||||
request->length);
|
||||
request->dma + request->actual,
|
||||
request_size);
|
||||
if (!use_dma) {
|
||||
c->channel_release(musb_ep->dma);
|
||||
musb_ep->dma = NULL;
|
||||
|
@ -386,8 +386,8 @@ static void txstate(struct musb *musb, struct musb_request *req)
|
|||
use_dma = use_dma && c->channel_program(
|
||||
musb_ep->dma, musb_ep->packet_sz,
|
||||
request->zero,
|
||||
request->dma,
|
||||
request->length);
|
||||
request->dma + request->actual,
|
||||
request_size);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
@ -501,26 +501,14 @@ void musb_g_tx(struct musb *musb, u8 epnum)
|
|||
request->zero = 0;
|
||||
}
|
||||
|
||||
/* ... or if not, then complete it. */
|
||||
musb_g_giveback(musb_ep, request, 0);
|
||||
|
||||
/*
|
||||
* Kickstart next transfer if appropriate;
|
||||
* the packet that just completed might not
|
||||
* be transmitted for hours or days.
|
||||
* REVISIT for double buffering...
|
||||
* FIXME revisit for stalls too...
|
||||
*/
|
||||
musb_ep_select(mbase, epnum);
|
||||
csr = musb_readw(epio, MUSB_TXCSR);
|
||||
if (csr & MUSB_TXCSR_FIFONOTEMPTY)
|
||||
return;
|
||||
|
||||
request = musb_ep->desc ? next_request(musb_ep) : NULL;
|
||||
if (!request) {
|
||||
DBG(4, "%s idle now\n",
|
||||
musb_ep->end_point.name);
|
||||
return;
|
||||
if (request->actual == request->length) {
|
||||
musb_g_giveback(musb_ep, request, 0);
|
||||
request = musb_ep->desc ? next_request(musb_ep) : NULL;
|
||||
if (!request) {
|
||||
DBG(4, "%s idle now\n",
|
||||
musb_ep->end_point.name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -568,11 +556,19 @@ static void rxstate(struct musb *musb, struct musb_request *req)
|
|||
{
|
||||
const u8 epnum = req->epnum;
|
||||
struct usb_request *request = &req->request;
|
||||
struct musb_ep *musb_ep = &musb->endpoints[epnum].ep_out;
|
||||
struct musb_ep *musb_ep;
|
||||
void __iomem *epio = musb->endpoints[epnum].regs;
|
||||
unsigned fifo_count = 0;
|
||||
u16 len = musb_ep->packet_sz;
|
||||
u16 len;
|
||||
u16 csr = musb_readw(epio, MUSB_RXCSR);
|
||||
struct musb_hw_ep *hw_ep = &musb->endpoints[epnum];
|
||||
|
||||
if (hw_ep->is_shared_fifo)
|
||||
musb_ep = &hw_ep->ep_in;
|
||||
else
|
||||
musb_ep = &hw_ep->ep_out;
|
||||
|
||||
len = musb_ep->packet_sz;
|
||||
|
||||
/* We shouldn't get here while DMA is active, but we do... */
|
||||
if (dma_channel_status(musb_ep->dma) == MUSB_DMA_STATUS_BUSY) {
|
||||
|
@ -647,8 +643,8 @@ static void rxstate(struct musb *musb, struct musb_request *req)
|
|||
*/
|
||||
|
||||
csr |= MUSB_RXCSR_DMAENAB;
|
||||
#ifdef USE_MODE1
|
||||
csr |= MUSB_RXCSR_AUTOCLEAR;
|
||||
#ifdef USE_MODE1
|
||||
/* csr |= MUSB_RXCSR_DMAMODE; */
|
||||
|
||||
/* this special sequence (enabling and then
|
||||
|
@ -663,10 +659,11 @@ static void rxstate(struct musb *musb, struct musb_request *req)
|
|||
if (request->actual < request->length) {
|
||||
int transfer_size = 0;
|
||||
#ifdef USE_MODE1
|
||||
transfer_size = min(request->length,
|
||||
transfer_size = min(request->length - request->actual,
|
||||
channel->max_len);
|
||||
#else
|
||||
transfer_size = len;
|
||||
transfer_size = min(request->length - request->actual,
|
||||
(unsigned)len);
|
||||
#endif
|
||||
if (transfer_size <= musb_ep->packet_sz)
|
||||
musb_ep->dma->desired_mode = 0;
|
||||
|
@ -740,9 +737,15 @@ void musb_g_rx(struct musb *musb, u8 epnum)
|
|||
u16 csr;
|
||||
struct usb_request *request;
|
||||
void __iomem *mbase = musb->mregs;
|
||||
struct musb_ep *musb_ep = &musb->endpoints[epnum].ep_out;
|
||||
struct musb_ep *musb_ep;
|
||||
void __iomem *epio = musb->endpoints[epnum].regs;
|
||||
struct dma_channel *dma;
|
||||
struct musb_hw_ep *hw_ep = &musb->endpoints[epnum];
|
||||
|
||||
if (hw_ep->is_shared_fifo)
|
||||
musb_ep = &hw_ep->ep_in;
|
||||
else
|
||||
musb_ep = &hw_ep->ep_out;
|
||||
|
||||
musb_ep_select(mbase, epnum);
|
||||
|
||||
|
@ -1081,7 +1084,7 @@ struct free_record {
|
|||
/*
|
||||
* Context: controller locked, IRQs blocked.
|
||||
*/
|
||||
static void musb_ep_restart(struct musb *musb, struct musb_request *req)
|
||||
void musb_ep_restart(struct musb *musb, struct musb_request *req)
|
||||
{
|
||||
DBG(3, "<== %s request %p len %u on hw_ep%d\n",
|
||||
req->tx ? "TX/IN" : "RX/OUT",
|
||||
|
|
|
@ -105,4 +105,6 @@ extern void musb_gadget_cleanup(struct musb *);
|
|||
|
||||
extern void musb_g_giveback(struct musb_ep *, struct usb_request *, int);
|
||||
|
||||
extern void musb_ep_restart(struct musb *, struct musb_request *);
|
||||
|
||||
#endif /* __MUSB_GADGET_H */
|
||||
|
|
|
@ -261,6 +261,7 @@ __acquires(musb->lock)
|
|||
ctrlrequest->wIndex & 0x0f;
|
||||
struct musb_ep *musb_ep;
|
||||
struct musb_hw_ep *ep;
|
||||
struct musb_request *request;
|
||||
void __iomem *regs;
|
||||
int is_in;
|
||||
u16 csr;
|
||||
|
@ -302,6 +303,14 @@ __acquires(musb->lock)
|
|||
musb_writew(regs, MUSB_RXCSR, csr);
|
||||
}
|
||||
|
||||
/* Maybe start the first request in the queue */
|
||||
request = to_musb_request(
|
||||
next_request(musb_ep));
|
||||
if (!musb_ep->busy && request) {
|
||||
DBG(3, "restarting the request\n");
|
||||
musb_ep_restart(musb, request);
|
||||
}
|
||||
|
||||
/* select ep0 again */
|
||||
musb_ep_select(mbase, 0);
|
||||
} break;
|
||||
|
|
|
@ -660,6 +660,12 @@ static bool musb_tx_dma_program(struct dma_controller *dma,
|
|||
|
||||
qh->segsize = length;
|
||||
|
||||
/*
|
||||
* Ensure the data reaches to main memory before starting
|
||||
* DMA transfer
|
||||
*/
|
||||
wmb();
|
||||
|
||||
if (!dma->channel_program(channel, pkt_size, mode,
|
||||
urb->transfer_dma + offset, length)) {
|
||||
dma->channel_release(channel);
|
||||
|
|
Loading…
Reference in New Issue