#define GENERIC /* let probe() bind using module params */
/* Some devices that can be used for testing will have "real" drivers. *Entriesforthoseneedtobeenabledherebyhand,afterdisabling *that"real"driver.
*/ //#define IBOT2 /* grab iBOT2 webcams */ //#define KEYSPAN_19Qi /* grab un-renumerated serial adapter */
/* this is accessed only through usbfs ioctl calls. *oneioctltoissueatest...onelockperdevice. *testscreateotherthreadsiftheyneedthem. *urbsandbuffersareallocateddynamically, *anddatagenerateddeterministically.
*/ struct usbtest_dev { struct usb_interface *intf; struct usbtest_info *info; int in_pipe; int out_pipe; int in_iso_pipe; int out_iso_pipe; int in_int_pipe; int out_int_pipe; struct usb_endpoint_descriptor *iso_in, *iso_out; struct usb_endpoint_descriptor *int_in, *int_out; struct mutex lock;
in = out = NULL;
iso_in = iso_out = NULL;
int_in = int_out = NULL;
alt = intf->altsetting + tmp;
if (override_alt >= 0 &&
override_alt != alt->desc.bAlternateSetting) continue;
/* take the first altsetting with in-bulk + out-bulk; *ignoreotherendpointsandaltsettings.
*/ for (ep = 0; ep < alt->desc.bNumEndpoints; ep++) { struct usb_host_endpoint *e; int edi;
e = alt->endpoint + ep;
edi = usb_endpoint_dir_in(&e->desc);
switch (usb_endpoint_type(&e->desc)) { case USB_ENDPOINT_XFER_BULK:
endpoint_update(edi, &in, &out, e); continue; case USB_ENDPOINT_XFER_INT: if (dev->info->intr)
endpoint_update(edi, &int_in, &int_out, e); continue; case USB_ENDPOINT_XFER_ISOC: if (dev->info->iso)
endpoint_update(edi, &iso_in, &iso_out, e);
fallthrough; default: continue;
}
} if ((in && out) || iso_in || iso_out || int_in || int_out) goto found;
} return -EINVAL;
if (!urb->transfer_buffer) {
usb_free_urb(urb); return NULL;
}
/* To test unaligned transfers add an offset and fill the
unused memory with a guard value */ if (offset) {
memset(urb->transfer_buffer, GUARD_BYTE, offset);
urb->transfer_buffer += offset; if (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)
urb->transfer_dma += offset;
}
/* For inbound transfers use guard byte so that test fails if
data not correctly copied */
memset(urb->transfer_buffer,
usb_pipein(urb->pipe) ? GUARD_BYTE : 0,
bytes); return urb;
}
/* *onlybit[1]ofbmAttributesisusedforLTMandothersare *reserved
*/ if (ss->bmAttributes & ~0x02) { /* reserved == 0 */
ERROR(tdev, "reserved bits set in bmAttributes\n"); return0;
}
/* bits[0:3] of wSpeedSupported is used and others are reserved */ if (le16_to_cpu(ss->wSpeedSupported) & ~0x0f) { /* reserved == 0 */
ERROR(tdev, "reserved bits set in wSpeedSupported\n"); return0;
}
/* sanity test for standard requests working with usb_control_mesg() and some *oftheutilityfunctionswhichuseit. * *thisdoesn'ttesthowendpointhaltsbehaveordatatogglesgetset,since *wewon'tdoI/Otobulk/interruptendpointshere(whichishowtochange *haltortoggle).toggletestingisimpracticalwithoutsupportfromhcds. * *thisavoidsfailingdeviceslinuxwouldnormallyworkwith,bynottesting *config/altsettingoperationsfordevicesthatonlysupporttheirdefaults. *suchdevicesrarelysupportthoseneedlessoperations. * *NOTEthatsincethisisasanitytest,it'snotexaminingboundarycases *toseeifusbcore,hcd,anddeviceallbehaveright.suchtestingwould *involvevariedreadsizesandotheroperationsequences.
*/ staticint ch9_postconfig(struct usbtest_dev *dev)
{ struct usb_interface *iface = dev->intf; struct usb_device *udev = interface_to_usbdev(iface); int i, alt, retval;
/* [9.2.3] if there's more than one altsetting, we need to be able to *setandgeteachone.mostlytruststhedescriptorsfromusbcore.
*/ for (i = 0; i < iface->num_altsetting; i++) {
/* 9.2.3 constrains the range here */
alt = iface->altsetting[i].desc.bAlternateSetting; if (alt < 0 || alt >= iface->num_altsetting) {
dev_err(&iface->dev, "invalid alt [%d].bAltSetting = %d\n",
i, alt);
}
/* [real world] get/set unimplemented if there's only one */ if (realworld && iface->num_altsetting == 1) continue;
/* [9.4.4] get_interface always works */
retval = get_altsetting(dev); if (retval != alt) {
dev_err(&iface->dev, "get alt should be %d, was %d\n",
alt, retval); return (retval < 0) ? retval : -EDOM;
}
}
/* [real world] get_config unimplemented if there's only one */ if (!realworld || udev->descriptor.bNumConfigurations != 1) { int expected = udev->actconfig->desc.bConfigurationValue;
switch (header->bDevCapabilityType) { case USB_CAP_TYPE_EXT: if (buf + USB_DT_USB_EXT_CAP_SIZE >
dev->buf + total ||
!is_good_ext(dev, buf)) {
dev_err(&iface->dev, "bogus usb 2.0 extension descriptor\n"); return -EDOM;
} break; case USB_SS_CAP_TYPE: if (buf + USB_DT_USB_SS_CAP_SIZE >
dev->buf + total ||
!is_good_ss_cap(dev, buf)) {
dev_err(&iface->dev, "bogus superspeed device capability descriptor\n"); return -EDOM;
} break; case CONTAINER_ID_TYPE: if (buf + USB_DT_USB_SS_CONTN_ID_SIZE >
dev->buf + total ||
!is_good_con_id(dev, buf)) {
dev_err(&iface->dev, "bogus container id descriptor\n"); return -EDOM;
} break; default: break;
}
}
}
/* there's always [9.4.3] at least one config descriptor [9.6.3] */ for (i = 0; i < udev->descriptor.bNumConfigurations; i++) {
retval = usb_get_descriptor(udev, USB_DT_CONFIG, i,
dev->buf, TBUF_SIZE); if (!is_good_config(dev, retval)) {
dev_err(&iface->dev, "config [%d] descriptor --> %d\n",
i, retval); return (retval < 0) ? retval : -EDOM;
}
/* FIXME cross-checking udev->config[i] to make sure usbcore *parseditright(etc)wouldbegoodtestingparanoia
*/
}
/* and sometimes [9.2.6.6] speed dependent descriptors */ if (le16_to_cpu(udev->descriptor.bcdUSB) == 0x0200) { struct usb_qualifier_descriptor *d = NULL;
/* device qualifier [9.6.2] */
retval = usb_get_descriptor(udev,
USB_DT_DEVICE_QUALIFIER, 0, dev->buf, sizeof(struct usb_qualifier_descriptor)); if (retval == -EPIPE) { if (udev->speed == USB_SPEED_HIGH) {
dev_err(&iface->dev, "hs dev qualifier --> %d\n",
retval); return retval;
} /* usb2.0 but not high-speed capable; fine */
} elseif (retval != sizeof(struct usb_qualifier_descriptor)) {
dev_err(&iface->dev, "dev qualifier --> %d\n", retval); return (retval < 0) ? retval : -EDOM;
} else
d = (struct usb_qualifier_descriptor *) dev->buf;
/* might not have [9.6.2] any other-speed configs [9.6.4] */ if (d) { unsigned max = d->bNumConfigurations; for (i = 0; i < max; i++) {
retval = usb_get_descriptor(udev,
USB_DT_OTHER_SPEED_CONFIG, i,
dev->buf, TBUF_SIZE); if (!is_good_config(dev, retval)) {
dev_err(&iface->dev, "other speed config --> %d\n",
retval); return (retval < 0) ? retval : -EDOM;
}
}
}
} /* FIXME fetch strings from at least the device descriptor */
/* [9.4.5] get_status always works */
retval = usb_get_std_status(udev, USB_RECIP_DEVICE, 0, dev->buf); if (retval) {
dev_err(&iface->dev, "get dev status --> %d\n", retval); return retval;
}
/* FIXME configuration.bmAttributes says if we could try to set/clear *thedevice'sremotewakeupfeature...ifwecan,testthathere
*/
retval = usb_get_std_status(udev, USB_RECIP_INTERFACE,
iface->altsetting[0].desc.bInterfaceNumber, dev->buf); if (retval) {
dev_err(&iface->dev, "get interface status --> %d\n", retval); return retval;
} /* FIXME get status for each endpoint in the interface */
/* use ch9 requests to test whether: *(a)queuesworkforcontrol,keepingNsubtestsqueuedand *active(auto-resubmit)forMloopsthroughthequeue. *(b)protocolstalls(control-only)willautorecover. *it'snotlikebulk/intr;nohaltclearing. *(c)shortcontrolreadsarereportedandhandled. *(d)queuesarealwaysprocessedin-order
*/
/* queue must transfer and complete in fifo order, unless *usb_unlink_urb()isusedtounlinksomethingnotatthe *physicalqueuehead(nottested).
*/ if (subcase->number > 0) { if ((subcase->number - ctx->last) != 1) {
ERROR(ctx->dev, "subcase %d completed out of order, last %d\n",
subcase->number, ctx->last);
status = -EDOM;
ctx->last = subcase->number; goto error;
}
}
ctx->last = subcase->number;
/* succeed or fault in only one way? */ if (status == subcase->expected)
status = 0;
/* some faults are allowed, not required */ if (subcase->expected > 0 && (
((status == -subcase->expected /* happened */
|| status == 0)))) /* didn't */
status = 0; /* sometimes more than one fault is allowed */ elseif (subcase->number == 12 && status == -EPIPE)
status = 0; else
ERROR(ctx->dev, "subtest %d error, status %d\n",
subcase->number, status);
}
/* unexpected status codes mean errors; ideally, in hardware */ if (status) {
error: if (ctx->status == 0) { int i;
/* allocate and init the urbs we'll queue. *aswithbulk/intrsglists,sglenisthequeuedepth;italso *controlswhichsubtestsrun(moreteststhansglen)orrerun.
*/
urb = kcalloc(param->sglen, sizeof(struct urb *), GFP_KERNEL); if (!urb) return -ENOMEM; for (i = 0; i < param->sglen; i++) { int pipe = usb_rcvctrlpipe(udev, 0); unsigned len; struct urb *u; struct usb_ctrlrequest req; struct subcase *reqp;
/* sign of this variable means: *-:testedcodemustreturnthis(negative)errorcode *+:testedcodemayreturnthis(negativetoo)errorcode
*/ int expected = 0;
/* requests here are mostly expected to succeed on any *device,butsomearechosentotriggerprotocolstalls *orshortreads.
*/
memset(&req, 0, sizeof(req));
req.bRequest = USB_REQ_GET_DESCRIPTOR;
req.bRequestType = USB_DIR_IN|USB_RECIP_DEVICE;
switch (i % NUM_SUBCASES) { case0: /* get device descriptor */
req.wValue = cpu_to_le16(USB_DT_DEVICE << 8);
len = sizeof(struct usb_device_descriptor); break; case1: /* get first config descriptor (only) */
req.wValue = cpu_to_le16((USB_DT_CONFIG << 8) | 0);
len = sizeof(struct usb_config_descriptor); break; case2: /* get altsetting (OFTEN STALLS) */
req.bRequest = USB_REQ_GET_INTERFACE;
req.bRequestType = USB_DIR_IN|USB_RECIP_INTERFACE; /* index = 0 means first interface */
len = 1;
expected = EPIPE; break; case3: /* get interface status */
req.bRequest = USB_REQ_GET_STATUS;
req.bRequestType = USB_DIR_IN|USB_RECIP_INTERFACE; /* interface 0 */
len = 2; break; case4: /* get device status */
req.bRequest = USB_REQ_GET_STATUS;
req.bRequestType = USB_DIR_IN|USB_RECIP_DEVICE;
len = 2; break; case5: /* get device qualifier (MAY STALL) */
req.wValue = cpu_to_le16 (USB_DT_DEVICE_QUALIFIER << 8);
len = sizeof(struct usb_qualifier_descriptor); if (udev->speed != USB_SPEED_HIGH)
expected = EPIPE; break; case6: /* get first config descriptor, plus interface */
req.wValue = cpu_to_le16((USB_DT_CONFIG << 8) | 0);
len = sizeof(struct usb_config_descriptor);
len += sizeof(struct usb_interface_descriptor); break; case7: /* get interface descriptor (ALWAYS STALLS) */
req.wValue = cpu_to_le16 (USB_DT_INTERFACE << 8); /* interface == 0 */
len = sizeof(struct usb_interface_descriptor);
expected = -EPIPE; break; /* NOTE: two consecutive stalls in the queue here.
* that tests fault recovery a bit more aggressively. */ case8: /* clear endpoint halt (MAY STALL) */
req.bRequest = USB_REQ_CLEAR_FEATURE;
req.bRequestType = USB_RECIP_ENDPOINT; /* wValue 0 == ep halt */ /* wIndex 0 == ep0 (shouldn't halt!) */
len = 0;
pipe = usb_sndctrlpipe(udev, 0);
expected = EPIPE; break; case9: /* get endpoint status */
req.bRequest = USB_REQ_GET_STATUS;
req.bRequestType = USB_DIR_IN|USB_RECIP_ENDPOINT; /* endpoint 0 */
len = 2; break; case10: /* trigger short read (EREMOTEIO) */
req.wValue = cpu_to_le16((USB_DT_CONFIG << 8) | 0);
len = 1024;
expected = -EREMOTEIO; break; /* NOTE: two consecutive _different_ faults in the queue. */ case11: /* get endpoint descriptor (ALWAYS STALLS) */
req.wValue = cpu_to_le16(USB_DT_ENDPOINT << 8); /* endpoint == 0 */
len = sizeof(struct usb_interface_descriptor);
expected = EPIPE; break; /* NOTE: sometimes even a third fault in the queue! */ case12: /* get string 0 descriptor (MAY STALL) */
req.wValue = cpu_to_le16(USB_DT_STRING << 8); /* string == 0, for language IDs */
len = sizeof(struct usb_interface_descriptor); /* may succeed when > 4 languages */
expected = EREMOTEIO; /* or EPIPE, if no strings */ break; case13: /* short read, resembling case 10 */
req.wValue = cpu_to_le16((USB_DT_CONFIG << 8) | 0); /* last data packet "should" be DATA1, not DATA0 */ if (udev->speed == USB_SPEED_SUPER)
len = 1024 - 512; else
len = 1024 - udev->descriptor.bMaxPacketSize0;
expected = -EREMOTEIO; break; case14: /* short read; try to fill the last packet */
req.wValue = cpu_to_le16((USB_DT_DEVICE << 8) | 0); /* device descriptor size == 18 bytes */
len = udev->descriptor.bMaxPacketSize0; if (udev->speed == USB_SPEED_SUPER)
len = 512; switch (len) { case8:
len = 24; break; case16:
len = 32; break;
}
expected = -EREMOTEIO; break; case15:
req.wValue = cpu_to_le16(USB_DT_BOS << 8); if (udev->bos)
len = le16_to_cpu(udev->bos->desc->wTotalLength); else
len = sizeof(struct usb_bos_descriptor); if (le16_to_cpu(udev->descriptor.bcdUSB) < 0x0201)
expected = -EPIPE; break; default:
ERROR(dev, "bogus number of ctrl queue testcases!\n");
context.status = -EINVAL; goto cleanup;
}
req.wLength = cpu_to_le16(len);
urb[i] = u = simple_alloc_urb(udev, pipe, len, 0); if (!u) goto cleanup;
staticvoid unlink1_callback(struct urb *urb)
{ int status = urb->status;
/* we "know" -EPIPE (stall) never happens */ if (!status)
status = usb_submit_urb(urb, GFP_ATOMIC); if (status) {
urb->status = status;
complete(urb->context);
}
}
staticint unlink1(struct usbtest_dev *dev, int pipe, int size, int async)
{ struct urb *urb; struct completion completion; int retval = 0;
if (usb_pipeout(urb->pipe)) {
simple_fill_buf(urb);
urb->transfer_flags |= URB_ZERO_PACKET;
}
/* keep the endpoint busy. there are lots of hc/hcd-internal *states,andtestingshouldgettoallofthemovertime. * *FIXMEwantadditionaltestsforwhenendpointisSTALLing *duetoerrors,orisjustNAKingrequests.
*/
retval = usb_submit_urb(urb, GFP_KERNEL); if (retval != 0) {
dev_err(&dev->intf->dev, "submit fail %d\n", retval); return retval;
}
/* unlinking that should always work. variable delay tests more *hcdstatesandcodepaths,evenwithlittleothersystemload.
*/
msleep(jiffies % (2 * INTERRUPT_RATE)); if (async) { while (!completion_done(&completion)) {
retval = usb_unlink_urb(urb);
if (retval == 0 && usb_pipein(urb->pipe))
retval = simple_check_buf(dev, urb);
switch (retval) { case -EBUSY: case -EIDRM: /* we can't unlink urbs while they're completing *orifthey'vecompleted,andwehaven't *resubmitted."normal"driverswouldprevent *resubmission,butsincewe'retestingunlink *paths,wecan't.
*/
ERROR(dev, "unlink retry\n"); continue; case0: case -EINPROGRESS: break;
staticvoid unlink_queued_callback(struct urb *urb)
{ int status = urb->status; struct queued_ctx *ctx = urb->context;
if (ctx->status) goto done; if (urb == ctx->urbs[ctx->num - 4] || urb == ctx->urbs[ctx->num - 2]) { if (status == -ECONNRESET) goto done; /* What error should we report if the URB completed normally? */
} if (status != 0)
ctx->status = status;
done: if (atomic_dec_and_test(&ctx->pending))
complete(&ctx->complete);
}
staticint unlink_queued(struct usbtest_dev *dev, int pipe, unsigned num, unsigned size)
{ struct queued_ctx ctx; struct usb_device *udev = testdev_to_usbdev(dev); void *buf;
dma_addr_t buf_dma; int i; int retval = -ENOMEM;
init_completion(&ctx.complete);
atomic_set(&ctx.pending, 1); /* One more than the actual value */
ctx.num = num;
ctx.status = 0;
/* Allocate and init the urbs we'll queue */
ctx.urbs = kcalloc(num, sizeof(struct urb *), GFP_KERNEL); if (!ctx.urbs) goto free_buf; for (i = 0; i < num; i++) {
ctx.urbs[i] = usb_alloc_urb(0, GFP_KERNEL); if (!ctx.urbs[i]) goto free_urbs;
usb_fill_bulk_urb(ctx.urbs[i], udev, pipe, buf, size,
unlink_queued_callback, &ctx);
ctx.urbs[i]->transfer_dma = buf_dma;
ctx.urbs[i]->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
if (usb_pipeout(ctx.urbs[i]->pipe)) {
simple_fill_buf(ctx.urbs[i]);
ctx.urbs[i]->transfer_flags |= URB_ZERO_PACKET;
}
}
/* Submit all the URBs and then unlink URBs num - 4 and num - 2. */ for (i = 0; i < num; i++) {
atomic_inc(&ctx.pending);
retval = usb_submit_urb(ctx.urbs[i], GFP_KERNEL); if (retval != 0) {
dev_err(&dev->intf->dev, "submit urbs[%d] fail %d\n",
i, retval);
atomic_dec(&ctx.pending);
ctx.status = retval; break;
}
} if (i == num) {
usb_unlink_urb(ctx.urbs[num - 4]);
usb_unlink_urb(ctx.urbs[num - 2]);
} else { while (--i >= 0)
usb_unlink_urb(ctx.urbs[i]);
}
if (atomic_dec_and_test(&ctx.pending)) /* The extra count */
complete(&ctx.complete);
wait_for_completion(&ctx.complete);
retval = ctx.status;
free_urbs: for (i = 0; i < num; i++)
usb_free_urb(ctx.urbs[i]);
kfree(ctx.urbs);
free_buf:
usb_free_coherent(udev, size, buf, buf_dma); return retval;
}
staticint verify_halted(struct usbtest_dev *tdev, int ep, struct urb *urb)
{ int retval;
u16 status;
/* should look and act halted */
retval = usb_get_std_status(urb->dev, USB_RECIP_ENDPOINT, ep, &status); if (retval < 0) {
ERROR(tdev, "ep %02x couldn't get halt status, %d\n",
ep, retval); return retval;
} if (status != 1) {
ERROR(tdev, "ep %02x bogus status: %04x != 1\n", ep, status); return -EINVAL;
}
retval = simple_io(tdev, urb, 1, 0, -EPIPE, __func__); if (retval != -EPIPE) return -EINVAL;
retval = simple_io(tdev, urb, 1, 0, -EPIPE, "verify_still_halted"); if (retval != -EPIPE) return -EINVAL; return0;
}
staticint test_halt(struct usbtest_dev *tdev, int ep, struct urb *urb)
{ int retval;
/* shouldn't look or act halted now */
retval = verify_not_halted(tdev, ep, urb); if (retval < 0) return retval;
/* set halt (protocol test only), verify it worked */
retval = usb_control_msg(urb->dev, usb_sndctrlpipe(urb->dev, 0),
USB_REQ_SET_FEATURE, USB_RECIP_ENDPOINT,
USB_ENDPOINT_HALT, ep,
NULL, 0, USB_CTRL_SET_TIMEOUT); if (retval < 0) {
ERROR(tdev, "ep %02x couldn't set halt, %d\n", ep, retval); return retval;
}
retval = verify_halted(tdev, ep, urb); if (retval < 0) { int ret;
/* clear halt anyways, else further tests will fail */
ret = usb_clear_halt(urb->dev, urb->pipe); if (ret)
ERROR(tdev, "ep %02x couldn't clear halt, %d\n",
ep, ret);
return retval;
}
/* clear halt (tests API + protocol), verify it worked */
retval = usb_clear_halt(urb->dev, urb->pipe); if (retval < 0) {
ERROR(tdev, "ep %02x couldn't clear halt, %d\n", ep, retval); return retval;
}
retval = verify_not_halted(tdev, ep, urb); if (retval < 0) return retval;
/* NOTE: could also verify SET_INTERFACE clear halts ... */
return0;
}
staticint test_toggle_sync(struct usbtest_dev *tdev, int ep, struct urb *urb)
{ int retval;
/* clear initial data toggle to DATA0 */
retval = usb_clear_halt(urb->dev, urb->pipe); if (retval < 0) {
ERROR(tdev, "ep %02x couldn't clear halt, %d\n", ep, retval); return retval;
}
/* transfer 3 data packets, should be DATA0, DATA1, DATA0 */
retval = simple_io(tdev, urb, 1, 0, 0, __func__); if (retval != 0) return -EINVAL;
/* clear halt resets device side data toggle, host should react to it */
retval = usb_clear_halt(urb->dev, urb->pipe); if (retval < 0) {
ERROR(tdev, "ep %02x couldn't clear halt, %d\n", ep, retval); return retval;
}
/* host should use DATA0 again after clear halt */
retval = simple_io(tdev, urb, 1, 0, 0, __func__);
return retval;
}
staticint halt_simple(struct usbtest_dev *dev)
{ int ep; int retval = 0; struct urb *urb; struct usb_device *udev = testdev_to_usbdev(dev);
if (urb->status == 0 && ctx->count > (ctx->pending - 1)
&& !ctx->submit_error) { int status = usb_submit_urb(urb, GFP_ATOMIC); switch (status) { case0: goto done; default:
dev_err(&ctx->dev->intf->dev, "resubmit err %d\n",
status);
fallthrough; case -ENODEV: /* disconnected */ case -ESHUTDOWN: /* endpoint disabled */
ctx->submit_error = 1; break;
}
}
ctx->pending--; if (ctx->pending == 0) { if (ctx->errors)
dev_err(&ctx->dev->intf->dev, "during the test, %lu errors out of %lu\n",
ctx->errors, ctx->packet_count);
complete(&ctx->done);
}
done:
spin_unlock_irqrestore(&ctx->lock, flags);
}
staticstruct urb *iso_alloc_urb( struct usb_device *udev, int pipe, struct usb_endpoint_descriptor *desc, long bytes, unsigned offset
)
{ struct urb *urb; unsigned i, maxp, packets;
urb->number_of_packets = packets;
urb->transfer_buffer_length = bytes;
urb->transfer_buffer = usb_alloc_coherent(udev, bytes + offset,
GFP_KERNEL,
&urb->transfer_dma); if (!urb->transfer_buffer) {
usb_free_urb(urb); return NULL;
} if (offset) {
memset(urb->transfer_buffer, GUARD_BYTE, offset);
urb->transfer_buffer += offset;
urb->transfer_dma += offset;
} /* For inbound transfers use guard byte so that test fails if
data not correctly copied */
memset(urb->transfer_buffer,
usb_pipein(urb->pipe) ? GUARD_BYTE : 0,
bytes);
for (i = 0; i < packets; i++) { /* here, only the last packet will be short */
urb->iso_frame_desc[i].length = min_t(unsignedint,
bytes, maxp);
bytes -= urb->iso_frame_desc[i].length;
spin_lock_irq(&context.lock); for (i = 0; i < param->sglen; i++) {
++context.pending;
status = usb_submit_urb(urbs[i], GFP_ATOMIC); if (status < 0) {
ERROR(dev, "submit iso[%d], error %d\n", i, status); if (i == 0) {
spin_unlock_irq(&context.lock); goto fail;
}
/* We only have this one interface to user space, through usbfs. *UsermodecodecanscanusbfstofindNdifferentdevices(maybeon *differentbusses)tousewhentesting,andallocateonethreadper *test.Sodiscoveryissimplified,andwehavenodevicenamingissues. * *Don'tusetheseonlyasstress/loadtests.Usethemalongwith *otherUSBbusactivity:plugging,unplugging,mousing,mp3playback, *videocapture,andsoon.Rundifferenttestsatdifferenttimes,in *differentsequences.Nothinghereshouldinteractwithotherdevices, *exceptindirectlybyconsumingUSBbandwidthandCPUresourcesfortest *threadsandrequestcompletion.Buttheonlywaytoknowthatforsure *istotestwhenHCqueuesareinusebymanydevices. * *WARNING:Becauseusbfsgrabsudev->dev.sembeforecallingthisioctl(), *itlocksoutusbcoreincertaincodepaths.Notably,ifyoudisconnect *thedevice-under-test,hub_wqwillwaitblockforeverwaitingforthe *ioctltocomplete...sothatusb_disconnect()canabortthepending *urbsandthencallusbtest_disconnect().Toabortatest,you'rebest *offjustkillingtheuserspacetaskandwaitingforittoexit.
*/
/* Basic testing only needs a device that can source or sink bulk traffic. *Anydevicecantestcontroltransfers(defaultwithGENERICbinding). * *SeveralentriesworkwiththedefaultEP0implementationthat'sbuilt *intoEZ-USBchips.There'sadefaultvendorIDwhichcanbeoverridden *by(very)smallconfigEEPROMS,butotherwiseallthesedevicesact *identicallyuntilfirmwareisloaded:onlyEP0works.Itturnsout *tobeeasytomakeotherendpointswork,withoutmodifyingthatEP0 *behavior.Fornow,weexpectthatkindoffirmware.
*/
/* an21xx or fx versions of ez-usb */ staticstruct usbtest_info ez1_info = {
.name = "EZ-USB device",
.ep_in = 2,
.ep_out = 2,
.alt = 1,
};
/* ezusb family device with dedicated usb test firmware,
*/ staticstruct usbtest_info fw_info = {
.name = "usb test device",
.ep_in = 2,
.ep_out = 2,
.alt = 1,
.autoconf = 1, /* iso and ctrl_out need autoconf */
.ctrl_out = 1,
.iso = 1, /* iso_ep's are #8 in/out */
};
/* peripheral running Linux and 'zero.c' test firmware, or *itsuser-modecousin.differentversionsofthisuse *differenthardwarewiththesamevendor/productcodes. *hostsideMUSTrelyontheendpointdescriptors.
*/ staticstruct usbtest_info gz_info = {
.name = "Linux gadget zero",
.autoconf = 1,
.ctrl_out = 1,
.iso = 1,
.intr = 1,
.alt = 0,
};
staticstruct usbtest_info um_info = {
.name = "Linux user mode test driver",
.autoconf = 1,
.alt = -1,
};
staticstruct usbtest_info um2_info = {
.name = "Linux user mode ISO test driver",
.autoconf = 1,
.iso = 1,
.alt = -1,
};
#ifdef IBOT2 /* this is a nice source of high speed bulk data; *usesanFX2,withfirmwareprovidedinthedevice
*/ staticstruct usbtest_info ibot2_info = {
.name = "iBOT2 webcam",
.ep_in = 2,
.alt = -1,
}; #endif
#ifdef GENERIC /* we can use any device to test control traffic */ staticstruct usbtest_info generic_info = {
.name = "Generic USB device",
.alt = -1,
}; #endif
#ifdef IBOT2 /* iBOT2 makes a nice source of high speed bulk-in data */ /* this does not coexist with a real iBOT2 driver! */
{ USB_DEVICE(0x0b62, 0x0059),
.driver_info = (unsignedlong) &ibot2_info,
}, #endif
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.46Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-10-01)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.