/* Some informational data */
MODULE_AUTHOR("Matthew Dharm <mdharm-usb@one-eyed-alien.net>");
MODULE_DESCRIPTION("USB Mass Storage driver for Linux");
MODULE_LICENSE("GPL");
staticunsignedint delay_use = 1 * MSEC_PER_SEC;
/** *parse_delay_str-parseanunsigneddecimalintegerdelay *@str:Stringtoparse. *@ndecimals:Numberofdecimaltoscaleup. *@suffix:Suffixstringtoparse. *@val:Wheretostoretheparsedvalue. * *Parseanunsigneddecimalvaluein@str,optionallyendwith@suffix. *Storestheparsedvaluein@valjustasitisif@strendswith@suffix. *Otherwisestorethevaluescaleupby10^(@ndecimal). * *Returns0onsuccess,anegativeerrorcodeotherwise.
*/ staticint parse_delay_str(constchar *str, int ndecimals, constchar *suffix, unsignedint *val)
{ int n, n2, l; char buf[16];
l = strlen(suffix);
n = strlen(str); if (n > 0 && str[n - 1] == '\n')
--n; if (n >= l && !strncmp(&str[n - l], suffix, l)) {
n -= l;
n2 = 0;
} else
n2 = ndecimals;
staticconststruct kernel_param_ops delay_use_ops = {
.set = delay_use_set,
.get = delay_use_get,
};
module_param_cb(delay_use, &delay_use_ops, &delay_use, 0644);
MODULE_PARM_DESC(delay_use, "time to delay before using a new device");
staticchar quirks[128];
module_param_string(quirks, quirks, sizeof(quirks), S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(quirks, "supplemental list of device IDs and their quirks");
for (;;) {
usb_stor_dbg(us, "*** thread sleeping\n"); if (wait_for_completion_interruptible(&us->cmnd_ready)) break;
usb_stor_dbg(us, "*** thread awakened\n");
/* lock the device pointers */
mutex_lock(&(us->dev_mutex));
/* lock access to the state */
scsi_lock(host);
/* When we are called with no command pending, we're done */
srb = us->srb; if (srb == NULL) {
scsi_unlock(host);
mutex_unlock(&us->dev_mutex);
usb_stor_dbg(us, "-- exiting\n"); break;
}
/* has the command timed out *already* ? */ if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) {
srb->result = DID_ABORT << 16; goto SkipForAbort;
}
scsi_unlock(host);
/* *rejectthecommandifthedirectionindicator *isUNKNOWN
*/ if (srb->sc_data_direction == DMA_BIDIRECTIONAL) {
usb_stor_dbg(us, "UNKNOWN data direction\n");
srb->result = DID_ERROR << 16;
}
/* Allow USB transfers to resume */
clear_bit(US_FLIDX_ABORTING, &us->dflags);
clear_bit(US_FLIDX_TIMED_OUT, &us->dflags);
}
/* finished working on this command */
us->srb = NULL;
scsi_unlock(host);
/* unlock the device pointers */
mutex_unlock(&us->dev_mutex);
/* now that the locks are released, notify the SCSI core */ if (srb) {
usb_stor_dbg(us, "scsi cmd done, result=0x%x\n",
srb->result);
scsi_done_direct(srb);
}
} /* for (;;) */
/* Wait until we are told to stop */ for (;;) {
set_current_state(TASK_INTERRUPTIBLE); if (kthread_should_stop()) break;
schedule();
}
__set_current_state(TASK_RUNNING); return0;
}
if (us->fflags)
dev_info(pdev, "Quirks match for vid %04x pid %04x: %llx\n",
le16_to_cpu(dev->descriptor.idVendor),
le16_to_cpu(dev->descriptor.idProduct),
us->fflags);
/* Get the pipe settings */ staticint get_pipes(struct us_data *us)
{ struct usb_host_interface *alt = us->pusb_intf->cur_altsetting; struct usb_endpoint_descriptor *ep_in; struct usb_endpoint_descriptor *ep_out; struct usb_endpoint_descriptor *ep_int; int res;
/* *Findthefirstendpointofeachtypeweneed. *Weareexpectingaminimumof2endpoints-inandout(bulk). *Anoptionalinterrupt-inisOK(necessaryforCBIprotocol). *Wewillignoreanyothers.
*/
res = usb_find_common_endpoints(alt, &ep_in, &ep_out, NULL, NULL); if (res) {
usb_stor_dbg(us, "bulk endpoints not found\n"); return res;
}
res = usb_find_int_in_endpoint(alt, &ep_int); if (res && us->protocol == USB_PR_CBI) {
usb_stor_dbg(us, "interrupt endpoint not found\n"); return res;
}
/* Calculate and store the pipe values */
us->send_ctrl_pipe = usb_sndctrlpipe(us->pusb_dev, 0);
us->recv_ctrl_pipe = usb_rcvctrlpipe(us->pusb_dev, 0);
us->send_bulk_pipe = usb_sndbulkpipe(us->pusb_dev,
usb_endpoint_num(ep_out));
us->recv_bulk_pipe = usb_rcvbulkpipe(us->pusb_dev,
usb_endpoint_num(ep_in)); if (ep_int) {
us->recv_intr_pipe = usb_rcvintpipe(us->pusb_dev,
usb_endpoint_num(ep_int));
us->ep_bInterval = ep_int->bInterval;
} return0;
}
/* Initialize all the dynamic resources we need */ staticint usb_stor_acquire_resources(struct us_data *us)
{ int p; struct task_struct *th;
us->current_urb = usb_alloc_urb(0, GFP_KERNEL); if (!us->current_urb) return -ENOMEM;
/* *Justbeforewestartourcontrolthread,initialize *thedeviceifitneedsinitialization
*/ if (us->unusual_dev->initFunction) {
p = us->unusual_dev->initFunction(us); if (p) return p;
}
/* Start up our control thread */
th = kthread_run(usb_stor_control_thread, us, "usb-storage"); if (IS_ERR(th)) {
dev_warn(&us->pusb_intf->dev, "Unable to start control thread\n"); return PTR_ERR(th);
}
us->ctl_thread = th;
return0;
}
/* Release all our dynamic resources */ staticvoid usb_stor_release_resources(struct us_data *us)
{ /* *Tellthecontrolthreadtoexit.TheSCSIhostmust *alreadyhavebeenremovedandtheDISCONNECTINGflagset *sothatwewon'tacceptanymorecommands.
*/
usb_stor_dbg(us, "-- sending exit command to thread\n");
complete(&us->cmnd_ready); if (us->ctl_thread)
kthread_stop(us->ctl_thread);
/* Call the destructor routine, if it exists */ if (us->extra_destructor) {
usb_stor_dbg(us, "-- calling extra_destructor()\n");
us->extra_destructor(us->extra);
}
/* Free the extra data and the URB */
kfree(us->extra);
usb_free_urb(us->current_urb);
}
/* Dissociate from the USB device */ staticvoid dissociate_dev(struct us_data *us)
{ /* Free the buffers */
kfree(us->cr);
usb_free_coherent(us->pusb_dev, US_IOBUF_SIZE, us->iobuf, us->iobuf_dma);
/* Remove our private data from the interface */
usb_set_intfdata(us->pusb_intf, NULL);
}
/* If the device is really gone, cut short reset delays */ if (us->pusb_dev->state == USB_STATE_NOTATTACHED) {
set_bit(US_FLIDX_DISCONNECTING, &us->dflags);
wake_up(&us->delay_wait);
}
/* Balance autopm calls if scanning was cancelled */ if (test_bit(US_FLIDX_SCAN_PENDING, &us->dflags))
usb_autopm_put_interface_no_suspend(us->pusb_intf);
if (usb_dev->bus->sg_tablesize) { return usb_dev->bus->sg_tablesize;
} return SG_ALL;
}
/* First part of general USB mass-storage probing */ int usb_stor_probe1(struct us_data **pus, struct usb_interface *intf, conststruct usb_device_id *id, conststruct us_unusual_dev *unusual_dev, conststruct scsi_host_template *sht)
{ struct Scsi_Host *host; struct us_data *us; int result;
dev_info(&intf->dev, "USB Mass Storage device detected\n");
/* *AsktheSCSIlayertoallocateahoststructure,withextra *spaceattheendforourprivateus_datastructure.
*/
host = scsi_host_alloc(sht, sizeof(*us)); if (!host) {
dev_warn(&intf->dev, "Unable to allocate the scsi host\n"); return -ENOMEM;
}
/* Second part of general USB mass-storage probing */ int usb_stor_probe2(struct us_data *us)
{ int result; struct device *dev = &us->pusb_intf->dev;
/* Make sure the transport and protocol have both been set */ if (!us->transport || !us->proto_handler) {
result = -ENXIO; goto BadDevice;
}
usb_stor_dbg(us, "Transport: %s\n", us->transport_name);
usb_stor_dbg(us, "Protocol: %s\n", us->protocol_name);
if (us->fflags & US_FL_SCM_MULT_TARG) { /* *SCMeUSCSIbridgedevicescanhavedifferentnumbers *ofLUNsondifferenttargets;allowalltobeprobed.
*/
us->max_lun = 7; /* The eUSCSI itself has ID 7, so avoid scanning that */
us_to_host(us)->this_id = 7; /* max_id is 8 initially, so no need to set it here */
} else { /* In the normal case there is only a single target */
us_to_host(us)->max_id = 1; /* *LikeWindows,wewon'tstoretheLUNbitsinCDB[1]for *SCSI-2devicesusingtheBulk-Onlytransport(eventhough *thisviolatestheSCSIspec).
*/ if (us->transport == usb_stor_Bulk_transport)
us_to_host(us)->no_scsi2_lun_in_cdb = 1;
}
/* fix for single-lun devices */ if (us->fflags & US_FL_SINGLE_LUN)
us->max_lun = 0;
/* Find the endpoints and calculate pipe values */
result = get_pipes(us); if (result) goto BadDevice;
/* *IfthedevicereturnsinvaliddataforthefirstREAD(10) *command,indicatethecommandshouldberetried.
*/ if (us->fflags & US_FL_INITIAL_READ10)
set_bit(US_FLIDX_REDO_READ10, &us->dflags);
/* Acquire all the other resources and add the host */
result = usb_stor_acquire_resources(us); if (result) goto BadDevice;
usb_autopm_get_interface_no_resume(us->pusb_intf);
snprintf(us->scsi_name, sizeof(us->scsi_name), "usb-storage %s",
dev_name(&us->pusb_intf->dev));
result = scsi_add_host(us_to_host(us), dev); if (result) {
dev_warn(dev, "Unable to add the scsi host\n"); goto HostAddErr;
}
/* Submit the delayed_work for SCSI-device scanning */
set_bit(US_FLIDX_SCAN_PENDING, &us->dflags);
if (delay_use > 0)
dev_dbg(dev, "waiting for device to settle before scanning\n");
queue_delayed_work(system_freezable_wq, &us->scan_dwork,
msecs_to_jiffies(delay_use)); return0;
/* We come here if there are any problems */
HostAddErr:
usb_autopm_put_interface_no_suspend(us->pusb_intf);
BadDevice:
usb_stor_dbg(us, "storage_probe() failed\n");
release_everything(us); return result;
}
EXPORT_SYMBOL_GPL(usb_stor_probe2);
/* Handle a USB mass-storage disconnect */ void usb_stor_disconnect(struct usb_interface *intf)
{ struct us_data *us = usb_get_intfdata(intf);
/* The main probe routine for standard devices */ staticint storage_probe(struct usb_interface *intf, conststruct usb_device_id *id)
{ conststruct us_unusual_dev *unusual_dev; struct us_data *us; int result; int size;
/* If uas is enabled and this device can do uas then ignore it. */ #if IS_ENABLED(CONFIG_USB_UAS) if (uas_use_uas_driver(intf, id, NULL)) return -ENXIO; #endif
/* *Ifthedeviceisn'tstandard(ishandledbyasubdriver *module)thendon'tacceptit.
*/ if (usb_usual_ignore_device(intf)) return -ENXIO;
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.38Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-09-27)
¤
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.