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.
|
If you are unsure about this, say N here.
|
||||||
|
|
||||||
config USB_SUSPEND
|
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
|
depends on USB && PM_RUNTIME
|
||||||
help
|
help
|
||||||
If you say Y here, you can use driver calls or the sysfs
|
If you say Y here, you can use driver calls or the sysfs
|
||||||
"power/level" file to suspend or resume individual USB
|
"power/control" file to enable or disable autosuspend for
|
||||||
peripherals and to enable or disable autosuspend (see
|
individual USB peripherals (see
|
||||||
Documentation/usb/power-management.txt for more details).
|
Documentation/usb/power-management.txt for more details).
|
||||||
|
|
||||||
Also, USB "remote wakeup" signaling is supported, whereby some
|
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,
|
int usb_register_dev(struct usb_interface *intf,
|
||||||
struct usb_class_driver *class_driver)
|
struct usb_class_driver *class_driver)
|
||||||
{
|
{
|
||||||
int retval = -EINVAL;
|
int retval;
|
||||||
int minor_base = class_driver->minor_base;
|
int minor_base = class_driver->minor_base;
|
||||||
int minor = 0;
|
int minor;
|
||||||
char name[20];
|
char name[20];
|
||||||
char *temp;
|
char *temp;
|
||||||
|
|
||||||
@ -173,12 +173,17 @@ int usb_register_dev(struct usb_interface *intf,
|
|||||||
*/
|
*/
|
||||||
minor_base = 0;
|
minor_base = 0;
|
||||||
#endif
|
#endif
|
||||||
intf->minor = -1;
|
|
||||||
|
|
||||||
dbg ("looking for a minor, starting at %d", minor_base);
|
|
||||||
|
|
||||||
if (class_driver->fops == NULL)
|
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);
|
down_write(&minor_rwsem);
|
||||||
for (minor = minor_base; minor < MAX_USB_MINORS; ++minor) {
|
for (minor = minor_base; minor < MAX_USB_MINORS; ++minor) {
|
||||||
@ -186,20 +191,12 @@ int usb_register_dev(struct usb_interface *intf,
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
usb_minors[minor] = class_driver->fops;
|
usb_minors[minor] = class_driver->fops;
|
||||||
|
intf->minor = minor;
|
||||||
retval = 0;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
up_write(&minor_rwsem);
|
up_write(&minor_rwsem);
|
||||||
|
if (intf->minor < 0)
|
||||||
if (retval)
|
return -EXFULL;
|
||||||
goto exit;
|
|
||||||
|
|
||||||
retval = init_usb_class();
|
|
||||||
if (retval)
|
|
||||||
goto exit;
|
|
||||||
|
|
||||||
intf->minor = minor;
|
|
||||||
|
|
||||||
/* create a usb class device for this usb interface */
|
/* create a usb class device for this usb interface */
|
||||||
snprintf(name, sizeof(name), class_driver->name, minor - minor_base);
|
snprintf(name, sizeof(name), class_driver->name, minor - minor_base);
|
||||||
@ -213,11 +210,11 @@ int usb_register_dev(struct usb_interface *intf,
|
|||||||
"%s", temp);
|
"%s", temp);
|
||||||
if (IS_ERR(intf->usb_dev)) {
|
if (IS_ERR(intf->usb_dev)) {
|
||||||
down_write(&minor_rwsem);
|
down_write(&minor_rwsem);
|
||||||
usb_minors[intf->minor] = NULL;
|
usb_minors[minor] = NULL;
|
||||||
|
intf->minor = -1;
|
||||||
up_write(&minor_rwsem);
|
up_write(&minor_rwsem);
|
||||||
retval = PTR_ERR(intf->usb_dev);
|
retval = PTR_ERR(intf->usb_dev);
|
||||||
}
|
}
|
||||||
exit:
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(usb_register_dev);
|
EXPORT_SYMBOL_GPL(usb_register_dev);
|
||||||
|
@ -1802,6 +1802,7 @@ free_interfaces:
|
|||||||
intf->dev.groups = usb_interface_groups;
|
intf->dev.groups = usb_interface_groups;
|
||||||
intf->dev.dma_mask = dev->dev.dma_mask;
|
intf->dev.dma_mask = dev->dev.dma_mask;
|
||||||
INIT_WORK(&intf->reset_ws, __usb_queue_reset_device);
|
INIT_WORK(&intf->reset_ws, __usb_queue_reset_device);
|
||||||
|
intf->minor = -1;
|
||||||
device_initialize(&intf->dev);
|
device_initialize(&intf->dev);
|
||||||
dev_set_name(&intf->dev, "%d-%s:%d.%d",
|
dev_set_name(&intf->dev, "%d-%s:%d.%d",
|
||||||
dev->bus->busnum, dev->devpath,
|
dev->bus->busnum, dev->devpath,
|
||||||
|
@ -322,6 +322,7 @@ cppi_channel_allocate(struct dma_controller *c,
|
|||||||
index, transmit ? 'T' : 'R', cppi_ch);
|
index, transmit ? 'T' : 'R', cppi_ch);
|
||||||
cppi_ch->hw_ep = ep;
|
cppi_ch->hw_ep = ep;
|
||||||
cppi_ch->channel.status = MUSB_DMA_STATUS_FREE;
|
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');
|
DBG(4, "Allocate CPPI%d %cX\n", index, transmit ? 'T' : 'R');
|
||||||
return &cppi_ch->channel;
|
return &cppi_ch->channel;
|
||||||
|
@ -300,6 +300,11 @@ static void txstate(struct musb *musb, struct musb_request *req)
|
|||||||
#ifndef CONFIG_MUSB_PIO_ONLY
|
#ifndef CONFIG_MUSB_PIO_ONLY
|
||||||
if (is_dma_capable() && musb_ep->dma) {
|
if (is_dma_capable() && musb_ep->dma) {
|
||||||
struct dma_controller *c = musb->dma_controller;
|
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);
|
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
|
#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)
|
if (request_size < musb_ep->packet_sz)
|
||||||
musb_ep->dma->desired_mode = 0;
|
musb_ep->dma->desired_mode = 0;
|
||||||
else
|
else
|
||||||
@ -373,8 +373,8 @@ static void txstate(struct musb *musb, struct musb_request *req)
|
|||||||
use_dma = use_dma && c->channel_program(
|
use_dma = use_dma && c->channel_program(
|
||||||
musb_ep->dma, musb_ep->packet_sz,
|
musb_ep->dma, musb_ep->packet_sz,
|
||||||
0,
|
0,
|
||||||
request->dma,
|
request->dma + request->actual,
|
||||||
request->length);
|
request_size);
|
||||||
if (!use_dma) {
|
if (!use_dma) {
|
||||||
c->channel_release(musb_ep->dma);
|
c->channel_release(musb_ep->dma);
|
||||||
musb_ep->dma = NULL;
|
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(
|
use_dma = use_dma && c->channel_program(
|
||||||
musb_ep->dma, musb_ep->packet_sz,
|
musb_ep->dma, musb_ep->packet_sz,
|
||||||
request->zero,
|
request->zero,
|
||||||
request->dma,
|
request->dma + request->actual,
|
||||||
request->length);
|
request_size);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -501,26 +501,14 @@ void musb_g_tx(struct musb *musb, u8 epnum)
|
|||||||
request->zero = 0;
|
request->zero = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ... or if not, then complete it. */
|
if (request->actual == request->length) {
|
||||||
musb_g_giveback(musb_ep, request, 0);
|
musb_g_giveback(musb_ep, request, 0);
|
||||||
|
request = musb_ep->desc ? next_request(musb_ep) : NULL;
|
||||||
/*
|
if (!request) {
|
||||||
* Kickstart next transfer if appropriate;
|
DBG(4, "%s idle now\n",
|
||||||
* the packet that just completed might not
|
musb_ep->end_point.name);
|
||||||
* be transmitted for hours or days.
|
return;
|
||||||
* 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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -568,11 +556,19 @@ static void rxstate(struct musb *musb, struct musb_request *req)
|
|||||||
{
|
{
|
||||||
const u8 epnum = req->epnum;
|
const u8 epnum = req->epnum;
|
||||||
struct usb_request *request = &req->request;
|
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;
|
void __iomem *epio = musb->endpoints[epnum].regs;
|
||||||
unsigned fifo_count = 0;
|
unsigned fifo_count = 0;
|
||||||
u16 len = musb_ep->packet_sz;
|
u16 len;
|
||||||
u16 csr = musb_readw(epio, MUSB_RXCSR);
|
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... */
|
/* We shouldn't get here while DMA is active, but we do... */
|
||||||
if (dma_channel_status(musb_ep->dma) == MUSB_DMA_STATUS_BUSY) {
|
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;
|
csr |= MUSB_RXCSR_DMAENAB;
|
||||||
#ifdef USE_MODE1
|
|
||||||
csr |= MUSB_RXCSR_AUTOCLEAR;
|
csr |= MUSB_RXCSR_AUTOCLEAR;
|
||||||
|
#ifdef USE_MODE1
|
||||||
/* csr |= MUSB_RXCSR_DMAMODE; */
|
/* csr |= MUSB_RXCSR_DMAMODE; */
|
||||||
|
|
||||||
/* this special sequence (enabling and then
|
/* 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) {
|
if (request->actual < request->length) {
|
||||||
int transfer_size = 0;
|
int transfer_size = 0;
|
||||||
#ifdef USE_MODE1
|
#ifdef USE_MODE1
|
||||||
transfer_size = min(request->length,
|
transfer_size = min(request->length - request->actual,
|
||||||
channel->max_len);
|
channel->max_len);
|
||||||
#else
|
#else
|
||||||
transfer_size = len;
|
transfer_size = min(request->length - request->actual,
|
||||||
|
(unsigned)len);
|
||||||
#endif
|
#endif
|
||||||
if (transfer_size <= musb_ep->packet_sz)
|
if (transfer_size <= musb_ep->packet_sz)
|
||||||
musb_ep->dma->desired_mode = 0;
|
musb_ep->dma->desired_mode = 0;
|
||||||
@ -740,9 +737,15 @@ void musb_g_rx(struct musb *musb, u8 epnum)
|
|||||||
u16 csr;
|
u16 csr;
|
||||||
struct usb_request *request;
|
struct usb_request *request;
|
||||||
void __iomem *mbase = musb->mregs;
|
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;
|
void __iomem *epio = musb->endpoints[epnum].regs;
|
||||||
struct dma_channel *dma;
|
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);
|
musb_ep_select(mbase, epnum);
|
||||||
|
|
||||||
@ -1081,7 +1084,7 @@ struct free_record {
|
|||||||
/*
|
/*
|
||||||
* Context: controller locked, IRQs blocked.
|
* 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",
|
DBG(3, "<== %s request %p len %u on hw_ep%d\n",
|
||||||
req->tx ? "TX/IN" : "RX/OUT",
|
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_g_giveback(struct musb_ep *, struct usb_request *, int);
|
||||||
|
|
||||||
|
extern void musb_ep_restart(struct musb *, struct musb_request *);
|
||||||
|
|
||||||
#endif /* __MUSB_GADGET_H */
|
#endif /* __MUSB_GADGET_H */
|
||||||
|
@ -261,6 +261,7 @@ __acquires(musb->lock)
|
|||||||
ctrlrequest->wIndex & 0x0f;
|
ctrlrequest->wIndex & 0x0f;
|
||||||
struct musb_ep *musb_ep;
|
struct musb_ep *musb_ep;
|
||||||
struct musb_hw_ep *ep;
|
struct musb_hw_ep *ep;
|
||||||
|
struct musb_request *request;
|
||||||
void __iomem *regs;
|
void __iomem *regs;
|
||||||
int is_in;
|
int is_in;
|
||||||
u16 csr;
|
u16 csr;
|
||||||
@ -302,6 +303,14 @@ __acquires(musb->lock)
|
|||||||
musb_writew(regs, MUSB_RXCSR, csr);
|
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 */
|
/* select ep0 again */
|
||||||
musb_ep_select(mbase, 0);
|
musb_ep_select(mbase, 0);
|
||||||
} break;
|
} break;
|
||||||
|
@ -660,6 +660,12 @@ static bool musb_tx_dma_program(struct dma_controller *dma,
|
|||||||
|
|
||||||
qh->segsize = length;
|
qh->segsize = length;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ensure the data reaches to main memory before starting
|
||||||
|
* DMA transfer
|
||||||
|
*/
|
||||||
|
wmb();
|
||||||
|
|
||||||
if (!dma->channel_program(channel, pkt_size, mode,
|
if (!dma->channel_program(channel, pkt_size, mode,
|
||||||
urb->transfer_dma + offset, length)) {
|
urb->transfer_dma + offset, length)) {
|
||||||
dma->channel_release(channel);
|
dma->channel_release(channel);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user