📄 message.c
字号:
/*
* message.c - synchronous message handling
*/
#if 0
#include <linux/pci.h> /* for scatterlist macros */
#include <linux/usb.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <asm/byteorder.h>
#else
#include "../miniport/usb_wrapper.h"
#endif
#include "hcd.h" /* for usbcore internals */
// ReactOS specific: No WAITQUEUEs here
#undef wake_up
#define wake_up(a) do {} while(0)
struct usb_api_data {
wait_queue_head_t wqh;
int done;
};
static void usb_api_blocking_completion(struct urb *urb, struct pt_regs *regs)
{
struct usb_api_data *awd = (struct usb_api_data *)urb->context;
awd->done = 1;
wmb();
wake_up(&awd->wqh);
}
// Starts urb and waits for completion or timeout
static int usb_start_wait_urb(struct urb *urb, int timeout, int* actual_length)
{
//DECLARE_WAITQUEUE(wait, current); // Fireball, 24Jan05 - silent gcc complaining about unused wait variable
struct usb_api_data awd;
int status;
//printk("usb_start_wait_urb(): urb devnum=%d, timeout=%d, urb->actual_length=%d\n", urb->dev->devnum, timeout, urb->actual_length);
init_waitqueue_head((PKEVENT)&awd.wqh);
awd.done = 0;
set_current_state(TASK_UNINTERRUPTIBLE);
add_wait_queue(&awd.wqh, &wait);
urb->context = &awd;
status = usb_submit_urb(urb, GFP_ATOMIC);
if (status) {
// something went wrong
usb_free_urb(urb);
set_current_state(TASK_RUNNING);
remove_wait_queue(&awd.wqh, &wait);
return status;
}
//printk("TRACE 3.1, timeout=%d, awd.done=%d\n", timeout, awd.done);
while (timeout && !awd.done)
{
timeout = schedule_timeout(timeout);
set_current_state(TASK_UNINTERRUPTIBLE);
rmb();
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&awd.wqh, &wait);
if (!timeout && !awd.done) {
if (urb->status != -EINPROGRESS) { /* No callback?!! */
printk(KERN_ERR "usb: raced timeout, "
"pipe 0x%x status %d time left %d\n",
urb->pipe, urb->status, timeout);
status = urb->status;
} else {
warn("usb_control/bulk_msg: timeout");
usb_unlink_urb(urb); // remove urb safely
status = -ETIMEDOUT;
}
} else
status = urb->status;
if (actual_length)
*actual_length = urb->actual_length;
usb_free_urb(urb);
return status;
}
/*-------------------------------------------------------------------*/
// returns status (negative) or length (positive)
int usb_internal_control_msg(struct usb_device *usb_dev, unsigned int pipe,
struct usb_ctrlrequest *cmd, void *data, int len, int timeout)
{
struct urb *urb;
int retv;
int length;
urb = usb_alloc_urb(0, GFP_NOIO);
if (!urb)
return -ENOMEM;
usb_fill_control_urb(urb, usb_dev, pipe, (unsigned char*)cmd, data, len,
usb_api_blocking_completion, 0);
retv = usb_start_wait_urb(urb, timeout, &length);
if (retv < 0)
return retv;
else
return length;
}
/**
* usb_control_msg - Builds a control urb, sends it off and waits for completion
* @dev: pointer to the usb device to send the message to
* @pipe: endpoint "pipe" to send the message to
* @request: USB message request value
* @requesttype: USB message request type value
* @value: USB message value
* @index: USB message index value
* @data: pointer to the data to send
* @size: length in bytes of the data to send
* @timeout: time in jiffies to wait for the message to complete before
* timing out (if 0 the wait is forever)
* Context: !in_interrupt ()
*
* This function sends a simple control message to a specified endpoint
* and waits for the message to complete, or timeout.
*
* If successful, it returns the number of bytes transferred, otherwise a negative error number.
*
* Don't use this function from within an interrupt context, like a
* bottom half handler. If you need an asynchronous message, or need to send
* a message from within interrupt context, use usb_submit_urb()
* If a thread in your driver uses this call, make sure your disconnect()
* method can wait for it to complete. Since you don't have a handle on
* the URB used, you can't cancel the request.
*/
int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype,
__u16 value, __u16 index, void *data, __u16 size, int timeout)
{
struct usb_ctrlrequest *dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_NOIO);
int ret;
if (!dr)
return -ENOMEM;
dr->bRequestType= requesttype;
dr->bRequest = request;
dr->wValue = cpu_to_le16p(&value);
dr->wIndex = cpu_to_le16p(&index);
dr->wLength = cpu_to_le16p(&size);
//printk("usb_control_msg: devnum=%d, size=%d, timeout=%d\n", dev->devnum, size, timeout);
ret = usb_internal_control_msg(dev, pipe, dr, data, size, timeout);
kfree(dr);
return ret;
}
/**
* usb_bulk_msg - Builds a bulk urb, sends it off and waits for completion
* @usb_dev: pointer to the usb device to send the message to
* @pipe: endpoint "pipe" to send the message to
* @data: pointer to the data to send
* @len: length in bytes of the data to send
* @actual_length: pointer to a location to put the actual length transferred in bytes
* @timeout: time in jiffies to wait for the message to complete before
* timing out (if 0 the wait is forever)
* Context: !in_interrupt ()
*
* This function sends a simple bulk message to a specified endpoint
* and waits for the message to complete, or timeout.
*
* If successful, it returns 0, otherwise a negative error number.
* The number of actual bytes transferred will be stored in the
* actual_length paramater.
*
* Don't use this function from within an interrupt context, like a
* bottom half handler. If you need an asynchronous message, or need to
* send a message from within interrupt context, use usb_submit_urb()
* If a thread in your driver uses this call, make sure your disconnect()
* method can wait for it to complete. Since you don't have a handle on
* the URB used, you can't cancel the request.
*/
int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe,
void *data, int len, int *actual_length, int timeout)
{
struct urb *urb;
if (len < 0)
return -EINVAL;
urb=usb_alloc_urb(0, GFP_KERNEL);
if (!urb)
return -ENOMEM;
usb_fill_bulk_urb(urb, usb_dev, pipe, data, len,
usb_api_blocking_completion, 0);
return usb_start_wait_urb(urb,timeout,actual_length);
}
/*-------------------------------------------------------------------*/
//#warning "Scatter-gather stuff disabled"
#if 0
static void sg_clean (struct usb_sg_request *io)
{
if (io->urbs) {
while (io->entries--)
usb_free_urb (io->urbs [io->entries]);
kfree (io->urbs);
io->urbs = 0;
}
if (io->dev->dev.dma_mask != 0)
usb_buffer_unmap_sg (io->dev, io->pipe, io->sg, io->nents);
io->dev = 0;
}
static void sg_complete (struct urb *urb, struct pt_regs *regs)
{
struct usb_sg_request *io = (struct usb_sg_request *) urb->context;
unsigned long flags;
spin_lock_irqsave (&io->lock, flags);
/* In 2.5 we require hcds' endpoint queues not to progress after fault
* reports, until the completion callback (this!) returns. That lets
* device driver code (like this routine) unlink queued urbs first,
* if it needs to, since the HC won't work on them at all. So it's
* not possible for page N+1 to overwrite page N, and so on.
*
* That's only for "hard" faults; "soft" faults (unlinks) sometimes
* complete before the HCD can get requests away from hardware,
* though never during cleanup after a hard fault.
*/
if (io->status
&& (io->status != -ECONNRESET
|| urb->status != -ECONNRESET)
&& urb->actual_length) {
dev_err (io->dev->bus->controller,
"dev %s ep%d%s scatterlist error %d/%d\n",
io->dev->devpath,
usb_pipeendpoint (urb->pipe),
usb_pipein (urb->pipe) ? "in" : "out",
urb->status, io->status);
// BUG ();
}
if (urb->status && urb->status != -ECONNRESET) {
int i, found, status;
io->status = urb->status;
/* the previous urbs, and this one, completed already.
* unlink the later ones so they won't rx/tx bad data,
*
* FIXME don't bother unlinking urbs that haven't yet been
* submitted; those non-error cases shouldn't be syslogged
*/
for (i = 0, found = 0; i < io->entries; i++) {
if (found) {
status = usb_unlink_urb (io->urbs [i]);
if (status && status != -EINPROGRESS)
err ("sg_complete, unlink --> %d",
status);
} else if (urb == io->urbs [i])
found = 1;
}
}
/* on the last completion, signal usb_sg_wait() */
io->bytes += urb->actual_length;
io->count--;
if (!io->count)
complete (&io->complete);
spin_unlock_irqrestore (&io->lock, flags);
}
/**
* usb_sg_init - initializes scatterlist-based bulk/interrupt I/O request
* @io: request block being initialized. until usb_sg_wait() returns,
* treat this as a pointer to an opaque block of memory,
* @dev: the usb device that will send or receive the data
* @pipe: endpoint "pipe" used to transfer the data
* @period: polling rate for interrupt endpoints, in frames or
* (for high speed endpoints) microframes; ignored for bulk
* @sg: scatterlist entries
* @nents: how many entries in the scatterlist
* @length: how many bytes to send from the scatterlist, or zero to
* send every byte identified in the list.
* @mem_flags: SLAB_* flags affecting memory allocations in this call
*
* Returns zero for success, else a negative errno value. This initializes a
* scatter/gather request, allocating resources such as I/O mappings and urb
* memory (except maybe memory used by USB controller drivers).
*
* The request must be issued using usb_sg_wait(), which waits for the I/O to
* complete (or to be canceled) and then cleans up all resources allocated by
* usb_sg_init().
*
* The request may be canceled with usb_sg_cancel(), either before or after
* usb_sg_wait() is called.
*/
int usb_sg_init (
struct usb_sg_request *io,
struct usb_device *dev,
unsigned pipe,
unsigned period,
struct scatterlist *sg,
int nents,
size_t length,
int mem_flags
)
{
int i;
int urb_flags;
int dma;
if (!io || !dev || !sg
|| usb_pipecontrol (pipe)
|| usb_pipeisoc (pipe)
|| nents <= 0)
return -EINVAL;
spin_lock_init (&io->lock);
io->dev = dev;
io->pipe = pipe;
io->sg = sg;
io->nents = nents;
/* not all host controllers use DMA (like the mainstream pci ones);
* they can use PIO (sl811) or be software over another transport.
*/
dma = (dev->dev.dma_mask != 0);
if (dma)
io->entries = usb_buffer_map_sg (dev, pipe, sg, nents);
else
io->entries = nents;
/* initialize all the urbs we'll use */
if (io->entries <= 0)
return io->entries;
io->count = 0;
io->urbs = kmalloc (io->entries * sizeof *io->urbs, mem_flags);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -