2007-12-09 23:27:42 +03:00
|
|
|
/* $NetBSD: umass.c,v 1.125 2007/12/09 20:28:24 jmcneill Exp $ */
|
2003-09-10 09:42:18 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Copyright (c) 2003 The NetBSD Foundation, Inc.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* This code is derived from software contributed to The NetBSD Foundation
|
2003-09-13 07:18:13 +04:00
|
|
|
* by Charles M. Hannum.
|
2003-09-10 09:42:18 +04:00
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
|
|
* must display the following acknowledgement:
|
|
|
|
* This product includes software developed by the NetBSD
|
|
|
|
* Foundation, Inc. and its contributors.
|
|
|
|
* 4. Neither the name of The NetBSD Foundation nor the names of its
|
|
|
|
* contributors may be used to endorse or promote products derived
|
|
|
|
* from this software without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
|
|
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
|
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
|
|
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
1999-08-29 04:30:08 +04:00
|
|
|
/*-
|
|
|
|
* Copyright (c) 1999 MAEKAWA Masahide <bishop@rr.iij4u.or.jp>,
|
2000-04-03 03:46:53 +04:00
|
|
|
* Nick Hibma <n_hibma@freebsd.org>
|
1999-08-29 04:30:08 +04:00
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
* SUCH DAMAGE.
|
|
|
|
*
|
2000-04-03 03:46:53 +04:00
|
|
|
* $FreeBSD: src/sys/dev/usb/umass.c,v 1.13 2000/03/26 01:39:12 n_hibma Exp $
|
1999-08-29 04:30:08 +04:00
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2000-12-29 04:24:55 +03:00
|
|
|
* Universal Serial Bus Mass Storage Class specs:
|
2003-11-07 20:03:25 +03:00
|
|
|
* http://www.usb.org/developers/devclass_docs/usb_msc_overview_1.2.pdf
|
|
|
|
* http://www.usb.org/developers/devclass_docs/usbmassbulk_10.pdf
|
|
|
|
* http://www.usb.org/developers/devclass_docs/usb_msc_cbi_1.1.pdf
|
|
|
|
* http://www.usb.org/developers/devclass_docs/usbmass-ufi10.pdf
|
2000-04-03 03:46:53 +04:00
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2003-12-04 16:57:30 +03:00
|
|
|
* Ported to NetBSD by Lennart Augustsson <augustss@NetBSD.org>.
|
2002-11-04 22:17:33 +03:00
|
|
|
* Parts of the code written by Jason R. Thorpe <thorpej@shagadelic.org>.
|
2000-04-03 03:46:53 +04:00
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The driver handles 3 Wire Protocols
|
|
|
|
* - Command/Bulk/Interrupt (CBI)
|
|
|
|
* - Command/Bulk/Interrupt with Command Completion Interrupt (CBI with CCI)
|
|
|
|
* - Mass Storage Bulk-Only (BBB)
|
|
|
|
* (BBB refers Bulk/Bulk/Bulk for Command/Data/Status phases)
|
1999-08-29 22:13:26 +04:00
|
|
|
*
|
2000-04-03 03:46:53 +04:00
|
|
|
* Over these wire protocols it handles the following command protocols
|
|
|
|
* - SCSI
|
2001-04-01 18:41:39 +04:00
|
|
|
* - 8070 (ATA/ATAPI for rewritable removable media)
|
|
|
|
* - UFI (USB Floppy Interface)
|
1999-08-29 22:13:26 +04:00
|
|
|
*
|
2001-04-01 18:41:39 +04:00
|
|
|
* 8070i is a transformed version of the SCSI command set. UFI is a transformed
|
2002-07-12 01:14:24 +04:00
|
|
|
* version of the 8070i command set. The sc->transform method is used to
|
2001-04-01 18:41:39 +04:00
|
|
|
* convert the commands into the appropriate format (if at all necessary).
|
|
|
|
* For example, ATAPI requires all commands to be 12 bytes in length amongst
|
|
|
|
* other things.
|
1999-08-29 22:13:26 +04:00
|
|
|
*
|
2000-04-03 03:46:53 +04:00
|
|
|
* The source code below is marked and can be split into a number of pieces
|
|
|
|
* (in this order):
|
1999-08-29 04:30:08 +04:00
|
|
|
*
|
2000-04-03 03:46:53 +04:00
|
|
|
* - probe/attach/detach
|
|
|
|
* - generic transfer routines
|
|
|
|
* - BBB
|
|
|
|
* - CBI
|
|
|
|
* - CBI_I (in addition to functions from CBI)
|
|
|
|
* - CAM (Common Access Method)
|
|
|
|
* - SCSI
|
|
|
|
* - UFI
|
|
|
|
* - 8070i
|
1999-08-29 21:34:11 +04:00
|
|
|
*
|
2000-04-03 03:46:53 +04:00
|
|
|
* The protocols are implemented using a state machine, for the transfers as
|
|
|
|
* well as for the resets. The state machine is contained in umass_*_state.
|
|
|
|
* The state machine is started through either umass_*_transfer or
|
|
|
|
* umass_*_reset.
|
1999-08-29 21:34:11 +04:00
|
|
|
*
|
2000-04-03 03:46:53 +04:00
|
|
|
* The reason for doing this is a) CAM performs a lot better this way and b) it
|
|
|
|
* avoids using tsleep from interrupt context (for example after a failed
|
|
|
|
* transfer).
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The SCSI related part of this driver has been derived from the
|
|
|
|
* dev/ppbus/vpo.c driver, by Nicolas Souchu (nsouch@freebsd.org).
|
1999-08-29 22:58:03 +04:00
|
|
|
*
|
2000-04-03 03:46:53 +04:00
|
|
|
* The CAM layer uses so called actions which are messages sent to the host
|
|
|
|
* adapter for completion. The actions come in through umass_cam_action. The
|
|
|
|
* appropriate block of routines is called depending on the transport protocol
|
|
|
|
* in use. When the transfer has finished, these routines call
|
|
|
|
* umass_cam_cb again to complete the CAM command.
|
1999-08-29 04:30:08 +04:00
|
|
|
*/
|
|
|
|
|
2001-11-13 09:24:53 +03:00
|
|
|
#include <sys/cdefs.h>
|
2007-12-09 23:27:42 +03:00
|
|
|
__KERNEL_RCSID(0, "$NetBSD: umass.c,v 1.125 2007/12/09 20:28:24 jmcneill Exp $");
|
2001-11-13 09:24:53 +03:00
|
|
|
|
2000-04-03 07:56:49 +04:00
|
|
|
#include "atapibus.h"
|
2001-12-24 16:25:52 +03:00
|
|
|
#include "scsibus.h"
|
2001-12-24 16:43:24 +03:00
|
|
|
#include "wd.h"
|
2000-04-03 07:56:49 +04:00
|
|
|
|
1999-08-29 04:30:08 +04:00
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/systm.h>
|
|
|
|
#include <sys/kernel.h>
|
2000-04-03 03:46:53 +04:00
|
|
|
#include <sys/conf.h>
|
|
|
|
#if defined(__NetBSD__) || defined(__OpenBSD__)
|
1999-08-29 04:30:08 +04:00
|
|
|
#include <sys/buf.h>
|
2000-04-03 03:46:53 +04:00
|
|
|
#include <sys/device.h>
|
|
|
|
#include <sys/malloc.h>
|
|
|
|
#undef KASSERT
|
|
|
|
#define KASSERT(cond, msg)
|
|
|
|
#elif defined(__FreeBSD__)
|
|
|
|
#include <sys/module.h>
|
|
|
|
#include <sys/bus.h>
|
|
|
|
#include <machine/clock.h>
|
|
|
|
#endif
|
1999-08-29 04:30:08 +04:00
|
|
|
|
|
|
|
#include <dev/usb/usb.h>
|
|
|
|
#include <dev/usb/usbdi.h>
|
|
|
|
#include <dev/usb/usbdi_util.h>
|
2000-04-03 03:46:53 +04:00
|
|
|
#include <dev/usb/usbdevs.h>
|
|
|
|
|
2001-04-13 16:24:10 +04:00
|
|
|
#include <dev/usb/umassvar.h>
|
2001-12-17 15:16:14 +03:00
|
|
|
#include <dev/usb/umass_quirks.h>
|
2001-12-24 16:25:52 +03:00
|
|
|
#include <dev/usb/umass_scsipi.h>
|
2001-12-24 16:43:24 +03:00
|
|
|
#include <dev/usb/umass_isdata.h>
|
2000-09-24 01:03:00 +04:00
|
|
|
|
2003-09-08 23:57:29 +04:00
|
|
|
#include <dev/scsipi/scsipi_all.h>
|
|
|
|
#include <dev/scsipi/scsipiconf.h>
|
|
|
|
|
2000-04-03 03:46:53 +04:00
|
|
|
|
|
|
|
#ifdef UMASS_DEBUG
|
2001-04-13 16:51:43 +04:00
|
|
|
int umassdebug = 0;
|
|
|
|
|
2005-05-31 23:20:37 +04:00
|
|
|
const char *states[TSTATE_STATES+1] = {
|
2000-04-03 03:46:53 +04:00
|
|
|
/* should be kept in sync with the list at transfer_state */
|
|
|
|
"Idle",
|
|
|
|
"BBB CBW",
|
|
|
|
"BBB Data",
|
|
|
|
"BBB Data bulk-in/-out clear stall",
|
|
|
|
"BBB CSW, 1st attempt",
|
|
|
|
"BBB CSW bulk-in clear stall",
|
|
|
|
"BBB CSW, 2nd attempt",
|
|
|
|
"BBB Reset",
|
|
|
|
"BBB bulk-in clear stall",
|
|
|
|
"BBB bulk-out clear stall",
|
|
|
|
"CBI Command",
|
|
|
|
"CBI Data",
|
|
|
|
"CBI Status",
|
|
|
|
"CBI Data bulk-in/-out clear stall",
|
|
|
|
"CBI Status intr-in clear stall",
|
|
|
|
"CBI Reset",
|
|
|
|
"CBI bulk-in clear stall",
|
|
|
|
"CBI bulk-out clear stall",
|
|
|
|
NULL
|
|
|
|
};
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* USB device probe/attach/detach functions */
|
|
|
|
USB_DECLARE_DRIVER(umass);
|
2000-06-01 18:28:57 +04:00
|
|
|
Static void umass_disco(struct umass_softc *sc);
|
2000-04-03 03:46:53 +04:00
|
|
|
|
|
|
|
/* generic transfer functions */
|
2000-06-01 18:28:57 +04:00
|
|
|
Static usbd_status umass_setup_transfer(struct umass_softc *sc,
|
1999-08-29 04:30:08 +04:00
|
|
|
usbd_pipe_handle pipe,
|
2000-04-03 03:46:53 +04:00
|
|
|
void *buffer, int buflen, int flags,
|
2000-06-01 18:28:57 +04:00
|
|
|
usbd_xfer_handle xfer);
|
|
|
|
Static usbd_status umass_setup_ctrl_transfer(struct umass_softc *sc,
|
2000-04-03 03:46:53 +04:00
|
|
|
usb_device_request_t *req,
|
2002-07-12 01:14:24 +04:00
|
|
|
void *buffer, int buflen, int flags,
|
2000-06-01 18:28:57 +04:00
|
|
|
usbd_xfer_handle xfer);
|
2001-12-14 08:58:13 +03:00
|
|
|
Static void umass_clear_endpoint_stall(struct umass_softc *sc, int endpt,
|
2001-12-12 16:23:20 +03:00
|
|
|
usbd_xfer_handle xfer);
|
2000-04-03 07:56:49 +04:00
|
|
|
#if 0
|
2000-06-01 18:28:57 +04:00
|
|
|
Static void umass_reset(struct umass_softc *sc, transfer_cb_f cb, void *priv);
|
2000-04-03 07:56:49 +04:00
|
|
|
#endif
|
1999-08-29 04:30:08 +04:00
|
|
|
|
|
|
|
/* Bulk-Only related functions */
|
2001-12-14 11:46:19 +03:00
|
|
|
Static void umass_bbb_transfer(struct umass_softc *, int, void *, int, void *,
|
|
|
|
int, int, u_int, umass_callback, void *);
|
|
|
|
Static void umass_bbb_reset(struct umass_softc *, int);
|
|
|
|
Static void umass_bbb_state(usbd_xfer_handle, usbd_private_handle, usbd_status);
|
2000-04-03 03:46:53 +04:00
|
|
|
|
2001-12-14 11:46:19 +03:00
|
|
|
usbd_status umass_bbb_get_max_lun(struct umass_softc *, u_int8_t *);
|
2000-04-03 03:46:53 +04:00
|
|
|
|
|
|
|
/* CBI related functions */
|
2002-07-12 01:14:24 +04:00
|
|
|
Static void umass_cbi_transfer(struct umass_softc *, int, void *, int, void *,
|
2001-12-14 11:46:19 +03:00
|
|
|
int, int, u_int, umass_callback, void *);
|
|
|
|
Static void umass_cbi_reset(struct umass_softc *, int);
|
|
|
|
Static void umass_cbi_state(usbd_xfer_handle, usbd_private_handle, usbd_status);
|
|
|
|
|
|
|
|
Static int umass_cbi_adsc(struct umass_softc *, char *, int, usbd_xfer_handle);
|
|
|
|
|
|
|
|
const struct umass_wire_methods umass_bbb_methods = {
|
|
|
|
umass_bbb_transfer,
|
|
|
|
umass_bbb_reset,
|
|
|
|
umass_bbb_state
|
|
|
|
};
|
|
|
|
|
|
|
|
const struct umass_wire_methods umass_cbi_methods = {
|
|
|
|
umass_cbi_transfer,
|
|
|
|
umass_cbi_reset,
|
|
|
|
umass_cbi_state
|
|
|
|
};
|
2000-04-03 03:46:53 +04:00
|
|
|
|
|
|
|
#ifdef UMASS_DEBUG
|
|
|
|
/* General debugging functions */
|
2000-06-01 18:28:57 +04:00
|
|
|
Static void umass_bbb_dump_cbw(struct umass_softc *sc,
|
|
|
|
umass_bbb_cbw_t *cbw);
|
|
|
|
Static void umass_bbb_dump_csw(struct umass_softc *sc,
|
|
|
|
umass_bbb_csw_t *csw);
|
|
|
|
Static void umass_dump_buffer(struct umass_softc *sc, u_int8_t *buffer,
|
|
|
|
int buflen, int printlen);
|
2000-04-03 03:46:53 +04:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* USB device probe/attach/detach
|
|
|
|
*/
|
|
|
|
|
2001-12-17 15:16:14 +03:00
|
|
|
USB_MATCH(umass)
|
2000-04-03 03:46:53 +04:00
|
|
|
{
|
Introduce different autoconf interface attributes for USB drivers
matching (and handling) a whole device and those which match an
interface only. This will allow to enforce some rules, eg that
the former don't use interface information for matching or that the
latter don't modify global device state.
The previous way left too much freedom do the drivers which led to
inconsistencies and abuse.
For now, I've not changed locators and submatch rules, this will
happen later.
There should not be any change in behaviour, except in the case of
some drivers which did behave inconsistently:
if_atu, if_axe, uep: matched the configured device in the interface
stage, but did configuration again. I've converted them to match
in the device stage.
ustir, utoppy: matched in the interface stage, but only against
vendor/device information, and used any configuration/interface
without checking. Changed to match in device stage, and added
some simple code to configure and use the first interface.
If you have one of those devices, please test!
2007-03-13 16:51:53 +03:00
|
|
|
USB_IFMATCH_START(umass, uaa);
|
2001-12-17 15:16:14 +03:00
|
|
|
const struct umass_quirk *quirk;
|
2001-11-25 22:15:46 +03:00
|
|
|
|
2001-12-17 15:16:14 +03:00
|
|
|
quirk = umass_lookup(uaa->vendor, uaa->product);
|
|
|
|
if (quirk != NULL)
|
|
|
|
return (quirk->uq_match);
|
2001-12-15 03:26:14 +03:00
|
|
|
|
Introduce different autoconf interface attributes for USB drivers
matching (and handling) a whole device and those which match an
interface only. This will allow to enforce some rules, eg that
the former don't use interface information for matching or that the
latter don't modify global device state.
The previous way left too much freedom do the drivers which led to
inconsistencies and abuse.
For now, I've not changed locators and submatch rules, this will
happen later.
There should not be any change in behaviour, except in the case of
some drivers which did behave inconsistently:
if_atu, if_axe, uep: matched the configured device in the interface
stage, but did configuration again. I've converted them to match
in the device stage.
ustir, utoppy: matched in the interface stage, but only against
vendor/device information, and used any configuration/interface
without checking. Changed to match in device stage, and added
some simple code to configure and use the first interface.
If you have one of those devices, please test!
2007-03-13 16:51:53 +03:00
|
|
|
if (uaa->class != UICLASS_MASS)
|
2000-04-03 03:46:53 +04:00
|
|
|
return (UMATCH_NONE);
|
1999-08-29 04:30:08 +04:00
|
|
|
|
Introduce different autoconf interface attributes for USB drivers
matching (and handling) a whole device and those which match an
interface only. This will allow to enforce some rules, eg that
the former don't use interface information for matching or that the
latter don't modify global device state.
The previous way left too much freedom do the drivers which led to
inconsistencies and abuse.
For now, I've not changed locators and submatch rules, this will
happen later.
There should not be any change in behaviour, except in the case of
some drivers which did behave inconsistently:
if_atu, if_axe, uep: matched the configured device in the interface
stage, but did configuration again. I've converted them to match
in the device stage.
ustir, utoppy: matched in the interface stage, but only against
vendor/device information, and used any configuration/interface
without checking. Changed to match in device stage, and added
some simple code to configure and use the first interface.
If you have one of those devices, please test!
2007-03-13 16:51:53 +03:00
|
|
|
switch (uaa->subclass) {
|
2001-12-17 15:16:14 +03:00
|
|
|
case UISUBCLASS_RBC:
|
2000-04-03 03:46:53 +04:00
|
|
|
case UISUBCLASS_SFF8020I:
|
2000-04-03 16:31:34 +04:00
|
|
|
case UISUBCLASS_QIC157:
|
2001-12-17 15:16:14 +03:00
|
|
|
case UISUBCLASS_UFI:
|
|
|
|
case UISUBCLASS_SFF8070I:
|
|
|
|
case UISUBCLASS_SCSI:
|
2000-08-12 18:52:44 +04:00
|
|
|
break;
|
2000-04-03 03:46:53 +04:00
|
|
|
default:
|
2001-12-17 15:16:14 +03:00
|
|
|
return (UMATCH_IFACECLASS);
|
2000-04-03 03:46:53 +04:00
|
|
|
}
|
|
|
|
|
Introduce different autoconf interface attributes for USB drivers
matching (and handling) a whole device and those which match an
interface only. This will allow to enforce some rules, eg that
the former don't use interface information for matching or that the
latter don't modify global device state.
The previous way left too much freedom do the drivers which led to
inconsistencies and abuse.
For now, I've not changed locators and submatch rules, this will
happen later.
There should not be any change in behaviour, except in the case of
some drivers which did behave inconsistently:
if_atu, if_axe, uep: matched the configured device in the interface
stage, but did configuration again. I've converted them to match
in the device stage.
ustir, utoppy: matched in the interface stage, but only against
vendor/device information, and used any configuration/interface
without checking. Changed to match in device stage, and added
some simple code to configure and use the first interface.
If you have one of those devices, please test!
2007-03-13 16:51:53 +03:00
|
|
|
switch (uaa->proto) {
|
2000-04-03 03:46:53 +04:00
|
|
|
case UIPROTO_MASS_CBI_I:
|
2001-12-17 15:16:14 +03:00
|
|
|
case UIPROTO_MASS_CBI:
|
2001-11-23 04:15:28 +03:00
|
|
|
case UIPROTO_MASS_BBB_OLD:
|
2001-12-17 15:16:14 +03:00
|
|
|
case UIPROTO_MASS_BBB:
|
2000-04-03 03:46:53 +04:00
|
|
|
break;
|
|
|
|
default:
|
2001-12-17 15:16:14 +03:00
|
|
|
return (UMATCH_IFACECLASS_IFACESUBCLASS);
|
2000-04-03 03:46:53 +04:00
|
|
|
}
|
1999-08-29 04:30:08 +04:00
|
|
|
|
2001-12-17 15:16:14 +03:00
|
|
|
return (UMATCH_IFACECLASS_IFACESUBCLASS_IFACEPROTO);
|
1999-08-29 04:30:08 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
USB_ATTACH(umass)
|
|
|
|
{
|
Introduce different autoconf interface attributes for USB drivers
matching (and handling) a whole device and those which match an
interface only. This will allow to enforce some rules, eg that
the former don't use interface information for matching or that the
latter don't modify global device state.
The previous way left too much freedom do the drivers which led to
inconsistencies and abuse.
For now, I've not changed locators and submatch rules, this will
happen later.
There should not be any change in behaviour, except in the case of
some drivers which did behave inconsistently:
if_atu, if_axe, uep: matched the configured device in the interface
stage, but did configuration again. I've converted them to match
in the device stage.
ustir, utoppy: matched in the interface stage, but only against
vendor/device information, and used any configuration/interface
without checking. Changed to match in device stage, and added
some simple code to configure and use the first interface.
If you have one of those devices, please test!
2007-03-13 16:51:53 +03:00
|
|
|
USB_IFATTACH_START(umass, sc, uaa);
|
2001-12-17 15:16:14 +03:00
|
|
|
const struct umass_quirk *quirk;
|
1999-08-29 04:30:08 +04:00
|
|
|
usb_interface_descriptor_t *id;
|
|
|
|
usb_endpoint_descriptor_t *ed;
|
2001-12-17 15:16:14 +03:00
|
|
|
const char *sWire, *sCommand;
|
2005-05-11 14:02:28 +04:00
|
|
|
char *devinfop;
|
2001-12-17 15:16:14 +03:00
|
|
|
usbd_status err;
|
2001-12-24 16:25:52 +03:00
|
|
|
int i, bno, error;
|
1999-08-29 04:30:08 +04:00
|
|
|
|
2005-05-11 14:02:28 +04:00
|
|
|
devinfop = usbd_devinfo_alloc(uaa->device, 0);
|
1999-08-29 04:30:08 +04:00
|
|
|
USB_ATTACH_SETUP;
|
2005-05-11 14:02:28 +04:00
|
|
|
printf("%s: %s\n", USBDEVNAME(sc->sc_dev), devinfop);
|
|
|
|
usbd_devinfo_free(devinfop);
|
1999-08-29 04:30:08 +04:00
|
|
|
|
2001-12-17 15:16:14 +03:00
|
|
|
sc->sc_udev = uaa->device;
|
2001-12-14 11:58:49 +03:00
|
|
|
sc->sc_iface = uaa->iface;
|
|
|
|
sc->sc_ifaceno = uaa->ifaceno;
|
1999-09-12 06:40:59 +04:00
|
|
|
|
2001-12-17 15:16:14 +03:00
|
|
|
quirk = umass_lookup(uaa->vendor, uaa->product);
|
|
|
|
if (quirk != NULL) {
|
|
|
|
sc->sc_wire = quirk->uq_wire;
|
|
|
|
sc->sc_cmd = quirk->uq_cmd;
|
|
|
|
sc->sc_quirks = quirk->uq_flags;
|
2001-12-29 16:46:23 +03:00
|
|
|
sc->sc_busquirks = quirk->uq_busquirks;
|
2001-12-17 15:16:14 +03:00
|
|
|
|
|
|
|
if (quirk->uq_fixup != NULL)
|
|
|
|
(*quirk->uq_fixup)(sc);
|
|
|
|
} else {
|
|
|
|
sc->sc_wire = UMASS_WPROTO_UNSPEC;
|
|
|
|
sc->sc_cmd = UMASS_CPROTO_UNSPEC;
|
|
|
|
sc->sc_quirks = 0;
|
2001-12-29 16:46:23 +03:00
|
|
|
sc->sc_busquirks = 0;
|
2001-12-17 15:16:14 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (sc->sc_wire == UMASS_WPROTO_UNSPEC) {
|
Introduce different autoconf interface attributes for USB drivers
matching (and handling) a whole device and those which match an
interface only. This will allow to enforce some rules, eg that
the former don't use interface information for matching or that the
latter don't modify global device state.
The previous way left too much freedom do the drivers which led to
inconsistencies and abuse.
For now, I've not changed locators and submatch rules, this will
happen later.
There should not be any change in behaviour, except in the case of
some drivers which did behave inconsistently:
if_atu, if_axe, uep: matched the configured device in the interface
stage, but did configuration again. I've converted them to match
in the device stage.
ustir, utoppy: matched in the interface stage, but only against
vendor/device information, and used any configuration/interface
without checking. Changed to match in device stage, and added
some simple code to configure and use the first interface.
If you have one of those devices, please test!
2007-03-13 16:51:53 +03:00
|
|
|
switch (uaa->proto) {
|
2001-12-17 15:16:14 +03:00
|
|
|
case UIPROTO_MASS_CBI:
|
|
|
|
sc->sc_wire = UMASS_WPROTO_CBI;
|
|
|
|
break;
|
|
|
|
case UIPROTO_MASS_CBI_I:
|
|
|
|
sc->sc_wire = UMASS_WPROTO_CBI_I;
|
|
|
|
break;
|
|
|
|
case UIPROTO_MASS_BBB:
|
|
|
|
case UIPROTO_MASS_BBB_OLD:
|
|
|
|
sc->sc_wire = UMASS_WPROTO_BBB;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
DPRINTF(UDMASS_GEN,
|
|
|
|
("%s: Unsupported wire protocol %u\n",
|
|
|
|
USBDEVNAME(sc->sc_dev),
|
Introduce different autoconf interface attributes for USB drivers
matching (and handling) a whole device and those which match an
interface only. This will allow to enforce some rules, eg that
the former don't use interface information for matching or that the
latter don't modify global device state.
The previous way left too much freedom do the drivers which led to
inconsistencies and abuse.
For now, I've not changed locators and submatch rules, this will
happen later.
There should not be any change in behaviour, except in the case of
some drivers which did behave inconsistently:
if_atu, if_axe, uep: matched the configured device in the interface
stage, but did configuration again. I've converted them to match
in the device stage.
ustir, utoppy: matched in the interface stage, but only against
vendor/device information, and used any configuration/interface
without checking. Changed to match in device stage, and added
some simple code to configure and use the first interface.
If you have one of those devices, please test!
2007-03-13 16:51:53 +03:00
|
|
|
uaa->proto));
|
2001-12-17 15:16:14 +03:00
|
|
|
USB_ATTACH_ERROR_RETURN;
|
|
|
|
}
|
2000-08-12 18:52:44 +04:00
|
|
|
}
|
1999-09-12 06:40:59 +04:00
|
|
|
|
2001-12-17 15:16:14 +03:00
|
|
|
if (sc->sc_cmd == UMASS_CPROTO_UNSPEC) {
|
Introduce different autoconf interface attributes for USB drivers
matching (and handling) a whole device and those which match an
interface only. This will allow to enforce some rules, eg that
the former don't use interface information for matching or that the
latter don't modify global device state.
The previous way left too much freedom do the drivers which led to
inconsistencies and abuse.
For now, I've not changed locators and submatch rules, this will
happen later.
There should not be any change in behaviour, except in the case of
some drivers which did behave inconsistently:
if_atu, if_axe, uep: matched the configured device in the interface
stage, but did configuration again. I've converted them to match
in the device stage.
ustir, utoppy: matched in the interface stage, but only against
vendor/device information, and used any configuration/interface
without checking. Changed to match in device stage, and added
some simple code to configure and use the first interface.
If you have one of those devices, please test!
2007-03-13 16:51:53 +03:00
|
|
|
switch (uaa->subclass) {
|
2001-12-17 15:16:14 +03:00
|
|
|
case UISUBCLASS_SCSI:
|
|
|
|
sc->sc_cmd = UMASS_CPROTO_SCSI;
|
|
|
|
break;
|
|
|
|
case UISUBCLASS_UFI:
|
|
|
|
sc->sc_cmd = UMASS_CPROTO_UFI;
|
|
|
|
break;
|
|
|
|
case UISUBCLASS_SFF8020I:
|
|
|
|
case UISUBCLASS_SFF8070I:
|
|
|
|
case UISUBCLASS_QIC157:
|
|
|
|
sc->sc_cmd = UMASS_CPROTO_ATAPI;
|
|
|
|
break;
|
|
|
|
case UISUBCLASS_RBC:
|
|
|
|
sc->sc_cmd = UMASS_CPROTO_RBC;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
DPRINTF(UDMASS_GEN,
|
|
|
|
("%s: Unsupported command protocol %u\n",
|
|
|
|
USBDEVNAME(sc->sc_dev),
|
Introduce different autoconf interface attributes for USB drivers
matching (and handling) a whole device and those which match an
interface only. This will allow to enforce some rules, eg that
the former don't use interface information for matching or that the
latter don't modify global device state.
The previous way left too much freedom do the drivers which led to
inconsistencies and abuse.
For now, I've not changed locators and submatch rules, this will
happen later.
There should not be any change in behaviour, except in the case of
some drivers which did behave inconsistently:
if_atu, if_axe, uep: matched the configured device in the interface
stage, but did configuration again. I've converted them to match
in the device stage.
ustir, utoppy: matched in the interface stage, but only against
vendor/device information, and used any configuration/interface
without checking. Changed to match in device stage, and added
some simple code to configure and use the first interface.
If you have one of those devices, please test!
2007-03-13 16:51:53 +03:00
|
|
|
uaa->subclass));
|
2001-02-08 16:24:05 +03:00
|
|
|
USB_ATTACH_ERROR_RETURN;
|
2001-12-17 15:16:14 +03:00
|
|
|
}
|
|
|
|
}
|
2001-02-08 16:24:05 +03:00
|
|
|
|
2001-12-17 15:16:14 +03:00
|
|
|
switch (sc->sc_wire) {
|
|
|
|
case UMASS_WPROTO_CBI:
|
|
|
|
sWire = "CBI";
|
2000-08-12 18:52:44 +04:00
|
|
|
break;
|
2001-12-17 15:16:14 +03:00
|
|
|
case UMASS_WPROTO_CBI_I:
|
|
|
|
sWire = "CBI with CCI";
|
2000-04-05 00:16:47 +04:00
|
|
|
break;
|
2001-12-17 15:16:14 +03:00
|
|
|
case UMASS_WPROTO_BBB:
|
|
|
|
sWire = "Bulk-Only";
|
2000-04-03 03:46:53 +04:00
|
|
|
break;
|
1999-09-12 06:40:59 +04:00
|
|
|
default:
|
2001-12-17 15:16:14 +03:00
|
|
|
sWire = "unknown";
|
2000-04-03 03:46:53 +04:00
|
|
|
break;
|
1999-09-12 06:40:59 +04:00
|
|
|
}
|
2001-12-17 15:16:14 +03:00
|
|
|
|
|
|
|
switch (sc->sc_cmd) {
|
|
|
|
case UMASS_CPROTO_RBC:
|
|
|
|
sCommand = "RBC";
|
2000-04-03 03:46:53 +04:00
|
|
|
break;
|
2001-12-17 15:16:14 +03:00
|
|
|
case UMASS_CPROTO_SCSI:
|
|
|
|
sCommand = "SCSI";
|
2000-04-03 03:46:53 +04:00
|
|
|
break;
|
2001-12-17 15:16:14 +03:00
|
|
|
case UMASS_CPROTO_UFI:
|
|
|
|
sCommand = "UFI";
|
|
|
|
break;
|
|
|
|
case UMASS_CPROTO_ATAPI:
|
|
|
|
sCommand = "ATAPI";
|
2000-04-05 00:16:47 +04:00
|
|
|
break;
|
2001-12-24 16:43:24 +03:00
|
|
|
case UMASS_CPROTO_ISD_ATA:
|
|
|
|
sCommand = "ISD-ATA";
|
|
|
|
break;
|
1999-09-12 06:40:59 +04:00
|
|
|
default:
|
2001-12-17 15:16:14 +03:00
|
|
|
sCommand = "unknown";
|
2000-04-05 00:16:47 +04:00
|
|
|
break;
|
1999-09-12 06:40:59 +04:00
|
|
|
}
|
2001-12-17 15:16:14 +03:00
|
|
|
|
|
|
|
printf("%s: using %s over %s\n", USBDEVNAME(sc->sc_dev), sCommand,
|
|
|
|
sWire);
|
1999-08-29 04:30:08 +04:00
|
|
|
|
2003-09-13 07:18:13 +04:00
|
|
|
if (quirk != NULL && quirk->uq_init != NULL) {
|
|
|
|
err = (*quirk->uq_init)(sc);
|
|
|
|
if (err) {
|
2003-09-30 00:04:25 +04:00
|
|
|
printf("%s: quirk init failed\n",
|
|
|
|
USBDEVNAME(sc->sc_dev));
|
2003-09-13 07:18:13 +04:00
|
|
|
umass_disco(sc);
|
|
|
|
USB_ATTACH_ERROR_RETURN;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-08-29 04:30:08 +04:00
|
|
|
/*
|
2000-04-03 03:46:53 +04:00
|
|
|
* In addition to the Control endpoint the following endpoints
|
|
|
|
* are required:
|
|
|
|
* a) bulk-in endpoint.
|
|
|
|
* b) bulk-out endpoint.
|
|
|
|
* and for Control/Bulk/Interrupt with CCI (CBI_I)
|
|
|
|
* c) intr-in
|
1999-08-29 04:30:08 +04:00
|
|
|
*
|
|
|
|
* The endpoint addresses are not fixed, so we have to read them
|
|
|
|
* from the device descriptors of the current interface.
|
|
|
|
*/
|
Introduce different autoconf interface attributes for USB drivers
matching (and handling) a whole device and those which match an
interface only. This will allow to enforce some rules, eg that
the former don't use interface information for matching or that the
latter don't modify global device state.
The previous way left too much freedom do the drivers which led to
inconsistencies and abuse.
For now, I've not changed locators and submatch rules, this will
happen later.
There should not be any change in behaviour, except in the case of
some drivers which did behave inconsistently:
if_atu, if_axe, uep: matched the configured device in the interface
stage, but did configuration again. I've converted them to match
in the device stage.
ustir, utoppy: matched in the interface stage, but only against
vendor/device information, and used any configuration/interface
without checking. Changed to match in device stage, and added
some simple code to configure and use the first interface.
If you have one of those devices, please test!
2007-03-13 16:51:53 +03:00
|
|
|
id = usbd_get_interface_descriptor(sc->sc_iface);
|
1999-08-29 04:30:08 +04:00
|
|
|
for (i = 0 ; i < id->bNumEndpoints ; i++) {
|
2001-12-14 11:58:49 +03:00
|
|
|
ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i);
|
2001-12-17 15:16:14 +03:00
|
|
|
if (ed == NULL) {
|
1999-08-29 04:30:08 +04:00
|
|
|
printf("%s: could not read endpoint descriptor\n",
|
|
|
|
USBDEVNAME(sc->sc_dev));
|
|
|
|
USB_ATTACH_ERROR_RETURN;
|
|
|
|
}
|
1999-09-05 02:26:11 +04:00
|
|
|
if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN
|
1999-08-29 04:30:08 +04:00
|
|
|
&& (ed->bmAttributes & UE_XFERTYPE) == UE_BULK) {
|
2001-12-14 08:58:13 +03:00
|
|
|
sc->sc_epaddr[UMASS_BULKIN] = ed->bEndpointAddress;
|
1999-09-05 02:26:11 +04:00
|
|
|
} else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT
|
1999-08-29 04:30:08 +04:00
|
|
|
&& (ed->bmAttributes & UE_XFERTYPE) == UE_BULK) {
|
2001-12-14 08:58:13 +03:00
|
|
|
sc->sc_epaddr[UMASS_BULKOUT] = ed->bEndpointAddress;
|
2001-12-17 15:16:14 +03:00
|
|
|
} else if (sc->sc_wire == UMASS_WPROTO_CBI_I
|
2000-04-03 03:46:53 +04:00
|
|
|
&& UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN
|
|
|
|
&& (ed->bmAttributes & UE_XFERTYPE) == UE_INTERRUPT) {
|
2001-12-14 08:58:13 +03:00
|
|
|
sc->sc_epaddr[UMASS_INTRIN] = ed->bEndpointAddress;
|
2000-04-03 03:46:53 +04:00
|
|
|
#ifdef UMASS_DEBUG
|
|
|
|
if (UGETW(ed->wMaxPacketSize) > 2) {
|
|
|
|
DPRINTF(UDMASS_CBI, ("%s: intr size is %d\n",
|
|
|
|
USBDEVNAME(sc->sc_dev),
|
|
|
|
UGETW(ed->wMaxPacketSize)));
|
|
|
|
}
|
|
|
|
#endif
|
1999-08-29 04:30:08 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-04-03 03:46:53 +04:00
|
|
|
/* check whether we found all the endpoints we need */
|
2001-12-14 08:58:13 +03:00
|
|
|
if (!sc->sc_epaddr[UMASS_BULKIN] || !sc->sc_epaddr[UMASS_BULKOUT] ||
|
2001-12-17 15:16:14 +03:00
|
|
|
(sc->sc_wire == UMASS_WPROTO_CBI_I &&
|
|
|
|
!sc->sc_epaddr[UMASS_INTRIN])) {
|
2003-09-30 00:04:25 +04:00
|
|
|
printf("%s: endpoint not found %u/%u/%u\n",
|
|
|
|
USBDEVNAME(sc->sc_dev), sc->sc_epaddr[UMASS_BULKIN],
|
|
|
|
sc->sc_epaddr[UMASS_BULKOUT],
|
|
|
|
sc->sc_epaddr[UMASS_INTRIN]);
|
2000-04-03 03:46:53 +04:00
|
|
|
USB_ATTACH_ERROR_RETURN;
|
|
|
|
}
|
|
|
|
|
1999-08-29 23:58:55 +04:00
|
|
|
/*
|
|
|
|
* Get the maximum LUN supported by the device.
|
|
|
|
*/
|
2003-09-08 23:30:59 +04:00
|
|
|
if (sc->sc_wire == UMASS_WPROTO_BBB) {
|
2000-04-03 03:46:53 +04:00
|
|
|
err = umass_bbb_get_max_lun(sc, &sc->maxlun);
|
|
|
|
if (err) {
|
|
|
|
printf("%s: unable to get Max Lun: %s\n",
|
|
|
|
USBDEVNAME(sc->sc_dev), usbd_errstr(err));
|
|
|
|
USB_ATTACH_ERROR_RETURN;
|
|
|
|
}
|
2003-09-08 23:57:29 +04:00
|
|
|
if (sc->maxlun > 0)
|
|
|
|
sc->sc_busquirks |= PQUIRK_FORCELUNS;
|
2000-04-03 03:46:53 +04:00
|
|
|
} else {
|
|
|
|
sc->maxlun = 0;
|
1999-08-29 23:58:55 +04:00
|
|
|
}
|
|
|
|
|
1999-08-29 04:30:08 +04:00
|
|
|
/* Open the bulk-in and -out pipe */
|
cc -pipe -ffreestanding -O2 -Werror -Wall -Wno-main -Wno-format-zero-length -Fix several problems with CCI handling, and enable it:
* We were never calling the callback function when we got a UFI CCI(!).
* We were passing a bogus residual count on non-UFI CCIs.
* After a REQUEST SENSE, the UFI CCI may include the ASC/ASCQ from the sense
information -- don't consider this a failure.
In addition, remove a horrible hack that was causing us to drop sense
information on the floor and return empty INQUIRY responses, often in the case
where there is a UNIT ATTENTION pending during the INQUIRY. (Some drives send
the data and then fail, some don't.)
This eliminates the need for quirks for the Y-E DATA FlashBuster.
These changes work on:
umass0: SAMSUNG SFD-321U [FW 0C], rev 1.10/2.10, addr 2
umass0: using UFI over CBI with CCI
sd0 at atapibus1 drive 0: <SMSC, USB FDC, 2.10> disk removable
umass0: TEAC TEAC FD-05PUB, rev 1.10/0.00, addr 2
umass0: using UFI over CBI with CCI
sd0 at atapibus0 drive 0: <TEAC, FD-05PUB, 1026> disk removable
umass0: Y-E DATA FlashBuster-U, rev 1.00/3.04, addr 2
umass0: using UFI over CBI with CCI
sd0 at atapibus0 drive 0: <Y-E DATA, USB-FDU, 3.04> disk removable
2003-09-10 06:49:18 +04:00
|
|
|
DPRINTF(UDMASS_USB, ("%s: opening iface %p epaddr %d for BULKOUT\n",
|
|
|
|
USBDEVNAME(sc->sc_dev), sc->sc_iface,
|
|
|
|
sc->sc_epaddr[UMASS_BULKOUT]));
|
2001-12-14 11:58:49 +03:00
|
|
|
err = usbd_open_pipe(sc->sc_iface, sc->sc_epaddr[UMASS_BULKOUT],
|
2001-12-14 08:58:13 +03:00
|
|
|
USBD_EXCLUSIVE_USE,
|
|
|
|
&sc->sc_pipe[UMASS_BULKOUT]);
|
1999-08-29 04:30:08 +04:00
|
|
|
if (err) {
|
2003-09-30 00:04:25 +04:00
|
|
|
printf("%s: cannot open %u-out pipe (bulk)\n",
|
|
|
|
USBDEVNAME(sc->sc_dev), sc->sc_epaddr[UMASS_BULKOUT]);
|
2000-04-03 03:46:53 +04:00
|
|
|
umass_disco(sc);
|
1999-08-29 04:30:08 +04:00
|
|
|
USB_ATTACH_ERROR_RETURN;
|
|
|
|
}
|
cc -pipe -ffreestanding -O2 -Werror -Wall -Wno-main -Wno-format-zero-length -Fix several problems with CCI handling, and enable it:
* We were never calling the callback function when we got a UFI CCI(!).
* We were passing a bogus residual count on non-UFI CCIs.
* After a REQUEST SENSE, the UFI CCI may include the ASC/ASCQ from the sense
information -- don't consider this a failure.
In addition, remove a horrible hack that was causing us to drop sense
information on the floor and return empty INQUIRY responses, often in the case
where there is a UNIT ATTENTION pending during the INQUIRY. (Some drives send
the data and then fail, some don't.)
This eliminates the need for quirks for the Y-E DATA FlashBuster.
These changes work on:
umass0: SAMSUNG SFD-321U [FW 0C], rev 1.10/2.10, addr 2
umass0: using UFI over CBI with CCI
sd0 at atapibus1 drive 0: <SMSC, USB FDC, 2.10> disk removable
umass0: TEAC TEAC FD-05PUB, rev 1.10/0.00, addr 2
umass0: using UFI over CBI with CCI
sd0 at atapibus0 drive 0: <TEAC, FD-05PUB, 1026> disk removable
umass0: Y-E DATA FlashBuster-U, rev 1.00/3.04, addr 2
umass0: using UFI over CBI with CCI
sd0 at atapibus0 drive 0: <Y-E DATA, USB-FDU, 3.04> disk removable
2003-09-10 06:49:18 +04:00
|
|
|
DPRINTF(UDMASS_USB, ("%s: opening iface %p epaddr %d for BULKIN\n",
|
|
|
|
USBDEVNAME(sc->sc_dev), sc->sc_iface,
|
|
|
|
sc->sc_epaddr[UMASS_BULKIN]));
|
2001-12-14 11:58:49 +03:00
|
|
|
err = usbd_open_pipe(sc->sc_iface, sc->sc_epaddr[UMASS_BULKIN],
|
2001-12-14 08:58:13 +03:00
|
|
|
USBD_EXCLUSIVE_USE, &sc->sc_pipe[UMASS_BULKIN]);
|
1999-08-29 04:30:08 +04:00
|
|
|
if (err) {
|
2003-09-30 00:04:25 +04:00
|
|
|
printf("%s: could not open %u-in pipe (bulk)\n",
|
|
|
|
USBDEVNAME(sc->sc_dev), sc->sc_epaddr[UMASS_BULKIN]);
|
2000-04-03 03:46:53 +04:00
|
|
|
umass_disco(sc);
|
1999-08-29 04:30:08 +04:00
|
|
|
USB_ATTACH_ERROR_RETURN;
|
|
|
|
}
|
2002-07-12 01:14:24 +04:00
|
|
|
/*
|
2000-04-03 03:46:53 +04:00
|
|
|
* Open the intr-in pipe if the protocol is CBI with CCI.
|
|
|
|
* Note: early versions of the Zip drive do have an interrupt pipe, but
|
|
|
|
* this pipe is unused
|
|
|
|
*
|
|
|
|
* We do not open the interrupt pipe as an interrupt pipe, but as a
|
|
|
|
* normal bulk endpoint. We send an IN transfer down the wire at the
|
|
|
|
* appropriate time, because we know exactly when to expect data on
|
|
|
|
* that endpoint. This saves bandwidth, but more important, makes the
|
|
|
|
* code for handling the data on that endpoint simpler. No data
|
|
|
|
* arriving concurrently.
|
|
|
|
*/
|
2001-12-17 15:16:14 +03:00
|
|
|
if (sc->sc_wire == UMASS_WPROTO_CBI_I) {
|
cc -pipe -ffreestanding -O2 -Werror -Wall -Wno-main -Wno-format-zero-length -Fix several problems with CCI handling, and enable it:
* We were never calling the callback function when we got a UFI CCI(!).
* We were passing a bogus residual count on non-UFI CCIs.
* After a REQUEST SENSE, the UFI CCI may include the ASC/ASCQ from the sense
information -- don't consider this a failure.
In addition, remove a horrible hack that was causing us to drop sense
information on the floor and return empty INQUIRY responses, often in the case
where there is a UNIT ATTENTION pending during the INQUIRY. (Some drives send
the data and then fail, some don't.)
This eliminates the need for quirks for the Y-E DATA FlashBuster.
These changes work on:
umass0: SAMSUNG SFD-321U [FW 0C], rev 1.10/2.10, addr 2
umass0: using UFI over CBI with CCI
sd0 at atapibus1 drive 0: <SMSC, USB FDC, 2.10> disk removable
umass0: TEAC TEAC FD-05PUB, rev 1.10/0.00, addr 2
umass0: using UFI over CBI with CCI
sd0 at atapibus0 drive 0: <TEAC, FD-05PUB, 1026> disk removable
umass0: Y-E DATA FlashBuster-U, rev 1.00/3.04, addr 2
umass0: using UFI over CBI with CCI
sd0 at atapibus0 drive 0: <Y-E DATA, USB-FDU, 3.04> disk removable
2003-09-10 06:49:18 +04:00
|
|
|
DPRINTF(UDMASS_USB, ("%s: opening iface %p epaddr %d for INTRIN\n",
|
|
|
|
USBDEVNAME(sc->sc_dev), sc->sc_iface,
|
|
|
|
sc->sc_epaddr[UMASS_INTRIN]));
|
2001-12-14 11:58:49 +03:00
|
|
|
err = usbd_open_pipe(sc->sc_iface, sc->sc_epaddr[UMASS_INTRIN],
|
2001-12-14 08:58:13 +03:00
|
|
|
USBD_EXCLUSIVE_USE, &sc->sc_pipe[UMASS_INTRIN]);
|
2000-04-03 03:46:53 +04:00
|
|
|
if (err) {
|
2003-09-30 00:04:25 +04:00
|
|
|
printf("%s: couldn't open %u-in (intr)\n",
|
|
|
|
USBDEVNAME(sc->sc_dev),
|
|
|
|
sc->sc_epaddr[UMASS_INTRIN]);
|
2000-04-03 03:46:53 +04:00
|
|
|
umass_disco(sc);
|
|
|
|
USB_ATTACH_ERROR_RETURN;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* initialisation of generic part */
|
|
|
|
sc->transfer_state = TSTATE_IDLE;
|
|
|
|
|
|
|
|
/* request a sufficient number of xfer handles */
|
|
|
|
for (i = 0; i < XFER_NR; i++) {
|
|
|
|
sc->transfer_xfer[i] = usbd_alloc_xfer(uaa->device);
|
2002-12-18 17:12:33 +03:00
|
|
|
if (sc->transfer_xfer[i] == NULL) {
|
2003-09-30 00:04:25 +04:00
|
|
|
printf("%s: Out of memory\n",
|
|
|
|
USBDEVNAME(sc->sc_dev));
|
2000-04-03 03:46:53 +04:00
|
|
|
umass_disco(sc);
|
|
|
|
USB_ATTACH_ERROR_RETURN;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* Allocate buffer for data transfer (it's huge). */
|
2001-12-17 15:16:14 +03:00
|
|
|
switch (sc->sc_wire) {
|
|
|
|
case UMASS_WPROTO_BBB:
|
2000-04-03 03:46:53 +04:00
|
|
|
bno = XFER_BBB_DATA;
|
|
|
|
goto dalloc;
|
2001-12-17 15:16:14 +03:00
|
|
|
case UMASS_WPROTO_CBI:
|
2000-04-03 03:46:53 +04:00
|
|
|
bno = XFER_CBI_DATA;
|
|
|
|
goto dalloc;
|
2001-12-17 15:16:14 +03:00
|
|
|
case UMASS_WPROTO_CBI_I:
|
2000-04-03 03:46:53 +04:00
|
|
|
bno = XFER_CBI_DATA;
|
|
|
|
dalloc:
|
2002-07-12 01:14:24 +04:00
|
|
|
sc->data_buffer = usbd_alloc_buffer(sc->transfer_xfer[bno],
|
2000-04-03 03:46:53 +04:00
|
|
|
UMASS_MAX_TRANSFER_SIZE);
|
|
|
|
if (sc->data_buffer == NULL) {
|
2003-09-30 00:04:25 +04:00
|
|
|
printf("%s: no buffer memory\n",
|
|
|
|
USBDEVNAME(sc->sc_dev));
|
2000-04-03 03:46:53 +04:00
|
|
|
umass_disco(sc);
|
|
|
|
USB_ATTACH_ERROR_RETURN;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Initialise the wire protocol specific methods */
|
2001-12-17 15:16:14 +03:00
|
|
|
switch (sc->sc_wire) {
|
|
|
|
case UMASS_WPROTO_BBB:
|
2001-12-14 11:46:19 +03:00
|
|
|
sc->sc_methods = &umass_bbb_methods;
|
2001-12-17 15:16:14 +03:00
|
|
|
break;
|
|
|
|
case UMASS_WPROTO_CBI:
|
|
|
|
case UMASS_WPROTO_CBI_I:
|
2001-12-14 11:46:19 +03:00
|
|
|
sc->sc_methods = &umass_cbi_methods;
|
2001-12-17 15:16:14 +03:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
umass_disco(sc);
|
|
|
|
USB_ATTACH_ERROR_RETURN;
|
2000-04-03 03:46:53 +04:00
|
|
|
}
|
|
|
|
|
2001-12-24 16:25:52 +03:00
|
|
|
error = 0;
|
|
|
|
switch (sc->sc_cmd) {
|
|
|
|
case UMASS_CPROTO_RBC:
|
|
|
|
case UMASS_CPROTO_SCSI:
|
|
|
|
#if NSCSIBUS > 0
|
|
|
|
error = umass_scsi_attach(sc);
|
|
|
|
#else
|
2003-04-26 16:46:59 +04:00
|
|
|
printf("%s: scsibus not configured\n", USBDEVNAME(sc->sc_dev));
|
2001-12-24 16:25:52 +03:00
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
|
|
|
|
case UMASS_CPROTO_UFI:
|
|
|
|
case UMASS_CPROTO_ATAPI:
|
|
|
|
#if NATAPIBUS > 0
|
|
|
|
error = umass_atapi_attach(sc);
|
|
|
|
#else
|
2003-04-26 16:46:59 +04:00
|
|
|
printf("%s: atapibus not configured\n",
|
|
|
|
USBDEVNAME(sc->sc_dev));
|
2001-12-24 16:25:52 +03:00
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
|
2001-12-24 16:43:24 +03:00
|
|
|
case UMASS_CPROTO_ISD_ATA:
|
|
|
|
#if NWD > 0
|
|
|
|
error = umass_isdata_attach(sc);
|
|
|
|
#else
|
|
|
|
printf("%s: isdata not configured\n", USBDEVNAME(sc->sc_dev));
|
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
|
2001-12-24 16:25:52 +03:00
|
|
|
default:
|
|
|
|
printf("%s: command protocol=0x%x not supported\n",
|
|
|
|
USBDEVNAME(sc->sc_dev), sc->sc_cmd);
|
2000-04-03 03:46:53 +04:00
|
|
|
umass_disco(sc);
|
1999-08-29 04:30:08 +04:00
|
|
|
USB_ATTACH_ERROR_RETURN;
|
|
|
|
}
|
2001-12-24 16:25:52 +03:00
|
|
|
if (error) {
|
|
|
|
printf("%s: bus attach failed\n", USBDEVNAME(sc->sc_dev));
|
|
|
|
umass_disco(sc);
|
|
|
|
USB_ATTACH_ERROR_RETURN;
|
|
|
|
}
|
|
|
|
|
|
|
|
usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
|
|
|
|
USBDEV(sc->sc_dev));
|
1999-08-29 04:30:08 +04:00
|
|
|
|
2007-12-09 23:27:42 +03:00
|
|
|
if (!pmf_device_register(self, NULL, NULL))
|
|
|
|
aprint_error_dev(self, "couldn't establish power handler\n");
|
|
|
|
|
2000-04-03 03:46:53 +04:00
|
|
|
DPRINTF(UDMASS_GEN, ("%s: Attach finished\n", USBDEVNAME(sc->sc_dev)));
|
|
|
|
|
1999-08-29 04:30:08 +04:00
|
|
|
USB_ATTACH_SUCCESS_RETURN;
|
|
|
|
}
|
|
|
|
|
1999-10-13 12:10:55 +04:00
|
|
|
USB_DETACH(umass)
|
1999-08-29 04:30:08 +04:00
|
|
|
{
|
1999-10-13 12:10:55 +04:00
|
|
|
USB_DETACH_START(umass, sc);
|
2003-09-30 00:04:25 +04:00
|
|
|
struct umassbus_softc *scbus;
|
2003-02-17 02:14:06 +03:00
|
|
|
int rv = 0, i, s;
|
1999-08-30 05:04:31 +04:00
|
|
|
|
2000-04-03 03:46:53 +04:00
|
|
|
DPRINTF(UDMASS_USB, ("%s: detached\n", USBDEVNAME(sc->sc_dev)));
|
1999-09-14 01:35:08 +04:00
|
|
|
|
2007-12-09 23:27:42 +03:00
|
|
|
pmf_device_deregister(self);
|
|
|
|
|
1999-09-14 01:35:08 +04:00
|
|
|
/* Abort the pipes to wake up any waiting processes. */
|
2001-12-14 08:58:13 +03:00
|
|
|
for (i = 0 ; i < UMASS_NEP ; i++) {
|
2004-12-29 02:35:21 +03:00
|
|
|
if (sc->sc_pipe[i] != NULL)
|
2001-12-14 08:58:13 +03:00
|
|
|
usbd_abort_pipe(sc->sc_pipe[i]);
|
|
|
|
}
|
1999-09-14 01:35:08 +04:00
|
|
|
|
2000-09-24 01:03:00 +04:00
|
|
|
/* Do we really need reference counting? Perhaps in ioctl() */
|
1999-09-14 01:35:08 +04:00
|
|
|
s = splusb();
|
|
|
|
if (--sc->sc_refcnt >= 0) {
|
2003-02-17 02:14:06 +03:00
|
|
|
#ifdef DIAGNOSTIC
|
|
|
|
printf("%s: waiting for refcnt\n", USBDEVNAME(sc->sc_dev));
|
|
|
|
#endif
|
1999-09-14 01:35:08 +04:00
|
|
|
/* Wait for processes to go away. */
|
|
|
|
usb_detach_wait(USBDEV(sc->sc_dev));
|
|
|
|
}
|
|
|
|
splx(s);
|
|
|
|
|
2003-09-30 00:04:25 +04:00
|
|
|
scbus = sc->bus;
|
2001-12-24 16:25:52 +03:00
|
|
|
if (scbus != NULL) {
|
|
|
|
if (scbus->sc_child != NULL)
|
|
|
|
rv = config_detach(scbus->sc_child, flags);
|
|
|
|
free(scbus, M_DEVBUF);
|
|
|
|
sc->bus = NULL;
|
|
|
|
}
|
2001-04-13 16:24:10 +04:00
|
|
|
|
2000-04-03 03:46:53 +04:00
|
|
|
if (rv != 0)
|
|
|
|
return (rv);
|
|
|
|
|
|
|
|
umass_disco(sc);
|
1999-08-29 04:30:08 +04:00
|
|
|
|
2000-02-02 16:18:45 +03:00
|
|
|
usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
|
|
|
|
USBDEV(sc->sc_dev));
|
|
|
|
|
2001-12-24 16:25:52 +03:00
|
|
|
return (rv);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
umass_activate(struct device *dev, enum devact act)
|
|
|
|
{
|
|
|
|
struct umass_softc *sc = (struct umass_softc *)dev;
|
|
|
|
struct umassbus_softc *scbus = sc->bus;
|
|
|
|
int rv = 0;
|
|
|
|
|
|
|
|
DPRINTF(UDMASS_USB, ("%s: umass_activate: %d\n",
|
|
|
|
USBDEVNAME(sc->sc_dev), act));
|
|
|
|
|
|
|
|
switch (act) {
|
|
|
|
case DVACT_ACTIVATE:
|
|
|
|
rv = EOPNOTSUPP;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DVACT_DEACTIVATE:
|
|
|
|
sc->sc_dying = 1;
|
2001-12-31 15:52:50 +03:00
|
|
|
if (scbus == NULL || scbus->sc_child == NULL)
|
2001-12-24 16:25:52 +03:00
|
|
|
break;
|
|
|
|
rv = config_deactivate(scbus->sc_child);
|
|
|
|
DPRINTF(UDMASS_USB, ("%s: umass_activate: child "
|
|
|
|
"returned %d\n", USBDEVNAME(sc->sc_dev), rv));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return (rv);
|
2000-04-03 03:46:53 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
Static void
|
2000-06-01 18:28:57 +04:00
|
|
|
umass_disco(struct umass_softc *sc)
|
2002-07-12 01:14:24 +04:00
|
|
|
{
|
2000-04-03 03:46:53 +04:00
|
|
|
int i;
|
|
|
|
|
|
|
|
DPRINTF(UDMASS_GEN, ("umass_disco\n"));
|
|
|
|
|
|
|
|
/* Free the xfers. */
|
|
|
|
for (i = 0; i < XFER_NR; i++)
|
|
|
|
if (sc->transfer_xfer[i] != NULL) {
|
|
|
|
usbd_free_xfer(sc->transfer_xfer[i]);
|
|
|
|
sc->transfer_xfer[i] = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Remove all the pipes. */
|
2001-12-14 08:58:13 +03:00
|
|
|
for (i = 0 ; i < UMASS_NEP ; i++) {
|
2003-01-01 18:55:48 +03:00
|
|
|
if (sc->sc_pipe[i] != NULL) {
|
2001-12-14 08:58:13 +03:00
|
|
|
usbd_close_pipe(sc->sc_pipe[i]);
|
2003-01-01 18:55:48 +03:00
|
|
|
sc->sc_pipe[i] = NULL;
|
|
|
|
}
|
2001-12-14 08:58:13 +03:00
|
|
|
}
|
2000-04-03 03:46:53 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Generic functions to handle transfers
|
1999-08-29 04:30:08 +04:00
|
|
|
*/
|
|
|
|
|
2000-04-03 03:46:53 +04:00
|
|
|
Static usbd_status
|
|
|
|
umass_setup_transfer(struct umass_softc *sc, usbd_pipe_handle pipe,
|
|
|
|
void *buffer, int buflen, int flags,
|
|
|
|
usbd_xfer_handle xfer)
|
1999-08-29 04:30:08 +04:00
|
|
|
{
|
|
|
|
usbd_status err;
|
|
|
|
|
2000-04-03 03:46:53 +04:00
|
|
|
if (sc->sc_dying)
|
|
|
|
return (USBD_IOERROR);
|
1999-08-29 04:30:08 +04:00
|
|
|
|
2000-04-03 03:46:53 +04:00
|
|
|
/* Initialiase a USB transfer and then schedule it */
|
1999-08-29 04:30:08 +04:00
|
|
|
|
2000-04-03 03:46:53 +04:00
|
|
|
usbd_setup_xfer(xfer, pipe, (void *)sc, buffer, buflen,
|
2001-12-14 11:46:19 +03:00
|
|
|
flags | sc->sc_xfer_flags, sc->timeout, sc->sc_methods->wire_state);
|
2000-04-03 03:46:53 +04:00
|
|
|
|
|
|
|
err = usbd_transfer(xfer);
|
|
|
|
DPRINTF(UDMASS_XFER,("%s: start xfer buffer=%p buflen=%d flags=0x%x "
|
|
|
|
"timeout=%d\n", USBDEVNAME(sc->sc_dev),
|
|
|
|
buffer, buflen, flags | sc->sc_xfer_flags, sc->timeout));
|
|
|
|
if (err && err != USBD_IN_PROGRESS) {
|
|
|
|
DPRINTF(UDMASS_BBB, ("%s: failed to setup transfer, %s\n",
|
1999-09-12 00:52:07 +04:00
|
|
|
USBDEVNAME(sc->sc_dev), usbd_errstr(err)));
|
2000-04-03 03:46:53 +04:00
|
|
|
return (err);
|
1999-08-29 04:30:08 +04:00
|
|
|
}
|
|
|
|
|
2000-04-03 03:46:53 +04:00
|
|
|
return (USBD_NORMAL_COMPLETION);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Static usbd_status
|
2001-12-14 09:21:56 +03:00
|
|
|
umass_setup_ctrl_transfer(struct umass_softc *sc, usb_device_request_t *req,
|
|
|
|
void *buffer, int buflen, int flags, usbd_xfer_handle xfer)
|
2000-04-03 03:46:53 +04:00
|
|
|
{
|
|
|
|
usbd_status err;
|
|
|
|
|
|
|
|
if (sc->sc_dying)
|
|
|
|
return (USBD_IOERROR);
|
|
|
|
|
|
|
|
/* Initialiase a USB control transfer and then schedule it */
|
|
|
|
|
2001-12-14 11:46:19 +03:00
|
|
|
usbd_setup_default_xfer(xfer, sc->sc_udev, (void *) sc, sc->timeout,
|
|
|
|
req, buffer, buflen, flags, sc->sc_methods->wire_state);
|
1999-08-29 04:30:08 +04:00
|
|
|
|
2000-04-03 03:46:53 +04:00
|
|
|
err = usbd_transfer(xfer);
|
|
|
|
if (err && err != USBD_IN_PROGRESS) {
|
|
|
|
DPRINTF(UDMASS_BBB, ("%s: failed to setup ctrl transfer, %s\n",
|
|
|
|
USBDEVNAME(sc->sc_dev), usbd_errstr(err)));
|
1999-08-29 04:30:08 +04:00
|
|
|
|
2000-04-03 03:46:53 +04:00
|
|
|
/* do not reset, as this would make us loop */
|
|
|
|
return (err);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (USBD_NORMAL_COMPLETION);
|
1999-08-29 04:30:08 +04:00
|
|
|
}
|
|
|
|
|
2000-04-03 03:46:53 +04:00
|
|
|
Static void
|
2001-12-14 08:58:13 +03:00
|
|
|
umass_clear_endpoint_stall(struct umass_softc *sc, int endpt,
|
|
|
|
usbd_xfer_handle xfer)
|
1999-08-29 23:58:55 +04:00
|
|
|
{
|
2000-04-03 03:46:53 +04:00
|
|
|
if (sc->sc_dying)
|
|
|
|
return;
|
1999-08-29 04:30:08 +04:00
|
|
|
|
2000-04-03 03:46:53 +04:00
|
|
|
DPRINTF(UDMASS_BBB, ("%s: Clear endpoint 0x%02x stall\n",
|
2001-12-31 18:54:27 +03:00
|
|
|
USBDEVNAME(sc->sc_dev), sc->sc_epaddr[endpt]));
|
1999-08-29 23:58:55 +04:00
|
|
|
|
2001-12-14 08:58:13 +03:00
|
|
|
usbd_clear_endpoint_toggle(sc->sc_pipe[endpt]);
|
1999-08-29 23:58:55 +04:00
|
|
|
|
2001-12-17 15:16:14 +03:00
|
|
|
sc->sc_req.bmRequestType = UT_WRITE_ENDPOINT;
|
|
|
|
sc->sc_req.bRequest = UR_CLEAR_FEATURE;
|
|
|
|
USETW(sc->sc_req.wValue, UF_ENDPOINT_HALT);
|
|
|
|
USETW(sc->sc_req.wIndex, sc->sc_epaddr[endpt]);
|
|
|
|
USETW(sc->sc_req.wLength, 0);
|
|
|
|
umass_setup_ctrl_transfer(sc, &sc->sc_req, NULL, 0, 0, xfer);
|
2000-04-03 03:46:53 +04:00
|
|
|
}
|
1999-09-12 00:52:07 +04:00
|
|
|
|
2000-04-03 07:56:49 +04:00
|
|
|
#if 0
|
2000-04-03 03:46:53 +04:00
|
|
|
Static void
|
|
|
|
umass_reset(struct umass_softc *sc, transfer_cb_f cb, void *priv)
|
|
|
|
{
|
|
|
|
sc->transfer_cb = cb;
|
|
|
|
sc->transfer_priv = priv;
|
1999-08-29 23:58:55 +04:00
|
|
|
|
2000-04-03 03:46:53 +04:00
|
|
|
/* The reset is a forced reset, so no error (yet) */
|
|
|
|
sc->reset(sc, STATUS_CMD_OK);
|
1999-08-29 23:58:55 +04:00
|
|
|
}
|
2000-04-03 07:56:49 +04:00
|
|
|
#endif
|
1999-08-29 04:30:08 +04:00
|
|
|
|
2000-04-03 03:46:53 +04:00
|
|
|
/*
|
|
|
|
* Bulk protocol specific functions
|
|
|
|
*/
|
|
|
|
|
|
|
|
Static void
|
|
|
|
umass_bbb_reset(struct umass_softc *sc, int status)
|
1999-08-29 04:30:08 +04:00
|
|
|
{
|
2001-12-17 15:16:14 +03:00
|
|
|
KASSERT(sc->sc_wire & UMASS_WPROTO_BBB,
|
|
|
|
("sc->sc_wire == 0x%02x wrong for umass_bbb_reset\n",
|
|
|
|
sc->sc_wire));
|
2000-04-03 03:46:53 +04:00
|
|
|
|
|
|
|
if (sc->sc_dying)
|
|
|
|
return;
|
1999-08-29 04:30:08 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Reset recovery (5.3.4 in Universal Serial Bus Mass Storage Class)
|
|
|
|
*
|
|
|
|
* For Reset Recovery the host shall issue in the following order:
|
|
|
|
* a) a Bulk-Only Mass Storage Reset
|
|
|
|
* b) a Clear Feature HALT to the Bulk-In endpoint
|
|
|
|
* c) a Clear Feature HALT to the Bulk-Out endpoint
|
2000-04-03 03:46:53 +04:00
|
|
|
*
|
|
|
|
* This is done in 3 steps, states:
|
|
|
|
* TSTATE_BBB_RESET1
|
|
|
|
* TSTATE_BBB_RESET2
|
|
|
|
* TSTATE_BBB_RESET3
|
|
|
|
*
|
|
|
|
* If the reset doesn't succeed, the device should be port reset.
|
1999-08-29 04:30:08 +04:00
|
|
|
*/
|
|
|
|
|
2000-04-03 03:46:53 +04:00
|
|
|
DPRINTF(UDMASS_BBB, ("%s: Bulk Reset\n",
|
1999-08-29 04:30:08 +04:00
|
|
|
USBDEVNAME(sc->sc_dev)));
|
2002-07-12 01:14:24 +04:00
|
|
|
|
2000-04-03 03:46:53 +04:00
|
|
|
sc->transfer_state = TSTATE_BBB_RESET1;
|
|
|
|
sc->transfer_status = status;
|
|
|
|
|
|
|
|
/* reset is a class specific interface write */
|
2001-12-17 15:16:14 +03:00
|
|
|
sc->sc_req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
|
|
|
|
sc->sc_req.bRequest = UR_BBB_RESET;
|
|
|
|
USETW(sc->sc_req.wValue, 0);
|
|
|
|
USETW(sc->sc_req.wIndex, sc->sc_ifaceno);
|
|
|
|
USETW(sc->sc_req.wLength, 0);
|
|
|
|
umass_setup_ctrl_transfer(sc, &sc->sc_req, NULL, 0, 0,
|
2000-04-03 03:46:53 +04:00
|
|
|
sc->transfer_xfer[XFER_BBB_RESET1]);
|
|
|
|
}
|
1999-08-29 04:30:08 +04:00
|
|
|
|
2000-04-03 03:46:53 +04:00
|
|
|
Static void
|
|
|
|
umass_bbb_transfer(struct umass_softc *sc, int lun, void *cmd, int cmdlen,
|
2001-11-25 22:05:22 +03:00
|
|
|
void *data, int datalen, int dir, u_int timeout,
|
2001-12-14 11:46:19 +03:00
|
|
|
umass_callback cb, void *priv)
|
2000-04-03 03:46:53 +04:00
|
|
|
{
|
|
|
|
static int dCBWtag = 42; /* unique for CBW of transfer */
|
1999-08-29 04:30:08 +04:00
|
|
|
|
2000-04-03 03:46:53 +04:00
|
|
|
DPRINTF(UDMASS_BBB,("%s: umass_bbb_transfer cmd=0x%02x\n",
|
2002-03-17 21:02:52 +03:00
|
|
|
USBDEVNAME(sc->sc_dev), *(u_char *)cmd));
|
1999-08-29 04:30:08 +04:00
|
|
|
|
2001-12-17 15:16:14 +03:00
|
|
|
KASSERT(sc->sc_wire & UMASS_WPROTO_BBB,
|
|
|
|
("sc->sc_wire == 0x%02x wrong for umass_bbb_transfer\n",
|
|
|
|
sc->sc_wire));
|
1999-08-29 04:30:08 +04:00
|
|
|
|
2004-06-30 09:53:46 +04:00
|
|
|
if (sc->sc_dying)
|
|
|
|
return;
|
|
|
|
|
2001-11-25 22:05:22 +03:00
|
|
|
/* Be a little generous. */
|
|
|
|
sc->timeout = timeout + USBD_DEFAULT_TIMEOUT;
|
|
|
|
|
1999-08-29 04:30:08 +04:00
|
|
|
/*
|
2000-04-03 03:46:53 +04:00
|
|
|
* Do a Bulk-Only transfer with cmdlen bytes from cmd, possibly
|
|
|
|
* a data phase of datalen bytes from/to the device and finally a
|
|
|
|
* csw read phase.
|
|
|
|
* If the data direction was inbound a maximum of datalen bytes
|
|
|
|
* is stored in the buffer pointed to by data.
|
|
|
|
*
|
|
|
|
* umass_bbb_transfer initialises the transfer and lets the state
|
2002-07-12 01:14:24 +04:00
|
|
|
* machine in umass_bbb_state handle the completion. It uses the
|
2000-04-03 03:46:53 +04:00
|
|
|
* following states:
|
|
|
|
* TSTATE_BBB_COMMAND
|
|
|
|
* -> TSTATE_BBB_DATA
|
|
|
|
* -> TSTATE_BBB_STATUS
|
|
|
|
* -> TSTATE_BBB_STATUS2
|
|
|
|
* -> TSTATE_BBB_IDLE
|
|
|
|
*
|
|
|
|
* An error in any of those states will invoke
|
|
|
|
* umass_bbb_reset.
|
1999-08-29 04:30:08 +04:00
|
|
|
*/
|
|
|
|
|
|
|
|
/* check the given arguments */
|
2000-04-03 03:46:53 +04:00
|
|
|
KASSERT(datalen == 0 || data != NULL,
|
|
|
|
("%s: datalen > 0, but no buffer",USBDEVNAME(sc->sc_dev)));
|
|
|
|
KASSERT(cmdlen <= CBWCDBLENGTH,
|
|
|
|
("%s: cmdlen exceeds CDB length in CBW (%d > %d)",
|
|
|
|
USBDEVNAME(sc->sc_dev), cmdlen, CBWCDBLENGTH));
|
|
|
|
KASSERT(dir == DIR_NONE || datalen > 0,
|
|
|
|
("%s: datalen == 0 while direction is not NONE\n",
|
1999-08-29 04:30:08 +04:00
|
|
|
USBDEVNAME(sc->sc_dev)));
|
2000-04-03 03:46:53 +04:00
|
|
|
KASSERT(datalen == 0 || dir != DIR_NONE,
|
|
|
|
("%s: direction is NONE while datalen is not zero\n",
|
|
|
|
USBDEVNAME(sc->sc_dev)));
|
|
|
|
KASSERT(sizeof(umass_bbb_cbw_t) == UMASS_BBB_CBW_SIZE,
|
|
|
|
("%s: CBW struct does not have the right size (%d vs. %d)\n",
|
|
|
|
USBDEVNAME(sc->sc_dev),
|
|
|
|
sizeof(umass_bbb_cbw_t), UMASS_BBB_CBW_SIZE));
|
|
|
|
KASSERT(sizeof(umass_bbb_csw_t) == UMASS_BBB_CSW_SIZE,
|
|
|
|
("%s: CSW struct does not have the right size (%d vs. %d)\n",
|
|
|
|
USBDEVNAME(sc->sc_dev),
|
|
|
|
sizeof(umass_bbb_csw_t), UMASS_BBB_CSW_SIZE));
|
1999-08-29 04:30:08 +04:00
|
|
|
|
|
|
|
/*
|
2000-04-03 03:46:53 +04:00
|
|
|
* Determine the direction of the data transfer and the length.
|
1999-08-29 04:30:08 +04:00
|
|
|
*
|
|
|
|
* dCBWDataTransferLength (datalen) :
|
|
|
|
* This field indicates the number of bytes of data that the host
|
|
|
|
* intends to transfer on the IN or OUT Bulk endpoint(as indicated by
|
|
|
|
* the Direction bit) during the execution of this command. If this
|
|
|
|
* field is set to 0, the device will expect that no data will be
|
|
|
|
* transferred IN or OUT during this command, regardless of the value
|
|
|
|
* of the Direction bit defined in dCBWFlags.
|
|
|
|
*
|
|
|
|
* dCBWFlags (dir) :
|
|
|
|
* The bits of the Flags field are defined as follows:
|
2000-04-03 03:46:53 +04:00
|
|
|
* Bits 0-6 reserved
|
|
|
|
* Bit 7 Direction - this bit shall be ignored if the
|
|
|
|
* dCBWDataTransferLength field is zero.
|
|
|
|
* 0 = data Out from host to device
|
|
|
|
* 1 = data In from device to host
|
1999-08-29 04:30:08 +04:00
|
|
|
*/
|
|
|
|
|
|
|
|
/* Fill in the Command Block Wrapper */
|
2000-04-03 03:46:53 +04:00
|
|
|
USETDW(sc->cbw.dCBWSignature, CBWSIGNATURE);
|
|
|
|
USETDW(sc->cbw.dCBWTag, dCBWtag);
|
|
|
|
dCBWtag++; /* cannot be done in macro (it will be done 4 times) */
|
|
|
|
USETDW(sc->cbw.dCBWDataTransferLength, datalen);
|
|
|
|
/* DIR_NONE is treated as DIR_OUT (0x00) */
|
|
|
|
sc->cbw.bCBWFlags = (dir == DIR_IN? CBWFLAGS_IN:CBWFLAGS_OUT);
|
|
|
|
sc->cbw.bCBWLUN = lun;
|
|
|
|
sc->cbw.bCDBLength = cmdlen;
|
2001-12-12 16:17:03 +03:00
|
|
|
memcpy(sc->cbw.CBWCDB, cmd, cmdlen);
|
2000-04-03 03:46:53 +04:00
|
|
|
|
|
|
|
DIF(UDMASS_BBB, umass_bbb_dump_cbw(sc, &sc->cbw));
|
|
|
|
|
|
|
|
/* store the details for the data transfer phase */
|
|
|
|
sc->transfer_dir = dir;
|
|
|
|
sc->transfer_data = data;
|
|
|
|
sc->transfer_datalen = datalen;
|
|
|
|
sc->transfer_actlen = 0;
|
|
|
|
sc->transfer_cb = cb;
|
|
|
|
sc->transfer_priv = priv;
|
|
|
|
sc->transfer_status = STATUS_CMD_OK;
|
|
|
|
|
|
|
|
/* move from idle to the command state */
|
|
|
|
sc->transfer_state = TSTATE_BBB_COMMAND;
|
1999-08-29 04:30:08 +04:00
|
|
|
|
|
|
|
/* Send the CBW from host to device via bulk-out endpoint. */
|
2001-12-14 08:58:13 +03:00
|
|
|
if (umass_setup_transfer(sc, sc->sc_pipe[UMASS_BULKOUT],
|
2000-04-03 03:46:53 +04:00
|
|
|
&sc->cbw, UMASS_BBB_CBW_SIZE, 0,
|
|
|
|
sc->transfer_xfer[XFER_BBB_CBW])) {
|
|
|
|
umass_bbb_reset(sc, STATUS_WIRE_FAILED);
|
1999-08-29 04:30:08 +04:00
|
|
|
}
|
2000-04-03 03:46:53 +04:00
|
|
|
}
|
1999-08-29 04:30:08 +04:00
|
|
|
|
|
|
|
|
2000-04-03 03:46:53 +04:00
|
|
|
Static void
|
|
|
|
umass_bbb_state(usbd_xfer_handle xfer, usbd_private_handle priv,
|
|
|
|
usbd_status err)
|
|
|
|
{
|
|
|
|
struct umass_softc *sc = (struct umass_softc *) priv;
|
|
|
|
usbd_xfer_handle next_xfer;
|
1999-08-29 04:30:08 +04:00
|
|
|
|
2001-12-17 15:16:14 +03:00
|
|
|
KASSERT(sc->sc_wire & UMASS_WPROTO_BBB,
|
|
|
|
("sc->sc_wire == 0x%02x wrong for umass_bbb_state\n",
|
|
|
|
sc->sc_wire));
|
1999-08-29 04:30:08 +04:00
|
|
|
|
2000-04-03 03:46:53 +04:00
|
|
|
if (sc->sc_dying)
|
|
|
|
return;
|
1999-08-29 04:30:08 +04:00
|
|
|
|
|
|
|
/*
|
2000-04-03 03:46:53 +04:00
|
|
|
* State handling for BBB transfers.
|
|
|
|
*
|
|
|
|
* The subroutine is rather long. It steps through the states given in
|
|
|
|
* Annex A of the Bulk-Only specification.
|
|
|
|
* Each state first does the error handling of the previous transfer
|
|
|
|
* and then prepares the next transfer.
|
|
|
|
* Each transfer is done asynchroneously so after the request/transfer
|
|
|
|
* has been submitted you will find a 'return;'.
|
1999-08-29 04:30:08 +04:00
|
|
|
*/
|
|
|
|
|
2000-04-03 03:46:53 +04:00
|
|
|
DPRINTF(UDMASS_BBB, ("%s: Handling BBB state %d (%s), xfer=%p, %s\n",
|
|
|
|
USBDEVNAME(sc->sc_dev), sc->transfer_state,
|
|
|
|
states[sc->transfer_state], xfer, usbd_errstr(err)));
|
1999-08-29 04:30:08 +04:00
|
|
|
|
2000-04-03 03:46:53 +04:00
|
|
|
switch (sc->transfer_state) {
|
1999-08-29 04:30:08 +04:00
|
|
|
|
2000-04-03 03:46:53 +04:00
|
|
|
/***** Bulk Transfer *****/
|
|
|
|
case TSTATE_BBB_COMMAND:
|
|
|
|
/* Command transport phase, error handling */
|
1999-08-29 04:30:08 +04:00
|
|
|
if (err) {
|
2000-04-03 03:46:53 +04:00
|
|
|
DPRINTF(UDMASS_BBB, ("%s: failed to send CBW\n",
|
|
|
|
USBDEVNAME(sc->sc_dev)));
|
|
|
|
/* If the device detects that the CBW is invalid, then
|
|
|
|
* the device may STALL both bulk endpoints and require
|
|
|
|
* a Bulk-Reset
|
|
|
|
*/
|
|
|
|
umass_bbb_reset(sc, STATUS_WIRE_FAILED);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Data transport phase, setup transfer */
|
|
|
|
sc->transfer_state = TSTATE_BBB_DATA;
|
|
|
|
if (sc->transfer_dir == DIR_IN) {
|
2001-12-14 08:58:13 +03:00
|
|
|
if (umass_setup_transfer(sc, sc->sc_pipe[UMASS_BULKIN],
|
2000-04-03 03:46:53 +04:00
|
|
|
sc->data_buffer, sc->transfer_datalen,
|
|
|
|
USBD_SHORT_XFER_OK | USBD_NO_COPY,
|
|
|
|
sc->transfer_xfer[XFER_BBB_DATA]))
|
|
|
|
umass_bbb_reset(sc, STATUS_WIRE_FAILED);
|
|
|
|
|
|
|
|
return;
|
|
|
|
} else if (sc->transfer_dir == DIR_OUT) {
|
2002-07-12 01:14:24 +04:00
|
|
|
memcpy(sc->data_buffer, sc->transfer_data,
|
2000-04-03 03:46:53 +04:00
|
|
|
sc->transfer_datalen);
|
2001-12-14 08:58:13 +03:00
|
|
|
if (umass_setup_transfer(sc, sc->sc_pipe[UMASS_BULKOUT],
|
2000-04-03 03:46:53 +04:00
|
|
|
sc->data_buffer, sc->transfer_datalen,
|
|
|
|
USBD_NO_COPY,/* fixed length transfer */
|
|
|
|
sc->transfer_xfer[XFER_BBB_DATA]))
|
|
|
|
umass_bbb_reset(sc, STATUS_WIRE_FAILED);
|
|
|
|
|
|
|
|
return;
|
1999-08-29 04:30:08 +04:00
|
|
|
} else {
|
2000-04-03 03:46:53 +04:00
|
|
|
DPRINTF(UDMASS_BBB, ("%s: no data phase\n",
|
|
|
|
USBDEVNAME(sc->sc_dev)));
|
1999-08-29 04:30:08 +04:00
|
|
|
}
|
|
|
|
|
2000-04-03 03:46:53 +04:00
|
|
|
/* FALLTHROUGH if no data phase, err == 0 */
|
|
|
|
case TSTATE_BBB_DATA:
|
2003-09-10 10:38:28 +04:00
|
|
|
/* Command transport phase error handling (ignored if no data
|
2000-04-03 03:46:53 +04:00
|
|
|
* phase (fallthrough from previous state)) */
|
|
|
|
if (sc->transfer_dir != DIR_NONE) {
|
|
|
|
/* retrieve the length of the transfer that was done */
|
|
|
|
usbd_get_xfer_status(xfer, NULL, NULL,
|
2003-09-10 10:38:28 +04:00
|
|
|
&sc->transfer_actlen, NULL);
|
|
|
|
DPRINTF(UDMASS_BBB, ("%s: BBB_DATA actlen=%d\n",
|
|
|
|
USBDEVNAME(sc->sc_dev), sc->transfer_actlen));
|
2000-04-03 03:46:53 +04:00
|
|
|
|
|
|
|
if (err) {
|
2001-11-13 11:01:40 +03:00
|
|
|
DPRINTF(UDMASS_BBB, ("%s: Data-%s %d failed, "
|
2000-04-03 03:46:53 +04:00
|
|
|
"%s\n", USBDEVNAME(sc->sc_dev),
|
|
|
|
(sc->transfer_dir == DIR_IN?"in":"out"),
|
|
|
|
sc->transfer_datalen,usbd_errstr(err)));
|
|
|
|
|
|
|
|
if (err == USBD_STALLED) {
|
2001-12-12 16:23:20 +03:00
|
|
|
sc->transfer_state = TSTATE_BBB_DCLEAR;
|
2000-04-03 03:46:53 +04:00
|
|
|
umass_clear_endpoint_stall(sc,
|
|
|
|
(sc->transfer_dir == DIR_IN?
|
2001-12-14 08:58:13 +03:00
|
|
|
UMASS_BULKIN:UMASS_BULKOUT),
|
2000-04-03 03:46:53 +04:00
|
|
|
sc->transfer_xfer[XFER_BBB_DCLEAR]);
|
|
|
|
} else {
|
|
|
|
/* Unless the error is a pipe stall the
|
|
|
|
* error is fatal.
|
|
|
|
*/
|
|
|
|
umass_bbb_reset(sc,STATUS_WIRE_FAILED);
|
|
|
|
}
|
2003-09-10 10:38:28 +04:00
|
|
|
return;
|
2000-04-03 03:46:53 +04:00
|
|
|
}
|
|
|
|
}
|
1999-08-29 04:30:08 +04:00
|
|
|
|
2003-09-10 09:20:21 +04:00
|
|
|
/* FALLTHROUGH, err == 0 (no data phase or successful) */
|
|
|
|
case TSTATE_BBB_DCLEAR: /* stall clear after data phase */
|
2000-04-03 03:46:53 +04:00
|
|
|
if (sc->transfer_dir == DIR_IN)
|
|
|
|
memcpy(sc->transfer_data, sc->data_buffer,
|
|
|
|
sc->transfer_actlen);
|
|
|
|
|
|
|
|
DIF(UDMASS_BBB, if (sc->transfer_dir == DIR_IN)
|
|
|
|
umass_dump_buffer(sc, sc->transfer_data,
|
|
|
|
sc->transfer_datalen, 48));
|
|
|
|
|
2003-01-06 15:46:05 +03:00
|
|
|
/* FALLTHROUGH, err == 0 (no data phase or successful) */
|
2000-04-03 03:46:53 +04:00
|
|
|
case TSTATE_BBB_SCLEAR: /* stall clear after status phase */
|
|
|
|
/* Reading of CSW after bulk stall condition in data phase
|
|
|
|
* (TSTATE_BBB_DATA2) or bulk-in stall condition after
|
|
|
|
* reading CSW (TSTATE_BBB_SCLEAR).
|
2003-01-06 15:46:05 +03:00
|
|
|
* In the case of no data phase or successful data phase,
|
2000-04-03 03:46:53 +04:00
|
|
|
* err == 0 and the following if block is passed.
|
|
|
|
*/
|
|
|
|
if (err) { /* should not occur */
|
2003-09-10 10:38:28 +04:00
|
|
|
printf("%s: BBB bulk-%s stall clear failed, %s\n",
|
|
|
|
USBDEVNAME(sc->sc_dev),
|
|
|
|
(sc->transfer_dir == DIR_IN? "in":"out"),
|
|
|
|
usbd_errstr(err));
|
2000-04-03 03:46:53 +04:00
|
|
|
umass_bbb_reset(sc, STATUS_WIRE_FAILED);
|
|
|
|
return;
|
|
|
|
}
|
2002-07-12 01:14:24 +04:00
|
|
|
|
2000-04-03 03:46:53 +04:00
|
|
|
/* Status transport phase, setup transfer */
|
|
|
|
if (sc->transfer_state == TSTATE_BBB_COMMAND ||
|
|
|
|
sc->transfer_state == TSTATE_BBB_DATA ||
|
|
|
|
sc->transfer_state == TSTATE_BBB_DCLEAR) {
|
2003-01-06 15:46:05 +03:00
|
|
|
/* After no data phase, successful data phase and
|
2000-04-03 03:46:53 +04:00
|
|
|
* after clearing bulk-in/-out stall condition
|
|
|
|
*/
|
|
|
|
sc->transfer_state = TSTATE_BBB_STATUS1;
|
|
|
|
next_xfer = sc->transfer_xfer[XFER_BBB_CSW1];
|
|
|
|
} else {
|
|
|
|
/* After first attempt of fetching CSW */
|
|
|
|
sc->transfer_state = TSTATE_BBB_STATUS2;
|
|
|
|
next_xfer = sc->transfer_xfer[XFER_BBB_CSW2];
|
|
|
|
}
|
1999-08-29 04:30:08 +04:00
|
|
|
|
2000-04-03 03:46:53 +04:00
|
|
|
/* Read the Command Status Wrapper via bulk-in endpoint. */
|
2001-12-14 08:58:13 +03:00
|
|
|
if (umass_setup_transfer(sc, sc->sc_pipe[UMASS_BULKIN],
|
|
|
|
&sc->csw, UMASS_BBB_CSW_SIZE, 0, next_xfer)) {
|
2000-04-03 03:46:53 +04:00
|
|
|
umass_bbb_reset(sc, STATUS_WIRE_FAILED);
|
|
|
|
return;
|
|
|
|
}
|
1999-08-29 04:30:08 +04:00
|
|
|
|
2000-04-03 03:46:53 +04:00
|
|
|
return;
|
|
|
|
case TSTATE_BBB_STATUS1: /* first attempt */
|
|
|
|
case TSTATE_BBB_STATUS2: /* second attempt */
|
|
|
|
/* Status transfer, error handling */
|
|
|
|
if (err) {
|
|
|
|
DPRINTF(UDMASS_BBB, ("%s: Failed to read CSW, %s%s\n",
|
|
|
|
USBDEVNAME(sc->sc_dev), usbd_errstr(err),
|
|
|
|
(sc->transfer_state == TSTATE_BBB_STATUS1?
|
|
|
|
", retrying":"")));
|
|
|
|
|
|
|
|
/* If this was the first attempt at fetching the CSW
|
|
|
|
* retry it, otherwise fail.
|
|
|
|
*/
|
|
|
|
if (sc->transfer_state == TSTATE_BBB_STATUS1) {
|
2001-12-12 16:23:20 +03:00
|
|
|
sc->transfer_state = TSTATE_BBB_SCLEAR;
|
2001-12-14 08:58:13 +03:00
|
|
|
umass_clear_endpoint_stall(sc, UMASS_BULKIN,
|
2001-11-23 04:15:28 +03:00
|
|
|
sc->transfer_xfer[XFER_BBB_SCLEAR]);
|
2000-04-03 03:46:53 +04:00
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
umass_bbb_reset(sc, STATUS_WIRE_FAILED);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
1999-08-29 04:30:08 +04:00
|
|
|
|
2000-04-03 03:46:53 +04:00
|
|
|
DIF(UDMASS_BBB, umass_bbb_dump_csw(sc, &sc->csw));
|
1999-08-29 04:30:08 +04:00
|
|
|
|
2001-11-25 22:15:46 +03:00
|
|
|
/* Translate weird command-status signatures. */
|
2001-12-17 15:16:14 +03:00
|
|
|
if ((sc->sc_quirks & UMASS_QUIRK_WRONG_CSWSIG) &&
|
2001-11-25 22:15:46 +03:00
|
|
|
UGETDW(sc->csw.dCSWSignature) == CSWSIGNATURE_OLYMPUS_C1)
|
|
|
|
USETDW(sc->csw.dCSWSignature, CSWSIGNATURE);
|
|
|
|
|
2002-12-06 06:57:51 +03:00
|
|
|
/* Translate invalid command-status tags */
|
|
|
|
if (sc->sc_quirks & UMASS_QUIRK_WRONG_CSWTAG)
|
|
|
|
USETDW(sc->csw.dCSWTag, UGETDW(sc->cbw.dCBWTag));
|
|
|
|
|
2000-04-03 03:46:53 +04:00
|
|
|
/* Check CSW and handle any error */
|
|
|
|
if (UGETDW(sc->csw.dCSWSignature) != CSWSIGNATURE) {
|
|
|
|
/* Invalid CSW: Wrong signature or wrong tag might
|
|
|
|
* indicate that the device is confused -> reset it.
|
|
|
|
*/
|
|
|
|
printf("%s: Invalid CSW: sig 0x%08x should be 0x%08x\n",
|
|
|
|
USBDEVNAME(sc->sc_dev),
|
|
|
|
UGETDW(sc->csw.dCSWSignature),
|
|
|
|
CSWSIGNATURE);
|
|
|
|
|
|
|
|
umass_bbb_reset(sc, STATUS_WIRE_FAILED);
|
|
|
|
return;
|
|
|
|
} else if (UGETDW(sc->csw.dCSWTag)
|
|
|
|
!= UGETDW(sc->cbw.dCBWTag)) {
|
|
|
|
printf("%s: Invalid CSW: tag %d should be %d\n",
|
|
|
|
USBDEVNAME(sc->sc_dev),
|
|
|
|
UGETDW(sc->csw.dCSWTag),
|
|
|
|
UGETDW(sc->cbw.dCBWTag));
|
1999-08-29 04:30:08 +04:00
|
|
|
|
2000-04-03 03:46:53 +04:00
|
|
|
umass_bbb_reset(sc, STATUS_WIRE_FAILED);
|
|
|
|
return;
|
1999-08-29 04:30:08 +04:00
|
|
|
|
2000-04-03 03:46:53 +04:00
|
|
|
/* CSW is valid here */
|
|
|
|
} else if (sc->csw.bCSWStatus > CSWSTATUS_PHASE) {
|
|
|
|
printf("%s: Invalid CSW: status %d > %d\n",
|
|
|
|
USBDEVNAME(sc->sc_dev),
|
|
|
|
sc->csw.bCSWStatus,
|
|
|
|
CSWSTATUS_PHASE);
|
1999-09-12 00:52:07 +04:00
|
|
|
|
2000-04-03 03:46:53 +04:00
|
|
|
umass_bbb_reset(sc, STATUS_WIRE_FAILED);
|
|
|
|
return;
|
|
|
|
} else if (sc->csw.bCSWStatus == CSWSTATUS_PHASE) {
|
|
|
|
printf("%s: Phase Error, residue = %d\n",
|
|
|
|
USBDEVNAME(sc->sc_dev),
|
|
|
|
UGETDW(sc->csw.dCSWDataResidue));
|
2002-07-12 01:14:24 +04:00
|
|
|
|
2000-04-03 03:46:53 +04:00
|
|
|
umass_bbb_reset(sc, STATUS_WIRE_FAILED);
|
|
|
|
return;
|
|
|
|
|
|
|
|
} else if (sc->transfer_actlen > sc->transfer_datalen) {
|
|
|
|
/* Buffer overrun! Don't let this go by unnoticed */
|
2002-09-27 19:35:29 +04:00
|
|
|
panic("%s: transferred %d bytes instead of %d bytes",
|
2000-04-03 03:46:53 +04:00
|
|
|
USBDEVNAME(sc->sc_dev),
|
|
|
|
sc->transfer_actlen, sc->transfer_datalen);
|
2001-06-04 10:01:40 +04:00
|
|
|
#if 0
|
2000-04-03 03:46:53 +04:00
|
|
|
} else if (sc->transfer_datalen - sc->transfer_actlen
|
|
|
|
!= UGETDW(sc->csw.dCSWDataResidue)) {
|
|
|
|
DPRINTF(UDMASS_BBB, ("%s: actlen=%d != residue=%d\n",
|
|
|
|
USBDEVNAME(sc->sc_dev),
|
|
|
|
sc->transfer_datalen - sc->transfer_actlen,
|
|
|
|
UGETDW(sc->csw.dCSWDataResidue)));
|
1999-08-29 04:30:08 +04:00
|
|
|
|
2000-04-03 03:46:53 +04:00
|
|
|
umass_bbb_reset(sc, STATUS_WIRE_FAILED);
|
|
|
|
return;
|
2001-06-04 10:01:40 +04:00
|
|
|
#endif
|
2000-04-03 03:46:53 +04:00
|
|
|
} else if (sc->csw.bCSWStatus == CSWSTATUS_FAILED) {
|
|
|
|
DPRINTF(UDMASS_BBB, ("%s: Command Failed, res = %d\n",
|
|
|
|
USBDEVNAME(sc->sc_dev),
|
|
|
|
UGETDW(sc->csw.dCSWDataResidue)));
|
1999-09-14 01:35:08 +04:00
|
|
|
|
2000-04-03 03:46:53 +04:00
|
|
|
/* SCSI command failed but transfer was succesful */
|
|
|
|
sc->transfer_state = TSTATE_IDLE;
|
|
|
|
sc->transfer_cb(sc, sc->transfer_priv,
|
|
|
|
UGETDW(sc->csw.dCSWDataResidue),
|
|
|
|
STATUS_CMD_FAILED);
|
1999-08-29 04:30:08 +04:00
|
|
|
|
2000-04-03 03:46:53 +04:00
|
|
|
return;
|
1999-09-12 00:52:07 +04:00
|
|
|
|
2000-04-03 03:46:53 +04:00
|
|
|
} else { /* success */
|
|
|
|
sc->transfer_state = TSTATE_IDLE;
|
|
|
|
sc->transfer_cb(sc, sc->transfer_priv,
|
|
|
|
UGETDW(sc->csw.dCSWDataResidue),
|
|
|
|
STATUS_CMD_OK);
|
1999-08-29 04:30:08 +04:00
|
|
|
|
2000-04-03 03:46:53 +04:00
|
|
|
return;
|
|
|
|
}
|
1999-08-29 04:30:08 +04:00
|
|
|
|
2000-04-03 03:46:53 +04:00
|
|
|
/***** Bulk Reset *****/
|
|
|
|
case TSTATE_BBB_RESET1:
|
|
|
|
if (err)
|
|
|
|
printf("%s: BBB reset failed, %s\n",
|
|
|
|
USBDEVNAME(sc->sc_dev), usbd_errstr(err));
|
1999-08-29 04:30:08 +04:00
|
|
|
|
2001-12-12 16:23:20 +03:00
|
|
|
sc->transfer_state = TSTATE_BBB_RESET2;
|
2001-12-14 08:58:13 +03:00
|
|
|
umass_clear_endpoint_stall(sc, UMASS_BULKIN,
|
2000-04-03 03:46:53 +04:00
|
|
|
sc->transfer_xfer[XFER_BBB_RESET2]);
|
1999-09-14 01:35:08 +04:00
|
|
|
|
2000-04-03 03:46:53 +04:00
|
|
|
return;
|
|
|
|
case TSTATE_BBB_RESET2:
|
|
|
|
if (err) /* should not occur */
|
|
|
|
printf("%s: BBB bulk-in clear stall failed, %s\n",
|
|
|
|
USBDEVNAME(sc->sc_dev), usbd_errstr(err));
|
|
|
|
/* no error recovery, otherwise we end up in a loop */
|
1999-08-29 04:30:08 +04:00
|
|
|
|
2001-12-12 16:23:20 +03:00
|
|
|
sc->transfer_state = TSTATE_BBB_RESET3;
|
2001-12-14 08:58:13 +03:00
|
|
|
umass_clear_endpoint_stall(sc, UMASS_BULKOUT,
|
2000-04-03 03:46:53 +04:00
|
|
|
sc->transfer_xfer[XFER_BBB_RESET3]);
|
1999-08-29 04:30:08 +04:00
|
|
|
|
2000-04-03 03:46:53 +04:00
|
|
|
return;
|
|
|
|
case TSTATE_BBB_RESET3:
|
|
|
|
if (err) /* should not occur */
|
|
|
|
printf("%s: BBB bulk-out clear stall failed, %s\n",
|
|
|
|
USBDEVNAME(sc->sc_dev), usbd_errstr(err));
|
|
|
|
/* no error recovery, otherwise we end up in a loop */
|
|
|
|
|
|
|
|
sc->transfer_state = TSTATE_IDLE;
|
|
|
|
if (sc->transfer_priv) {
|
|
|
|
sc->transfer_cb(sc, sc->transfer_priv,
|
|
|
|
sc->transfer_datalen,
|
|
|
|
sc->transfer_status);
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
/***** Default *****/
|
|
|
|
default:
|
2002-09-27 19:35:29 +04:00
|
|
|
panic("%s: Unknown state %d",
|
2000-04-03 03:46:53 +04:00
|
|
|
USBDEVNAME(sc->sc_dev), sc->transfer_state);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Command/Bulk/Interrupt (CBI) specific functions
|
|
|
|
*/
|
|
|
|
|
|
|
|
Static int
|
|
|
|
umass_cbi_adsc(struct umass_softc *sc, char *buffer, int buflen,
|
|
|
|
usbd_xfer_handle xfer)
|
|
|
|
{
|
2001-12-17 15:16:14 +03:00
|
|
|
KASSERT(sc->sc_wire & (UMASS_WPROTO_CBI|UMASS_WPROTO_CBI_I),
|
|
|
|
("sc->sc_wire == 0x%02x wrong for umass_cbi_adsc\n",
|
|
|
|
sc->sc_wire));
|
|
|
|
|
2007-01-09 19:46:02 +03:00
|
|
|
if ((sc->sc_cmd == UMASS_CPROTO_RBC) &&
|
|
|
|
(sc->sc_quirks & UMASS_QUIRK_RBC_PAD_TO_12) != 0 && buflen < 12) {
|
|
|
|
(void)memset(buffer + buflen, 0, 12 - buflen);
|
|
|
|
buflen = 12;
|
|
|
|
}
|
|
|
|
|
2001-12-17 15:16:14 +03:00
|
|
|
sc->sc_req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
|
|
|
|
sc->sc_req.bRequest = UR_CBI_ADSC;
|
|
|
|
USETW(sc->sc_req.wValue, 0);
|
|
|
|
USETW(sc->sc_req.wIndex, sc->sc_ifaceno);
|
|
|
|
USETW(sc->sc_req.wLength, buflen);
|
|
|
|
return umass_setup_ctrl_transfer(sc, &sc->sc_req, buffer,
|
2000-04-03 03:46:53 +04:00
|
|
|
buflen, 0, xfer);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Static void
|
|
|
|
umass_cbi_reset(struct umass_softc *sc, int status)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
# define SEND_DIAGNOSTIC_CMDLEN 12
|
|
|
|
|
2001-12-17 15:16:14 +03:00
|
|
|
KASSERT(sc->sc_wire & (UMASS_WPROTO_CBI|UMASS_WPROTO_CBI_I),
|
|
|
|
("sc->sc_wire == 0x%02x wrong for umass_cbi_reset\n",
|
|
|
|
sc->sc_wire));
|
2000-04-03 03:46:53 +04:00
|
|
|
|
|
|
|
if (sc->sc_dying)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Command Block Reset Protocol
|
2002-07-12 01:14:24 +04:00
|
|
|
*
|
2000-04-03 03:46:53 +04:00
|
|
|
* First send a reset request to the device. Then clear
|
|
|
|
* any possibly stalled bulk endpoints.
|
|
|
|
|
|
|
|
* This is done in 3 steps, states:
|
|
|
|
* TSTATE_CBI_RESET1
|
|
|
|
* TSTATE_CBI_RESET2
|
|
|
|
* TSTATE_CBI_RESET3
|
|
|
|
*
|
|
|
|
* If the reset doesn't succeed, the device should be port reset.
|
|
|
|
*/
|
|
|
|
|
|
|
|
DPRINTF(UDMASS_CBI, ("%s: CBI Reset\n",
|
|
|
|
USBDEVNAME(sc->sc_dev)));
|
2002-07-12 01:14:24 +04:00
|
|
|
|
2000-04-03 03:46:53 +04:00
|
|
|
KASSERT(sizeof(sc->cbl) >= SEND_DIAGNOSTIC_CMDLEN,
|
|
|
|
("%s: CBL struct is too small (%d < %d)\n",
|
|
|
|
USBDEVNAME(sc->sc_dev),
|
|
|
|
sizeof(sc->cbl), SEND_DIAGNOSTIC_CMDLEN));
|
|
|
|
|
|
|
|
sc->transfer_state = TSTATE_CBI_RESET1;
|
|
|
|
sc->transfer_status = status;
|
|
|
|
|
|
|
|
/* The 0x1d code is the SEND DIAGNOSTIC command. To distingiush between
|
|
|
|
* the two the last 10 bytes of the cbl is filled with 0xff (section
|
|
|
|
* 2.2 of the CBI spec).
|
|
|
|
*/
|
|
|
|
sc->cbl[0] = 0x1d; /* Command Block Reset */
|
|
|
|
sc->cbl[1] = 0x04;
|
|
|
|
for (i = 2; i < SEND_DIAGNOSTIC_CMDLEN; i++)
|
|
|
|
sc->cbl[i] = 0xff;
|
|
|
|
|
|
|
|
umass_cbi_adsc(sc, sc->cbl, SEND_DIAGNOSTIC_CMDLEN,
|
|
|
|
sc->transfer_xfer[XFER_CBI_RESET1]);
|
|
|
|
/* XXX if the command fails we should reset the port on the bub */
|
|
|
|
}
|
|
|
|
|
|
|
|
Static void
|
2006-11-16 04:32:37 +03:00
|
|
|
umass_cbi_transfer(struct umass_softc *sc, int lun,
|
2001-11-25 22:05:22 +03:00
|
|
|
void *cmd, int cmdlen, void *data, int datalen, int dir,
|
2001-12-14 11:46:19 +03:00
|
|
|
u_int timeout, umass_callback cb, void *priv)
|
2000-04-03 03:46:53 +04:00
|
|
|
{
|
|
|
|
DPRINTF(UDMASS_CBI,("%s: umass_cbi_transfer cmd=0x%02x, len=%d\n",
|
2002-03-17 21:02:52 +03:00
|
|
|
USBDEVNAME(sc->sc_dev), *(u_char *)cmd, datalen));
|
2000-04-03 03:46:53 +04:00
|
|
|
|
2001-12-17 15:16:14 +03:00
|
|
|
KASSERT(sc->sc_wire & (UMASS_WPROTO_CBI|UMASS_WPROTO_CBI_I),
|
|
|
|
("sc->sc_wire == 0x%02x wrong for umass_cbi_transfer\n",
|
|
|
|
sc->sc_wire));
|
2000-04-03 03:46:53 +04:00
|
|
|
|
|
|
|
if (sc->sc_dying)
|
|
|
|
return;
|
|
|
|
|
2001-11-25 22:05:22 +03:00
|
|
|
/* Be a little generous. */
|
|
|
|
sc->timeout = timeout + USBD_DEFAULT_TIMEOUT;
|
|
|
|
|
2000-04-03 03:46:53 +04:00
|
|
|
/*
|
|
|
|
* Do a CBI transfer with cmdlen bytes from cmd, possibly
|
|
|
|
* a data phase of datalen bytes from/to the device and finally a
|
|
|
|
* csw read phase.
|
|
|
|
* If the data direction was inbound a maximum of datalen bytes
|
|
|
|
* is stored in the buffer pointed to by data.
|
|
|
|
*
|
|
|
|
* umass_cbi_transfer initialises the transfer and lets the state
|
2002-07-12 01:14:24 +04:00
|
|
|
* machine in umass_cbi_state handle the completion. It uses the
|
2000-04-03 03:46:53 +04:00
|
|
|
* following states:
|
|
|
|
* TSTATE_CBI_COMMAND
|
|
|
|
* -> XXX fill in
|
|
|
|
*
|
|
|
|
* An error in any of those states will invoke
|
|
|
|
* umass_cbi_reset.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* check the given arguments */
|
|
|
|
KASSERT(datalen == 0 || data != NULL,
|
|
|
|
("%s: datalen > 0, but no buffer",USBDEVNAME(sc->sc_dev)));
|
|
|
|
KASSERT(datalen == 0 || dir != DIR_NONE,
|
|
|
|
("%s: direction is NONE while datalen is not zero\n",
|
|
|
|
USBDEVNAME(sc->sc_dev)));
|
|
|
|
|
|
|
|
/* store the details for the data transfer phase */
|
|
|
|
sc->transfer_dir = dir;
|
|
|
|
sc->transfer_data = data;
|
|
|
|
sc->transfer_datalen = datalen;
|
|
|
|
sc->transfer_actlen = 0;
|
|
|
|
sc->transfer_cb = cb;
|
|
|
|
sc->transfer_priv = priv;
|
|
|
|
sc->transfer_status = STATUS_CMD_OK;
|
|
|
|
|
|
|
|
/* move from idle to the command state */
|
|
|
|
sc->transfer_state = TSTATE_CBI_COMMAND;
|
|
|
|
|
|
|
|
/* Send the Command Block from host to device via control endpoint. */
|
|
|
|
if (umass_cbi_adsc(sc, cmd, cmdlen, sc->transfer_xfer[XFER_CBI_CB]))
|
|
|
|
umass_cbi_reset(sc, STATUS_WIRE_FAILED);
|
|
|
|
}
|
|
|
|
|
|
|
|
Static void
|
|
|
|
umass_cbi_state(usbd_xfer_handle xfer, usbd_private_handle priv,
|
|
|
|
usbd_status err)
|
|
|
|
{
|
|
|
|
struct umass_softc *sc = (struct umass_softc *) priv;
|
|
|
|
|
2001-12-17 15:16:14 +03:00
|
|
|
KASSERT(sc->sc_wire & (UMASS_WPROTO_CBI|UMASS_WPROTO_CBI_I),
|
|
|
|
("sc->sc_wire == 0x%02x wrong for umass_cbi_state\n",
|
|
|
|
sc->sc_wire));
|
2000-04-03 03:46:53 +04:00
|
|
|
|
|
|
|
if (sc->sc_dying)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* State handling for CBI transfers.
|
|
|
|
*/
|
|
|
|
|
|
|
|
DPRINTF(UDMASS_CBI, ("%s: Handling CBI state %d (%s), xfer=%p, %s\n",
|
|
|
|
USBDEVNAME(sc->sc_dev), sc->transfer_state,
|
|
|
|
states[sc->transfer_state], xfer, usbd_errstr(err)));
|
|
|
|
|
|
|
|
switch (sc->transfer_state) {
|
|
|
|
|
|
|
|
/***** CBI Transfer *****/
|
|
|
|
case TSTATE_CBI_COMMAND:
|
|
|
|
if (err == USBD_STALLED) {
|
|
|
|
DPRINTF(UDMASS_CBI, ("%s: Command Transport failed\n",
|
|
|
|
USBDEVNAME(sc->sc_dev)));
|
|
|
|
/* Status transport by control pipe (section 2.3.2.1).
|
|
|
|
* The command contained in the command block failed.
|
|
|
|
*
|
|
|
|
* The control pipe has already been unstalled by the
|
|
|
|
* USB stack.
|
|
|
|
* Section 2.4.3.1.1 states that the bulk in endpoints
|
|
|
|
* should not stalled at this point.
|
|
|
|
*/
|
|
|
|
|
|
|
|
sc->transfer_state = TSTATE_IDLE;
|
|
|
|
sc->transfer_cb(sc, sc->transfer_priv,
|
|
|
|
sc->transfer_datalen,
|
|
|
|
STATUS_CMD_FAILED);
|
|
|
|
|
|
|
|
return;
|
|
|
|
} else if (err) {
|
|
|
|
DPRINTF(UDMASS_CBI, ("%s: failed to send ADSC\n",
|
|
|
|
USBDEVNAME(sc->sc_dev)));
|
|
|
|
umass_cbi_reset(sc, STATUS_WIRE_FAILED);
|
|
|
|
return;
|
|
|
|
}
|
2002-07-12 01:14:24 +04:00
|
|
|
|
2003-09-10 10:38:28 +04:00
|
|
|
/* Data transport phase, setup transfer */
|
2000-04-03 03:46:53 +04:00
|
|
|
sc->transfer_state = TSTATE_CBI_DATA;
|
|
|
|
if (sc->transfer_dir == DIR_IN) {
|
2001-12-14 08:58:13 +03:00
|
|
|
if (umass_setup_transfer(sc, sc->sc_pipe[UMASS_BULKIN],
|
2004-06-25 18:14:34 +04:00
|
|
|
sc->data_buffer, sc->transfer_datalen,
|
2000-04-03 03:46:53 +04:00
|
|
|
USBD_SHORT_XFER_OK | USBD_NO_COPY,
|
|
|
|
sc->transfer_xfer[XFER_CBI_DATA]))
|
|
|
|
umass_cbi_reset(sc, STATUS_WIRE_FAILED);
|
|
|
|
|
2003-09-10 10:38:28 +04:00
|
|
|
return;
|
2000-04-03 03:46:53 +04:00
|
|
|
} else if (sc->transfer_dir == DIR_OUT) {
|
2002-07-12 01:14:24 +04:00
|
|
|
memcpy(sc->data_buffer, sc->transfer_data,
|
2000-04-03 03:46:53 +04:00
|
|
|
sc->transfer_datalen);
|
2001-12-14 08:58:13 +03:00
|
|
|
if (umass_setup_transfer(sc, sc->sc_pipe[UMASS_BULKOUT],
|
2004-06-25 18:14:34 +04:00
|
|
|
sc->data_buffer, sc->transfer_datalen,
|
2000-04-03 03:46:53 +04:00
|
|
|
USBD_NO_COPY,/* fixed length transfer */
|
|
|
|
sc->transfer_xfer[XFER_CBI_DATA]))
|
|
|
|
umass_cbi_reset(sc, STATUS_WIRE_FAILED);
|
|
|
|
|
2003-09-10 10:38:28 +04:00
|
|
|
return;
|
2000-04-03 03:46:53 +04:00
|
|
|
} else {
|
|
|
|
DPRINTF(UDMASS_CBI, ("%s: no data phase\n",
|
|
|
|
USBDEVNAME(sc->sc_dev)));
|
|
|
|
}
|
|
|
|
|
2003-09-10 10:38:28 +04:00
|
|
|
/* FALLTHROUGH if no data phase, err == 0 */
|
2000-04-03 03:46:53 +04:00
|
|
|
case TSTATE_CBI_DATA:
|
2003-09-10 10:38:28 +04:00
|
|
|
/* Command transport phase error handling (ignored if no data
|
|
|
|
* phase (fallthrough from previous state)) */
|
|
|
|
if (sc->transfer_dir != DIR_NONE) {
|
|
|
|
/* retrieve the length of the transfer that was done */
|
|
|
|
usbd_get_xfer_status(xfer, NULL, NULL,
|
|
|
|
&sc->transfer_actlen, NULL);
|
|
|
|
DPRINTF(UDMASS_CBI, ("%s: CBI_DATA actlen=%d\n",
|
|
|
|
USBDEVNAME(sc->sc_dev), sc->transfer_actlen));
|
2000-04-03 03:46:53 +04:00
|
|
|
|
2003-09-10 10:38:28 +04:00
|
|
|
if (err) {
|
|
|
|
DPRINTF(UDMASS_CBI, ("%s: Data-%s %d failed, "
|
|
|
|
"%s\n", USBDEVNAME(sc->sc_dev),
|
|
|
|
(sc->transfer_dir == DIR_IN?"in":"out"),
|
|
|
|
sc->transfer_datalen,usbd_errstr(err)));
|
2000-04-03 03:46:53 +04:00
|
|
|
|
2003-09-10 10:38:28 +04:00
|
|
|
if (err == USBD_STALLED) {
|
|
|
|
sc->transfer_state = TSTATE_CBI_DCLEAR;
|
|
|
|
umass_clear_endpoint_stall(sc,
|
|
|
|
(sc->transfer_dir == DIR_IN?
|
|
|
|
UMASS_BULKIN:UMASS_BULKOUT),
|
2000-04-03 03:46:53 +04:00
|
|
|
sc->transfer_xfer[XFER_CBI_DCLEAR]);
|
2003-09-10 10:38:28 +04:00
|
|
|
} else {
|
|
|
|
/* Unless the error is a pipe stall the
|
|
|
|
* error is fatal.
|
|
|
|
*/
|
|
|
|
umass_cbi_reset(sc, STATUS_WIRE_FAILED);
|
|
|
|
}
|
|
|
|
return;
|
2000-04-03 03:46:53 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sc->transfer_dir == DIR_IN)
|
|
|
|
memcpy(sc->transfer_data, sc->data_buffer,
|
|
|
|
sc->transfer_actlen);
|
|
|
|
|
|
|
|
DIF(UDMASS_CBI, if (sc->transfer_dir == DIR_IN)
|
|
|
|
umass_dump_buffer(sc, sc->transfer_data,
|
|
|
|
sc->transfer_actlen, 48));
|
|
|
|
|
2003-09-10 10:38:28 +04:00
|
|
|
/* Status phase */
|
2001-12-17 15:16:14 +03:00
|
|
|
if (sc->sc_wire == UMASS_WPROTO_CBI_I) {
|
2000-04-03 03:46:53 +04:00
|
|
|
sc->transfer_state = TSTATE_CBI_STATUS;
|
|
|
|
memset(&sc->sbl, 0, sizeof(sc->sbl));
|
2001-12-14 08:58:13 +03:00
|
|
|
if (umass_setup_transfer(sc, sc->sc_pipe[UMASS_INTRIN],
|
2000-04-03 03:46:53 +04:00
|
|
|
&sc->sbl, sizeof(sc->sbl),
|
|
|
|
0, /* fixed length transfer */
|
cc -pipe -ffreestanding -O2 -Werror -Wall -Wno-main -Wno-format-zero-length -Fix several problems with CCI handling, and enable it:
* We were never calling the callback function when we got a UFI CCI(!).
* We were passing a bogus residual count on non-UFI CCIs.
* After a REQUEST SENSE, the UFI CCI may include the ASC/ASCQ from the sense
information -- don't consider this a failure.
In addition, remove a horrible hack that was causing us to drop sense
information on the floor and return empty INQUIRY responses, often in the case
where there is a UNIT ATTENTION pending during the INQUIRY. (Some drives send
the data and then fail, some don't.)
This eliminates the need for quirks for the Y-E DATA FlashBuster.
These changes work on:
umass0: SAMSUNG SFD-321U [FW 0C], rev 1.10/2.10, addr 2
umass0: using UFI over CBI with CCI
sd0 at atapibus1 drive 0: <SMSC, USB FDC, 2.10> disk removable
umass0: TEAC TEAC FD-05PUB, rev 1.10/0.00, addr 2
umass0: using UFI over CBI with CCI
sd0 at atapibus0 drive 0: <TEAC, FD-05PUB, 1026> disk removable
umass0: Y-E DATA FlashBuster-U, rev 1.00/3.04, addr 2
umass0: using UFI over CBI with CCI
sd0 at atapibus0 drive 0: <Y-E DATA, USB-FDU, 3.04> disk removable
2003-09-10 06:49:18 +04:00
|
|
|
sc->transfer_xfer[XFER_CBI_STATUS]))
|
2000-04-03 03:46:53 +04:00
|
|
|
umass_cbi_reset(sc, STATUS_WIRE_FAILED);
|
|
|
|
} else {
|
|
|
|
/* No command completion interrupt. Request
|
|
|
|
* sense to get status of command.
|
|
|
|
*/
|
|
|
|
sc->transfer_state = TSTATE_IDLE;
|
|
|
|
sc->transfer_cb(sc, sc->transfer_priv,
|
|
|
|
sc->transfer_datalen - sc->transfer_actlen,
|
|
|
|
STATUS_CMD_UNKNOWN);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
|
|
|
|
case TSTATE_CBI_STATUS:
|
|
|
|
if (err) {
|
|
|
|
DPRINTF(UDMASS_CBI, ("%s: Status Transport failed\n",
|
|
|
|
USBDEVNAME(sc->sc_dev)));
|
|
|
|
/* Status transport by interrupt pipe (section 2.3.2.2).
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (err == USBD_STALLED) {
|
2001-12-12 16:23:20 +03:00
|
|
|
sc->transfer_state = TSTATE_CBI_SCLEAR;
|
2001-12-14 08:58:13 +03:00
|
|
|
umass_clear_endpoint_stall(sc, UMASS_INTRIN,
|
2000-04-03 03:46:53 +04:00
|
|
|
sc->transfer_xfer[XFER_CBI_SCLEAR]);
|
|
|
|
} else {
|
|
|
|
umass_cbi_reset(sc, STATUS_WIRE_FAILED);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Dissect the information in the buffer */
|
|
|
|
|
cc -pipe -ffreestanding -O2 -Werror -Wall -Wno-main -Wno-format-zero-length -Fix several problems with CCI handling, and enable it:
* We were never calling the callback function when we got a UFI CCI(!).
* We were passing a bogus residual count on non-UFI CCIs.
* After a REQUEST SENSE, the UFI CCI may include the ASC/ASCQ from the sense
information -- don't consider this a failure.
In addition, remove a horrible hack that was causing us to drop sense
information on the floor and return empty INQUIRY responses, often in the case
where there is a UNIT ATTENTION pending during the INQUIRY. (Some drives send
the data and then fail, some don't.)
This eliminates the need for quirks for the Y-E DATA FlashBuster.
These changes work on:
umass0: SAMSUNG SFD-321U [FW 0C], rev 1.10/2.10, addr 2
umass0: using UFI over CBI with CCI
sd0 at atapibus1 drive 0: <SMSC, USB FDC, 2.10> disk removable
umass0: TEAC TEAC FD-05PUB, rev 1.10/0.00, addr 2
umass0: using UFI over CBI with CCI
sd0 at atapibus0 drive 0: <TEAC, FD-05PUB, 1026> disk removable
umass0: Y-E DATA FlashBuster-U, rev 1.00/3.04, addr 2
umass0: using UFI over CBI with CCI
sd0 at atapibus0 drive 0: <Y-E DATA, USB-FDU, 3.04> disk removable
2003-09-10 06:49:18 +04:00
|
|
|
{
|
|
|
|
u_int32_t actlen;
|
|
|
|
usbd_get_xfer_status(xfer,NULL,NULL,&actlen,NULL);
|
|
|
|
DPRINTF(UDMASS_CBI, ("%s: CBI_STATUS actlen=%d\n",
|
|
|
|
USBDEVNAME(sc->sc_dev), actlen));
|
|
|
|
if (actlen != 2)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2001-12-17 15:16:14 +03:00
|
|
|
if (sc->sc_cmd == UMASS_CPROTO_UFI) {
|
2000-04-03 03:46:53 +04:00
|
|
|
int status;
|
2002-07-12 01:14:24 +04:00
|
|
|
|
2000-04-03 03:46:53 +04:00
|
|
|
/* Section 3.4.3.1.3 specifies that the UFI command
|
|
|
|
* protocol returns an ASC and ASCQ in the interrupt
|
|
|
|
* data block.
|
|
|
|
*/
|
|
|
|
|
|
|
|
DPRINTF(UDMASS_CBI, ("%s: UFI CCI, ASC = 0x%02x, "
|
|
|
|
"ASCQ = 0x%02x\n",
|
|
|
|
USBDEVNAME(sc->sc_dev),
|
|
|
|
sc->sbl.ufi.asc, sc->sbl.ufi.ascq));
|
|
|
|
|
cc -pipe -ffreestanding -O2 -Werror -Wall -Wno-main -Wno-format-zero-length -Fix several problems with CCI handling, and enable it:
* We were never calling the callback function when we got a UFI CCI(!).
* We were passing a bogus residual count on non-UFI CCIs.
* After a REQUEST SENSE, the UFI CCI may include the ASC/ASCQ from the sense
information -- don't consider this a failure.
In addition, remove a horrible hack that was causing us to drop sense
information on the floor and return empty INQUIRY responses, often in the case
where there is a UNIT ATTENTION pending during the INQUIRY. (Some drives send
the data and then fail, some don't.)
This eliminates the need for quirks for the Y-E DATA FlashBuster.
These changes work on:
umass0: SAMSUNG SFD-321U [FW 0C], rev 1.10/2.10, addr 2
umass0: using UFI over CBI with CCI
sd0 at atapibus1 drive 0: <SMSC, USB FDC, 2.10> disk removable
umass0: TEAC TEAC FD-05PUB, rev 1.10/0.00, addr 2
umass0: using UFI over CBI with CCI
sd0 at atapibus0 drive 0: <TEAC, FD-05PUB, 1026> disk removable
umass0: Y-E DATA FlashBuster-U, rev 1.00/3.04, addr 2
umass0: using UFI over CBI with CCI
sd0 at atapibus0 drive 0: <Y-E DATA, USB-FDU, 3.04> disk removable
2003-09-10 06:49:18 +04:00
|
|
|
if ((sc->sbl.ufi.asc == 0 && sc->sbl.ufi.ascq == 0) ||
|
|
|
|
sc->sc_sense)
|
2000-04-03 03:46:53 +04:00
|
|
|
status = STATUS_CMD_OK;
|
|
|
|
else
|
|
|
|
status = STATUS_CMD_FAILED;
|
|
|
|
|
cc -pipe -ffreestanding -O2 -Werror -Wall -Wno-main -Wno-format-zero-length -Fix several problems with CCI handling, and enable it:
* We were never calling the callback function when we got a UFI CCI(!).
* We were passing a bogus residual count on non-UFI CCIs.
* After a REQUEST SENSE, the UFI CCI may include the ASC/ASCQ from the sense
information -- don't consider this a failure.
In addition, remove a horrible hack that was causing us to drop sense
information on the floor and return empty INQUIRY responses, often in the case
where there is a UNIT ATTENTION pending during the INQUIRY. (Some drives send
the data and then fail, some don't.)
This eliminates the need for quirks for the Y-E DATA FlashBuster.
These changes work on:
umass0: SAMSUNG SFD-321U [FW 0C], rev 1.10/2.10, addr 2
umass0: using UFI over CBI with CCI
sd0 at atapibus1 drive 0: <SMSC, USB FDC, 2.10> disk removable
umass0: TEAC TEAC FD-05PUB, rev 1.10/0.00, addr 2
umass0: using UFI over CBI with CCI
sd0 at atapibus0 drive 0: <TEAC, FD-05PUB, 1026> disk removable
umass0: Y-E DATA FlashBuster-U, rev 1.00/3.04, addr 2
umass0: using UFI over CBI with CCI
sd0 at atapibus0 drive 0: <Y-E DATA, USB-FDU, 3.04> disk removable
2003-09-10 06:49:18 +04:00
|
|
|
/* No autosense, command successful */
|
|
|
|
sc->transfer_state = TSTATE_IDLE;
|
|
|
|
sc->transfer_cb(sc, sc->transfer_priv,
|
|
|
|
sc->transfer_datalen - sc->transfer_actlen, status);
|
2000-04-03 03:46:53 +04:00
|
|
|
} else {
|
cc -pipe -ffreestanding -O2 -Werror -Wall -Wno-main -Wno-format-zero-length -Fix several problems with CCI handling, and enable it:
* We were never calling the callback function when we got a UFI CCI(!).
* We were passing a bogus residual count on non-UFI CCIs.
* After a REQUEST SENSE, the UFI CCI may include the ASC/ASCQ from the sense
information -- don't consider this a failure.
In addition, remove a horrible hack that was causing us to drop sense
information on the floor and return empty INQUIRY responses, often in the case
where there is a UNIT ATTENTION pending during the INQUIRY. (Some drives send
the data and then fail, some don't.)
This eliminates the need for quirks for the Y-E DATA FlashBuster.
These changes work on:
umass0: SAMSUNG SFD-321U [FW 0C], rev 1.10/2.10, addr 2
umass0: using UFI over CBI with CCI
sd0 at atapibus1 drive 0: <SMSC, USB FDC, 2.10> disk removable
umass0: TEAC TEAC FD-05PUB, rev 1.10/0.00, addr 2
umass0: using UFI over CBI with CCI
sd0 at atapibus0 drive 0: <TEAC, FD-05PUB, 1026> disk removable
umass0: Y-E DATA FlashBuster-U, rev 1.00/3.04, addr 2
umass0: using UFI over CBI with CCI
sd0 at atapibus0 drive 0: <Y-E DATA, USB-FDU, 3.04> disk removable
2003-09-10 06:49:18 +04:00
|
|
|
int status;
|
|
|
|
|
2000-04-03 03:46:53 +04:00
|
|
|
/* Command Interrupt Data Block */
|
cc -pipe -ffreestanding -O2 -Werror -Wall -Wno-main -Wno-format-zero-length -Fix several problems with CCI handling, and enable it:
* We were never calling the callback function when we got a UFI CCI(!).
* We were passing a bogus residual count on non-UFI CCIs.
* After a REQUEST SENSE, the UFI CCI may include the ASC/ASCQ from the sense
information -- don't consider this a failure.
In addition, remove a horrible hack that was causing us to drop sense
information on the floor and return empty INQUIRY responses, often in the case
where there is a UNIT ATTENTION pending during the INQUIRY. (Some drives send
the data and then fail, some don't.)
This eliminates the need for quirks for the Y-E DATA FlashBuster.
These changes work on:
umass0: SAMSUNG SFD-321U [FW 0C], rev 1.10/2.10, addr 2
umass0: using UFI over CBI with CCI
sd0 at atapibus1 drive 0: <SMSC, USB FDC, 2.10> disk removable
umass0: TEAC TEAC FD-05PUB, rev 1.10/0.00, addr 2
umass0: using UFI over CBI with CCI
sd0 at atapibus0 drive 0: <TEAC, FD-05PUB, 1026> disk removable
umass0: Y-E DATA FlashBuster-U, rev 1.00/3.04, addr 2
umass0: using UFI over CBI with CCI
sd0 at atapibus0 drive 0: <Y-E DATA, USB-FDU, 3.04> disk removable
2003-09-10 06:49:18 +04:00
|
|
|
|
2000-04-03 03:46:53 +04:00
|
|
|
DPRINTF(UDMASS_CBI, ("%s: type=0x%02x, value=0x%02x\n",
|
|
|
|
USBDEVNAME(sc->sc_dev),
|
|
|
|
sc->sbl.common.type, sc->sbl.common.value));
|
|
|
|
|
|
|
|
if (sc->sbl.common.type == IDB_TYPE_CCI) {
|
cc -pipe -ffreestanding -O2 -Werror -Wall -Wno-main -Wno-format-zero-length -Fix several problems with CCI handling, and enable it:
* We were never calling the callback function when we got a UFI CCI(!).
* We were passing a bogus residual count on non-UFI CCIs.
* After a REQUEST SENSE, the UFI CCI may include the ASC/ASCQ from the sense
information -- don't consider this a failure.
In addition, remove a horrible hack that was causing us to drop sense
information on the floor and return empty INQUIRY responses, often in the case
where there is a UNIT ATTENTION pending during the INQUIRY. (Some drives send
the data and then fail, some don't.)
This eliminates the need for quirks for the Y-E DATA FlashBuster.
These changes work on:
umass0: SAMSUNG SFD-321U [FW 0C], rev 1.10/2.10, addr 2
umass0: using UFI over CBI with CCI
sd0 at atapibus1 drive 0: <SMSC, USB FDC, 2.10> disk removable
umass0: TEAC TEAC FD-05PUB, rev 1.10/0.00, addr 2
umass0: using UFI over CBI with CCI
sd0 at atapibus0 drive 0: <TEAC, FD-05PUB, 1026> disk removable
umass0: Y-E DATA FlashBuster-U, rev 1.00/3.04, addr 2
umass0: using UFI over CBI with CCI
sd0 at atapibus0 drive 0: <Y-E DATA, USB-FDU, 3.04> disk removable
2003-09-10 06:49:18 +04:00
|
|
|
switch (sc->sbl.common.value & IDB_VALUE_STATUS_MASK) {
|
|
|
|
case IDB_VALUE_PASS:
|
|
|
|
status = STATUS_CMD_OK;
|
|
|
|
break;
|
|
|
|
case IDB_VALUE_FAIL:
|
|
|
|
case IDB_VALUE_PERSISTENT:
|
|
|
|
status = STATUS_CMD_FAILED;
|
|
|
|
break;
|
|
|
|
case IDB_VALUE_PHASE:
|
2003-10-29 02:37:59 +03:00
|
|
|
default: /* XXX: gcc */
|
cc -pipe -ffreestanding -O2 -Werror -Wall -Wno-main -Wno-format-zero-length -Fix several problems with CCI handling, and enable it:
* We were never calling the callback function when we got a UFI CCI(!).
* We were passing a bogus residual count on non-UFI CCIs.
* After a REQUEST SENSE, the UFI CCI may include the ASC/ASCQ from the sense
information -- don't consider this a failure.
In addition, remove a horrible hack that was causing us to drop sense
information on the floor and return empty INQUIRY responses, often in the case
where there is a UNIT ATTENTION pending during the INQUIRY. (Some drives send
the data and then fail, some don't.)
This eliminates the need for quirks for the Y-E DATA FlashBuster.
These changes work on:
umass0: SAMSUNG SFD-321U [FW 0C], rev 1.10/2.10, addr 2
umass0: using UFI over CBI with CCI
sd0 at atapibus1 drive 0: <SMSC, USB FDC, 2.10> disk removable
umass0: TEAC TEAC FD-05PUB, rev 1.10/0.00, addr 2
umass0: using UFI over CBI with CCI
sd0 at atapibus0 drive 0: <TEAC, FD-05PUB, 1026> disk removable
umass0: Y-E DATA FlashBuster-U, rev 1.00/3.04, addr 2
umass0: using UFI over CBI with CCI
sd0 at atapibus0 drive 0: <Y-E DATA, USB-FDU, 3.04> disk removable
2003-09-10 06:49:18 +04:00
|
|
|
status = STATUS_WIRE_FAILED;
|
|
|
|
break;
|
2000-04-03 03:46:53 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
sc->transfer_state = TSTATE_IDLE;
|
|
|
|
sc->transfer_cb(sc, sc->transfer_priv,
|
cc -pipe -ffreestanding -O2 -Werror -Wall -Wno-main -Wno-format-zero-length -Fix several problems with CCI handling, and enable it:
* We were never calling the callback function when we got a UFI CCI(!).
* We were passing a bogus residual count on non-UFI CCIs.
* After a REQUEST SENSE, the UFI CCI may include the ASC/ASCQ from the sense
information -- don't consider this a failure.
In addition, remove a horrible hack that was causing us to drop sense
information on the floor and return empty INQUIRY responses, often in the case
where there is a UNIT ATTENTION pending during the INQUIRY. (Some drives send
the data and then fail, some don't.)
This eliminates the need for quirks for the Y-E DATA FlashBuster.
These changes work on:
umass0: SAMSUNG SFD-321U [FW 0C], rev 1.10/2.10, addr 2
umass0: using UFI over CBI with CCI
sd0 at atapibus1 drive 0: <SMSC, USB FDC, 2.10> disk removable
umass0: TEAC TEAC FD-05PUB, rev 1.10/0.00, addr 2
umass0: using UFI over CBI with CCI
sd0 at atapibus0 drive 0: <TEAC, FD-05PUB, 1026> disk removable
umass0: Y-E DATA FlashBuster-U, rev 1.00/3.04, addr 2
umass0: using UFI over CBI with CCI
sd0 at atapibus0 drive 0: <Y-E DATA, USB-FDU, 3.04> disk removable
2003-09-10 06:49:18 +04:00
|
|
|
sc->transfer_datalen - sc->transfer_actlen, status);
|
2000-04-03 03:46:53 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
|
|
|
|
case TSTATE_CBI_DCLEAR:
|
2004-06-25 18:07:27 +04:00
|
|
|
if (err) { /* should not occur */
|
2003-09-10 10:38:28 +04:00
|
|
|
printf("%s: CBI bulk-%s stall clear failed, %s\n",
|
|
|
|
USBDEVNAME(sc->sc_dev),
|
|
|
|
(sc->transfer_dir == DIR_IN? "in":"out"),
|
|
|
|
usbd_errstr(err));
|
2004-06-25 18:07:27 +04:00
|
|
|
umass_cbi_reset(sc, STATUS_WIRE_FAILED);
|
2004-06-26 06:17:00 +04:00
|
|
|
} else {
|
|
|
|
sc->transfer_state = TSTATE_IDLE;
|
|
|
|
sc->transfer_cb(sc, sc->transfer_priv,
|
|
|
|
sc->transfer_datalen, STATUS_CMD_FAILED);
|
|
|
|
}
|
2000-04-03 03:46:53 +04:00
|
|
|
return;
|
|
|
|
|
|
|
|
case TSTATE_CBI_SCLEAR:
|
2004-06-25 18:07:27 +04:00
|
|
|
if (err) { /* should not occur */
|
2000-04-03 03:46:53 +04:00
|
|
|
printf("%s: CBI intr-in stall clear failed, %s\n",
|
|
|
|
USBDEVNAME(sc->sc_dev), usbd_errstr(err));
|
2004-06-25 18:07:27 +04:00
|
|
|
umass_cbi_reset(sc, STATUS_WIRE_FAILED);
|
2004-06-26 06:17:00 +04:00
|
|
|
} else {
|
|
|
|
sc->transfer_state = TSTATE_IDLE;
|
|
|
|
sc->transfer_cb(sc, sc->transfer_priv,
|
|
|
|
sc->transfer_datalen, STATUS_CMD_FAILED);
|
|
|
|
}
|
2000-04-03 03:46:53 +04:00
|
|
|
return;
|
|
|
|
|
|
|
|
/***** CBI Reset *****/
|
|
|
|
case TSTATE_CBI_RESET1:
|
|
|
|
if (err)
|
|
|
|
printf("%s: CBI reset failed, %s\n",
|
|
|
|
USBDEVNAME(sc->sc_dev), usbd_errstr(err));
|
|
|
|
|
2001-12-12 16:23:20 +03:00
|
|
|
sc->transfer_state = TSTATE_CBI_RESET2;
|
2001-12-14 08:58:13 +03:00
|
|
|
umass_clear_endpoint_stall(sc, UMASS_BULKIN,
|
2000-04-03 03:46:53 +04:00
|
|
|
sc->transfer_xfer[XFER_CBI_RESET2]);
|
|
|
|
|
|
|
|
return;
|
|
|
|
case TSTATE_CBI_RESET2:
|
|
|
|
if (err) /* should not occur */
|
|
|
|
printf("%s: CBI bulk-in stall clear failed, %s\n",
|
|
|
|
USBDEVNAME(sc->sc_dev), usbd_errstr(err));
|
|
|
|
/* no error recovery, otherwise we end up in a loop */
|
|
|
|
|
2001-12-12 16:23:20 +03:00
|
|
|
sc->transfer_state = TSTATE_CBI_RESET3;
|
2001-12-14 08:58:13 +03:00
|
|
|
umass_clear_endpoint_stall(sc, UMASS_BULKOUT,
|
2000-04-03 03:46:53 +04:00
|
|
|
sc->transfer_xfer[XFER_CBI_RESET3]);
|
|
|
|
|
|
|
|
return;
|
|
|
|
case TSTATE_CBI_RESET3:
|
|
|
|
if (err) /* should not occur */
|
|
|
|
printf("%s: CBI bulk-out stall clear failed, %s\n",
|
|
|
|
USBDEVNAME(sc->sc_dev), usbd_errstr(err));
|
|
|
|
/* no error recovery, otherwise we end up in a loop */
|
|
|
|
|
|
|
|
sc->transfer_state = TSTATE_IDLE;
|
|
|
|
if (sc->transfer_priv) {
|
|
|
|
sc->transfer_cb(sc, sc->transfer_priv,
|
|
|
|
sc->transfer_datalen,
|
|
|
|
sc->transfer_status);
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
/***** Default *****/
|
|
|
|
default:
|
2002-09-27 19:35:29 +04:00
|
|
|
panic("%s: Unknown state %d",
|
2000-04-03 03:46:53 +04:00
|
|
|
USBDEVNAME(sc->sc_dev), sc->transfer_state);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
usbd_status
|
|
|
|
umass_bbb_get_max_lun(struct umass_softc *sc, u_int8_t *maxlun)
|
|
|
|
{
|
|
|
|
usb_device_request_t req;
|
|
|
|
usbd_status err;
|
|
|
|
|
|
|
|
*maxlun = 0; /* Default to 0. */
|
|
|
|
|
|
|
|
DPRINTF(UDMASS_BBB, ("%s: Get Max Lun\n", USBDEVNAME(sc->sc_dev)));
|
|
|
|
|
|
|
|
/* The Get Max Lun command is a class-specific request. */
|
|
|
|
req.bmRequestType = UT_READ_CLASS_INTERFACE;
|
|
|
|
req.bRequest = UR_BBB_GET_MAX_LUN;
|
|
|
|
USETW(req.wValue, 0);
|
2001-12-14 11:58:49 +03:00
|
|
|
USETW(req.wIndex, sc->sc_ifaceno);
|
2000-04-03 03:46:53 +04:00
|
|
|
USETW(req.wLength, 1);
|
|
|
|
|
2003-09-04 04:02:59 +04:00
|
|
|
err = usbd_do_request_flags(sc->sc_udev, &req, maxlun,
|
|
|
|
USBD_SHORT_XFER_OK, 0, USBD_DEFAULT_TIMEOUT);
|
2000-04-03 03:46:53 +04:00
|
|
|
switch (err) {
|
|
|
|
case USBD_NORMAL_COMPLETION:
|
|
|
|
DPRINTF(UDMASS_BBB, ("%s: Max Lun %d\n",
|
|
|
|
USBDEVNAME(sc->sc_dev), *maxlun));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case USBD_STALLED:
|
|
|
|
/*
|
|
|
|
* Device doesn't support Get Max Lun request.
|
|
|
|
*/
|
|
|
|
err = USBD_NORMAL_COMPLETION;
|
|
|
|
DPRINTF(UDMASS_BBB, ("%s: Get Max Lun not supported\n",
|
|
|
|
USBDEVNAME(sc->sc_dev)));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case USBD_SHORT_XFER:
|
|
|
|
/*
|
|
|
|
* XXX This must mean Get Max Lun is not supported, too!
|
|
|
|
*/
|
|
|
|
err = USBD_NORMAL_COMPLETION;
|
|
|
|
DPRINTF(UDMASS_BBB, ("%s: Get Max Lun SHORT_XFER\n",
|
|
|
|
USBDEVNAME(sc->sc_dev)));
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
printf("%s: Get Max Lun failed: %s\n",
|
|
|
|
USBDEVNAME(sc->sc_dev), usbd_errstr(err));
|
|
|
|
/* XXX Should we port_reset the device? */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (err);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef UMASS_DEBUG
|
|
|
|
Static void
|
|
|
|
umass_bbb_dump_cbw(struct umass_softc *sc, umass_bbb_cbw_t *cbw)
|
|
|
|
{
|
|
|
|
int clen = cbw->bCDBLength;
|
|
|
|
int dlen = UGETDW(cbw->dCBWDataTransferLength);
|
|
|
|
u_int8_t *c = cbw->CBWCDB;
|
|
|
|
int tag = UGETDW(cbw->dCBWTag);
|
|
|
|
int flags = cbw->bCBWFlags;
|
|
|
|
|
2001-12-31 15:15:46 +03:00
|
|
|
DPRINTF(UDMASS_BBB, ("%s: CBW %d: cmdlen=%d "
|
|
|
|
"(0x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%s), "
|
2000-04-03 03:46:53 +04:00
|
|
|
"data = %d bytes, dir = %s\n",
|
|
|
|
USBDEVNAME(sc->sc_dev), tag, clen,
|
2001-12-31 15:15:46 +03:00
|
|
|
c[0], c[1], c[2], c[3], c[4], c[5],
|
|
|
|
c[6], c[7], c[8], c[9],
|
|
|
|
(clen > 10? "...":""),
|
2000-04-03 03:46:53 +04:00
|
|
|
dlen, (flags == CBWFLAGS_IN? "in":
|
|
|
|
(flags == CBWFLAGS_OUT? "out":"<invalid>"))));
|
|
|
|
}
|
|
|
|
|
|
|
|
Static void
|
|
|
|
umass_bbb_dump_csw(struct umass_softc *sc, umass_bbb_csw_t *csw)
|
|
|
|
{
|
|
|
|
int sig = UGETDW(csw->dCSWSignature);
|
2004-06-22 16:21:04 +04:00
|
|
|
int tag = UGETDW(csw->dCSWTag);
|
2000-04-03 03:46:53 +04:00
|
|
|
int res = UGETDW(csw->dCSWDataResidue);
|
|
|
|
int status = csw->bCSWStatus;
|
|
|
|
|
|
|
|
DPRINTF(UDMASS_BBB, ("%s: CSW %d: sig = 0x%08x (%s), tag = %d, "
|
|
|
|
"res = %d, status = 0x%02x (%s)\n", USBDEVNAME(sc->sc_dev),
|
|
|
|
tag, sig, (sig == CSWSIGNATURE? "valid":"invalid"),
|
|
|
|
tag, res,
|
|
|
|
status, (status == CSWSTATUS_GOOD? "good":
|
|
|
|
(status == CSWSTATUS_FAILED? "failed":
|
|
|
|
(status == CSWSTATUS_PHASE? "phase":"<invalid>")))));
|
|
|
|
}
|
|
|
|
|
|
|
|
Static void
|
|
|
|
umass_dump_buffer(struct umass_softc *sc, u_int8_t *buffer, int buflen,
|
|
|
|
int printlen)
|
|
|
|
{
|
|
|
|
int i, j;
|
|
|
|
char s1[40];
|
|
|
|
char s2[40];
|
|
|
|
char s3[5];
|
|
|
|
|
|
|
|
s1[0] = '\0';
|
|
|
|
s3[0] = '\0';
|
|
|
|
|
2004-04-22 04:17:10 +04:00
|
|
|
snprintf(s2, sizeof(s2), " buffer=%p, buflen=%d", buffer, buflen);
|
2000-04-03 03:46:53 +04:00
|
|
|
for (i = 0; i < buflen && i < printlen; i++) {
|
|
|
|
j = i % 16;
|
|
|
|
if (j == 0 && i != 0) {
|
|
|
|
DPRINTF(UDMASS_GEN, ("%s: 0x %s%s\n",
|
|
|
|
USBDEVNAME(sc->sc_dev), s1, s2));
|
|
|
|
s2[0] = '\0';
|
|
|
|
}
|
2004-04-22 04:17:10 +04:00
|
|
|
snprintf(&s1[j * 2], sizeof(s1) - j * 2, "%02x",
|
|
|
|
buffer[i] & 0xff);
|
2000-04-03 03:46:53 +04:00
|
|
|
}
|
|
|
|
if (buflen > printlen)
|
2004-04-22 04:17:10 +04:00
|
|
|
snprintf(s3, sizeof(s3), " ...");
|
2000-04-03 03:46:53 +04:00
|
|
|
DPRINTF(UDMASS_GEN, ("%s: 0x %s%s%s\n",
|
|
|
|
USBDEVNAME(sc->sc_dev), s1, s2, s3));
|
|
|
|
}
|
|
|
|
#endif
|