freebsd_network: Implement USB routines needed by Ralink USB modules.

Tested by nephele with a RT2573. The device starts and scans for networks,
but hits some USB errors probably related to buffer sizing which I'm
not quite sure what the cause of could be. More work (by someone who
owns these devices) may be required.
This commit is contained in:
Augustin Cavalier
2022-06-29 13:16:13 -04:00
parent db4df8fcf5
commit e410069738
2 changed files with 125 additions and 3 deletions
@@ -353,14 +353,29 @@ void usb_pause_mtx(struct mtx *mtx, int _ticks);
enum usb_dev_speed usbd_get_speed(struct usb_device* udev);
void* usbd_xfer_softc(struct usb_xfer *xfer);
void* usbd_xfer_get_priv(struct usb_xfer* xfer);
void usbd_xfer_set_priv(struct usb_xfer* xfer, void* ptr);
uint8_t usbd_xfer_state(struct usb_xfer *xfer);
usb_frlength_t usbd_xfer_max_len(struct usb_xfer *xfer);
struct usb_page_cache *usbd_xfer_get_frame(struct usb_xfer *, usb_frcount_t);
void usbd_xfer_set_frames(struct usb_xfer *xfer, usb_frcount_t n);
void usbd_xfer_set_frame_data(struct usb_xfer *xfer, usb_frcount_t frindex,
void *ptr, usb_frlength_t len);
void usbd_xfer_set_frame_len(struct usb_xfer *xfer, usb_frcount_t frindex,
usb_frlength_t len);
void usbd_xfer_set_stall(struct usb_xfer *xfer);
void usbd_xfer_status(struct usb_xfer *xfer, int *actlen, int *sumlen,
int *aframes, int *nframes);
void usbd_frame_zero(struct usb_page_cache *cache, usb_frlength_t offset,
usb_frlength_t len);
void usbd_copy_in(struct usb_page_cache *cache, usb_frlength_t offset,
const void *ptr, usb_frlength_t len);
void usbd_copy_out(struct usb_page_cache *cache, usb_frlength_t offset,
void *ptr, usb_frlength_t len);
void usbd_m_copy_in(struct usb_page_cache *cache, usb_frlength_t dst_offset,
struct mbuf *m, usb_size_t src_offset, usb_frlength_t src_len);
void usbd_transfer_submit(struct usb_xfer *xfer);
void usbd_transfer_start(struct usb_xfer *xfer);
void usbd_transfer_stop(struct usb_xfer *xfer);
+110 -3
View File
@@ -165,6 +165,7 @@ map_usb_error(status_t err)
case B_OK: return USB_ERR_NORMAL_COMPLETION;
case B_DEV_STALLED: return USB_ERR_STALLED;
case B_CANCELED: return USB_ERR_CANCELLED;
case B_TIMED_OUT: return USB_ERR_TIMEOUT;
}
return USB_ERR_INVAL;
}
@@ -217,9 +218,14 @@ usbd_get_speed(struct freebsd_usb_device* udev)
}
struct usb_page_cache {
void* buffer;
size_t length;
};
struct usb_xfer {
struct mtx* mutex;
void* priv_sc;
void* priv_sc, *priv;
usb_callback_t* callback;
usb_xfer_flags flags;
usb_frlength_t max_data_length;
@@ -227,8 +233,10 @@ struct usb_xfer {
usb_device device;
uint8 type;
usb_pipe pipe;
iovec* frames;
int nframes;
usb_page_cache* buffers;
int max_frame_count, nframes;
uint8 usb_state;
bool in_progress;
@@ -272,6 +280,7 @@ usbd_transfer_setup(struct freebsd_usb_device* udev,
struct usb_xfer* xfer = new usb_xfer;
xfer->mutex = xfer_mtx;
xfer->priv_sc = priv_sc;
xfer->priv = NULL;
xfer->callback = setup->callback;
xfer->flags = setup->flags;
xfer->max_data_length = setup->bufsize;
@@ -305,7 +314,9 @@ usbd_transfer_setup(struct freebsd_usb_device* udev,
xfer->nframes = setup->frames;
if (xfer->nframes == 0)
xfer->nframes = 1;
xfer->frames = (iovec*)calloc(xfer->nframes, sizeof(iovec));
xfer->max_frame_count = xfer->nframes;
xfer->frames = (iovec*)calloc(xfer->max_frame_count, sizeof(iovec));
xfer->buffers = NULL;
xfer->usb_state = USB_ST_SETUP;
xfer->in_progress = false;
@@ -329,6 +340,12 @@ usbd_transfer_unsetup(struct usb_xfer** pxfer, uint16_t n_setup)
struct usb_xfer* xfer = pxfer[i];
usbd_transfer_drain(xfer);
cv_destroy(&xfer->condition);
if (xfer->buffers != NULL) {
for (int i = 0; i < xfer->max_frame_count; i++)
free(xfer->buffers[i].buffer);
free(xfer->buffers);
}
free(xfer->frames);
delete xfer;
}
@@ -349,6 +366,20 @@ usbd_xfer_softc(struct usb_xfer* xfer)
}
extern "C" void*
usbd_xfer_get_priv(struct usb_xfer* xfer)
{
return xfer->priv;
}
extern "C" void
usbd_xfer_set_priv(struct usb_xfer* xfer, void* ptr)
{
xfer->priv = ptr;
}
extern "C" uint8_t
usbd_xfer_state(struct usb_xfer* xfer)
{
@@ -356,6 +387,14 @@ usbd_xfer_state(struct usb_xfer* xfer)
}
extern "C" void
usbd_xfer_set_frames(struct usb_xfer* xfer, usb_frcount_t n)
{
KASSERT(n <= uint32_t(xfer->max_frame_count), ("frame index overflow"));
xfer->nframes = n;
}
extern "C" void
usbd_xfer_set_frame_data(struct usb_xfer* xfer,
usb_frcount_t frindex, void* ptr, usb_frlength_t len)
@@ -367,6 +406,74 @@ usbd_xfer_set_frame_data(struct usb_xfer* xfer,
}
extern "C" void
usbd_xfer_set_frame_len(struct usb_xfer* xfer,
usb_frcount_t frindex, usb_frlength_t len)
{
KASSERT(frindex < uint32_t(xfer->nframes), ("frame index overflow"));
KASSERT(len <= uint32_t(xfer->max_data_length), ("length overflow"));
// Trigger buffer allocation if necessary.
if (xfer->frames[frindex].iov_base == NULL)
usbd_xfer_get_frame(xfer, frindex);
xfer->frames[frindex].iov_len = len;
}
extern "C" struct usb_page_cache*
usbd_xfer_get_frame(struct usb_xfer* xfer, usb_frcount_t frindex)
{
KASSERT(frindex < uint32_t(xfer->max_frame_count), ("frame index overflow"));
if (xfer->buffers == NULL)
xfer->buffers = (usb_page_cache*)calloc(xfer->max_frame_count, sizeof(usb_page_cache));
usb_page_cache* cache = &xfer->buffers[frindex];
if (cache->buffer == NULL) {
cache->buffer = malloc(xfer->max_data_length);
cache->length = xfer->max_data_length;
}
xfer->frames[frindex].iov_base = cache->buffer;
return cache;
}
extern "C" void
usbd_frame_zero(struct usb_page_cache* cache,
usb_frlength_t offset, usb_frlength_t len)
{
KASSERT((offset + len) < uint32_t(cache->length), ("buffer overflow"));
memset((uint8*)cache->buffer + offset, 0, len);
}
extern "C" void
usbd_copy_in(struct usb_page_cache* cache, usb_frlength_t offset,
const void *ptr, usb_frlength_t len)
{
KASSERT((offset + len) < uint32_t(cache->length), ("buffer overflow"));
memcpy((uint8*)cache->buffer + offset, ptr, len);
}
extern "C" void
usbd_copy_out(struct usb_page_cache* cache, usb_frlength_t offset,
void *ptr, usb_frlength_t len)
{
KASSERT((offset + len) < uint32_t(cache->length), ("buffer overflow"));
memcpy(ptr, (uint8*)cache->buffer + offset, len);
}
extern "C" void
usbd_m_copy_in(struct usb_page_cache* cache, usb_frlength_t dst_offset,
struct mbuf *m, usb_size_t src_offset, usb_frlength_t src_len)
{
m_copydata(m, src_offset, src_len, (caddr_t)((uint8*)cache->buffer + dst_offset));
}
extern "C" void
usbd_xfer_set_stall(struct usb_xfer *xfer)
{