svn commit: r188957 - in head/sys: conf dev/ata dev/sound/usb dev/usb/sound dev/usb/storage modules/ata/atausb modules/sound/driver/uaudio

Andrew Thompson thompsa at FreeBSD.org
Mon Feb 23 13:19:20 PST 2009


Author: thompsa
Date: Mon Feb 23 21:19:18 2009
New Revision: 188957
URL: http://svn.freebsd.org/changeset/base/188957

Log:
  Move the uaudio and ata-usb drivers into their correct locations.

Added:
  head/sys/dev/ata/ata-usb.c
     - copied unchanged from r188946, head/sys/dev/usb/storage/ata-usb.c
  head/sys/dev/sound/usb/uaudio.c
     - copied, changed from r188946, head/sys/dev/usb/sound/uaudio.c
  head/sys/dev/sound/usb/uaudio.h
     - copied unchanged from r188946, head/sys/dev/usb/sound/uaudio.h
  head/sys/dev/sound/usb/uaudio_pcm.c
     - copied, changed from r188946, head/sys/dev/usb/sound/uaudio_pcm.c
  head/sys/dev/sound/usb/uaudioreg.h
     - copied unchanged from r188946, head/sys/dev/usb/sound/uaudio_reg.h
Deleted:
  head/sys/dev/usb/sound/
  head/sys/dev/usb/storage/ata-usb.c
Modified:
  head/sys/conf/files
  head/sys/modules/ata/atausb/Makefile
  head/sys/modules/sound/driver/uaudio/Makefile

Modified: head/sys/conf/files
==============================================================================
--- head/sys/conf/files	Mon Feb 23 21:09:28 2009	(r188956)
+++ head/sys/conf/files	Mon Feb 23 21:19:18 2009	(r188957)
@@ -502,6 +502,7 @@ dev/ata/chipsets/ata-sis.c	optional ata 
 dev/ata/chipsets/ata-via.c	optional ata pci | atavia
 dev/ata/ata-disk.c		optional atadisk
 dev/ata/ata-raid.c		optional ataraid
+dev/ata/ata-usb.c		optional atausb usb
 legacy/dev/ata/ata-usb.c	optional atausb ousb
 dev/ata/atapi-cd.c		optional atapicd
 dev/ata/atapi-fd.c		optional atapifd
@@ -1393,7 +1394,8 @@ dev/sound/pcm/mixer_if.m	optional sound
 dev/sound/pcm/sndstat.c		optional sound
 dev/sound/pcm/sound.c		optional sound
 dev/sound/pcm/vchan.c		optional sound
-#dev/sound/usb/upcm.c		optional snd_upcm ousb
+dev/sound/usb/uaudio.c		optional snd_uaudio usb
+dev/sound/usb/uaudio_pcm.c	optional snd_uaudio usb
 legacy/dev/sound/usb/uaudio.c		optional snd_uaudio ousb
 legacy/dev/sound/usb/uaudio_pcm.c	optional snd_uaudio ousb
 dev/sound/midi/midi.c		optional sound
@@ -1552,7 +1554,6 @@ dev/usb/controller/usb_controller.c	opti
 #
 # USB storage drivers
 #
-dev/usb/storage/ata-usb.c	optional atausb
 dev/usb/storage/umass.c		optional umass
 dev/usb/storage/urio.c		optional urio
 dev/usb/storage/ustorage_fs.c	optional usfs
@@ -1654,11 +1655,6 @@ dev/usb/template/usb_template_mtp.c	opti
 #
 dev/usb/image/uscanner.c	optional uscanner
 #
-# USB sound and MIDI drivers
-#
-dev/usb/sound/uaudio.c		optional usound
-dev/usb/sound/uaudio_pcm.c	optional usound
-#
 # USB END
 #
 dev/utopia/idtphy.c		optional utopia

