Commit 43abf8d7 authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://kernel.bkbits.net/gregkh/linux/linus-2.6

into home.osdl.org:/home/torvalds/v2.5/linux
parents f5ecfe8f 3ddbe676
...@@ -217,33 +217,35 @@ struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum) ...@@ -217,33 +217,35 @@ struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum)
/** /**
* usb_epnum_to_ep_desc - get the endpoint object with a given endpoint number * usb_epnum_to_ep_desc - get the endpoint object with a given endpoint number
* @dev: the device whose current configuration is considered * @dev: the device whose current configuration+altsettings is considered
* @epnum: the desired endpoint * @epnum: the desired endpoint, masked with USB_DIR_IN as appropriate.
* *
* This walks the device descriptor for the currently active configuration, * This walks the device descriptor for the currently active configuration,
* and returns a pointer to the endpoint with that particular endpoint * and returns a pointer to the endpoint with that particular endpoint
* number, or null. * number, or null.
* *
* Note that interface descriptors are not required to assign endpont * Note that interface descriptors are not required to list endpoint
* numbers sequentially, so that it would be incorrect to assume that * numbers in any standardized order, so that it would be wrong to
* the first endpoint in that descriptor corresponds to interface zero. * assume that ep2in precedes either ep5in, ep2out, or even ep1out.
* This routine helps device drivers avoid such mistakes. * This routine helps device drivers avoid such mistakes.
*/ */
struct usb_endpoint_descriptor * struct usb_endpoint_descriptor *
usb_epnum_to_ep_desc(struct usb_device *dev, unsigned epnum) usb_epnum_to_ep_desc(struct usb_device *dev, unsigned epnum)
{ {
int i, j, k; int i, k;
for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) {
for (j = 0; j < dev->actconfig->interface[i]->num_altsetting; j++) struct usb_interface *intf;
for (k = 0; k < dev->actconfig->interface[i]-> struct usb_host_interface *alt;
altsetting[j].desc.bNumEndpoints; k++)
if (epnum == dev->actconfig->interface[i]-> /* only endpoints in current altseting are active */
altsetting[j].endpoint[k] intf = dev->actconfig->interface[i];
.desc.bEndpointAddress) alt = intf->altsetting + intf->act_altsetting;
return &dev->actconfig->interface[i]->
altsetting[j].endpoint[k] for (k = 0; k < alt->desc.bNumEndpoints; k++)
.desc; if (epnum == alt->endpoint[k].desc.bEndpointAddress)
return &alt->endpoint[k].desc;
}
return NULL; return NULL;
} }
......
...@@ -147,6 +147,30 @@ config USB_ETH_SA1100 ...@@ -147,6 +147,30 @@ config USB_ETH_SA1100
depends on USB_ETH && USB_SA1100 depends on USB_ETH && USB_SA1100
default y default y
config USB_GADGETFS
tristate "Gadget Filesystem (EXPERIMENTAL)"
depends on USB_GADGET && (USB_DUMMY_HCD || USB_NET2280 || USB_PXA2XX) && EXPERIMENTAL
help
This driver provides a filesystem based API that lets user mode
programs implement a single-configuration USB device, including
endpoint I/O and control requests that don't relate to enumeration.
All endpoints, transfer speeds, and transfer types supported by
the hardware are available, through read() and write() calls.
Say "y" to link the driver statically, or "m" to build a
dynamically linked module called "gadgetfs".
config USB_GADGETFS_NET2280
bool
# for now, treat the "dummy" hcd as if it were a net2280
depends on USB_GADGETFS && (USB_NET2280 || USB_DUMMY_HCD)
default y
config USB_GADGETFS_PXA2XX
bool
depends on USB_GADGETFS && USB_PXA2XX
default y
endchoice endchoice
# endmenuconfig # endmenuconfig
...@@ -8,7 +8,9 @@ obj-$(CONFIG_USB_NET2280) += net2280.o ...@@ -8,7 +8,9 @@ obj-$(CONFIG_USB_NET2280) += net2280.o
# #
g_zero-objs := zero.o usbstring.o g_zero-objs := zero.o usbstring.o
g_ether-objs := ether.o usbstring.o g_ether-objs := ether.o usbstring.o
gadgetfs-objs := inode.o usbstring.o
obj-$(CONFIG_USB_ZERO) += g_zero.o obj-$(CONFIG_USB_ZERO) += g_zero.o
obj-$(CONFIG_USB_ETH) += g_ether.o obj-$(CONFIG_USB_ETH) += g_ether.o
obj-$(CONFIG_USB_GADGETFS) += gadgetfs.o
This diff is collapsed.
...@@ -156,6 +156,7 @@ static struct uhci_td *uhci_alloc_td(struct uhci_hcd *uhci, struct usb_device *d ...@@ -156,6 +156,7 @@ static struct uhci_td *uhci_alloc_td(struct uhci_hcd *uhci, struct usb_device *d
td->dev = dev; td->dev = dev;
INIT_LIST_HEAD(&td->list); INIT_LIST_HEAD(&td->list);
INIT_LIST_HEAD(&td->remove_list);
INIT_LIST_HEAD(&td->fl_list); INIT_LIST_HEAD(&td->fl_list);
usb_get_dev(dev); usb_get_dev(dev);
...@@ -286,6 +287,8 @@ static void uhci_free_td(struct uhci_hcd *uhci, struct uhci_td *td) ...@@ -286,6 +287,8 @@ static void uhci_free_td(struct uhci_hcd *uhci, struct uhci_td *td)
{ {
if (!list_empty(&td->list)) if (!list_empty(&td->list))
dbg("td %p is still in list!", td); dbg("td %p is still in list!", td);
if (!list_empty(&td->remove_list))
dbg("td %p still in remove_list!", td);
if (!list_empty(&td->fl_list)) if (!list_empty(&td->fl_list))
dbg("td %p is still in fl_list!", td); dbg("td %p is still in fl_list!", td);
...@@ -702,6 +705,7 @@ static void uhci_destroy_urb_priv(struct uhci_hcd *uhci, struct urb *urb) ...@@ -702,6 +705,7 @@ static void uhci_destroy_urb_priv(struct uhci_hcd *uhci, struct urb *urb)
{ {
struct list_head *head, *tmp; struct list_head *head, *tmp;
struct urb_priv *urbp; struct urb_priv *urbp;
unsigned long flags;
urbp = (struct urb_priv *)urb->hcpriv; urbp = (struct urb_priv *)urb->hcpriv;
if (!urbp) if (!urbp)
...@@ -713,6 +717,13 @@ static void uhci_destroy_urb_priv(struct uhci_hcd *uhci, struct urb *urb) ...@@ -713,6 +717,13 @@ static void uhci_destroy_urb_priv(struct uhci_hcd *uhci, struct urb *urb)
if (!list_empty(&urbp->complete_list)) if (!list_empty(&urbp->complete_list))
warn("uhci_destroy_urb_priv: urb %p still on uhci->complete_list", urb); warn("uhci_destroy_urb_priv: urb %p still on uhci->complete_list", urb);
spin_lock_irqsave(&uhci->td_remove_list_lock, flags);
/* Check to see if the remove list is empty. Set the IOC bit */
/* to force an interrupt so we can remove the TD's*/
if (list_empty(&uhci->td_remove_list))
uhci_set_next_interrupt(uhci);
head = &urbp->td_list; head = &urbp->td_list;
tmp = head->next; tmp = head->next;
while (tmp != head) { while (tmp != head) {
...@@ -722,9 +733,11 @@ static void uhci_destroy_urb_priv(struct uhci_hcd *uhci, struct urb *urb) ...@@ -722,9 +733,11 @@ static void uhci_destroy_urb_priv(struct uhci_hcd *uhci, struct urb *urb)
uhci_remove_td_from_urb(td); uhci_remove_td_from_urb(td);
uhci_remove_td(uhci, td); uhci_remove_td(uhci, td);
uhci_free_td(uhci, td); list_add(&td->remove_list, &uhci->td_remove_list);
} }
spin_unlock_irqrestore(&uhci->td_remove_list_lock, flags);
urb->hcpriv = NULL; urb->hcpriv = NULL;
kmem_cache_free(uhci_up_cachep, urbp); kmem_cache_free(uhci_up_cachep, urbp);
} }
...@@ -1801,6 +1814,26 @@ static void uhci_free_pending_qhs(struct uhci_hcd *uhci) ...@@ -1801,6 +1814,26 @@ static void uhci_free_pending_qhs(struct uhci_hcd *uhci)
spin_unlock_irqrestore(&uhci->qh_remove_list_lock, flags); spin_unlock_irqrestore(&uhci->qh_remove_list_lock, flags);
} }
static void uhci_free_pending_tds(struct uhci_hcd *uhci)
{
struct list_head *tmp, *head;
unsigned long flags;
spin_lock_irqsave(&uhci->td_remove_list_lock, flags);
head = &uhci->td_remove_list;
tmp = head->next;
while (tmp != head) {
struct uhci_td *td = list_entry(tmp, struct uhci_td, remove_list);
tmp = tmp->next;
list_del_init(&td->remove_list);
uhci_free_td(uhci, td);
}
spin_unlock_irqrestore(&uhci->td_remove_list_lock, flags);
}
static void uhci_finish_urb(struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs) static void uhci_finish_urb(struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs)
{ {
struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
...@@ -1899,6 +1932,8 @@ static void uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs) ...@@ -1899,6 +1932,8 @@ static void uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs)
uhci_free_pending_qhs(uhci); uhci_free_pending_qhs(uhci);
uhci_free_pending_tds(uhci);
uhci_remove_pending_qhs(uhci); uhci_remove_pending_qhs(uhci);
uhci_clear_next_interrupt(uhci); uhci_clear_next_interrupt(uhci);
...@@ -2207,6 +2242,9 @@ static int uhci_start(struct usb_hcd *hcd) ...@@ -2207,6 +2242,9 @@ static int uhci_start(struct usb_hcd *hcd)
spin_lock_init(&uhci->qh_remove_list_lock); spin_lock_init(&uhci->qh_remove_list_lock);
INIT_LIST_HEAD(&uhci->qh_remove_list); INIT_LIST_HEAD(&uhci->qh_remove_list);
spin_lock_init(&uhci->td_remove_list_lock);
INIT_LIST_HEAD(&uhci->td_remove_list);
spin_lock_init(&uhci->urb_remove_list_lock); spin_lock_init(&uhci->urb_remove_list_lock);
INIT_LIST_HEAD(&uhci->urb_remove_list); INIT_LIST_HEAD(&uhci->urb_remove_list);
...@@ -2418,11 +2456,13 @@ static void uhci_stop(struct usb_hcd *hcd) ...@@ -2418,11 +2456,13 @@ static void uhci_stop(struct usb_hcd *hcd)
* to this bus since there are no more parents * to this bus since there are no more parents
*/ */
uhci_free_pending_qhs(uhci); uhci_free_pending_qhs(uhci);
uhci_free_pending_tds(uhci);
uhci_remove_pending_qhs(uhci); uhci_remove_pending_qhs(uhci);
reset_hc(uhci); reset_hc(uhci);
uhci_free_pending_qhs(uhci); uhci_free_pending_qhs(uhci);
uhci_free_pending_tds(uhci);
release_uhci(uhci); release_uhci(uhci);
} }
......
...@@ -190,6 +190,7 @@ struct uhci_td { ...@@ -190,6 +190,7 @@ struct uhci_td {
struct urb *urb; struct urb *urb;
struct list_head list; /* P: urb->lock */ struct list_head list; /* P: urb->lock */
struct list_head remove_list; /* P: uhci->td_remove_list_lock */
int frame; /* for iso: what frame? */ int frame; /* for iso: what frame? */
struct list_head fl_list; /* P: uhci->frame_list_lock */ struct list_head fl_list; /* P: uhci->frame_list_lock */
...@@ -350,6 +351,10 @@ struct uhci_hcd { ...@@ -350,6 +351,10 @@ struct uhci_hcd {
spinlock_t qh_remove_list_lock; spinlock_t qh_remove_list_lock;
struct list_head qh_remove_list; /* P: uhci->qh_remove_list_lock */ struct list_head qh_remove_list; /* P: uhci->qh_remove_list_lock */
/* List of TD's that are done, but waiting to be freed (race) */
spinlock_t td_remove_list_lock;
struct list_head td_remove_list; /* P: uhci->td_remove_list_lock */
/* List of asynchronously unlinked URB's */ /* List of asynchronously unlinked URB's */
spinlock_t urb_remove_list_lock; spinlock_t urb_remove_list_lock;
struct list_head urb_remove_list; /* P: uhci->urb_remove_list_lock */ struct list_head urb_remove_list; /* P: uhci->urb_remove_list_lock */
......
...@@ -245,6 +245,7 @@ static void pl2303_set_termios (struct usb_serial_port *port, struct termios *ol ...@@ -245,6 +245,7 @@ static void pl2303_set_termios (struct usb_serial_port *port, struct termios *ol
unsigned char *buf; unsigned char *buf;
int baud; int baud;
int i; int i;
u8 control;
dbg("%s - port %d", __FUNCTION__, port->number); dbg("%s - port %d", __FUNCTION__, port->number);
...@@ -360,17 +361,19 @@ static void pl2303_set_termios (struct usb_serial_port *port, struct termios *ol ...@@ -360,17 +361,19 @@ static void pl2303_set_termios (struct usb_serial_port *port, struct termios *ol
0, 0, buf, 7, 100); 0, 0, buf, 7, 100);
dbg ("0x21:0x20:0:0 %d", i); dbg ("0x21:0x20:0:0 %d", i);
if (cflag && CBAUD) { /* change control lines if we are switching to or from B0 */
u8 control;
spin_lock_irqsave(&priv->lock, flags); spin_lock_irqsave(&priv->lock, flags);
if ((cflag && CBAUD) == B0) control = priv->line_control;
if ((cflag & CBAUD) == B0)
priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS); priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
else else
priv->line_control |= (CONTROL_DTR | CONTROL_RTS); priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
if (control != priv->line_control) {
control = priv->line_control; control = priv->line_control;
spin_unlock_irqrestore(&priv->lock, flags); spin_unlock_irqrestore(&priv->lock, flags);
set_control_lines (serial->dev, control); set_control_lines(serial->dev, control);
} else {
spin_unlock_irqrestore(&priv->lock, flags);
} }
buf[0] = buf[1] = buf[2] = buf[3] = buf[4] = buf[5] = buf[6] = 0; buf[0] = buf[1] = buf[2] = buf[3] = buf[4] = buf[5] = buf[6] = 0;
...@@ -404,6 +407,9 @@ static int pl2303_open (struct usb_serial_port *port, struct file *filp) ...@@ -404,6 +407,9 @@ static int pl2303_open (struct usb_serial_port *port, struct file *filp)
dbg("%s - port %d", __FUNCTION__, port->number); dbg("%s - port %d", __FUNCTION__, port->number);
usb_clear_halt(serial->dev, port->write_urb->pipe);
usb_clear_halt(serial->dev, port->read_urb->pipe);
#define FISH(a,b,c,d) \ #define FISH(a,b,c,d) \
result=usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev,0), \ result=usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev,0), \
b, a, c, d, buf, 1, 100); \ b, a, c, d, buf, 1, 100); \
......
...@@ -618,6 +618,13 @@ UNUSUAL_DEV( 0x0ed1, 0x6660, 0x0100, 0x0300, ...@@ -618,6 +618,13 @@ UNUSUAL_DEV( 0x0ed1, 0x6660, 0x0100, 0x0300,
US_SC_DEVICE, US_PR_DEVICE, NULL, US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_FIX_INQUIRY ), US_FL_FIX_INQUIRY ),
/* Submitted by Joris Struyve <joris@struyve.be> */
UNUSUAL_DEV( 0x0d96, 0x410a, 0x0001, 0xffff,
"Medion",
"MD 7425",
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_FIX_INQUIRY),
/* Reported by Kevin Cernekee <kpc-usbdev@gelato.uiuc.edu> /* Reported by Kevin Cernekee <kpc-usbdev@gelato.uiuc.edu>
* Tested on hardware version 1.10. * Tested on hardware version 1.10.
* Entry is needed only for the initializer function override. * Entry is needed only for the initializer function override.
......
#include <asm/types.h>
#include <asm/ioctl.h>
#include <linux/usb_ch9.h>
/*
* Filesystem based user-mode API to USB Gadget controller hardware
*
* Almost everything can be done with only read and write operations,
* on endpoint files found in one directory. They are configured by
* writing descriptors, and then may be used for normal stream style
* i/o requests. When ep0 is configured, the device can enumerate;
* when it's closed, the device disconnects from usb.
*
* Configuration and device descriptors get written to /dev/gadget/$CHIP,
* which may then be used to read usb_gadgetfs_event structs. The driver
* may activate endpoints as it handles SET_CONFIGURATION setup events,
* or earlier; writing endpoint descriptors to /dev/gadget/$ENDPOINT
* then performing data transfers by reading or writing.
*/
/*
* Events are delivered on the ep0 file descriptor, if the user mode driver
* reads from this file descriptor after writing the descriptors. Don't
* stop polling this descriptor, if you write that kind of driver.
*/
enum usb_gadgetfs_event_type {
GADGETFS_NOP = 0,
GADGETFS_CONNECT,
GADGETFS_DISCONNECT,
GADGETFS_SETUP,
GADGETFS_SUSPEND,
// and likely more !
};
struct usb_gadgetfs_event {
enum usb_gadgetfs_event_type type;
union {
// NOP, DISCONNECT, SUSPEND: nothing
// ... some hardware can't report disconnection
// CONNECT: just the speed
enum usb_device_speed speed;
// SETUP: packet; DATA phase i/o precedes next event
// (setup.bmRequestType & USB_DIR_IN) flags direction
// ... includes SET_CONFIGURATION, SET_INTERFACE
struct usb_ctrlrequest setup;
} u;
};
/* endpoint ioctls */
/* IN transfers may be reported to the gadget driver as complete
* when the fifo is loaded, before the host reads the data;
* OUT transfers may be reported to the host's "client" driver as
* complete when they're sitting in the FIFO unread.
* THIS returns how many bytes are "unclaimed" in the endpoint fifo
* (needed for precise fault handling, when the hardware allows it)
*/
#define GADGETFS_FIFO_STATUS _IO('g',1)
/* discards any unclaimed data in the fifo. */
#define GADGETFS_FIFO_FLUSH _IO('g',2)
/* resets endpoint halt+toggle; used to implement set_interface.
* some hardware (like pxa2xx) can't support this.
*/
#define GADGETFS_CLEAR_HALT _IO('g',3)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment