提交 cb9cae03 编写于 作者: L Linus Torvalds

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
......@@ -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 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
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);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册