Copied: head/sys/dev/ata/ata-usb.c (from r188946, head/sys/dev/usb/storage/ata-usb.c)
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/dev/ata/ata-usb.c	Mon Feb 23 21:19:18 2009	(r188957, copy of r188946, head/sys/dev/usb/storage/ata-usb.c)
@@ -0,0 +1,1102 @@
+/*-
+ * Copyright (c) 2006 - 2008 Søren Schmidt <sos at FreeBSD.org>
+ * All rights reserved.
+ *
+ * Copyright (c) 2006 Hans Petter Selasky
+ * 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,
+ *    without modification, immediately at the beginning of the file.
+ * 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 ``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 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "usbdevs.h"
+#include <dev/usb/usb.h>
+#include <dev/usb/usb_mfunc.h>
+#include <dev/usb/usb_error.h>
+
+#include <dev/usb/usb_core.h>
+#include <dev/usb/usb_util.h>
+#include <dev/usb/usb_busdma.h>
+#include <dev/usb/usb_request.h>
+#include <dev/usb/usb_debug.h>
+#include <dev/usb/usb_process.h>
+#include <dev/usb/usb_transfer.h>
+
+#include <sys/ata.h>
+#include <sys/bio.h>
+#include <sys/sema.h>
+#include <sys/taskqueue.h>
+#include <vm/uma.h>
+
+#include <dev/ata/ata-all.h>
+#include <ata_if.h>
+
+#define	ATAUSB_BULK_SIZE (1<<17)
+
+/* Command Block Wrapper */
+struct bbb_cbw {
+	uint8_t	signature[4];
+#define	CBWSIGNATURE		0x43425355
+
+	uint8_t	tag[4];
+	uint8_t	transfer_length[4];
+	uint8_t	flags;
+#define	CBWFLAGS_OUT  		0x00
+#define	CBWFLAGS_IN  		0x80
+
+	uint8_t	lun;
+	uint8_t	length;
+#define	CBWCDBLENGTH     	16
+
+	uint8_t	cdb[CBWCDBLENGTH];
+} __packed;
+
+/* Command Status Wrapper */
+struct bbb_csw {
+	uint8_t	signature[4];
+#define	CSWSIGNATURE     	0x53425355
+
+	uint8_t	tag[4];
+	uint8_t	residue[4];
+	uint8_t	status;
+#define	CSWSTATUS_GOOD   	0x0
+#define	CSWSTATUS_FAILED 	0x1
+#define	CSWSTATUS_PHASE  	0x2
+} __packed;
+
+/* USB-ATA 'controller' softc */
+struct atausb2_softc {
+	struct bbb_cbw cbw;
+	struct bbb_csw csw;
+	struct mtx locked_mtx;
+
+	struct ata_channel *locked_ch;
+	struct ata_channel *restart_ch;
+	struct ata_request *ata_request;
+
+#define	ATAUSB_T_BBB_RESET1        0
+#define	ATAUSB_T_BBB_RESET2        1
+#define	ATAUSB_T_BBB_RESET3        2
+#define	ATAUSB_T_BBB_COMMAND       3
+#define	ATAUSB_T_BBB_DATA_READ     4
+#define	ATAUSB_T_BBB_DATA_RD_CS    5
+#define	ATAUSB_T_BBB_DATA_WRITE    6
+#define	ATAUSB_T_BBB_DATA_WR_CS    7
+#define	ATAUSB_T_BBB_STATUS        8
+#define	ATAUSB_T_BBB_MAX           9
+
+#define	ATAUSB_T_MAX ATAUSB_T_BBB_MAX
+
+	struct usb2_xfer *xfer[ATAUSB_T_MAX];
+	caddr_t	ata_data;
+	device_t dev;
+
+	uint32_t timeout;
+	uint32_t ata_donecount;
+	uint32_t ata_bytecount;
+
+	uint8_t	last_xfer_no;
+	uint8_t	usb2_speed;
+	uint8_t	intr_stalled;
+	uint8_t	maxlun;
+	uint8_t	iface_no;
+	uint8_t	status_try;
+};
+
+static const int atausbdebug = 0;
+
+/* prototypes */
+
+static device_probe_t atausb2_probe;
+static device_attach_t atausb2_attach;
+static device_detach_t atausb2_detach;
+
+static usb2_callback_t atausb2_t_bbb_reset1_callback;
+static usb2_callback_t atausb2_t_bbb_reset2_callback;
+static usb2_callback_t atausb2_t_bbb_reset3_callback;
+static usb2_callback_t atausb2_t_bbb_command_callback;
+static usb2_callback_t atausb2_t_bbb_data_read_callback;
+static usb2_callback_t atausb2_t_bbb_data_rd_cs_callback;
+static usb2_callback_t atausb2_t_bbb_data_write_callback;
+static usb2_callback_t atausb2_t_bbb_data_wr_cs_callback;
+static usb2_callback_t atausb2_t_bbb_status_callback;
+static usb2_callback_t atausb2_tr_error;
+
+static void atausb2_cancel_request(struct atausb2_softc *sc);
+static void atausb2_transfer_start(struct atausb2_softc *sc, uint8_t xfer_no);
+static void atausb2_t_bbb_data_clear_stall_callback(struct usb2_xfer *xfer, uint8_t next_xfer, uint8_t stall_xfer);
+static int ata_usbchannel_begin_transaction(struct ata_request *request);
+static int ata_usbchannel_end_transaction(struct ata_request *request);
+
+static device_probe_t ata_usbchannel_probe;
+static device_attach_t ata_usbchannel_attach;
+static device_detach_t ata_usbchannel_detach;
+
+static ata_setmode_t ata_usbchannel_setmode;
+static ata_locking_t ata_usbchannel_locking;
+
+/*
+ * USB frontend part
+ */
+
+struct usb2_config atausb2_config[ATAUSB_T_BBB_MAX] = {
+
+	[ATAUSB_T_BBB_RESET1] = {
+		.type = UE_CONTROL,
+		.endpoint = 0x00,	/* Control pipe */
+		.direction = UE_DIR_ANY,
+		.mh.bufsize = sizeof(struct usb2_device_request),
+		.mh.flags = {},
+		.mh.callback = &atausb2_t_bbb_reset1_callback,
+		.mh.timeout = 5000,	/* 5 seconds */
+		.mh.interval = 500,	/* 500 milliseconds */
+	},
+
+	[ATAUSB_T_BBB_RESET2] = {
+		.type = UE_CONTROL,
+		.endpoint = 0x00,	/* Control pipe */
+		.direction = UE_DIR_ANY,
+		.mh.bufsize = sizeof(struct usb2_device_request),
+		.mh.flags = {},
+		.mh.callback = &atausb2_t_bbb_reset2_callback,
+		.mh.timeout = 5000,	/* 5 seconds */
+		.mh.interval = 50,	/* 50 milliseconds */
+	},
+
+	[ATAUSB_T_BBB_RESET3] = {
+		.type = UE_CONTROL,
+		.endpoint = 0x00,	/* Control pipe */
+		.direction = UE_DIR_ANY,
+		.mh.bufsize = sizeof(struct usb2_device_request),
+		.mh.flags = {},
+		.mh.callback = &atausb2_t_bbb_reset3_callback,
+		.mh.timeout = 5000,	/* 5 seconds */
+		.mh.interval = 50,	/* 50 milliseconds */
+	},
+
+	[ATAUSB_T_BBB_COMMAND] = {
+		.type = UE_BULK,
+		.endpoint = UE_ADDR_ANY,
+		.direction = UE_DIR_OUT,
+		.mh.bufsize = sizeof(struct bbb_cbw),
+		.mh.flags = {},
+		.mh.callback = &atausb2_t_bbb_command_callback,
+		.mh.timeout = 5000,	/* 5 seconds */
+	},
+
+	[ATAUSB_T_BBB_DATA_READ] = {
+		.type = UE_BULK,
+		.endpoint = UE_ADDR_ANY,
+		.direction = UE_DIR_IN,
+		.mh.bufsize = ATAUSB_BULK_SIZE,
+		.mh.flags = {.proxy_buffer = 1,.short_xfer_ok = 1,},
+		.mh.callback = &atausb2_t_bbb_data_read_callback,
+		.mh.timeout = 0,	/* overwritten later */
+	},
+
+	[ATAUSB_T_BBB_DATA_RD_CS] = {
+		.type = UE_CONTROL,
+		.endpoint = 0x00,	/* Control pipe */
+		.direction = UE_DIR_ANY,
+		.mh.bufsize = sizeof(struct usb2_device_request),
+		.mh.flags = {},
+		.mh.callback = &atausb2_t_bbb_data_rd_cs_callback,
+		.mh.timeout = 5000,	/* 5 seconds */
+	},
+
+	[ATAUSB_T_BBB_DATA_WRITE] = {
+		.type = UE_BULK,
+		.endpoint = UE_ADDR_ANY,
+		.direction = UE_DIR_OUT,
+		.mh.bufsize = ATAUSB_BULK_SIZE,
+		.mh.flags = {.proxy_buffer = 1,.short_xfer_ok = 1,},
+		.mh.callback = &atausb2_t_bbb_data_write_callback,
+		.mh.timeout = 0,	/* overwritten later */
+	},
+
+	[ATAUSB_T_BBB_DATA_WR_CS] = {
+		.type = UE_CONTROL,
+		.endpoint = 0x00,	/* Control pipe */
+		.direction = UE_DIR_ANY,
+		.mh.bufsize = sizeof(struct usb2_device_request),
+		.mh.flags = {},
+		.mh.callback = &atausb2_t_bbb_data_wr_cs_callback,
+		.mh.timeout = 5000,	/* 5 seconds */
+	},
+
+	[ATAUSB_T_BBB_STATUS] = {
+		.type = UE_BULK,
+		.endpoint = UE_ADDR_ANY,
+		.direction = UE_DIR_IN,
+		.mh.bufsize = sizeof(struct bbb_csw),
+		.mh.flags = {.short_xfer_ok = 1,},
+		.mh.callback = &atausb2_t_bbb_status_callback,
+		.mh.timeout = 5000,	/* ms */
+	},
+};
+
+static devclass_t atausb2_devclass;
+
+static device_method_t atausb2_methods[] = {
+	DEVMETHOD(device_probe, atausb2_probe),
+	DEVMETHOD(device_attach, atausb2_attach),
+	DEVMETHOD(device_detach, atausb2_detach),
+	{0, 0}
+};
+
+static driver_t atausb2_driver = {
+	.name = "atausb",
+	.methods = atausb2_methods,
+	.size = sizeof(struct atausb2_softc),
+};
+
+DRIVER_MODULE(atausb, ushub, atausb2_driver, atausb2_devclass, 0, 0);
+MODULE_DEPEND(atausb, usb, 1, 1, 1);
+MODULE_VERSION(atausb, 1);
+
+static int
+atausb2_probe(device_t dev)
+{
+	struct usb2_attach_arg *uaa = device_get_ivars(dev);
+	struct usb2_interface_descriptor *id;
+
+	if (uaa->usb2_mode != USB_MODE_HOST) {
+		return (ENXIO);
+	}
+	if (uaa->use_generic == 0) {
+		/* give other drivers a try first */
+		return (ENXIO);
+	}
+	id = usb2_get_interface_descriptor(uaa->iface);
+	if ((!id) || (id->bInterfaceClass != UICLASS_MASS)) {
+		return (ENXIO);
+	}
+	switch (id->bInterfaceSubClass) {
+	case UISUBCLASS_QIC157:
+	case UISUBCLASS_RBC:
+	case UISUBCLASS_SCSI:
+	case UISUBCLASS_SFF8020I:
+	case UISUBCLASS_SFF8070I:
+	case UISUBCLASS_UFI:
+		switch (id->bInterfaceProtocol) {
+		case UIPROTO_MASS_CBI:
+		case UIPROTO_MASS_CBI_I:
+		case UIPROTO_MASS_BBB:
+		case UIPROTO_MASS_BBB_OLD:
+			return (0);
+		default:
+			return (0);
+		}
+		break;
+	default:
+		return (0);
+	}
+}
+
+static int
+atausb2_attach(device_t dev)
+{
+	struct atausb2_softc *sc = device_get_softc(dev);
+	struct usb2_attach_arg *uaa = device_get_ivars(dev);
+	struct usb2_interface_descriptor *id;
+	const char *proto, *subclass;
+	struct usb2_device_request request;
+	uint16_t i;
+	uint8_t maxlun;
+	uint8_t has_intr;
+	int err;
+
+	device_set_usb2_desc(dev);
+
+	sc->dev = dev;
+	sc->maxlun = 0;
+	sc->locked_ch = NULL;
+	sc->restart_ch = NULL;
+	sc->usb2_speed = usb2_get_speed(uaa->device);
+	mtx_init(&sc->locked_mtx, "ATAUSB lock", NULL, (MTX_DEF | MTX_RECURSE));
+
+	id = usb2_get_interface_descriptor(uaa->iface);
+	switch (id->bInterfaceProtocol) {
+	case UIPROTO_MASS_BBB:
+	case UIPROTO_MASS_BBB_OLD:
+		proto = "Bulk-Only";
+		break;
+	case UIPROTO_MASS_CBI:
+		proto = "CBI";
+		break;
+	case UIPROTO_MASS_CBI_I:
+		proto = "CBI with CCI";
+		break;
+	default:
+		proto = "Unknown";
+	}
+
+	switch (id->bInterfaceSubClass) {
+	case UISUBCLASS_RBC:
+		subclass = "RBC";
+		break;
+	case UISUBCLASS_QIC157:
+	case UISUBCLASS_SFF8020I:
+	case UISUBCLASS_SFF8070I:
+		subclass = "ATAPI";
+		break;
+	case UISUBCLASS_SCSI:
+		subclass = "SCSI";
+		break;
+	case UISUBCLASS_UFI:
+		subclass = "UFI";
+		break;
+	default:
+		subclass = "Unknown";
+	}
+
+	has_intr = (id->bInterfaceProtocol == UIPROTO_MASS_CBI_I);
+	sc->iface_no = id->bInterfaceNumber;
+
+	device_printf(dev, "using %s over %s\n", subclass, proto);
+	if (strcmp(proto, "Bulk-Only") ||
+	    (strcmp(subclass, "ATAPI") && strcmp(subclass, "SCSI"))) {
+		goto detach;
+	}
+	err = usb2_transfer_setup(uaa->device, &uaa->info.bIfaceIndex,
+	    sc->xfer, atausb2_config, ATAUSB_T_BBB_MAX, sc,
+	    &sc->locked_mtx);
+
+	/* skip reset first time */
+	sc->last_xfer_no = ATAUSB_T_BBB_COMMAND;
+
+	if (err) {
+		device_printf(sc->dev, "could not setup required "
+		    "transfers, %s\n", usb2_errstr(err));
+		goto detach;
+	}
+	/* get number of devices so we can add matching channels */
+	request.bmRequestType = UT_READ_CLASS_INTERFACE;
+	request.bRequest = 0xfe;	/* GET_MAX_LUN; */
+	USETW(request.wValue, 0);
+	USETW(request.wIndex, sc->iface_no);
+	USETW(request.wLength, sizeof(maxlun));
+	err = usb2_do_request(uaa->device, &Giant, &request, &maxlun);
+
+	if (err) {
+		if (bootverbose) {
+			device_printf(sc->dev, "get maxlun not supported %s\n",
+			    usb2_errstr(err));
+		}
+	} else {
+		sc->maxlun = maxlun;
+		if (bootverbose) {
+			device_printf(sc->dev, "maxlun=%d\n", sc->maxlun);
+		}
+	}
+
+	/* ata channels are children to this USB control device */
+	for (i = 0; i <= sc->maxlun; i++) {
+		if (!device_add_child(sc->dev, "ata",
+		    devclass_find_free_unit(ata_devclass, 2))) {
+			device_printf(sc->dev, "failed to attach ata child device\n");
+			goto detach;
+		}
+	}
+	bus_generic_attach(sc->dev);
+
+	return (0);
+
+detach:
+	atausb2_detach(dev);
+	return (ENXIO);
+}
+
+static int
+atausb2_detach(device_t dev)
+{
+	struct atausb2_softc *sc = device_get_softc(dev);
+	device_t *children;
+	int nchildren, i;
+
+	/* teardown our statemachine */
+
+	usb2_transfer_unsetup(sc->xfer, ATAUSB_T_MAX);
+
+	/* detach & delete all children, if any */
+
+	if (!device_get_children(dev, &children, &nchildren)) {
+		for (i = 0; i < nchildren; i++) {
+			device_delete_child(dev, children[i]);
+		}
+		free(children, M_TEMP);
+	}
+	mtx_destroy(&sc->locked_mtx);
+	return (0);
+}
+
+static void
+atausb2_transfer_start(struct atausb2_softc *sc, uint8_t xfer_no)
+{
+	if (atausbdebug) {
+		device_printf(sc->dev, "BBB transfer %d\n", xfer_no);
+	}
+	if (sc->xfer[xfer_no]) {
+		sc->last_xfer_no = xfer_no;
+		usb2_transfer_start(sc->xfer[xfer_no]);
+	} else {
+		atausb2_cancel_request(sc);
+	}
+}
+
+static void
+atausb2_t_bbb_reset1_callback(struct usb2_xfer *xfer)
+{
+	struct atausb2_softc *sc = xfer->priv_sc;
+	struct usb2_device_request req;
+
+	switch (USB_GET_STATE(xfer)) {
+	case USB_ST_TRANSFERRED:
+		atausb2_transfer_start(sc, ATAUSB_T_BBB_RESET2);
+		return;
+
+	case USB_ST_SETUP:
+		req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
+		req.bRequest = 0xff;	/* bulk-only reset */
+		USETW(req.wValue, 0);
+		req.wIndex[0] = sc->iface_no;
+		req.wIndex[1] = 0;
+		USETW(req.wLength, 0);
+
+		usb2_copy_in(xfer->frbuffers, 0, &req, sizeof(req));
+
+		xfer->frlengths[0] = sizeof(req);
+		xfer->nframes = 1;
+		usb2_start_hardware(xfer);
+		return;
+
+	default:			/* Error */
+		atausb2_tr_error(xfer);
+		return;
+
+	}
+}
+
+static void
+atausb2_t_bbb_reset2_callback(struct usb2_xfer *xfer)
+{
+	atausb2_t_bbb_data_clear_stall_callback(xfer, ATAUSB_T_BBB_RESET3,
+	    ATAUSB_T_BBB_DATA_READ);
+}
+
+static void
+atausb2_t_bbb_reset3_callback(struct usb2_xfer *xfer)
+{
+	atausb2_t_bbb_data_clear_stall_callback(xfer, ATAUSB_T_BBB_COMMAND,
+	    ATAUSB_T_BBB_DATA_WRITE);
+}
+
+static void
+atausb2_t_bbb_data_clear_stall_callback(struct usb2_xfer *xfer,
+    uint8_t next_xfer,
+    uint8_t stall_xfer)
+{
+	struct atausb2_softc *sc = xfer->priv_sc;
+
+	switch (USB_GET_STATE(xfer)) {
+	case USB_ST_TRANSFERRED:
+tr_transferred:
+		atausb2_transfer_start(sc, next_xfer);
+		return;
+
+	case USB_ST_SETUP:
+		if (usb2_clear_stall_callback(xfer, sc->xfer[stall_xfer])) {
+			goto tr_transferred;
+		}
+		return;
+
+	default:			/* Error */
+		atausb2_tr_error(xfer);
+		return;
+
+	}
+}
+
+static void
+atausb2_t_bbb_command_callback(struct usb2_xfer *xfer)
+{
+	struct atausb2_softc *sc = xfer->priv_sc;
+	struct ata_request *request = sc->ata_request;
+	struct ata_channel *ch;
+	uint32_t tag;
+
+	switch (USB_GET_STATE(xfer)) {
+	case USB_ST_TRANSFERRED:
+		atausb2_transfer_start
+		    (sc, ((request->flags & ATA_R_READ) ? ATAUSB_T_BBB_DATA_READ :
+		    (request->flags & ATA_R_WRITE) ? ATAUSB_T_BBB_DATA_WRITE :
+		    ATAUSB_T_BBB_STATUS));
+		return;
+
+	case USB_ST_SETUP:
+
+		sc->status_try = 0;
+
+		if (request) {
+			ch = device_get_softc(request->parent);
+
+			sc->timeout = (request->timeout * 1000) + 5000;
+
+			tag = UGETDW(sc->cbw.tag) + 1;
+
+			USETDW(sc->cbw.signature, CBWSIGNATURE);
+			USETDW(sc->cbw.tag, tag);
+			USETDW(sc->cbw.transfer_length, request->bytecount);
+			sc->cbw.flags = (request->flags & ATA_R_READ) ? CBWFLAGS_IN : CBWFLAGS_OUT;
+			sc->cbw.lun = ch->unit;
+			sc->cbw.length = 16;
+			bzero(sc->cbw.cdb, 16);
+			bcopy(request->u.atapi.ccb, sc->cbw.cdb, 12);	/* XXX SOS */
+
+			usb2_copy_in(xfer->frbuffers, 0, &sc->cbw, sizeof(sc->cbw));
+
+			xfer->frlengths[0] = sizeof(sc->cbw);
+			usb2_start_hardware(xfer);
+		}
+		return;
+
+	default:			/* Error */
+		atausb2_tr_error(xfer);
+		return;
+
+	}
+}
+
+static void
+atausb2_t_bbb_data_read_callback(struct usb2_xfer *xfer)
+{
+	struct atausb2_softc *sc = xfer->priv_sc;
+	uint32_t max_bulk = xfer->max_data_length;
+
+	switch (USB_GET_STATE(xfer)) {
+	case USB_ST_TRANSFERRED:
+
+		usb2_copy_out(xfer->frbuffers, 0,
+		    sc->ata_data, xfer->actlen);
+
+		sc->ata_bytecount -= xfer->actlen;
+		sc->ata_data += xfer->actlen;
+		sc->ata_donecount += xfer->actlen;
+
+		if (xfer->actlen < xfer->sumlen) {
+			/* short transfer */
+			sc->ata_bytecount = 0;
+		}
+	case USB_ST_SETUP:
+
+		if (atausbdebug > 1) {
+			device_printf(sc->dev, "%s: max_bulk=%d, ata_bytecount=%d\n",
+			    __FUNCTION__, max_bulk, sc->ata_bytecount);
+		}
+		if (sc->ata_bytecount == 0) {
+			atausb2_transfer_start(sc, ATAUSB_T_BBB_STATUS);
+			return;
+		}
+		if (max_bulk > sc->ata_bytecount) {
+			max_bulk = sc->ata_bytecount;
+		}
+		xfer->timeout = sc->timeout;
+		xfer->frlengths[0] = max_bulk;
+
+		usb2_start_hardware(xfer);
+		return;
+
+	default:			/* Error */
+		if (xfer->error == USB_ERR_CANCELLED) {
+			atausb2_tr_error(xfer);
+		} else {
+			atausb2_transfer_start(sc, ATAUSB_T_BBB_DATA_RD_CS);
+		}
+		return;
+
+	}
+}
+
+static void
+atausb2_t_bbb_data_rd_cs_callback(struct usb2_xfer *xfer)
+{
+	atausb2_t_bbb_data_clear_stall_callback(xfer, ATAUSB_T_BBB_STATUS,
+	    ATAUSB_T_BBB_DATA_READ);
+}
+
+static void
+atausb2_t_bbb_data_write_callback(struct usb2_xfer *xfer)
+{
+	struct atausb2_softc *sc = xfer->priv_sc;
+	uint32_t max_bulk = xfer->max_data_length;
+
+	switch (USB_GET_STATE(xfer)) {
+	case USB_ST_TRANSFERRED:
+
+		sc->ata_bytecount -= xfer->actlen;
+		sc->ata_data += xfer->actlen;
+		sc->ata_donecount += xfer->actlen;
+
+	case USB_ST_SETUP:
+
+		if (atausbdebug > 1) {
+			device_printf(sc->dev, "%s: max_bulk=%d, ata_bytecount=%d\n",
+			    __FUNCTION__, max_bulk, sc->ata_bytecount);
+		}
+		if (sc->ata_bytecount == 0) {
+			atausb2_transfer_start(sc, ATAUSB_T_BBB_STATUS);
+			return;
+		}
+		if (max_bulk > sc->ata_bytecount) {
+			max_bulk = sc->ata_bytecount;
+		}
+		xfer->timeout = sc->timeout;
+		xfer->frlengths[0] = max_bulk;
+
+		usb2_copy_in(xfer->frbuffers, 0,
+		    sc->ata_data, max_bulk);
+
+		usb2_start_hardware(xfer);
+		return;
+
+	default:			/* Error */
+		if (xfer->error == USB_ERR_CANCELLED) {
+			atausb2_tr_error(xfer);
+		} else {
+			atausb2_transfer_start(sc, ATAUSB_T_BBB_DATA_WR_CS);
+		}
+		return;
+
+	}
+}
+
+static void
+atausb2_t_bbb_data_wr_cs_callback(struct usb2_xfer *xfer)
+{
+	atausb2_t_bbb_data_clear_stall_callback(xfer, ATAUSB_T_BBB_STATUS,
+	    ATAUSB_T_BBB_DATA_WRITE);
+}
+
+static void
+atausb2_t_bbb_status_callback(struct usb2_xfer *xfer)
+{
+	struct atausb2_softc *sc = xfer->priv_sc;
+	struct ata_request *request = sc->ata_request;
+	uint32_t residue;
+
+	switch (USB_GET_STATE(xfer)) {
+	case USB_ST_TRANSFERRED:
+
+		if (xfer->actlen < sizeof(sc->csw)) {
+			bzero(&sc->csw, sizeof(sc->csw));
+		}
+		usb2_copy_out(xfer->frbuffers, 0, &sc->csw, xfer->actlen);
+
+		if (request->flags & (ATA_R_READ | ATA_R_WRITE)) {
+			request->donecount = sc->ata_donecount;
+		}
+		residue = UGETDW(sc->csw.residue);
+
+		if (!residue) {
+			residue = (request->bytecount - request->donecount);
+		}
+		if (residue > request->bytecount) {
+			if (atausbdebug) {
+				device_printf(sc->dev, "truncating residue from %d "
+				    "to %d bytes\n", residue,
+				    request->bytecount);
+			}
+			residue = request->bytecount;
+		}
+		/* check CSW and handle eventual error */
+		if (UGETDW(sc->csw.signature) != CSWSIGNATURE) {
+			if (atausbdebug) {
+				device_printf(sc->dev, "bad CSW signature 0x%08x != 0x%08x\n",
+				    UGETDW(sc->csw.signature), CSWSIGNATURE);
+			}
+			goto tr_error;
+		} else if (UGETDW(sc->csw.tag) != UGETDW(sc->cbw.tag)) {
+			if (atausbdebug) {
+				device_printf(sc->dev, "bad CSW tag %d != %d\n",
+				    UGETDW(sc->csw.tag), UGETDW(sc->cbw.tag));
+			}
+			goto tr_error;
+		} else if (sc->csw.status > CSWSTATUS_PHASE) {
+			if (atausbdebug) {
+				device_printf(sc->dev, "bad CSW status %d > %d\n",
+				    sc->csw.status, CSWSTATUS_PHASE);
+			}
+			goto tr_error;
+		} else if (sc->csw.status == CSWSTATUS_PHASE) {
+			if (atausbdebug) {
+				device_printf(sc->dev, "phase error residue = %d\n", residue);
+			}
+			goto tr_error;
+		} else if (request->donecount > request->bytecount) {
+			if (atausbdebug) {
+				device_printf(sc->dev, "buffer overrun %d > %d\n",
+				    request->donecount, request->bytecount);
+			}
+			goto tr_error;
+		} else if (sc->csw.status == CSWSTATUS_FAILED) {
+			if (atausbdebug) {
+				device_printf(sc->dev, "CSWSTATUS_FAILED\n");
+			}
+			request->error = ATA_E_ATAPI_SENSE_MASK;
+		}
+		sc->last_xfer_no = ATAUSB_T_BBB_COMMAND;
+
+		sc->ata_request = NULL;
+
+		/* drop the USB transfer lock while doing the ATA interrupt */
+		mtx_unlock(&sc->locked_mtx);
+
+		ata_interrupt(device_get_softc(request->parent));
+
+		mtx_lock(&sc->locked_mtx);
+		return;
+
+	case USB_ST_SETUP:
+		xfer->frlengths[0] = xfer->max_data_length;
+		usb2_start_hardware(xfer);
+		return;
+
+	default:
+tr_error:
+		if ((xfer->error == USB_ERR_CANCELLED) ||
+		    (sc->status_try)) {
+			atausb2_tr_error(xfer);
+		} else {
+			sc->status_try = 1;
+			atausb2_transfer_start(sc, ATAUSB_T_BBB_DATA_RD_CS);
+		}
+		return;
+
+	}
+}
+
+static void
+atausb2_cancel_request(struct atausb2_softc *sc)
+{
+	struct ata_request *request;
+
+	mtx_assert(&sc->locked_mtx, MA_OWNED);
+
+	request = sc->ata_request;
+	sc->ata_request = NULL;
+	sc->last_xfer_no = ATAUSB_T_BBB_RESET1;
+
+	if (request) {
+		request->error = ATA_E_ATAPI_SENSE_MASK;
+
+		mtx_unlock(&sc->locked_mtx);
+
+		ata_interrupt(device_get_softc(request->parent));
+
+		mtx_lock(&sc->locked_mtx);
+	}
+}
+
+static void
+atausb2_tr_error(struct usb2_xfer *xfer)
+{
+	struct atausb2_softc *sc = xfer->priv_sc;
+
+	if (xfer->error != USB_ERR_CANCELLED) {
+
+		if (atausbdebug) {
+			device_printf(sc->dev, "transfer failed, %s, in state %d "
+			    "-> BULK reset\n", usb2_errstr(xfer->error),
+			    sc->last_xfer_no);
+		}
+	}
+	atausb2_cancel_request(sc);
+}
+
+/*
+ * ATA backend part
+ */
+struct atapi_inquiry {
+	uint8_t	device_type;
+	uint8_t	device_modifier;
+	uint8_t	version;
+	uint8_t	response_format;
+	uint8_t	length;
+	uint8_t	reserved[2];
+	uint8_t	flags;
+	uint8_t	vendor[8];
+	uint8_t	product[16];
+	uint8_t	revision[4];
+	/* uint8_t    crap[60]; */
+} __packed;
+
+static int
+ata_usbchannel_begin_transaction(struct ata_request *request)
+{
+	struct atausb2_softc *sc =
+	device_get_softc(device_get_parent(request->parent));
+	int error;
+
+	if (atausbdebug > 1) {
+		device_printf(request->dev, "begin_transaction %s\n",
+		    ata_cmd2str(request));
+	}
+	mtx_lock(&sc->locked_mtx);
+
+	/* sanity, just in case */
+	if (sc->ata_request) {
+		device_printf(request->dev, "begin is busy, "
+		    "state = %d\n", sc->last_xfer_no);
+		request->result = EBUSY;
+		error = ATA_OP_FINISHED;
+		goto done;
+	}
+	/*
+	 * XXX SOS convert the request into the format used, only BBB for
+	 * now
+	 */
+
+	/* ATA/ATAPI IDENTIFY needs special treatment */
+	if (!(request->flags & ATA_R_ATAPI)) {
+		if (request->u.ata.command != ATA_ATAPI_IDENTIFY) {
+			device_printf(request->dev, "%s unsupported\n",
+			    ata_cmd2str(request));
+			request->result = EIO;
+			error = ATA_OP_FINISHED;
+			goto done;
+		}
+		request->flags |= ATA_R_ATAPI;
+		bzero(request->u.atapi.ccb, 16);
+		request->u.atapi.ccb[0] = ATAPI_INQUIRY;
+		request->u.atapi.ccb[4] = 255;	/* sizeof(struct
+						 * atapi_inquiry); */
+		request->data += 256;	/* arbitrary offset into ata_param */
+		request->bytecount = 255;	/* sizeof(struct
+						 * atapi_inquiry); */
+	}
+	if (sc->xfer[sc->last_xfer_no]) {
+
+		sc->ata_request = request;
+		sc->ata_bytecount = request->bytecount;
+		sc->ata_data = request->data;
+		sc->ata_donecount = 0;
+
+		usb2_transfer_start(sc->xfer[sc->last_xfer_no]);
+		error = ATA_OP_CONTINUES;
+	} else {
+		request->result = EIO;
+		error = ATA_OP_FINISHED;
+	}
+
+done:
+	mtx_unlock(&sc->locked_mtx);
+	return (error);
+}
+
+static int
+ata_usbchannel_end_transaction(struct ata_request *request)
+{
+	if (atausbdebug > 1) {
+		device_printf(request->dev, "end_transaction %s\n",
+		    ata_cmd2str(request));
+	}
+	/*
+	 * XXX SOS convert the request from the format used, only BBB for
+	 * now
+	 */
+
+	/* ATA/ATAPI IDENTIFY needs special treatment */
+	if ((request->flags & ATA_R_ATAPI) &&
+	    (request->u.atapi.ccb[0] == ATAPI_INQUIRY)) {
+		struct ata_device *atadev = device_get_softc(request->dev);
+		struct atapi_inquiry *inquiry = (struct atapi_inquiry *)request->data;
+		uint16_t *ptr;
+
+		/* convert inquiry data into simple ata_param like format */
+		atadev->param.config = ATA_PROTO_ATAPI | ATA_PROTO_ATAPI_12;
+		atadev->param.config |= (inquiry->device_type & 0x1f) << 8;
+		bzero(atadev->param.model, sizeof(atadev->param.model));
+		strncpy(atadev->param.model, inquiry->vendor, 8);
+		strcpy(atadev->param.model, "  ");
+		strncpy(atadev->param.model, inquiry->product, 16);
+		ptr = (uint16_t *)(atadev->param.model + sizeof(atadev->param.model));
+		while (--ptr >= (uint16_t *)atadev->param.model) {
+			*ptr = ntohs(*ptr);
+		}
+		strncpy(atadev->param.revision, inquiry->revision, 4);
+		ptr = (uint16_t *)(atadev->param.revision + sizeof(atadev->param.revision));
+		while (--ptr >= (uint16_t *)atadev->param.revision) {
+			*ptr = ntohs(*ptr);
+		}
+		request->result = 0;
+	}
+	return (ATA_OP_FINISHED);
+}
+
+static int

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-head mailing list