Commit dfc0c2b8 authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://kernel.bkbits.net/jgarzik/irda-2.5

into home.osdl.org:/home/torvalds/v2.5/linux
parents f17c892b 43abf8d7
......@@ -474,7 +474,7 @@ static void shutdown_socket(struct pcmcia_socket *s)
DEBUG(1, "cs: shutdown_socket(%p)\n", s);
/* Blank out the socket state */
s->state &= SOCKET_PRESENT|SOCKET_SETUP_PENDING;
s->state &= SOCKET_PRESENT|SOCKET_INUSE;
s->socket = dead_socket;
s->ops->init(s);
s->irq.AssignedIRQ = s->irq.Config = 0;
......@@ -657,7 +657,6 @@ static int socket_setup(struct pcmcia_socket *skt, int initial_delay)
pcmcia_error(skt, "unsupported voltage key.\n");
return CS_BAD_TYPE;
}
skt->state |= SOCKET_PRESENT;
skt->socket.flags = SS_DEBOUNCED;
skt->ops->set_socket(skt, &skt->socket);
......@@ -678,11 +677,12 @@ static int socket_insert(struct pcmcia_socket *skt)
{
int ret;
if (!try_module_get(skt->owner))
if (!cs_socket_get(skt))
return CS_NO_CARD;
ret = socket_setup(skt, setup_delay);
if (ret == CS_SUCCESS) {
skt->state |= SOCKET_PRESENT;
#ifdef CONFIG_CARDBUS
if (skt->state & SOCKET_CARDBUS) {
cb_alloc(skt);
......@@ -693,7 +693,7 @@ static int socket_insert(struct pcmcia_socket *skt)
skt->socket.flags &= ~SS_DEBOUNCED;
} else {
socket_shutdown(skt);
module_put(skt->owner);
cs_socket_put(skt);
}
return ret;
......@@ -741,10 +741,8 @@ static int socket_resume(struct pcmcia_socket *skt)
}
skt->socket.flags &= ~SS_DEBOUNCED;
} else {
unsigned int old_state = skt->state;
socket_shutdown(skt);
if (old_state & SOCKET_PRESENT)
module_put(skt->owner);
cs_socket_put(skt);
}
skt->state &= ~SOCKET_SUSPEND;
......@@ -755,7 +753,7 @@ static int socket_resume(struct pcmcia_socket *skt)
static void socket_remove(struct pcmcia_socket *skt)
{
socket_shutdown(skt);
module_put(skt->owner);
cs_socket_put(skt);
}
/*
......@@ -1020,7 +1018,7 @@ int pcmcia_bind_device(bind_req_t *req)
init_waitqueue_head(&client->mtd_req);
client->next = s->clients;
s->clients = client;
DEBUG(1, "cs: bind_device(): client 0x%p, sock %d, dev %s\n",
DEBUG(1, "cs: bind_device(): client 0x%p, sock %p, dev %s\n",
client, client->Socket, client->dev_info);
return CS_SUCCESS;
} /* bind_device */
......@@ -1063,7 +1061,7 @@ int pcmcia_bind_mtd(mtd_bind_t *req)
/*====================================================================*/
int pcmcia_deregister_client(client_handle_t handle)
int pcmcia_deregister_clientR(client_handle_t handle)
{
client_t **client;
struct pcmcia_socket *s;
......@@ -1346,8 +1344,6 @@ int pcmcia_get_status(client_handle_t handle, cs_status_t *status)
status->CardState |= CS_EVENT_PM_SUSPEND;
if (!(s->state & SOCKET_PRESENT))
return CS_NO_CARD;
if (s->state & SOCKET_SETUP_PENDING)
status->CardState |= CS_EVENT_CARD_INSERTION;
/* Get info from the PRR, if necessary */
if (handle->Function == BIND_FN_ALL) {
......@@ -1524,6 +1520,10 @@ int pcmcia_register_client(client_handle_t *handle, client_reg_t *req)
if (client == NULL)
return CS_OUT_OF_RESOURCE;
/*
* Prevent this racing with a card insertion.
*/
down(&s->skt_sem);
*handle = client;
client->state &= ~CLIENT_UNBOUND;
client->Socket = s;
......@@ -1547,22 +1547,28 @@ int pcmcia_register_client(client_handle_t *handle, client_reg_t *req)
s->config = kmalloc(sizeof(config_t) * s->functions,
GFP_KERNEL);
if (!s->config)
return CS_OUT_OF_RESOURCE;
goto out_no_resource;
memset(s->config, 0, sizeof(config_t) * s->functions);
}
DEBUG(1, "cs: register_client(): client 0x%p, sock %d, dev %s\n",
DEBUG(1, "cs: register_client(): client 0x%p, sock %p, dev %s\n",
client, client->Socket, client->dev_info);
if (client->EventMask & CS_EVENT_REGISTRATION_COMPLETE)
EVENT(client, CS_EVENT_REGISTRATION_COMPLETE, CS_EVENT_PRI_LOW);
if ((s->state & SOCKET_PRESENT) &&
!(s->state & SOCKET_SETUP_PENDING)) {
if ((s->state & (SOCKET_PRESENT|SOCKET_CARDBUS)) == SOCKET_PRESENT) {
if (client->EventMask & CS_EVENT_CARD_INSERTION)
EVENT(client, CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW);
else
client->PendingEvents |= CS_EVENT_CARD_INSERTION;
}
up(&s->skt_sem);
return CS_SUCCESS;
out_no_resource:
up(&s->skt_sem);
return CS_OUT_OF_RESOURCE;
} /* register_client */
/*====================================================================*/
......@@ -2081,7 +2087,7 @@ int pcmcia_reset_card(client_handle_t handle, client_req_t *req)
if (CHECK_HANDLE(handle))
return CS_BAD_HANDLE;
DEBUG(1, "cs: resetting socket %d\n", handle->Socket);
DEBUG(1, "cs: resetting socket %p\n", handle->Socket);
skt = SOCKET(handle);
down(&skt->skt_sem);
......@@ -2130,7 +2136,7 @@ int pcmcia_suspend_card(client_handle_t handle, client_req_t *req)
if (CHECK_HANDLE(handle))
return CS_BAD_HANDLE;
DEBUG(1, "cs: suspending socket %d\n", handle->Socket);
DEBUG(1, "cs: suspending socket %p\n", handle->Socket);
skt = SOCKET(handle);
down(&skt->skt_sem);
......@@ -2157,7 +2163,7 @@ int pcmcia_resume_card(client_handle_t handle, client_req_t *req)
if (CHECK_HANDLE(handle))
return CS_BAD_HANDLE;
DEBUG(1, "cs: waking up socket %d\n", handle->Socket);
DEBUG(1, "cs: waking up socket %p\n", handle->Socket);
skt = SOCKET(handle);
down(&skt->skt_sem);
......@@ -2190,7 +2196,7 @@ int pcmcia_eject_card(client_handle_t handle, client_req_t *req)
if (CHECK_HANDLE(handle))
return CS_BAD_HANDLE;
DEBUG(1, "cs: user eject request on socket %d\n", handle->Socket);
DEBUG(1, "cs: user eject request on socket %p\n", handle->Socket);
skt = SOCKET(handle);
down(&skt->skt_sem);
......@@ -2219,7 +2225,7 @@ int pcmcia_insert_card(client_handle_t handle, client_req_t *req)
if (CHECK_HANDLE(handle))
return CS_BAD_HANDLE;
DEBUG(1, "cs: user insert request on socket %d\n", handle->Socket);
DEBUG(1, "cs: user insert request on socket %p\n", handle->Socket);
skt = SOCKET(handle);
down(&skt->skt_sem);
......
......@@ -99,7 +99,7 @@ struct cis_cache_entry {
/* Flags in socket state */
#define SOCKET_PRESENT 0x0008
#define SOCKET_SETUP_PENDING 0x0010
#define SOCKET_INUSE 0x0010
#define SOCKET_SHUTDOWN_PENDING 0x0020
#define SOCKET_RESET_PENDING 0x0040
#define SOCKET_SUSPEND 0x0080
......@@ -109,6 +109,26 @@ struct cis_cache_entry {
#define SOCKET_CARDBUS 0x8000
#define SOCKET_CARDBUS_CONFIG 0x10000
static inline int cs_socket_get(struct pcmcia_socket *skt)
{
int ret;
WARN_ON(skt->state & SOCKET_INUSE);
ret = try_module_get(skt->owner);
if (ret)
skt->state |= SOCKET_INUSE;
return ret;
}
static inline void cs_socket_put(struct pcmcia_socket *skt)
{
if (skt->state & SOCKET_INUSE) {
skt->state &= ~SOCKET_INUSE;
module_put(skt->owner);
}
}
#define CHECK_HANDLE(h) \
(((h) == NULL) || ((h)->client_magic != CLIENT_MAGIC))
......
......@@ -900,7 +900,7 @@ static int __devinit yenta_probe (struct pci_dev *dev, const struct pci_device_i
/* We must finish initialization here */
if (!socket->cb_irq || request_irq(socket->cb_irq, yenta_interrupt, SA_SHIRQ, pci_name(socket->dev), socket)) {
if (!socket->cb_irq || request_irq(socket->cb_irq, yenta_interrupt, SA_SHIRQ, "yenta", socket)) {
/* No IRQ or request_irq failed. Poll */
socket->cb_irq = 0; /* But zero is a valid IRQ number. */
init_timer(&socket->poll_timer);
......
......@@ -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
* @dev: the device whose current configuration is considered
* @epnum: the desired endpoint
* @dev: the device whose current configuration+altsettings is considered
* @epnum: the desired endpoint, masked with USB_DIR_IN as appropriate.
*
* This walks the device descriptor for the currently active configuration,
* and returns a pointer to the endpoint with that particular endpoint
* number, or null.
*
* Note that interface descriptors are not required to assign endpont
* numbers sequentially, so that it would be incorrect to assume that
* the first endpoint in that descriptor corresponds to interface zero.
* Note that interface descriptors are not required to list endpoint
* numbers in any standardized order, so that it would be wrong to
* assume that ep2in precedes either ep5in, ep2out, or even ep1out.
* This routine helps device drivers avoid such mistakes.
*/
struct usb_endpoint_descriptor *
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 (j = 0; j < dev->actconfig->interface[i]->num_altsetting; j++)
for (k = 0; k < dev->actconfig->interface[i]->
altsetting[j].desc.bNumEndpoints; k++)
if (epnum == dev->actconfig->interface[i]->
altsetting[j].endpoint[k]
.desc.bEndpointAddress)
return &dev->actconfig->interface[i]->
altsetting[j].endpoint[k]
.desc;
for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) {
struct usb_interface *intf;
struct usb_host_interface *alt;
/* only endpoints in current altseting are active */
intf = dev->actconfig->interface[i];
alt = intf->altsetting + intf->act_altsetting;
for (k = 0; k < alt->desc.bNumEndpoints; k++)
if (epnum == alt->endpoint[k].desc.bEndpointAddress)
return &alt->endpoint[k].desc;
}
return NULL;
}
......
......@@ -147,6 +147,30 @@ config USB_ETH_SA1100
depends on USB_ETH && USB_SA1100
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
# endmenuconfig
......@@ -8,7 +8,9 @@ obj-$(CONFIG_USB_NET2280) += net2280.o
#
g_zero-objs := zero.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_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
td->dev = dev;
INIT_LIST_HEAD(&td->list);
INIT_LIST_HEAD(&td->remove_list);
INIT_LIST_HEAD(&td->fl_list);
usb_get_dev(dev);
......@@ -286,6 +287,8 @@ static void uhci_free_td(struct uhci_hcd *uhci, struct uhci_td *td)
{
if (!list_empty(&td->list))
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))
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)
{
struct list_head *head, *tmp;
struct urb_priv *urbp;
unsigned long flags;
urbp = (struct urb_priv *)urb->hcpriv;
if (!urbp)
......@@ -713,6 +717,13 @@ static void uhci_destroy_urb_priv(struct uhci_hcd *uhci, struct urb *urb)
if (!list_empty(&urbp->complete_list))
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;
tmp = head->next;
while (tmp != head) {
......@@ -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(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;
kmem_cache_free(uhci_up_cachep, urbp);
}
......@@ -1801,6 +1814,26 @@ static void uhci_free_pending_qhs(struct uhci_hcd *uhci)
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)
{
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)
uhci_free_pending_qhs(uhci);
uhci_free_pending_tds(uhci);
uhci_remove_pending_qhs(uhci);
uhci_clear_next_interrupt(uhci);
......@@ -2207,6 +2242,9 @@ static int uhci_start(struct usb_hcd *hcd)
spin_lock_init(&uhci->qh_remove_list_lock);
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);
INIT_LIST_HEAD(&uhci->urb_remove_list);
......@@ -2418,11 +2456,13 @@ static void uhci_stop(struct usb_hcd *hcd)
* to this bus since there are no more parents
*/
uhci_free_pending_qhs(uhci);
uhci_free_pending_tds(uhci);
uhci_remove_pending_qhs(uhci);
reset_hc(uhci);
uhci_free_pending_qhs(uhci);
uhci_free_pending_tds(uhci);
release_uhci(uhci);
}
......
......@@ -190,6 +190,7 @@ struct uhci_td {
struct urb *urb;
struct list_head list; /* P: urb->lock */
struct list_head remove_list; /* P: uhci->td_remove_list_lock */
int frame; /* for iso: what frame? */
struct list_head fl_list; /* P: uhci->frame_list_lock */
......@@ -350,6 +351,10 @@ struct uhci_hcd {
spinlock_t 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 */
spinlock_t 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
unsigned char *buf;
int baud;
int i;
u8 control;
dbg("%s - port %d", __FUNCTION__, port->number);
......@@ -360,17 +361,19 @@ static void pl2303_set_termios (struct usb_serial_port *port, struct termios *ol
0, 0, buf, 7, 100);
dbg ("0x21:0x20:0:0 %d", i);
if (cflag && CBAUD) {
u8 control;
spin_lock_irqsave(&priv->lock, flags);
if ((cflag && CBAUD) == B0)
priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
else
priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
/* change control lines if we are switching to or from B0 */
spin_lock_irqsave(&priv->lock, flags);
control = priv->line_control;
if ((cflag & CBAUD) == B0)
priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
else
priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
if (control != priv->line_control) {
control = priv->line_control;
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;
......@@ -404,6 +407,9 @@ static int pl2303_open (struct usb_serial_port *port, struct file *filp)
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) \
result=usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev,0), \
b, a, c, d, buf, 1, 100); \
......
......@@ -618,6 +618,13 @@ UNUSUAL_DEV( 0x0ed1, 0x6660, 0x0100, 0x0300,
US_SC_DEVICE, US_PR_DEVICE, NULL,
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>
* Tested on hardware version 1.10.
* Entry is needed only for the initializer function override.
......
......@@ -850,29 +850,6 @@ static inline void ide_unmap_buffer(struct request *rq, char *buffer, unsigned l
if (rq->bio)
bio_kunmap_irq(buffer, flags);
}
#else /* !CONFIG_IDE_TASKFILE_IO */
static inline void *task_map_rq(struct request *rq, unsigned long *flags)
{
/*
* fs request
*/
if (rq->cbio)
return rq_map_buffer(rq, flags);
/*
* task request
*/
return rq->buffer + blk_rq_offset(rq);
}
static inline void task_unmap_rq(struct request *rq, char *buffer, unsigned long *flags)
{
if (rq->cbio)
rq_unmap_buffer(buffer, flags);
}
#endif /* !CONFIG_IDE_TASKFILE_IO */
#define IDE_CHIPSET_PCI_MASK \
......@@ -1472,9 +1449,19 @@ static inline void task_sectors(ide_drive_t *drive, struct request *rq,
unsigned nsect, int rw)
{
unsigned long flags;
unsigned int bio_rq;
char *buf;
buf = task_map_rq(rq, &flags);
/*
* bio_rq flag is needed because we can call
* rq_unmap_buffer() with rq->cbio == NULL
*/
bio_rq = rq->cbio ? 1 : 0;
if (bio_rq)
buf = rq_map_buffer(rq, &flags); /* fs request */
else
buf = rq->buffer + blk_rq_offset(rq); /* task request */
/*
* IRQ can happen instantly after reading/writing
......@@ -1487,9 +1474,9 @@ static inline void task_sectors(ide_drive_t *drive, struct request *rq,
else
taskfile_input_data(drive, buf, nsect * SECTOR_WORDS);
task_unmap_rq(rq, buf, &flags);
if (bio_rq)
rq_unmap_buffer(buf, &flags);
}
#endif /* CONFIG_IDE_TASKFILE_IO */
extern int drive_is_ready(ide_drive_t *);
......
#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)
......@@ -49,16 +49,18 @@ union futex_key {
struct {
unsigned long pgoff;
struct inode *inode;
int offset;
} shared;
struct {
unsigned long uaddr;
struct mm_struct *mm;
int offset;
} private;
struct {
unsigned long word;
void *ptr;
int offset;
} both;
int offset;
};
/*
......@@ -91,7 +93,7 @@ static inline struct list_head *hash_futex(union futex_key *key)
{
return &futex_queues[hash_long(key->both.word
+ (unsigned long) key->both.ptr
+ key->offset, FUTEX_HASHBITS)];
+ key->both.offset, FUTEX_HASHBITS)];
}
/*
......@@ -101,7 +103,7 @@ static inline int match_futex(union futex_key *key1, union futex_key *key2)
{
return (key1->both.word == key2->both.word
&& key1->both.ptr == key2->both.ptr
&& key1->offset == key2->offset);
&& key1->both.offset == key2->both.offset);
}
/*
......@@ -127,10 +129,10 @@ static int get_futex_key(unsigned long uaddr, union futex_key *key)
/*
* The futex address must be "naturally" aligned.
*/
key->offset = uaddr % PAGE_SIZE;
if (unlikely((key->offset % sizeof(u32)) != 0))
key->both.offset = uaddr % PAGE_SIZE;
if (unlikely((key->both.offset % sizeof(u32)) != 0))
return -EINVAL;
uaddr -= key->offset;
uaddr -= key->both.offset;
/*
* The futex is hashed differently depending on whether
......@@ -199,6 +201,7 @@ static int get_futex_key(unsigned long uaddr, union futex_key *key)
key->shared.pgoff =
page->index << (PAGE_CACHE_SHIFT - PAGE_SHIFT);
put_page(page);
return 0;
}
return err;
}
......@@ -208,7 +211,7 @@ static int get_futex_key(unsigned long uaddr, union futex_key *key)
* Wake up all waiters hashed on the physical page that is mapped
* to this virtual address:
*/
static inline int futex_wake(unsigned long uaddr, int num)
static int futex_wake(unsigned long uaddr, int num)
{
struct list_head *i, *next, *head;
union futex_key key;
......@@ -247,7 +250,7 @@ static inline int futex_wake(unsigned long uaddr, int num)
* Requeue all waiters hashed on one physical page to another
* physical page.
*/
static inline int futex_requeue(unsigned long uaddr1, unsigned long uaddr2,
static int futex_requeue(unsigned long uaddr1, unsigned long uaddr2,
int nr_wake, int nr_requeue)
{
struct list_head *i, *next, *head1, *head2;
......@@ -282,6 +285,9 @@ static inline int futex_requeue(unsigned long uaddr1, unsigned long uaddr2,
this->key = key2;
if (ret - nr_wake >= nr_requeue)
break;
/* Make sure to stop if key1 == key2 */
if (head1 == head2 && head1 != next)
head1 = i;
}
}
}
......@@ -320,7 +326,7 @@ static inline int unqueue_me(struct futex_q *q)
return ret;
}
static inline int futex_wait(unsigned long uaddr, int val, unsigned long time)
static int futex_wait(unsigned long uaddr, int val, unsigned long time)
{
DECLARE_WAITQUEUE(wait, current);
int ret, curval;
......
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