Commit 7fcc2c87 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Merge kroah.com:/home/greg/linux/BK/bleeding_edge-2.5

into kroah.com:/home/greg/linux/BK/gregkh-2.5
parents 94eda096 9c5e6f5a
......@@ -41,17 +41,13 @@ SPECIFIC DEVICES SUPPORTED
ConnectTech WhiteHEAT 4 port converter
ConnectTech has been very forthcoming with information about their
device, including providing a unit to test with. This driver will end up
being fully supported.
device, including providing a unit to test with.
Current status:
The device's firmware is downloaded on connection, the new firmware
runs properly and all four ports are successfully recognized and connected.
Data can be sent and received through the device on all ports.
Hardware flow control needs to be implemented.
The driver is officially supported by Connect Tech Inc.
http://www.connecttech.com
For any questions or problems with this driver, please contact Greg
Kroah-Hartman at greg@kroah.com
For any questions or problems with this driver, please contact
Stuart MacDonald at stuartm@connecttech.com
HandSpring Visor, Palm USB, and Clié USB driver
......
......@@ -1830,6 +1830,14 @@ L: linux-usb-devel@lists.sourceforge.net
W: http://www.kroah.com/linux/
S: Maintained
USB SERIAL WHITEHEAT DRIVER
P: Stuart MacDonald
M: stuartm@connecttech.com
L: linux-usb-users@lists.sourceforge.net
L: linux-usb-devel@lists.sourceforge.net
W: http://www.connecttech.com
S: Supported
USB SUBSYSTEM
P: Greg Kroah-Hartman
M: greg@kroah.com
......
......@@ -1142,6 +1142,7 @@ int usb_new_device(struct usb_device *dev, struct device *parent)
struct usb_interface_descriptor *desc = interface->altsetting;
interface->dev.parent = &dev->dev;
interface->dev.driver = NULL;
interface->dev.bus = &usb_bus_type;
sprintf (&interface->dev.bus_id[0], "%d-%s:%d",
dev->bus->busnum, dev->devpath,
......
......@@ -79,7 +79,7 @@ static void dbg_hcc_params (struct ehci_hcd *ehci, char *label)
if (HCC_EXT_CAPS (params)) {
// EHCI 0.96 ... could interpret these (legacy?)
dbg ("%s extended capabilities at pci %d",
dbg ("%s extended capabilities at pci %2x",
label, HCC_EXT_CAPS (params));
}
if (HCC_ISOC_CACHE (params)) {
......@@ -546,6 +546,18 @@ show_registers (struct device *dev, char *buf, size_t count, loff_t off)
next += temp;
}
#ifdef EHCI_STATS
temp = snprintf (next, size, "irq normal %ld err %ld reclaim %ld\n",
ehci->stats.normal, ehci->stats.error, ehci->stats.reclaim);
size -= temp;
next += temp;
temp = snprintf (next, size, "complete %ld unlink %ld qpatch %ld\n",
ehci->stats.complete, ehci->stats.unlink, ehci->stats.qpatch);
size -= temp;
next += temp;
#endif
spin_unlock_irqrestore (&ehci->lock, flags);
return count - size;
......
......@@ -63,8 +63,7 @@
* First was PCMCIA, like ISA; then CardBus, which is PCI.
* Next comes "CardBay", using USB 2.0 signals.
*
* Contains additional contributions by: Brad Hards, Rory Bolt, ...
*
* Contains additional contributions by Brad Hards, Rory Bolt, and others.
* Special thanks to Intel and VIA for providing host controllers to
* test this driver on, and Cypress (including In-System Design) for
* providing early devices for those host controllers to talk to!
......@@ -93,14 +92,20 @@
* 2001-June Works with usb-storage and NEC EHCI on 2.4
*/
#define DRIVER_VERSION "2002-Aug-28"
#define DRIVER_VERSION "2002-Sep-23"
#define DRIVER_AUTHOR "David Brownell"
#define DRIVER_DESC "USB 2.0 'Enhanced' Host Controller (EHCI) Driver"
static const char hcd_name [] = "ehci-hcd";
// #define EHCI_VERBOSE_DEBUG
// #define have_split_iso
#ifdef DEBUG
#define EHCI_STATS
#endif
#define INTR_AUTOMAGIC /* to be removed later in 2.5 */
/* magic numbers that can affect system performance */
......@@ -118,6 +123,12 @@ static int log2_irq_thresh = 0; // 0 to 6
MODULE_PARM (log2_irq_thresh, "i");
MODULE_PARM_DESC (log2_irq_thresh, "log2 IRQ latency, 1-64 microframes");
/* allow irqs at least every N URB completions */
static int max_completions = 16;
MODULE_PARM (max_completions, "i");
MODULE_PARM_DESC (max_completions,
"limit for urb completions called with irqs disenabled");
#define INTR_MASK (STS_IAA | STS_FATAL | STS_ERR | STS_INT)
/*-------------------------------------------------------------------------*/
......@@ -426,11 +437,10 @@ static int ehci_start (struct usb_hcd *hcd)
/* PCI Serial Bus Release Number is at 0x60 offset */
pci_read_config_byte (hcd->pdev, 0x60, &tempbyte);
temp = readw (&ehci->caps->hci_version);
info ("USB %x.%x support enabled, EHCI rev %x.%02x",
((tempbyte & 0xf0)>>4),
(tempbyte & 0x0f),
temp >> 8,
temp & 0xff);
info ("USB %x.%x support enabled, EHCI rev %x.%02x, %s %s",
((tempbyte & 0xf0)>>4), (tempbyte & 0x0f),
temp >> 8, temp & 0xff,
hcd_name, DRIVER_VERSION);
/*
* From here on, khubd concurrently accesses the root
......@@ -441,11 +451,7 @@ static int ehci_start (struct usb_hcd *hcd)
*/
usb_connect (udev);
udev->speed = USB_SPEED_HIGH;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,32)
if (usb_new_device (udev) != 0) {
#else
if (usb_register_root_hub (udev, &ehci->hcd.pdev->dev) != 0) {
#endif
if (hcd_register_root (hcd) != 0) {
if (hcd->state == USB_STATE_RUNNING)
ehci_ready (ehci);
ehci_reset (ehci);
......@@ -487,6 +493,13 @@ static void ehci_stop (struct usb_hcd *hcd)
ehci_tasklet ((unsigned long) ehci);
ehci_mem_cleanup (ehci);
#ifdef EHCI_STATS
dbg ("irq normal %ld err %ld reclaim %ld",
ehci->stats.normal, ehci->stats.error, ehci->stats.reclaim);
dbg ("complete %ld unlink %ld qpatch %ld",
ehci->stats.complete, ehci->stats.unlink, ehci->stats.qpatch);
#endif
dbg_status (ehci, "ehci_stop completed", readl (&ehci->regs->status));
}
......@@ -591,21 +604,16 @@ dbg ("%s: resume port %d", hcd_to_bus (hcd)->bus_name, i);
static void ehci_tasklet (unsigned long param)
{
struct ehci_hcd *ehci = (struct ehci_hcd *) param;
unsigned long flags;
// FIXME don't pass flags; on sparc they aren't really flags.
// qh_completions can just leave irqs blocked,
// then have scan_async() allow IRQs if it's very busy
spin_lock_irqsave (&ehci->lock, flags);
spin_lock_irq (&ehci->lock);
if (ehci->reclaim_ready)
flags = end_unlink_async (ehci, flags);
flags = scan_async (ehci, flags);
end_unlink_async (ehci);
scan_async (ehci);
if (ehci->next_uframe != -1)
flags = scan_periodic (ehci, flags);
scan_periodic (ehci);
spin_unlock_irqrestore (&ehci->lock, flags);
spin_unlock_irq (&ehci->lock);
}
/*-------------------------------------------------------------------------*/
......@@ -639,11 +647,17 @@ static void ehci_irq (struct usb_hcd *hcd)
/* INT, ERR, and IAA interrupt rates can be throttled */
/* normal [4.15.1.2] or error [4.15.1.1] completion */
if (likely ((status & (STS_INT|STS_ERR)) != 0))
if (likely ((status & (STS_INT|STS_ERR)) != 0)) {
if (likely ((status & STS_ERR) == 0))
COUNT (ehci->stats.normal);
else
COUNT (ehci->stats.error);
bh = 1;
}
/* complete the unlinking of some qh [4.15.2.3] */
if (status & STS_IAA) {
COUNT (ehci->stats.reclaim);
ehci->reclaim_ready = 1;
bh = 1;
}
......@@ -765,10 +779,10 @@ static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
spin_lock_irqsave (&ehci->lock, flags);
if (qh->qh_state == QH_STATE_LINKED) {
/* messy, can spin or block a microframe ... */
flags = intr_deschedule (ehci, qh, 1, flags);
intr_deschedule (ehci, qh, 1);
/* qh_state == IDLE */
}
flags = qh_completions (ehci, qh, flags);
qh_completions (ehci, qh);
/* reschedule QH iff another request is queued */
if (!list_empty (&qh->qtd_list)
......@@ -881,8 +895,6 @@ static void ehci_free_config (struct usb_hcd *hcd, struct usb_device *udev)
/*-------------------------------------------------------------------------*/
static const char hcd_name [] = "ehci-hcd";
static const struct hc_driver ehci_driver = {
.description = hcd_name,
......
......@@ -239,7 +239,8 @@ static int ehci_hub_control (
/* whoever resets must GetPortStatus to complete it!! */
if ((temp & PORT_RESET)
&& jiffies > ehci->reset_done [wIndex]) {
&& time_after (jiffies,
ehci->reset_done [wIndex])) {
status |= 1 << USB_PORT_FEAT_C_RESET;
/* force reset to complete */
......
......@@ -158,16 +158,13 @@ static inline void qtd_copy_status (struct urb *urb, size_t length, u32 token)
}
}
/* urb->lock ignored from here on (hcd is done with urb) */
static unsigned long ehci_urb_done (
struct ehci_hcd *ehci,
struct urb *urb,
unsigned long flags
) {
static void ehci_urb_done (struct ehci_hcd *ehci, struct urb *urb)
{
#ifdef INTR_AUTOMAGIC
struct urb *resubmit = 0;
struct usb_device *dev = 0;
static int ehci_urb_enqueue (struct usb_hcd *, struct urb *, int);
#endif
if (likely (urb->hcpriv != 0)) {
......@@ -199,8 +196,15 @@ static unsigned long ehci_urb_done (
urb->status = 0;
}
if (likely (urb->status == 0))
COUNT (ehci->stats.complete);
else if (urb->status == -ECONNRESET || urb->status == -ENOENT)
COUNT (ehci->stats.unlink);
else
COUNT (ehci->stats.error);
/* complete() can reenter this HCD */
spin_unlock_irqrestore (&ehci->lock, flags);
spin_unlock (&ehci->lock);
usb_hcd_giveback_urb (&ehci->hcd, urb);
#ifdef INTR_AUTOMAGIC
......@@ -222,24 +226,25 @@ static unsigned long ehci_urb_done (
}
#endif
spin_lock_irqsave (&ehci->lock, flags);
return flags;
spin_lock (&ehci->lock);
}
/*
* Process and free completed qtds for a qh, returning URBs to drivers.
* Chases up to qh->hw_current, returns irqsave flags (maybe modified).
* Chases up to qh->hw_current. Returns number of completions called,
* indicating how much "real" work we did.
*/
static unsigned long
qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh, unsigned long flags)
static unsigned
qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
{
struct ehci_qtd *qtd, *last;
struct list_head *next, *qtd_list = &qh->qtd_list;
int unlink = 0, halted = 0;
unsigned count = 0;
if (unlikely (list_empty (qtd_list)))
return flags;
return count;
/* scan QTDs till end of list, or we reach an active one */
for (qtd = list_entry (qtd_list->next, struct ehci_qtd, qtd_list),
......@@ -252,8 +257,10 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh, unsigned long flags)
/* clean up any state from previous QTD ...*/
if (last) {
if (likely (last->urb != urb))
flags = ehci_urb_done (ehci, last->urb, flags);
if (likely (last->urb != urb)) {
ehci_urb_done (ehci, last->urb);
count++;
}
/* qh overlays can have HC's old cached copies of
* next qtd ptrs, if an URB was queued afterwards.
......@@ -262,6 +269,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh, unsigned long flags)
&& last->hw_next != qh->hw_qtd_next) {
qh->hw_alt_next = last->hw_alt_next;
qh->hw_qtd_next = last->hw_next;
COUNT (ehci->stats.qpatch);
}
ehci_qtd_free (ehci, last);
......@@ -347,7 +355,8 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh, unsigned long flags)
/* last urb's completion might still need calling */
if (likely (last != 0)) {
flags = ehci_urb_done (ehci, last->urb, flags);
ehci_urb_done (ehci, last->urb);
count++;
ehci_qtd_free (ehci, last);
}
......@@ -357,7 +366,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh, unsigned long flags)
struct ehci_qtd, qtd_list));
}
return flags;
return count;
}
/*-------------------------------------------------------------------------*/
......@@ -890,8 +899,7 @@ submit_async (
/* the async qh for the qtds being reclaimed are now unlinked from the HC */
/* caller must not own ehci->lock */
static unsigned long
end_unlink_async (struct ehci_hcd *ehci, unsigned long flags)
static void end_unlink_async (struct ehci_hcd *ehci)
{
struct ehci_qh *qh = ehci->reclaim;
......@@ -903,18 +911,15 @@ end_unlink_async (struct ehci_hcd *ehci, unsigned long flags)
ehci->reclaim = 0;
ehci->reclaim_ready = 0;
flags = qh_completions (ehci, qh, flags);
qh_completions (ehci, qh);
if (!list_empty (&qh->qtd_list)
&& HCD_IS_RUNNING (ehci->hcd.state))
qh_link_async (ehci, qh);
else
qh_put (ehci, qh); // refcount from async list
return flags;
}
/* makes sure the async qh will become idle */
/* caller must own ehci->lock */
......@@ -944,12 +949,14 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
if (unlikely (qh == ehci->async && qh->qh_next.qh == qh)) {
/* can't get here without STS_ASS set */
if (ehci->hcd.state != USB_STATE_HALT) {
if (cmd & CMD_PSE) {
writel (cmd & ~CMD_ASE, &ehci->regs->command);
(void) handshake (&ehci->regs->status,
STS_ASS, 0, 150);
} else
ehci_ready (ehci);
(void) handshake (&ehci->regs->status, STS_ASS, 0, 150);
#if 0
// one VT8235 system wants to die with STS_FATAL
// unless this qh is leaked here. others seem ok...
qh = qh_get (qh);
dbg_qh ("async/off", ehci, qh);
#endif
}
qh->qh_next.qh = ehci->async = 0;
......@@ -986,13 +993,15 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
/*-------------------------------------------------------------------------*/
static unsigned long
scan_async (struct ehci_hcd *ehci, unsigned long flags)
static void
scan_async (struct ehci_hcd *ehci)
{
struct ehci_qh *qh;
unsigned count;
rescan:
qh = ehci->async;
count = 0;
if (likely (qh != 0)) {
do {
/* clean any finished work for this qh */
......@@ -1001,13 +1010,16 @@ scan_async (struct ehci_hcd *ehci, unsigned long flags)
qh = qh_get (qh);
/* concurrent unlink could happen here */
flags = qh_completions (ehci, qh, flags);
count += qh_completions (ehci, qh);
qh_put (ehci, qh);
}
/* unlink idle entries, reducing HC PCI usage as
* well as HCD schedule-scanning costs. removing
* the last qh is deferred, since it's costly.
*
* FIXME don't unlink idle entries so quickly; it
* can penalize (common) half duplex protocols.
*/
if (list_empty (&qh->qtd_list) && !ehci->reclaim) {
if (qh->qh_next.qh != qh) {
......@@ -1020,10 +1032,18 @@ scan_async (struct ehci_hcd *ehci, unsigned long flags)
jiffies + EHCI_ASYNC_JIFFIES);
}
}
/* keep latencies down: let any irqs in */
if (count > max_completions) {
spin_unlock_irq (&ehci->lock);
cpu_relax ();
spin_lock_irq (&ehci->lock);
goto rescan;
}
qh = qh->qh_next.qh;
if (!qh) /* unlinked? */
goto rescan;
} while (qh != ehci->async);
}
return flags;
}
......@@ -222,11 +222,10 @@ static int disable_periodic (struct ehci_hcd *ehci)
// FIXME microframe periods not yet handled
static unsigned long intr_deschedule (
static void intr_deschedule (
struct ehci_hcd *ehci,
struct ehci_qh *qh,
int wait,
unsigned long flags
int wait
) {
int status;
unsigned frame = qh->start;
......@@ -256,10 +255,8 @@ static unsigned long intr_deschedule (
*/
if (((ehci_get_frame (&ehci->hcd) - frame) % qh->period) == 0) {
if (wait) {
spin_unlock_irqrestore (&ehci->lock, flags);
udelay (125);
qh->hw_next = EHCI_LIST_END;
spin_lock_irqsave (&ehci->lock, flags);
} else {
/* we may not be IDLE yet, but if the qh is empty
* the race is very short. then if qh also isn't
......@@ -276,10 +273,9 @@ static unsigned long intr_deschedule (
hcd_to_bus (&ehci->hcd)->bandwidth_allocated -=
(qh->usecs + qh->c_usecs) / qh->period;
vdbg ("descheduled qh %p, per = %d frame = %d count = %d, urbs = %d",
dbg ("descheduled qh %p, period = %d frame = %d count = %d, urbs = %d",
qh, qh->period, frame,
atomic_read (&qh->refcount), ehci->periodic_sched);
return flags;
}
static int check_period (
......@@ -414,7 +410,7 @@ static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh)
/* stuff into the periodic schedule */
qh->qh_state = QH_STATE_LINKED;
dbg ("qh %p usecs %d/%d period %d.0 starting %d.%d (gap %d)",
dbg ("scheduled qh %p usecs %d/%d period %d.0 starting %d.%d (gap %d)",
qh, qh->usecs, qh->c_usecs,
qh->period, frame, uframe, qh->gap_uf);
do {
......@@ -495,29 +491,30 @@ static int intr_submit (
return status;
}
static unsigned long
static unsigned
intr_complete (
struct ehci_hcd *ehci,
unsigned frame,
struct ehci_qh *qh,
unsigned long flags /* caller owns ehci->lock ... */
struct ehci_qh *qh
) {
unsigned count;
/* nothing to report? */
if (likely ((qh->hw_token & __constant_cpu_to_le32 (QTD_STS_ACTIVE))
!= 0))
return flags;
return 0;
if (unlikely (list_empty (&qh->qtd_list))) {
dbg ("intr qh %p no TDs?", qh);
return flags;
return 0;
}
/* handle any completions */
flags = qh_completions (ehci, qh, flags);
count = qh_completions (ehci, qh);
if (unlikely (list_empty (&qh->qtd_list)))
flags = intr_deschedule (ehci, qh, 0, flags);
intr_deschedule (ehci, qh, 0);
return flags;
return count;
}
/*-------------------------------------------------------------------------*/
......@@ -866,12 +863,11 @@ itd_schedule (struct ehci_hcd *ehci, struct urb *urb)
#define ISO_ERRS (EHCI_ISOC_BUF_ERR | EHCI_ISOC_BABBLE | EHCI_ISOC_XACTERR)
static unsigned long
static unsigned
itd_complete (
struct ehci_hcd *ehci,
struct ehci_itd *itd,
unsigned uframe,
unsigned long flags
unsigned uframe
) {
struct urb *urb = itd->urb;
struct usb_iso_packet_descriptor *desc;
......@@ -909,7 +905,7 @@ itd_complete (
/* handle completion now? */
if ((itd->index + 1) != urb->number_of_packets)
return flags;
return 0;
/*
* Always give the urb back to the driver ... expect it to submit
......@@ -924,16 +920,17 @@ itd_complete (
if (urb->status == -EINPROGRESS)
urb->status = 0;
spin_unlock_irqrestore (&ehci->lock, flags);
/* complete() can reenter this HCD */
spin_unlock (&ehci->lock);
usb_hcd_giveback_urb (&ehci->hcd, urb);
spin_lock_irqsave (&ehci->lock, flags);
spin_lock (&ehci->lock);
/* defer stopping schedule; completion can submit */
ehci->periodic_sched--;
if (!ehci->periodic_sched)
(void) disable_periodic (ehci);
return flags;
return 1;
}
/*-------------------------------------------------------------------------*/
......@@ -945,10 +942,6 @@ static int itd_submit (struct ehci_hcd *ehci, struct urb *urb, int mem_flags)
dbg ("itd_submit urb %p", urb);
/* NOTE DMA mapping assumes this ... */
if (urb->iso_frame_desc [0].offset != 0)
return -EINVAL;
/* allocate ITDs w/o locking anything */
status = itd_urb_transaction (ehci, urb, mem_flags);
if (status < 0)
......@@ -979,10 +972,11 @@ static int itd_submit (struct ehci_hcd *ehci, struct urb *urb, int mem_flags)
/*-------------------------------------------------------------------------*/
static unsigned long
scan_periodic (struct ehci_hcd *ehci, unsigned long flags)
static void
scan_periodic (struct ehci_hcd *ehci)
{
unsigned frame, clock, now_uframe, mod;
unsigned count = 0;
mod = ehci->periodic_size << 3;
......@@ -1005,6 +999,14 @@ scan_periodic (struct ehci_hcd *ehci, unsigned long flags)
u32 type, *hw_p;
unsigned uframes;
/* keep latencies down: let any irqs in */
if (count > max_completions) {
spin_unlock_irq (&ehci->lock);
cpu_relax ();
count = 0;
spin_lock_irq (&ehci->lock);
}
restart:
/* scan schedule to _before_ current frame index */
if (frame == clock)
......@@ -1028,8 +1030,8 @@ scan_periodic (struct ehci_hcd *ehci, unsigned long flags)
last = (q.qh->hw_next == EHCI_LIST_END);
temp = q.qh->qh_next;
type = Q_NEXT_TYPE (q.qh->hw_next);
flags = intr_complete (ehci, frame,
qh_get (q.qh), flags);
count += intr_complete (ehci, frame,
qh_get (q.qh));
qh_put (ehci, q.qh);
q = temp;
break;
......@@ -1061,8 +1063,8 @@ scan_periodic (struct ehci_hcd *ehci, unsigned long flags)
type = Q_NEXT_TYPE (*hw_p);
/* might free q.itd ... */
flags = itd_complete (ehci,
temp.itd, uf, flags);
count += itd_complete (ehci,
temp.itd, uf);
break;
}
}
......@@ -1078,7 +1080,7 @@ scan_periodic (struct ehci_hcd *ehci, unsigned long flags)
#ifdef have_split_iso
case Q_TYPE_SITD:
last = (q.sitd->hw_next == EHCI_LIST_END);
flags = sitd_complete (ehci, q.sitd, flags);
sitd_complete (ehci, q.sitd);
type = Q_NEXT_TYPE (q.sitd->hw_next);
// FIXME unlink SITD after split completes
......@@ -1124,5 +1126,4 @@ scan_periodic (struct ehci_hcd *ehci, unsigned long flags)
} else
frame = (frame + 1) % ehci->periodic_size;
}
return flags;
}
......@@ -21,6 +21,23 @@
/* definitions used for the EHCI driver */
/* statistics can be kept for for tuning/monitoring */
struct ehci_stats {
/* irq usage */
unsigned long normal;
unsigned long error;
unsigned long reclaim;
/* termination of urbs from core */
unsigned long complete;
unsigned long unlink;
/* qhs patched to recover from td queueing race
* (can avoid by using 'dummy td', allowing fewer irqs)
*/
unsigned long qpatch;
};
/* ehci_hcd->lock guards shared data against other CPUs:
* ehci_hcd: async, reclaim, periodic (and shadow), ...
* hcd_dev: ep[]
......@@ -72,6 +89,13 @@ struct ehci_hcd { /* one per controller */
struct pci_pool *sitd_pool; /* sitd per split iso urb */
struct timer_list watchdog;
#ifdef EHCI_STATS
struct ehci_stats stats;
# define COUNT(x) do { (x)++; } while (0)
#else
# define COUNT(x) do {} while (0)
#endif
};
/* unwrap an HCD pointer to get an EHCI_HCD pointer */
......@@ -400,10 +424,22 @@ struct ehci_fstn {
#define SUBMIT_URB(urb,mem_flags) usb_submit_urb(urb)
#define STUB_DEBUG_FILES
static inline int hcd_register_root (struct usb_hcd *hcd)
{
return usb_new_device (hcd_to_bus (hcd)->root_hub);
}
#else /* LINUX_VERSION_CODE */
// hcd_to_bus() eventually moves to hcd.h on 2.5 too
static inline struct usb_bus *hcd_to_bus (struct usb_hcd *hcd)
{ return &hcd->self; }
// ... as does hcd_register_root()
static inline int hcd_register_root (struct usb_hcd *hcd)
{
return usb_register_root_hub (
hcd_to_bus (hcd)->root_hub, &hcd->pdev->dev);
}
#define SUBMIT_URB(urb,mem_flags) usb_submit_urb(urb,mem_flags)
......
......@@ -92,6 +92,7 @@
#endif
#include <linux/usb.h>
#include <linux/version.h>
#include "../core/hcd.h"
#include <asm/io.h>
......@@ -108,7 +109,7 @@
* - lots more testing!!
*/
#define DRIVER_VERSION "2002-Sep-03"
#define DRIVER_VERSION "2002-Sep-17"
#define DRIVER_AUTHOR "Roman Weissgaerber, David Brownell"
#define DRIVER_DESC "USB 1.1 'Open' Host Controller (OHCI) Driver"
......@@ -318,9 +319,6 @@ ohci_free_config (struct usb_hcd *hcd, struct usb_device *udev)
struct hcd_dev *dev = (struct hcd_dev *) udev->hcpriv;
int i;
unsigned long flags;
#ifdef DEBUG
int rescans = 0;
#endif
rescan:
/* free any eds, and dummy tds, still hanging around */
......@@ -340,16 +338,18 @@ ohci_free_config (struct usb_hcd *hcd, struct usb_device *udev)
td_free (ohci, ed->dummy);
break;
default:
#ifdef DEBUG
err ("illegal ED %d state in free_config, %d",
err ("%s-%s ed %p (#%d) not unlinked; disconnect() bug? %d",
ohci->hcd.self.bus_name, udev->devpath, ed,
i, ed->state);
#endif
/* ED_OPER: some driver disconnect() is broken,
* it didn't even start its unlinks much less wait
* for their completions.
* OTHERWISE: hcd bug, ed is garbage
*
* ... we can't recycle this memory in either case,
* so just leak it to avoid oopsing.
*/
BUG ();
continue;
}
ed_free (ohci, ed);
}
......@@ -360,13 +360,9 @@ ohci_free_config (struct usb_hcd *hcd, struct usb_device *udev)
#ifdef DEBUG
/* a driver->disconnect() returned before its unlinks completed? */
if (in_interrupt ()) {
dbg ("WARNING: spin in interrupt; driver->disconnect() bug");
dbg ("dev usb-%s-%s ep 0x%x",
warn ("disconnect() bug for dev usb-%s-%s ep 0x%x",
ohci->hcd.self.bus_name, udev->devpath, i);
}
BUG_ON (!(readl (&ohci->regs->intrenable) & OHCI_INTR_SF));
BUG_ON (rescans >= 2); /* HWBUG */
rescans++;
#endif
spin_unlock_irqrestore (&ohci->lock, flags);
......
......@@ -36,12 +36,7 @@ static void finish_urb (struct ohci_hcd *ohci, struct urb *urb)
{
unsigned long flags;
#ifdef DEBUG
if (!urb->hcpriv) {
err ("already unlinked!");
BUG ();
}
#endif
// ASSERT (urb->hcpriv != 0);
urb_free_priv (ohci, urb->hcpriv);
urb->hcpriv = NULL;
......@@ -51,6 +46,7 @@ static void finish_urb (struct ohci_hcd *ohci, struct urb *urb)
urb->status = 0;
spin_unlock_irqrestore (&urb->lock, flags);
// what lock protects these?
switch (usb_pipetype (urb->pipe)) {
case PIPE_ISOCHRONOUS:
ohci->hcd.self.bandwidth_isoc_reqs--;
......@@ -425,6 +421,9 @@ static struct ed *ed_get (
/* FIXME: Don't do this without knowing it's safe to clobber this
* state/mode info. Currently the upper layers don't support such
* guarantees; we're lucky changing config/altsetting is rare.
* The state/mode info also changes during enumeration: set_address
* uses the 'wrong' device address, and ep0 maxpacketsize will often
* improve on the initial value.
*/
if (ed->state == ED_IDLE) {
u32 info;
......@@ -454,25 +453,6 @@ static struct ed *ed_get (
}
ed->hwINFO = info;
#ifdef DEBUG
/*
* There are two other cases we ought to change hwINFO, both during
* enumeration. There, the control request completes, unlinks, and
* the next request gets queued before the unlink completes, so it
* uses old/wrong hwINFO. How much of a problem is this? khubd is
* already retrying after such failures...
*/
} else if (type == PIPE_CONTROL) {
u32 info = le32_to_cpup (&ed->hwINFO);
if (!(info & 0x7f))
dbg ("RETRY ctrl: address != 0");
info >>= 16;
if (info != udev->epmaxpacketin [0])
dbg ("RETRY ctrl: maxpacket %d != 8",
udev->epmaxpacketin [0]);
#endif /* DEBUG */
}
done:
......@@ -526,10 +506,7 @@ td_fill (unsigned int info,
struct urb_priv *urb_priv = urb->hcpriv;
int is_iso = info & TD_ISO;
if (index >= urb_priv->length) {
err ("internal OHCI error: TD index > length");
return;
}
// ASSERT (index < urb_priv->length);
/* aim for only one interrupt per urb. mostly applies to control
* and iso; other urbs rarely need more than one TD per urb.
......@@ -578,6 +555,7 @@ td_fill (unsigned int info,
wmb ();
/* append to queue */
list_add_tail (&td->td_list, &td->ed->td_list);
td->ed->hwTailP = td->hwNextTD;
}
......@@ -698,8 +676,7 @@ static void td_submit_urb (
ohci->hcd.self.bandwidth_isoc_reqs++;
break;
}
if (urb_priv->length != cnt)
dbg ("TD LENGTH %d != CNT %d", urb_priv->length, cnt);
// ASSERT (urb_priv->length == cnt);
}
/*-------------------------------------------------------------------------*
......@@ -714,6 +691,8 @@ static void td_done (struct urb *urb, struct td *td)
u32 tdINFO = le32_to_cpup (&td->hwINFO);
int cc = 0;
list_del (&td->td_list);
/* ISO ... drivers see per-TD length/status */
if (tdINFO & TD_ISO) {
u16 tdPSW = le16_to_cpu (td->hwPSW [0]);
......@@ -792,74 +771,106 @@ static void td_done (struct urb *urb, struct td *td)
/*-------------------------------------------------------------------------*/
static inline struct td *
ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev)
{
struct urb *urb = td->urb;
struct ed *ed = td->ed;
struct list_head *tmp = td->td_list.next;
u32 toggle = ed->hwHeadP & ED_C;
/* clear ed halt; this is the td that caused it, but keep it inactive
* until its urb->complete() has a chance to clean up.
*/
ed->hwINFO |= ED_SKIP;
wmb ();
td->ed->hwHeadP &= ~ED_H;
while (tmp != &ed->td_list) {
struct td *next;
next = list_entry (tmp, struct td, td_list);
tmp = next->td_list.next;
/* move other tds from this urb to the donelist, after 'td'.
* order won't matter here: no errors, nothing transferred.
*
* NOTE: this "knows" short control reads won't need fixup:
* hc went from the (one) data TD to the status td. that'll
* change if multi-td control DATA segments are supported,
* and we want to send the status packet.
*/
if (next->urb == urb) {
u32 info = next->hwINFO;
info |= cpu_to_le32 (TD_DONE);
info &= ~cpu_to_le32 (TD_CC);
next->hwINFO = info;
next->next_dl_td = rev;
rev = next;
continue;
}
/* restart ed with first td of this next urb */
ed->hwHeadP = cpu_to_le32 (next->td_dma) | toggle;
tmp = 0;
break;
}
/* no urbs queued? then ED is empty. */
if (tmp)
ed->hwHeadP = cpu_to_le32 (ed->dummy->td_dma) | toggle;
/* help for troubleshooting: */
dbg ("urb %p usb-%s-%s ep-%d-%s cc %d --> status %d",
urb,
urb->dev->bus->bus_name, urb->dev->devpath,
usb_pipeendpoint (urb->pipe),
usb_pipein (urb->pipe) ? "IN" : "OUT",
cc, cc_to_error [cc]);
return rev;
}
/* replies to the request have to be on a FIFO basis so
* we unreverse the hc-reversed done-list
*/
static struct td *dl_reverse_done_list (struct ohci_hcd *ohci)
{
__u32 td_list_hc;
u32 td_dma;
struct td *td_rev = NULL;
struct td *td_list = NULL;
urb_priv_t *urb_priv = NULL;
struct td *td = NULL;
unsigned long flags;
spin_lock_irqsave (&ohci->lock, flags);
td_list_hc = le32_to_cpup (&ohci->hcca->done_head);
td_dma = le32_to_cpup (&ohci->hcca->done_head);
ohci->hcca->done_head = 0;
while (td_list_hc) {
/* get TD from hc's singly linked list, and
* prepend to ours. ed->td_list changes later.
*/
while (td_dma) {
int cc;
td_list = dma_to_td (ohci, td_list_hc);
td_list->hwINFO |= cpu_to_le32 (TD_DONE);
td = dma_to_td (ohci, td_dma);
cc = TD_CC_GET (le32_to_cpup (&td_list->hwINFO));
if (cc != TD_CC_NOERROR) {
urb_priv = (urb_priv_t *) td_list->urb->hcpriv;
td->hwINFO |= cpu_to_le32 (TD_DONE);
cc = TD_CC_GET (le32_to_cpup (&td->hwINFO));
/* Non-iso endpoints can halt on error; un-halt,
* and dequeue any other TDs from this urb.
* No other TD could have caused the halt.
*/
if (td_list->ed->hwHeadP & ED_H) {
if (urb_priv && ((td_list->index + 1)
< urb_priv->length)) {
#ifdef DEBUG
struct urb *urb = td_list->urb;
/* help for troubleshooting: */
dbg ("urb %p usb-%s-%s ep-%d-%s "
"(td %d/%d), "
"cc %d --> status %d",
td_list->urb,
urb->dev->bus->bus_name,
urb->dev->devpath,
usb_pipeendpoint (urb->pipe),
usb_pipein (urb->pipe)
? "IN" : "OUT",
1 + td_list->index,
urb_priv->length,
cc, cc_to_error [cc]);
#endif
td_list->ed->hwHeadP =
(urb_priv->td [urb_priv->length - 1]->hwNextTD
& __constant_cpu_to_le32 (TD_MASK))
| (td_list->ed->hwHeadP & ED_C);
urb_priv->td_cnt += urb_priv->length
- td_list->index - 1;
} else
td_list->ed->hwHeadP &= ~ED_H;
}
}
if (cc != TD_CC_NOERROR && (td->ed->hwHeadP & ED_H))
td_rev = ed_halted (ohci, td, cc, td_rev);
td_list->next_dl_td = td_rev;
td_rev = td_list;
td_list_hc = le32_to_cpup (&td_list->hwNextTD);
td->next_dl_td = td_rev;
td_rev = td;
td_dma = le32_to_cpup (&td->hwNextTD);
}
spin_unlock_irqrestore (&ohci->lock, flags);
return td_list;
return td_rev;
}
/*-------------------------------------------------------------------------*/
......@@ -874,9 +885,9 @@ static void finish_unlinks (struct ohci_hcd *ohci, u16 tick)
rescan_all:
for (last = &ohci->ed_rm_list, ed = *last; ed != NULL; ed = *last) {
struct td *td, *td_next, *tdHeadP, *tdTailP;
u32 *td_p;
struct list_head *entry, *tmp;
int completed, modified;
u32 *prev;
/* only take off EDs that the HC isn't using, accounting for
* frame counter wraps.
......@@ -897,53 +908,52 @@ static void finish_unlinks (struct ohci_hcd *ohci, u16 tick)
/* unlink urbs as requested, but rescan the list after
* we call a completion since it might have unlinked
* another (earlier) urb
*
* FIXME use td_list to scan, not td hashtables.
*/
rescan_this:
completed = 0;
prev = &ed->hwHeadP;
list_for_each_safe (entry, tmp, &ed->td_list) {
struct td *td;
struct urb *urb;
urb_priv_t *urb_priv;
u32 savebits;
tdTailP = dma_to_td (ohci, le32_to_cpup (&ed->hwTailP));
tdHeadP = dma_to_td (ohci, le32_to_cpup (&ed->hwHeadP));
td_p = &ed->hwHeadP;
td = list_entry (entry, struct td, td_list);
urb = td->urb;
urb_priv = td->urb->hcpriv;
for (td = tdHeadP; td != tdTailP; td = td_next) {
struct urb *urb = td->urb;
urb_priv_t *urb_priv = td->urb->hcpriv;
if (urb_priv->state != URB_DEL) {
prev = &td->hwNextTD;
continue;
}
td_next = dma_to_td (ohci,
le32_to_cpup (&td->hwNextTD));
if (urb_priv->state == URB_DEL) {
/* patch pointer hc uses */
savebits = *prev & cpu_to_le32 (TD_MASK);
*prev = td->hwNextTD | savebits;
/* HC may have partly processed this TD */
td_done (urb, td);
urb_priv->td_cnt++;
*td_p = td->hwNextTD | (*td_p & ~TD_MASK);
/* URB is done; clean up */
/* if URB is done, clean up */
if (urb_priv->td_cnt == urb_priv->length) {
modified = completed = 1;
spin_unlock (&ohci->lock);
finish_urb (ohci, urb);
spin_lock (&ohci->lock);
}
} else {
td_p = &td->hwNextTD;
}
}
if (completed && !list_empty (&ed->td_list))
goto rescan_this;
/* ED's now officially unlinked, hc doesn't see */
ed->state = ED_IDLE;
ed->hwINFO &= ~ED_SKIP;
ed->hwINFO &= ~(ED_SKIP | ED_DEQUEUE);
ed->hwHeadP &= ~ED_H;
ed->hwNextED = 0;
/* but if there's work queued, reschedule */
tdHeadP = dma_to_td (ohci, le32_to_cpup (&ed->hwHeadP));
if (tdHeadP != tdTailP) {
if (completed)
goto rescan_this;
if (!list_empty (&ed->td_list)) {
if (!ohci->disabled && !ohci->sleeping)
ed_schedule (ohci, ed);
}
......@@ -1027,10 +1037,15 @@ static void dl_done_list (struct ohci_hcd *ohci, struct td *td)
}
/* clean schedule: unlink EDs that are no longer busy */
if ((ed->hwHeadP & __constant_cpu_to_le32 (TD_MASK))
== ed->hwTailP
&& (ed->state == ED_OPER))
if (list_empty (&ed->td_list))
ed_deschedule (ohci, ed);
/* ... reenabling halted EDs only after fault cleanup */
else if (!(ed->hwINFO & ED_DEQUEUE)) {
td = list_entry (ed->td_list.next, struct td, td_list);
if (!(td->hwINFO & TD_DONE))
ed->hwINFO &= ~ED_SKIP;
}
td = td_next;
}
spin_unlock_irqrestore (&ohci->lock, flags);
......
......@@ -112,3 +112,13 @@ CONFIG_USB_SPEEDTCH
For more information, see Johan Verrept's webpages at
<http://linux-usb.sourceforge.net/SpeedTouch/>.
CONFIG_USB_LCD
Say Y here if you want to connect an USBLCD to your computer's
USB port. The USBLCD is a small USB interface board for
alphanumeric LCD modules. See <http://www.usblcd.de> for more
information.
This code is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
The module will be called usblcd.o. If you want to compile it as
a module, say M here and read <file:Documentation/modules.txt>.
/*****************************************************************************
* USBLCD Kernel Driver *
* See http://www.usblcd.de for Hardware and Documentation. *
* Version 1.01 *
* Version 1.03 *
* (C) 2002 Adams IT Services <info@usblcd.de> *
* *
* This file is licensed under the GPL. See COPYING in the package. *
......@@ -18,7 +18,7 @@
#include <asm/uaccess.h>
#include <linux/usb.h>
#define DRIVER_VERSION "USBLCD Driver Version 1.01"
#define DRIVER_VERSION "USBLCD Driver Version 1.03"
#define USBLCD_MINOR 144
......@@ -26,7 +26,7 @@
#define IOCTL_GET_DRV_VERSION 2
/* stall/wait timeout for USBLCD */
#define NAK_TIMEOUT (HZ)
#define NAK_TIMEOUT (10*HZ)
#define IBUF_SIZE 0x1000
#define OBUF_SIZE 0x10000
......@@ -318,7 +318,7 @@ static void disconnect_lcd(struct usb_interface *intf)
}
static struct usb_device_id id_table [] = {
{ .idVendor = 0x1212, .match_flags = USB_DEVICE_ID_MATCH_VENDOR, },
{ .idVendor = 0x10D2, .match_flags = USB_DEVICE_ID_MATCH_VENDOR, },
{},
};
......
......@@ -232,6 +232,7 @@ struct usb_serial_device_type {
extern int usb_serial_register(struct usb_serial_device_type *new_device);
extern void usb_serial_deregister(struct usb_serial_device_type *device);
extern void usb_serial_port_softint(void *private);
extern int usb_serial_probe(struct usb_interface *iface, const struct usb_device_id *id);
extern void usb_serial_disconnect(struct usb_interface *iface);
......
......@@ -498,7 +498,7 @@ int ezusb_writememory (struct usb_serial *serial, int address, unsigned char *da
return -ENOMEM;
}
memcpy (transfer_buffer, data, length);
result = usb_control_msg (serial->dev, usb_sndctrlpipe(serial->dev, 0), bRequest, 0x40, address, 0, transfer_buffer, length, 300);
result = usb_control_msg (serial->dev, usb_sndctrlpipe(serial->dev, 0), bRequest, 0x40, address, 0, transfer_buffer, length, 3*HZ);
kfree (transfer_buffer);
return result;
}
......@@ -557,13 +557,12 @@ static int serial_open (struct tty_struct *tty, struct file * filp)
retval = serial->type->open(port, filp);
else
retval = generic_open(port, filp);
}
if (retval) {
port->open_count = 0;
if (serial->type->owner)
__MOD_DEC_USE_COUNT(serial->type->owner);
}
}
up (&port->sem);
return retval;
......@@ -1091,6 +1090,8 @@ static void generic_write_bulk_callback (struct urb *urb)
return;
}
usb_serial_port_softint((void *)port);
queue_task(&port->tqueue, &tq_immediate);
mark_bh(IMMEDIATE_BH);
......@@ -1109,14 +1110,18 @@ static void generic_shutdown (struct usb_serial *serial)
}
}
static void port_softint(void *private)
void usb_serial_port_softint(void *private)
{
struct usb_serial_port *port = (struct usb_serial_port *)private;
struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
struct usb_serial *serial;
struct tty_struct *tty;
dbg("%s - port %d", __FUNCTION__, port->number);
if (!port)
return;
serial = get_usb_serial (port, __FUNCTION__);
if (!serial)
return;
......@@ -1400,7 +1405,7 @@ int usb_serial_probe(struct usb_interface *interface,
port->number = i + serial->minor;
port->serial = serial;
port->magic = USB_SERIAL_PORT_MAGIC;
port->tqueue.routine = port_softint;
port->tqueue.routine = usb_serial_port_softint;
port->tqueue.data = port;
init_MUTEX (&port->sem);
}
......@@ -1690,6 +1695,7 @@ EXPORT_SYMBOL(usb_serial_register);
EXPORT_SYMBOL(usb_serial_deregister);
EXPORT_SYMBOL(usb_serial_probe);
EXPORT_SYMBOL(usb_serial_disconnect);
EXPORT_SYMBOL(usb_serial_port_softint);
#ifdef USES_EZUSB_FUNCTIONS
EXPORT_SYMBOL(ezusb_writememory);
EXPORT_SYMBOL(ezusb_set_reset);
......
/*
* USB ConnectTech WhiteHEAT driver
*
* Copyright (C) 2002
* Connect Tech Inc.
*
* Copyright (C) 1999 - 2001
* Greg Kroah-Hartman (greg@kroah.com)
*
......@@ -11,6 +14,9 @@
*
* See Documentation/usb/usb-serial.txt for more information on using this driver
*
* (10/09/2002) Stuart MacDonald (stuartm@connecttech.com)
* Upgrade to full working driver
*
* (05/30/2001) gkh
* switched from using spinlock to a semaphore, which fixes lots of problems.
*
......@@ -71,6 +77,8 @@
#include <linux/spinlock.h>
#include <asm/uaccess.h>
#include <linux/usb.h>
#include <linux/serial_reg.h>
#include <linux/serial.h>
#ifdef CONFIG_USB_SERIAL_DEBUG
static int debug = 1;
......@@ -85,8 +93,8 @@
/*
* Version Information
*/
#define DRIVER_VERSION "v1.2"
#define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>"
#define DRIVER_VERSION "v2.0"
#define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Stuart MacDonald <stuartm@connecttech.com>"
#define DRIVER_DESC "USB ConnectTech WhiteHEAT driver"
#define CONNECT_TECH_VENDOR_ID 0x0710
......@@ -125,16 +133,25 @@ static struct usb_driver whiteheat_driver = {
.id_table = id_table_combined,
};
/* function prototypes for the Connect Tech WhiteHEAT prerenumeration device */
static int whiteheat_firmware_download (struct usb_serial *serial);
static int whiteheat_firmware_attach (struct usb_serial *serial);
/* function prototypes for the Connect Tech WhiteHEAT serial converter */
static int whiteheat_attach (struct usb_serial *serial);
static void whiteheat_shutdown (struct usb_serial *serial);
static int whiteheat_open (struct usb_serial_port *port, struct file *filp);
static void whiteheat_close (struct usb_serial_port *port, struct file *filp);
static int whiteheat_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count);
static int whiteheat_write_room (struct usb_serial_port *port);
static int whiteheat_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
static void whiteheat_set_termios (struct usb_serial_port *port, struct termios * old);
static void whiteheat_break_ctl (struct usb_serial_port *port, int break_state);
static int whiteheat_chars_in_buffer (struct usb_serial_port *port);
static void whiteheat_throttle (struct usb_serial_port *port);
static void whiteheat_unthrottle (struct usb_serial_port *port);
static int whiteheat_firmware_download (struct usb_serial *serial);
static int whiteheat_attach (struct usb_serial *serial);
static void whiteheat_shutdown (struct usb_serial *serial);
static void whiteheat_read_callback (struct urb *urb);
static void whiteheat_write_callback (struct urb *urb);
static struct usb_serial_device_type whiteheat_fake_device = {
.owner = THIS_MODULE,
......@@ -145,6 +162,7 @@ static struct usb_serial_device_type whiteheat_fake_device = {
.num_bulk_out = NUM_DONT_CARE,
.num_ports = 1,
.probe = whiteheat_firmware_download,
.attach = whiteheat_firmware_attach,
};
static struct usb_serial_device_type whiteheat_device = {
......@@ -155,201 +173,311 @@ static struct usb_serial_device_type whiteheat_device = {
.num_bulk_in = NUM_DONT_CARE,
.num_bulk_out = NUM_DONT_CARE,
.num_ports = 4,
.attach = whiteheat_attach,
.shutdown = whiteheat_shutdown,
.open = whiteheat_open,
.close = whiteheat_close,
.throttle = whiteheat_throttle,
.unthrottle = whiteheat_unthrottle,
.write = whiteheat_write,
.write_room = whiteheat_write_room,
.ioctl = whiteheat_ioctl,
.set_termios = whiteheat_set_termios,
.attach = whiteheat_attach,
.shutdown = whiteheat_shutdown,
.break_ctl = whiteheat_break_ctl,
.chars_in_buffer = whiteheat_chars_in_buffer,
.throttle = whiteheat_throttle,
.unthrottle = whiteheat_unthrottle,
.read_bulk_callback = whiteheat_read_callback,
.write_bulk_callback = whiteheat_write_callback,
};
struct whiteheat_private {
struct whiteheat_command_private {
spinlock_t lock;
__u8 port_running;
__u8 command_finished;
wait_queue_head_t wait_command; /* for handling sleeping while waiting for a command to finish */
__u8 result_buffer[64];
};
/* local function prototypes */
static inline void set_rts (struct usb_serial_port *port, unsigned char rts);
static inline void set_dtr (struct usb_serial_port *port, unsigned char dtr);
static inline void set_break (struct usb_serial_port *port, unsigned char brk);
#define THROTTLED 0x01
#define ACTUALLY_THROTTLED 0x02
struct whiteheat_private {
spinlock_t lock;
__u8 flags;
__u8 mcr;
};
/* local function prototypes */
static int start_command_port(struct usb_serial *serial);
static void stop_command_port(struct usb_serial *serial);
static void command_port_write_callback(struct urb *urb);
static void command_port_read_callback(struct urb *urb);
static int firm_send_command(struct usb_serial_port *port, __u8 command, __u8 *data, __u8 datasize);
static int firm_open(struct usb_serial_port *port);
static int firm_close(struct usb_serial_port *port);
static int firm_setup_port(struct usb_serial_port *port);
static int firm_set_rts(struct usb_serial_port *port, __u8 onoff);
static int firm_set_dtr(struct usb_serial_port *port, __u8 onoff);
static int firm_set_break(struct usb_serial_port *port, __u8 onoff);
static int firm_purge(struct usb_serial_port *port, __u8 rxtx);
static int firm_get_dtr_rts(struct usb_serial_port *port);
static int firm_report_tx_done(struct usb_serial_port *port);
#define COMMAND_PORT 4
#define COMMAND_TIMEOUT (2*HZ) /* 2 second timeout for a command */
#define CLOSING_DELAY (30 * HZ)
/*****************************************************************************
* Connect Tech's White Heat specific driver functions
* Connect Tech's White Heat prerenumeration driver functions
*****************************************************************************/
static void command_port_write_callback (struct urb *urb)
/* steps to download the firmware to the WhiteHEAT device:
- hold the reset (by writing to the reset bit of the CPUCS register)
- download the VEND_AX.HEX file to the chip using VENDOR_REQUEST-ANCHOR_LOAD
- release the reset (by writing to the CPUCS register)
- download the WH.HEX file for all addresses greater than 0x1b3f using
VENDOR_REQUEST-ANCHOR_EXTERNAL_RAM_LOAD
- hold the reset
- download the WH.HEX file for all addresses less than 0x1b40 using
VENDOR_REQUEST_ANCHOR_LOAD
- release the reset
- device renumerated itself and comes up as new device id with all
firmware download completed.
*/
static int whiteheat_firmware_download (struct usb_serial *serial)
{
int response;
const struct whiteheat_hex_record *record;
dbg("%s", __FUNCTION__);
if (urb->status) {
dbg ("nonzero urb status: %d", urb->status);
return;
response = ezusb_set_reset (serial, 1);
record = &whiteheat_loader[0];
while (record->address != 0xffff) {
response = ezusb_writememory (serial, record->address,
(unsigned char *)record->data, record->data_size, 0xa0);
if (response < 0) {
err("%s - ezusb_writememory failed for loader (%d %04X %p %d)",
__FUNCTION__, response, record->address, record->data, record->data_size);
break;
}
++record;
}
usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, urb->transfer_buffer);
response = ezusb_set_reset (serial, 0);
return;
record = &whiteheat_firmware[0];
while (record->address < 0x1b40) {
++record;
}
while (record->address != 0xffff) {
response = ezusb_writememory (serial, record->address,
(unsigned char *)record->data, record->data_size, 0xa3);
if (response < 0) {
err("%s - ezusb_writememory failed for first firmware step (%d %04X %p %d)",
__FUNCTION__, response, record->address, record->data, record->data_size);
break;
}
++record;
}
response = ezusb_set_reset (serial, 1);
record = &whiteheat_firmware[0];
while (record->address < 0x1b40) {
response = ezusb_writememory (serial, record->address,
(unsigned char *)record->data, record->data_size, 0xa0);
if (response < 0) {
err("%s - ezusb_writememory failed for second firmware step (%d %04X %p %d)",
__FUNCTION__, response, record->address, record->data, record->data_size);
break;
}
++record;
}
response = ezusb_set_reset (serial, 0);
return 0;
}
static void command_port_read_callback (struct urb *urb)
static int whiteheat_firmware_attach (struct usb_serial *serial)
{
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
/* We want this device to fail to have a driver assigned to it */
return 1;
}
/*****************************************************************************
* Connect Tech's White Heat serial driver functions
*****************************************************************************/
static int whiteheat_attach (struct usb_serial *serial)
{
struct usb_serial_port *command_port;
struct whiteheat_command_private *command_info;
struct usb_serial_port *port;
struct whiteheat_private *info;
unsigned char *data = urb->transfer_buffer;
int result;
struct whiteheat_hw_info *hw_info;
int pipe;
int ret;
int alen;
__u8 command[2] = { WHITEHEAT_GET_HW_INFO, 0 };
__u8 result[sizeof(*hw_info) + 1];
int i;
dbg("%s", __FUNCTION__);
command_port = &serial->port[COMMAND_PORT];
if (urb->status) {
dbg("%s - nonzero urb status: %d", __FUNCTION__, urb->status);
return;
pipe = usb_sndbulkpipe (serial->dev, command_port->bulk_out_endpointAddress);
ret = usb_bulk_msg (serial->dev, pipe, command, sizeof(command), &alen, COMMAND_TIMEOUT);
if (ret) {
err("%s: Couldn't send command [%d]", serial->type->name, ret);
goto no_firmware;
} else if (alen != sizeof(command)) {
err("%s: Send command incomplete [%d]", serial->type->name, alen);
goto no_firmware;
}
if (!serial) {
dbg("%s - bad serial pointer, exiting", __FUNCTION__);
return;
pipe = usb_rcvbulkpipe (serial->dev, command_port->bulk_in_endpointAddress);
ret = usb_bulk_msg (serial->dev, pipe, result, sizeof(result), &alen, COMMAND_TIMEOUT);
if (ret) {
err("%s: Couldn't get results [%d]", serial->type->name, ret);
goto no_firmware;
} else if (alen != sizeof(result)) {
err("%s: Get results incomplete [%d]", serial->type->name, alen);
goto no_firmware;
} else if (result[0] != command[0]) {
err("%s: Command failed [%d]", serial->type->name, result[0]);
goto no_firmware;
}
usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data);
hw_info = (struct whiteheat_hw_info *)&result[1];
info = (struct whiteheat_private *)port->private;
if (!info) {
dbg("%s - info is NULL, exiting.", __FUNCTION__);
return;
}
info("%s: Driver %s: Firmware v%d.%02d", serial->type->name,
DRIVER_VERSION, hw_info->sw_major_rev, hw_info->sw_minor_rev);
/* right now, if the command is COMMAND_COMPLETE, just flip the bit saying the command finished */
/* in the future we're going to have to pay attention to the actual command that completed */
if (data[0] == WHITEHEAT_CMD_COMPLETE) {
info->command_finished = WHITEHEAT_CMD_COMPLETE;
wake_up_interruptible(&info->wait_command);
}
for (i = 0; i < serial->num_ports; i++) {
port = &serial->port[i];
info = (struct whiteheat_private *)kmalloc(sizeof(struct whiteheat_private), GFP_KERNEL);
if (info == NULL)
goto no_memory;
if (data[0] == WHITEHEAT_CMD_FAILURE) {
info->command_finished = WHITEHEAT_CMD_FAILURE;
wake_up_interruptible(&info->wait_command);
spin_lock_init(&info->lock);
info->flags = 0;
info->mcr = 0;
port->private = info;
}
/* Continue trying to always read */
FILL_BULK_URB(port->read_urb, serial->dev,
usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
command_port_read_callback, port);
result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
if (result)
dbg("%s - failed resubmitting read urb, error %d", __FUNCTION__, result);
}
command_info = (struct whiteheat_command_private *)kmalloc(sizeof(struct whiteheat_command_private), GFP_KERNEL);
if (command_info == NULL)
goto no_memory;
spin_lock_init(&command_info->lock);
command_info->port_running = 0;
init_waitqueue_head(&command_info->wait_command);
command_port->private = command_info;
command_port->write_urb->complete = command_port_write_callback;
command_port->read_urb->complete = command_port_read_callback;
static int whiteheat_send_cmd (struct usb_serial *serial, __u8 command, __u8 *data, __u8 datasize)
{
struct whiteheat_private *info;
struct usb_serial_port *port;
int timeout;
__u8 *transfer_buffer;
int retval = 0;
return 0;
dbg("%s - command %d", __FUNCTION__, command);
no_firmware:
/* Firmware likely not running */
err("%s: Unable to retrieve firmware version, try replugging\n", serial->type->name);
err("%s: If the firmware is not running (status led not blinking)\n", serial->type->name);
err("%s: please contact support@connecttech.com\n", serial->type->name);
return -ENODEV;
no_memory:
for (i--; i >= 0; i--) {
port = &serial->port[i];
kfree(port->private);
}
err("%s: Out of memory for port structures\n", serial->type->name);
return -ENOMEM;
}
port = &serial->port[COMMAND_PORT];
info = (struct whiteheat_private *)port->private;
info->command_finished = FALSE;
transfer_buffer = (__u8 *)port->write_urb->transfer_buffer;
transfer_buffer[0] = command;
memcpy (&transfer_buffer[1], data, datasize);
port->write_urb->transfer_buffer_length = datasize + 1;
port->write_urb->dev = serial->dev;
retval = usb_submit_urb (port->write_urb, GFP_KERNEL);
if (retval) {
dbg("%s - submit urb failed", __FUNCTION__);
goto exit;
}
static void whiteheat_shutdown (struct usb_serial *serial)
{
struct usb_serial_port *command_port;
struct usb_serial_port *port;
int i;
/* wait for the command to complete */
timeout = COMMAND_TIMEOUT;
while (timeout && (info->command_finished == FALSE)) {
timeout = interruptible_sleep_on_timeout (&info->wait_command, timeout);
}
dbg("%s", __FUNCTION__);
if (info->command_finished == FALSE) {
dbg("%s - command timed out.", __FUNCTION__);
retval = -ETIMEDOUT;
goto exit;
}
/* free up our private data for our command port */
command_port = &serial->port[COMMAND_PORT];
kfree (command_port->private);
command_port->private = NULL;
if (info->command_finished == WHITEHEAT_CMD_FAILURE) {
dbg("%s - command failed.", __FUNCTION__);
retval = -EIO;
goto exit;
for (i = 0; i < serial->num_ports; i++) {
port = &serial->port[i];
kfree(port->private);
port->private = NULL;
}
if (info->command_finished == WHITEHEAT_CMD_COMPLETE)
dbg("%s - command completed.", __FUNCTION__);
exit:
return retval;
return;
}
static int whiteheat_open (struct usb_serial_port *port, struct file *filp)
{
struct whiteheat_min_set open_command;
struct usb_serial_port *command_port;
struct whiteheat_private *info;
int retval = 0;
struct termios old_term;
dbg("%s - port %d", __FUNCTION__, port->number);
/* set up some stuff for our command port */
command_port = &port->serial->port[COMMAND_PORT];
if (command_port->private == NULL) {
info = (struct whiteheat_private *)kmalloc (sizeof(struct whiteheat_private), GFP_KERNEL);
if (info == NULL) {
err("%s - out of memory", __FUNCTION__);
retval = -ENOMEM;
goto exit;
}
init_waitqueue_head(&info->wait_command);
command_port->private = info;
command_port->write_urb->complete = command_port_write_callback;
command_port->read_urb->complete = command_port_read_callback;
command_port->read_urb->dev = port->serial->dev;
command_port->tty = port->tty; /* need this to "fake" our our sanity check macros */
retval = usb_submit_urb (command_port->read_urb, GFP_KERNEL);
if (retval) {
err("%s - failed submitting read urb, error %d", __FUNCTION__, retval);
retval = start_command_port(port->serial);
if (retval)
goto exit;
}
}
/* Start reading from the device */
port->read_urb->dev = port->serial->dev;
retval = usb_submit_urb(port->read_urb, GFP_KERNEL);
if (retval) {
err("%s - failed submitting read urb, error %d", __FUNCTION__, retval);
stop_command_port(port->serial);
goto exit;
}
/* send an open port command */
/* firmware uses 1 based port numbering */
open_command.port = port->number - port->serial->minor + 1;
retval = whiteheat_send_cmd (port->serial, WHITEHEAT_OPEN, (__u8 *)&open_command, sizeof(open_command));
if (retval)
retval = firm_open(port);
if (retval) {
stop_command_port(port->serial);
goto exit;
}
retval = firm_purge(port, WHITEHEAT_PURGE_RX | WHITEHEAT_PURGE_TX);
if (retval) {
firm_close(port);
stop_command_port(port->serial);
goto exit;
}
old_term.c_cflag = ~port->tty->termios->c_cflag;
old_term.c_iflag = ~port->tty->termios->c_iflag;
whiteheat_set_termios(port, &old_term);
/* Need to do device specific setup here (control lines, baud rate, etc.) */
/* FIXME!!! */
retval = firm_set_rts(port, WHITEHEAT_RTS_ON);
if (retval) {
firm_close(port);
stop_command_port(port->serial);
goto exit;
}
retval = firm_set_dtr(port, WHITEHEAT_DTR_ON);
if (retval) {
firm_set_rts(port, WHITEHEAT_RTS_OFF);
firm_close(port);
stop_command_port(port->serial);
goto exit;
}
exit:
dbg("%s - exit, retval = %d", __FUNCTION__, retval);
......@@ -359,129 +487,259 @@ static int whiteheat_open (struct usb_serial_port *port, struct file *filp)
static void whiteheat_close(struct usb_serial_port *port, struct file * filp)
{
struct whiteheat_min_set close_command;
dbg("%s - port %d", __FUNCTION__, port->number);
/* send a close command to the port */
/* firmware uses 1 based port numbering */
close_command.port = port->number - port->serial->minor + 1;
whiteheat_send_cmd (port->serial, WHITEHEAT_CLOSE, (__u8 *)&close_command, sizeof(close_command));
if (tty_hung_up_p(filp)) {
return;
}
port->tty->closing = 1;
/*
* Not currently in use; tty_wait_until_sent() calls
* serial_chars_in_buffer() which deadlocks on the second semaphore
* acquisition. This should be fixed at some point. Greg's been
* notified.
if ((filp->f_flags & (O_NDELAY | O_NONBLOCK)) == 0) {
tty_wait_until_sent(port->tty, CLOSING_DELAY);
}
*/
if (port->tty->driver.flush_buffer)
port->tty->driver.flush_buffer(port->tty);
if (port->tty->ldisc.flush_buffer)
port->tty->ldisc.flush_buffer(port->tty);
/* Need to change the control lines here */
/* FIXME */
firm_report_tx_done(port);
firm_set_dtr(port, WHITEHEAT_DTR_OFF);
firm_set_rts(port, WHITEHEAT_RTS_OFF);
firm_close(port);
/* shutdown our bulk reads and writes */
usb_unlink_urb (port->write_urb);
usb_unlink_urb (port->read_urb);
}
static int whiteheat_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg)
{
dbg("%s - port %d, cmd 0x%.4x", __FUNCTION__, port->number, cmd);
stop_command_port(port->serial);
return -ENOIOCTLCMD;
port->tty->closing = 0;
}
static void whiteheat_set_termios (struct usb_serial_port *port, struct termios *old_termios)
static int whiteheat_write(struct usb_serial_port *port, int from_user, const unsigned char *buf, int count)
{
unsigned int cflag;
struct whiteheat_port_settings port_settings;
struct usb_serial *serial = port->serial;
int result;
dbg("%s -port %d", __FUNCTION__, port->number);
dbg("%s - port %d", __FUNCTION__, port->number);
if ((!port->tty) || (!port->tty->termios)) {
dbg("%s - no tty structures", __FUNCTION__);
goto exit;
if (count == 0) {
dbg("%s - write request of 0 bytes", __FUNCTION__);
return (0);
}
cflag = port->tty->termios->c_cflag;
/* check that they really want us to change something */
if (old_termios) {
if ((cflag == old_termios->c_cflag) &&
(RELEVANT_IFLAG(port->tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) {
dbg("%s - nothing to change...", __FUNCTION__);
goto exit;
}
if (port->write_urb->status == -EINPROGRESS) {
dbg ("%s - already writing", __FUNCTION__);
return (0);
}
/* set the port number */
/* firmware uses 1 based port numbering */
port_settings.port = port->number + 1;
count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
/* get the byte size */
switch (cflag & CSIZE) {
case CS5: port_settings.bits = 5; break;
case CS6: port_settings.bits = 6; break;
case CS7: port_settings.bits = 7; break;
default:
case CS8: port_settings.bits = 8; break;
if (from_user) {
if (copy_from_user(port->write_urb->transfer_buffer, buf, count))
return -EFAULT;
}
else {
memcpy (port->write_urb->transfer_buffer, buf, count);
}
dbg("%s - data bits = %d", __FUNCTION__, port_settings.bits);
/* determine the parity */
if (cflag & PARENB)
if (cflag & PARODD)
port_settings.parity = 'o';
else
port_settings.parity = 'e';
else
port_settings.parity = 'n';
dbg("%s - parity = %c", __FUNCTION__, port_settings.parity);
usb_serial_debug_data (__FILE__, __FUNCTION__, count, port->write_urb->transfer_buffer);
/* figure out the stop bits requested */
if (cflag & CSTOPB)
port_settings.stop = 2;
port->write_urb->dev = serial->dev;
port->write_urb->transfer_buffer_length = count;
result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
if (result)
err("%s - failed submitting write urb, error %d", __FUNCTION__, result);
else
port_settings.stop = 1;
dbg("%s - stop bits = %d", __FUNCTION__, port_settings.stop);
result = count;
return result;
}
/* figure out the flow control settings */
if (cflag & CRTSCTS)
port_settings.hflow = (WHITEHEAT_CTS_FLOW | WHITEHEAT_RTS_FLOW);
else
port_settings.hflow = 0;
dbg("%s - hardware flow control = %s %s %s %s", __FUNCTION__,
(port_settings.hflow & WHITEHEAT_CTS_FLOW) ? "CTS" : "",
(port_settings.hflow & WHITEHEAT_RTS_FLOW) ? "RTS" : "",
(port_settings.hflow & WHITEHEAT_DSR_FLOW) ? "DSR" : "",
(port_settings.hflow & WHITEHEAT_DTR_FLOW) ? "DTR" : "");
/* determine software flow control */
if (I_IXOFF(port->tty))
port_settings.sflow = 'b';
static int whiteheat_write_room(struct usb_serial_port *port)
{
int room = 0;
dbg("%s - port %d", __FUNCTION__, port->number);
if (port->write_urb->status != -EINPROGRESS)
room = port->bulk_out_size;
dbg("%s - returns %d", __FUNCTION__, room);
return (room);
}
static int whiteheat_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg)
{
struct whiteheat_private *info = (struct whiteheat_private *)port->private;
unsigned int modem_signals = 0;
struct serial_struct serstruct;
dbg("%s - port %d, cmd 0x%.4x", __FUNCTION__, port->number, cmd);
switch (cmd) {
case TIOCMGET:
firm_get_dtr_rts(port);
if (info->mcr & UART_MCR_DTR)
modem_signals |= TIOCM_DTR;
if (info->mcr & UART_MCR_RTS)
modem_signals |= TIOCM_RTS;
if (copy_to_user((unsigned int *)arg, &modem_signals, sizeof(unsigned int)));
return -EFAULT;
break;
case TIOCMSET:
if (copy_from_user(&modem_signals, (unsigned int *)arg, sizeof(unsigned int)))
return -EFAULT;
if (modem_signals & TIOCM_DTR)
info->mcr |= UART_MCR_DTR;
else
port_settings.sflow = 'n';
dbg("%s - software flow control = %c", __FUNCTION__, port_settings.sflow);
info->mcr &= ~UART_MCR_DTR;
if (modem_signals & TIOCM_RTS)
info->mcr |= UART_MCR_RTS;
else
info->mcr &= ~UART_MCR_RTS;
port_settings.xon = START_CHAR(port->tty);
port_settings.xoff = STOP_CHAR(port->tty);
dbg("%s - XON = %2x, XOFF = %2x", __FUNCTION__, port_settings.xon, port_settings.xoff);
firm_set_dtr(port, info->mcr & UART_MCR_DTR);
firm_set_rts(port, info->mcr & UART_MCR_RTS);
/* get the baud rate wanted */
port_settings.baud = tty_get_baud_rate(port->tty);
dbg("%s - baud rate = %d", __FUNCTION__, port_settings.baud);
break;
/* handle any settings that aren't specified in the tty structure */
port_settings.lloop = 0;
case TIOCMBIS:
if (copy_from_user(&modem_signals, (unsigned int *)arg, sizeof(unsigned int)))
return -EFAULT;
/* now send the message to the device */
whiteheat_send_cmd (port->serial, WHITEHEAT_SETUP_PORT, (__u8 *)&port_settings, sizeof(port_settings));
if (modem_signals & TIOCM_DTR)
info->mcr |= UART_MCR_DTR;
if (modem_signals & TIOCM_RTS)
info->mcr |= UART_MCR_RTS;
firm_set_dtr(port, info->mcr & UART_MCR_DTR);
firm_set_rts(port, info->mcr & UART_MCR_RTS);
break;
case TIOCMBIC:
if (copy_from_user(&modem_signals, (unsigned int *)arg, sizeof(unsigned int)))
return -EFAULT;
if (modem_signals & TIOCM_DTR)
info->mcr &= ~UART_MCR_DTR;
if (modem_signals & TIOCM_RTS)
info->mcr &= ~UART_MCR_RTS;
firm_set_dtr(port, info->mcr & UART_MCR_DTR);
firm_set_rts(port, info->mcr & UART_MCR_RTS);
break;
case TIOCGSERIAL:
memset(&serstruct, 0, sizeof(serstruct));
serstruct.type = PORT_16654;
serstruct.line = port->serial->minor;
serstruct.port = port->number;
serstruct.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ;
serstruct.xmit_fifo_size = port->bulk_out_size;
serstruct.custom_divisor = 0;
serstruct.baud_base = 460800;
serstruct.close_delay = CLOSING_DELAY;
serstruct.closing_wait = CLOSING_DELAY;
if (copy_to_user((void *)arg, &serstruct, sizeof(serstruct)))
return -EFAULT;
break;
case TIOCSSERIAL:
if (copy_from_user(&serstruct, (void *)arg, sizeof(serstruct)))
return -EFAULT;
/*
* For now this is ignored. dip sets the ASYNC_[V]HI flags
* but this isn't used by us at all. Maybe someone somewhere
* will need the custom_divisor setting.
*/
break;
default:
return -ENOIOCTLCMD;
}
return 0;
}
static void whiteheat_set_termios (struct usb_serial_port *port, struct termios *old_termios)
{
dbg("%s -port %d", __FUNCTION__, port->number);
if ((!port->tty) || (!port->tty->termios)) {
dbg("%s - no tty structures", __FUNCTION__);
goto exit;
}
/* check that they really want us to change something */
if (old_termios) {
if ((port->tty->termios->c_cflag == old_termios->c_cflag) &&
(RELEVANT_IFLAG(port->tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) {
dbg("%s - nothing to change...", __FUNCTION__);
goto exit;
}
}
firm_setup_port(port);
exit:
return;
}
static void whiteheat_break_ctl(struct usb_serial_port *port, int break_state) {
firm_set_break(port, break_state);
}
static int whiteheat_chars_in_buffer(struct usb_serial_port *port)
{
int chars = 0;
dbg("%s - port %d", __FUNCTION__, port->number);
if (port->write_urb->status == -EINPROGRESS)
chars = port->write_urb->transfer_buffer_length;
dbg ("%s - returns %d", __FUNCTION__, chars);
return (chars);
}
static void whiteheat_throttle (struct usb_serial_port *port)
{
struct whiteheat_private *info = (struct whiteheat_private *)port->private;
unsigned long flags;
dbg("%s - port %d", __FUNCTION__, port->number);
/* Change the control signals */
/* FIXME!!! */
spin_lock_irqsave(&info->lock, flags);
info->flags |= THROTTLED;
spin_unlock_irqrestore(&info->lock, flags);
return;
}
......@@ -489,194 +747,441 @@ static void whiteheat_throttle (struct usb_serial_port *port)
static void whiteheat_unthrottle (struct usb_serial_port *port)
{
struct whiteheat_private *info = (struct whiteheat_private *)port->private;
int result;
unsigned long flags;
dbg("%s - port %d", __FUNCTION__, port->number);
/* Change the control signals */
/* FIXME!!! */
spin_lock_irqsave(&info->lock, flags);
if (info->flags & ACTUALLY_THROTTLED) {
/* Continue trying to always read */
port->read_urb->dev = port->serial->dev;
result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
if (result)
err("%s - failed resubmitting read urb, error %d", __FUNCTION__, result);
}
info->flags &= ~(THROTTLED | ACTUALLY_THROTTLED);
spin_unlock_irqrestore(&info->lock, flags);
return;
}
/* steps to download the firmware to the WhiteHEAT device:
- hold the reset (by writing to the reset bit of the CPUCS register)
- download the VEND_AX.HEX file to the chip using VENDOR_REQUEST-ANCHOR_LOAD
- release the reset (by writing to the CPUCS register)
- download the WH.HEX file for all addresses greater than 0x1b3f using
VENDOR_REQUEST-ANCHOR_EXTERNAL_RAM_LOAD
- hold the reset
- download the WH.HEX file for all addresses less than 0x1b40 using
VENDOR_REQUEST_ANCHOR_LOAD
- release the reset
- device renumerated itself and comes up as new device id with all
firmware download completed.
*/
static int whiteheat_firmware_download (struct usb_serial *serial)
/*****************************************************************************
* Connect Tech's White Heat callback routines
*****************************************************************************/
static void command_port_write_callback (struct urb *urb)
{
int response;
const struct whiteheat_hex_record *record;
dbg("%s", __FUNCTION__);
response = ezusb_set_reset (serial, 1);
if (urb->status) {
dbg ("nonzero urb status: %d", urb->status);
return;
}
record = &whiteheat_loader[0];
while (record->address != 0xffff) {
response = ezusb_writememory (serial, record->address,
(unsigned char *)record->data, record->data_size, 0xa0);
if (response < 0) {
err("%s - ezusb_writememory failed for loader (%d %04X %p %d)",
__FUNCTION__, response, record->address, record->data, record->data_size);
break;
usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, urb->transfer_buffer);
return;
}
static void command_port_read_callback (struct urb *urb)
{
struct usb_serial_port *command_port = (struct usb_serial_port *)urb->context;
struct usb_serial *serial = get_usb_serial (command_port, __FUNCTION__);
struct whiteheat_command_private *command_info;
unsigned char *data = urb->transfer_buffer;
int result;
unsigned long flags;
dbg("%s", __FUNCTION__);
if (urb->status) {
dbg("%s - nonzero urb status: %d", __FUNCTION__, urb->status);
return;
}
++record;
if (!serial) {
dbg("%s - bad serial pointer, exiting", __FUNCTION__);
return;
}
response = ezusb_set_reset (serial, 0);
usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data);
record = &whiteheat_firmware[0];
while (record->address < 0x1b40) {
++record;
command_info = (struct whiteheat_command_private *)command_port->private;
if (!command_info) {
dbg ("%s - command_info is NULL, exiting.", __FUNCTION__);
return;
}
while (record->address != 0xffff) {
response = ezusb_writememory (serial, record->address,
(unsigned char *)record->data, record->data_size, 0xa3);
if (response < 0) {
err("%s - ezusb_writememory failed for first firmware step (%d %04X %p %d)",
__FUNCTION__, response, record->address, record->data, record->data_size);
break;
spin_lock_irqsave(&command_info->lock, flags);
if (data[0] == WHITEHEAT_CMD_COMPLETE) {
command_info->command_finished = WHITEHEAT_CMD_COMPLETE;
wake_up_interruptible(&command_info->wait_command);
} else if (data[0] == WHITEHEAT_CMD_FAILURE) {
command_info->command_finished = WHITEHEAT_CMD_FAILURE;
wake_up_interruptible(&command_info->wait_command);
} else if (data[0] == WHITEHEAT_EVENT) {
/* These are unsolicited reports from the firmware, hence no waiting command to wakeup */
dbg("%s - event received", __FUNCTION__);
} else if (data[0] == WHITEHEAT_GET_DTR_RTS) {
memcpy(command_info->result_buffer, &data[1], urb->actual_length - 1);
command_info->command_finished = WHITEHEAT_CMD_COMPLETE;
wake_up_interruptible(&command_info->wait_command);
} else {
dbg("%s - bad reply from firmware", __FUNCTION__);
}
++record;
/* Continue trying to always read */
command_port->read_urb->dev = serial->dev;
result = usb_submit_urb(command_port->read_urb, GFP_ATOMIC);
spin_unlock_irqrestore(&command_info->lock, flags);
if (result)
dbg("%s - failed resubmitting read urb, error %d", __FUNCTION__, result);
}
static void whiteheat_read_callback(struct urb *urb)
{
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
struct tty_struct *tty;
unsigned char *data = urb->transfer_buffer;
int i;
int result;
struct whiteheat_private *info = (struct whiteheat_private *)port->private;
unsigned long flags;
dbg("%s - port %d", __FUNCTION__, port->number);
if (!serial) {
dbg("%s - bad serial pointer, exiting", __FUNCTION__);
return;
}
response = ezusb_set_reset (serial, 1);
if (urb->status) {
dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status);
return;
}
record = &whiteheat_firmware[0];
while (record->address < 0x1b40) {
response = ezusb_writememory (serial, record->address,
(unsigned char *)record->data, record->data_size, 0xa0);
if (response < 0) {
err("%s - ezusb_writememory failed for second firmware step (%d %04X %p %d)",
__FUNCTION__, response, record->address, record->data, record->data_size);
break;
usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data);
tty = port->tty;
if (tty && urb->actual_length) {
for (i = 0; i < urb->actual_length ; ++i) {
/* if we insert more than TTY_FLIPBUF_SIZE characters, we drop them. */
if(tty->flip.count >= TTY_FLIPBUF_SIZE) {
tty_flip_buffer_push(tty);
}
++record;
/* this doesn't actually push the data through unless tty->low_latency is set */
tty_insert_flip_char(tty, data[i], 0);
}
tty_flip_buffer_push(tty);
}
response = ezusb_set_reset (serial, 0);
spin_lock_irqsave(&info->lock, flags);
if (info->flags & THROTTLED) {
info->flags |= ACTUALLY_THROTTLED;
spin_unlock_irqrestore(&info->lock, flags);
return;
}
spin_unlock_irqrestore(&info->lock, flags);
/* we want this device to fail to have a driver assigned to it. */
return 1;
/* Continue trying to always read */
port->read_urb->dev = serial->dev;
result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
if (result)
err("%s - failed resubmitting read urb, error %d", __FUNCTION__, result);
}
static int whiteheat_attach (struct usb_serial *serial)
static void whiteheat_write_callback(struct urb *urb)
{
struct whiteheat_hw_info *hw_info;
int pipe;
int ret;
int alen;
__u8 command[2] = { WHITEHEAT_GET_HW_INFO, 0 };
__u8 result[sizeof(*hw_info) + 1];
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
pipe = usb_rcvbulkpipe (serial->dev, 7);
usb_bulk_msg (serial->dev, pipe, result, sizeof(result), &alen, 2 * HZ);
/*
* We ignore the return code. In the case where rmmod/insmod is
* performed with a WhiteHEAT connected, the above times out
* because the endpoint is already prepped, meaning the below succeeds
* regardless. All other cases the above succeeds.
*/
dbg("%s - port %d", __FUNCTION__, port->number);
pipe = usb_sndbulkpipe (serial->dev, 7);
ret = usb_bulk_msg (serial->dev, pipe, command, sizeof(command), &alen, 2 * HZ);
if (ret) {
err("%s: Couldn't send command [%d]", serial->type->name, ret);
goto error_out;
} else if (alen != sizeof(command)) {
err("%s: Send command incomplete [%d]", serial->type->name, alen);
goto error_out;
if (!serial) {
dbg("%s - bad serial pointer, exiting", __FUNCTION__);
return;
}
pipe = usb_rcvbulkpipe (serial->dev, 7);
ret = usb_bulk_msg (serial->dev, pipe, result, sizeof(result), &alen, 2 * HZ);
if (ret) {
err("%s: Couldn't get results [%d]", serial->type->name, ret);
goto error_out;
} else if (alen != sizeof(result)) {
err("%s: Get results incomplete [%d]", serial->type->name, alen);
goto error_out;
} else if (result[0] != command[0]) {
err("%s: Command failed [%d]", serial->type->name, result[0]);
goto error_out;
if (urb->status) {
dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
return;
}
hw_info = (struct whiteheat_hw_info *)&result[1];
usb_serial_port_softint((void *)port);
info("%s: Driver %s: Firmware v%d.%02d", serial->type->name,
DRIVER_VERSION, hw_info->sw_major_rev, hw_info->sw_minor_rev);
queue_task(&port->tqueue, &tq_immediate);
mark_bh(IMMEDIATE_BH);
return 0;
error_out:
err("%s: Unable to retrieve firmware version, try replugging\n", serial->type->name);
/*
* Return that we've claimed the interface. A failure here may be
* due to interception by the command_callback routine or other
* causes that don't mean that the firmware isn't running. This may
* change in the future. Probably should actually.
*/
return 0;
return;
}
static void whiteheat_shutdown (struct usb_serial *serial)
/*****************************************************************************
* Connect Tech's White Heat firmware interface
*****************************************************************************/
static int firm_send_command (struct usb_serial_port *port, __u8 command, __u8 *data, __u8 datasize)
{
struct usb_serial_port *command_port;
struct whiteheat_command_private *command_info;
struct whiteheat_private *info;
int timeout;
__u8 *transfer_buffer;
int retval = 0;
unsigned long flags;
dbg("%s", __FUNCTION__);
dbg("%s - command %d", __FUNCTION__, command);
/* free up our private data for our command port */
command_port = &serial->port[COMMAND_PORT];
if (command_port->private != NULL) {
kfree (command_port->private);
command_port->private = NULL;
command_port = &port->serial->port[COMMAND_PORT];
command_info = (struct whiteheat_command_private *)command_port->private;
spin_lock_irqsave(&command_info->lock, flags);
command_info->command_finished = FALSE;
transfer_buffer = (__u8 *)command_port->write_urb->transfer_buffer;
transfer_buffer[0] = command;
memcpy (&transfer_buffer[1], data, datasize);
command_port->write_urb->transfer_buffer_length = datasize + 1;
command_port->write_urb->dev = port->serial->dev;
retval = usb_submit_urb (command_port->write_urb, GFP_KERNEL);
spin_unlock_irqrestore(&command_info->lock, flags);
if (retval) {
dbg("%s - submit urb failed", __FUNCTION__);
goto exit;
}
return;
/* wait for the command to complete */
timeout = COMMAND_TIMEOUT;
while (timeout && (command_info->command_finished == FALSE)) {
timeout = interruptible_sleep_on_timeout (&command_info->wait_command, timeout);
}
spin_lock_irqsave(&command_info->lock, flags);
if (command_info->command_finished == FALSE) {
dbg("%s - command timed out.", __FUNCTION__);
retval = -ETIMEDOUT;
goto exit;
}
if (command_info->command_finished == WHITEHEAT_CMD_FAILURE) {
dbg("%s - command failed.", __FUNCTION__);
retval = -EIO;
goto exit;
}
if (command_info->command_finished == WHITEHEAT_CMD_COMPLETE) {
dbg("%s - command completed.", __FUNCTION__);
switch (command) {
case WHITEHEAT_GET_DTR_RTS:
info = (struct whiteheat_private *)port->private;
memcpy(&info->mcr, command_info->result_buffer, sizeof(struct whiteheat_dr_info));
break;
}
}
exit:
spin_unlock_irqrestore(&command_info->lock, flags);
return retval;
}
static void set_command (struct usb_serial_port *port, unsigned char state, unsigned char command)
{
struct whiteheat_rdb_set rdb_command;
static int firm_open(struct usb_serial_port *port) {
struct whiteheat_simple open_command;
open_command.port = port->number - port->serial->minor + 1;
return firm_send_command(port, WHITEHEAT_OPEN, (__u8 *)&open_command, sizeof(open_command));
}
/* send a set rts command to the port */
/* firmware uses 1 based port numbering */
rdb_command.port = port->number - port->serial->minor + 1;
rdb_command.state = state;
whiteheat_send_cmd (port->serial, command, (__u8 *)&rdb_command, sizeof(rdb_command));
static int firm_close(struct usb_serial_port *port) {
struct whiteheat_simple close_command;
close_command.port = port->number - port->serial->minor + 1;
return firm_send_command(port, WHITEHEAT_CLOSE, (__u8 *)&close_command, sizeof(close_command));
}
static inline void set_rts (struct usb_serial_port *port, unsigned char rts)
{
set_command (port, rts, WHITEHEAT_SET_RTS);
static int firm_setup_port(struct usb_serial_port *port) {
struct whiteheat_port_settings port_settings;
unsigned int cflag = port->tty->termios->c_cflag;
port_settings.port = port->number + 1;
/* get the byte size */
switch (cflag & CSIZE) {
case CS5: port_settings.bits = 5; break;
case CS6: port_settings.bits = 6; break;
case CS7: port_settings.bits = 7; break;
default:
case CS8: port_settings.bits = 8; break;
}
dbg("%s - data bits = %d", __FUNCTION__, port_settings.bits);
/* determine the parity */
if (cflag & PARENB)
if (cflag & CMSPAR)
if (cflag & PARODD)
port_settings.parity = WHITEHEAT_PAR_MARK;
else
port_settings.parity = WHITEHEAT_PAR_SPACE;
else
if (cflag & PARODD)
port_settings.parity = WHITEHEAT_PAR_ODD;
else
port_settings.parity = WHITEHEAT_PAR_EVEN;
else
port_settings.parity = WHITEHEAT_PAR_NONE;
dbg("%s - parity = %c", __FUNCTION__, port_settings.parity);
/* figure out the stop bits requested */
if (cflag & CSTOPB)
port_settings.stop = 2;
else
port_settings.stop = 1;
dbg("%s - stop bits = %d", __FUNCTION__, port_settings.stop);
/* figure out the flow control settings */
if (cflag & CRTSCTS)
port_settings.hflow = (WHITEHEAT_HFLOW_CTS | WHITEHEAT_HFLOW_RTS);
else
port_settings.hflow = WHITEHEAT_HFLOW_NONE;
dbg("%s - hardware flow control = %s %s %s %s", __FUNCTION__,
(port_settings.hflow & WHITEHEAT_HFLOW_CTS) ? "CTS" : "",
(port_settings.hflow & WHITEHEAT_HFLOW_RTS) ? "RTS" : "",
(port_settings.hflow & WHITEHEAT_HFLOW_DSR) ? "DSR" : "",
(port_settings.hflow & WHITEHEAT_HFLOW_DTR) ? "DTR" : "");
/* determine software flow control */
if (I_IXOFF(port->tty))
port_settings.sflow = WHITEHEAT_SFLOW_RXTX;
else
port_settings.sflow = WHITEHEAT_SFLOW_NONE;
dbg("%s - software flow control = %c", __FUNCTION__, port_settings.sflow);
port_settings.xon = START_CHAR(port->tty);
port_settings.xoff = STOP_CHAR(port->tty);
dbg("%s - XON = %2x, XOFF = %2x", __FUNCTION__, port_settings.xon, port_settings.xoff);
/* get the baud rate wanted */
port_settings.baud = tty_get_baud_rate(port->tty);
dbg("%s - baud rate = %d", __FUNCTION__, port_settings.baud);
/* handle any settings that aren't specified in the tty structure */
port_settings.lloop = 0;
/* now send the message to the device */
return firm_send_command(port, WHITEHEAT_SETUP_PORT, (__u8 *)&port_settings, sizeof(port_settings));
}
static int firm_set_rts(struct usb_serial_port *port, __u8 onoff) {
struct whiteheat_set_rdb rts_command;
rts_command.port = port->number - port->serial->minor + 1;
rts_command.state = onoff;
return firm_send_command(port, WHITEHEAT_SET_RTS, (__u8 *)&rts_command, sizeof(rts_command));
}
static int firm_set_dtr(struct usb_serial_port *port, __u8 onoff) {
struct whiteheat_set_rdb dtr_command;
dtr_command.port = port->number - port->serial->minor + 1;
dtr_command.state = onoff;
return firm_send_command(port, WHITEHEAT_SET_RTS, (__u8 *)&dtr_command, sizeof(dtr_command));
}
static int firm_set_break(struct usb_serial_port *port, __u8 onoff) {
struct whiteheat_set_rdb break_command;
break_command.port = port->number - port->serial->minor + 1;
break_command.state = onoff;
return firm_send_command(port, WHITEHEAT_SET_RTS, (__u8 *)&break_command, sizeof(break_command));
}
static int firm_purge(struct usb_serial_port *port, __u8 rxtx) {
struct whiteheat_purge purge_command;
purge_command.port = port->number - port->serial->minor + 1;
purge_command.what = rxtx;
return firm_send_command(port, WHITEHEAT_PURGE, (__u8 *)&purge_command, sizeof(purge_command));
}
static int firm_get_dtr_rts(struct usb_serial_port *port) {
struct whiteheat_simple get_dr_command;
get_dr_command.port = port->number - port->serial->minor + 1;
return firm_send_command(port, WHITEHEAT_GET_DTR_RTS, (__u8 *)&get_dr_command, sizeof(get_dr_command));
}
static inline void set_dtr (struct usb_serial_port *port, unsigned char dtr)
static int firm_report_tx_done(struct usb_serial_port *port) {
struct whiteheat_simple close_command;
close_command.port = port->number - port->serial->minor + 1;
return firm_send_command(port, WHITEHEAT_REPORT_TX_DONE, (__u8 *)&close_command, sizeof(close_command));
}
/*****************************************************************************
* Connect Tech's White Heat utility functions
*****************************************************************************/
static int start_command_port(struct usb_serial *serial)
{
set_command (port, dtr, WHITEHEAT_SET_DTR);
struct usb_serial_port *command_port;
struct whiteheat_command_private *command_info;
unsigned long flags;
int retval = 0;
command_port = &serial->port[COMMAND_PORT];
command_info = (struct whiteheat_command_private *)command_port->private;
spin_lock_irqsave(&command_info->lock, flags);
if (!command_info->port_running) {
command_port->read_urb->dev = serial->dev;
retval = usb_submit_urb(command_port->read_urb, GFP_KERNEL);
if (retval) {
err("%s - failed submitting read urb, error %d", __FUNCTION__, retval);
goto exit;
}
}
command_info->port_running++;
exit:
spin_unlock_irqrestore(&command_info->lock, flags);
return retval;
}
static inline void set_break (struct usb_serial_port *port, unsigned char brk)
static void stop_command_port(struct usb_serial *serial)
{
set_command (port, brk, WHITEHEAT_SET_BREAK);
struct usb_serial_port *command_port;
struct whiteheat_command_private *command_info;
unsigned long flags;
command_port = &serial->port[COMMAND_PORT];
command_info = (struct whiteheat_command_private *)command_port->private;
spin_lock_irqsave(&command_info->lock, flags);
command_info->port_running--;
if (!command_info->port_running)
usb_unlink_urb(command_port->read_urb);
spin_unlock_irqrestore(&command_info->lock, flags);
}
/*****************************************************************************
* Connect Tech's White Heat module functions
*****************************************************************************/
static int __init whiteheat_init (void)
{
usb_serial_register (&whiteheat_fake_device);
......@@ -704,4 +1209,3 @@ MODULE_LICENSE("GPL");
MODULE_PARM(debug, "i");
MODULE_PARM_DESC(debug, "Debug enabled or not");
/*
* USB ConnectTech WhiteHEAT driver
*
* Copyright (C) 2002
* Connect Tech Inc.
*
* Copyright (C) 1999, 2000
* Greg Kroah-Hartman (greg@kroah.com)
*
......@@ -20,6 +23,7 @@
#define FALSE 0
#define TRUE 1
/* WhiteHEAT commands */
#define WHITEHEAT_OPEN 1 /* open the port */
#define WHITEHEAT_CLOSE 2 /* close the port */
......@@ -39,109 +43,192 @@
#define WHITEHEAT_CMD_COMPLETE 16 /* reply for certain commands */
#define WHITEHEAT_CMD_FAILURE 17 /* reply for failed commands */
/* Data for the WHITEHEAT_SETUP_PORT command */
#define WHITEHEAT_CTS_FLOW 0x08
#define WHITEHEAT_RTS_FLOW 0x80
#define WHITEHEAT_DSR_FLOW 0x10
#define WHITEHEAT_DTR_FLOW 0x02
/*
* Commands to the firmware
*/
/*
* WHITEHEAT_OPEN
* WHITEHEAT_CLOSE
* WHITEHEAT_STATUS
* WHITEHEAT_GET_DTR_RTS
* WHITEHEAT_REPORT_TX_DONE
*/
struct whiteheat_simple {
__u8 port; /* port number (1 to N) */
};
/*
* WHITEHEAT_SETUP_PORT
*/
#define WHITEHEAT_PAR_NONE 'n' /* no parity */
#define WHITEHEAT_PAR_EVEN 'e' /* even parity */
#define WHITEHEAT_PAR_ODD 'o' /* odd parity */
#define WHITEHEAT_PAR_SPACE '0' /* space (force 0) parity */
#define WHITEHEAT_PAR_MARK '1' /* mark (force 1) parity */
#define WHITEHEAT_SFLOW_NONE 'n' /* no software flow control */
#define WHITEHEAT_SFLOW_RX 'r' /* XOFF/ON is sent when RX fills/empties */
#define WHITEHEAT_SFLOW_TX 't' /* when received XOFF/ON will stop/start TX */
#define WHITEHEAT_SFLOW_RXTX 'b' /* both SFLOW_RX and SFLOW_TX */
#define WHITEHEAT_HFLOW_NONE 0x00 /* no hardware flow control */
#define WHITEHEAT_HFLOW_RTS_TOGGLE 0x01 /* RTS is on during transmit, off otherwise */
#define WHITEHEAT_HFLOW_DTR 0x02 /* DTR is off/on when RX fills/empties */
#define WHITEHEAT_HFLOW_CTS 0x08 /* when received CTS off/on will stop/start TX */
#define WHITEHEAT_HFLOW_DSR 0x10 /* when received DSR off/on will stop/start TX */
#define WHITEHEAT_HFLOW_RTS 0x80 /* RTS is off/on when RX fills/empties */
struct whiteheat_port_settings {
__u8 port; /* port number (1 to N) */
__u32 baud; /* any value allowed, default 9600, arrives little endian, range is 7 - 460800 */
__u8 bits; /* 5, 6, 7, or 8, default 8 */
__u32 baud; /* any value 7 - 460800, firmware calculates best fit; arrives little endian */
__u8 bits; /* 5, 6, 7, or 8 */
__u8 stop; /* 1 or 2, default 1 (2 = 1.5 if bits = 5) */
__u8 parity; /* 'n, e, o, 0, or 1' (ascii), default 'n'
* n = none e = even o = odd
* 0 = force 0 1 = force 1 */
__u8 sflow; /* 'n, r, t, or b' (ascii), default 'n'
* n = none
* r = receive (XOFF/XON transmitted when receiver fills / empties)
* t = transmit (XOFF/XON received will stop/start TX)
* b = both */
__u8 xoff; /* XOFF byte value, default 0x13 */
__u8 xon; /* XON byte value, default 0x11 */
__u8 hflow; /* bits indicate mode as follows:
* CTS (0x08) (CTS off/on will control/cause TX off/on)
* DSR (0x10) (DSR off/on will control/cause TX off/on)
* RTS (0x80) (RTS off/on when receiver fills/empties)
* DTR (0x02) (DTR off/on when receiver fills/empties) */
__u8 lloop; /* local loopback 0 or 1, default 0 */
__u8 parity; /* see WHITEHEAT_PAR_* above */
__u8 sflow; /* see WHITEHEAT_SFLOW_* above */
__u8 xoff; /* XOFF byte value */
__u8 xon; /* XON byte value */
__u8 hflow; /* see WHITEHEAT_HFLOW_* above */
__u8 lloop; /* 0/1 turns local loopback mode off/on */
} __attribute__ ((packed));
/* data for WHITEHEAT_SET_RTS, WHITEHEAT_SET_DTR, and WHITEHEAT_SET_BREAK commands */
struct whiteheat_rdb_set {
/*
* WHITEHEAT_SET_RTS
* WHITEHEAT_SET_DTR
* WHITEHEAT_SET_BREAK
*/
#define WHITEHEAT_RTS_OFF 0x00
#define WHITEHEAT_RTS_ON 0x01
#define WHITEHEAT_DTR_OFF 0x00
#define WHITEHEAT_DTR_ON 0x01
#define WHITEHEAT_BREAK_OFF 0x00
#define WHITEHEAT_BREAK_ON 0x01
struct whiteheat_set_rdb {
__u8 port; /* port number (1 to N) */
__u8 state; /* 0 = off, non-zero = on */
__u8 state; /* 0/1 turns signal off/on */
};
/* data for:
WHITEHEAT_OPEN
WHITEHEAT_CLOSE
WHITEHEAT_STATUS
WHITEHEAT_GET_DTR_RTS
WHITEHEAT_REPORT_TX_DONE */
struct whiteheat_min_set {
__u8 port; /* port number (1 to N) */
/*
* WHITEHEAT_DUMP
*/
#define WHITEHEAT_DUMP_MEM_DATA 'd' /* data */
#define WHITEHEAT_DUMP_MEM_IDATA 'i' /* idata */
#define WHITEHEAT_DUMP_MEM_BDATA 'b' /* bdata */
#define WHITEHEAT_DUMP_MEM_XDATA 'x' /* xdata */
/*
* Allowable address ranges (firmware checks address):
* Type DATA: 0x00 - 0xff
* Type IDATA: 0x80 - 0xff
* Type BDATA: 0x20 - 0x2f
* Type XDATA: 0x0000 - 0xffff
*
* B/I/DATA all read the local memory space
* XDATA reads the external memory space
* BDATA returns bits as bytes
*
* NOTE: 0x80 - 0xff (local space) are the Special Function Registers
* of the 8051, and some have on-read side-effects.
*/
struct whiteheat_dump {
__u8 mem_type; /* see WHITEHEAT_DUMP_* above */
__u16 addr; /* address, see restrictions above */
__u16 length; /* number of bytes to dump, max 63 bytes */
};
/* data for WHITEHEAT_PURGE command */
#define WHITEHEAT_PURGE_INPUT 0x01
#define WHITEHEAT_PURGE_OUTPUT 0x02
struct whiteheat_purge_set {
/*
* WHITEHEAT_PURGE
*/
#define WHITEHEAT_PURGE_RX 0x01 /* purge rx fifos */
#define WHITEHEAT_PURGE_TX 0x02 /* purge tx fifos */
struct whiteheat_purge {
__u8 port; /* port number (1 to N) */
__u8 what; /* bit pattern of what to purge */
};
/* data for WHITEHEAT_DUMP command */
struct whiteheat_dump_info {
__u8 mem_type; /* memory type: 'd' = data, 'i' = idata, 'b' = bdata, 'x' = xdata */
__u16 addr; /* memory address to dump, address range depends on the above mem_type:
* 'd' = 0 to ff (80 to FF is SFR's)
* 'i' = 80 to ff
* 'b' = 20 to 2f (bits returned as bytes)
* 'x' = 0000 to ffff (also code space) */
__u16 length; /* number of bytes to dump, max 64 */
};
/* data for WHITEHEAT_ECHO command */
struct whiteheat_echo_set {
/*
* WHITEHEAT_ECHO
*/
struct whiteheat_echo {
__u8 port; /* port number (1 to N) */
__u8 length; /* length of message to echo */
__u8 length; /* length of message to echo, max 61 bytes */
__u8 echo_data[61]; /* data to echo */
};
/* data returned from WHITEHEAT_STATUS command */
#define WHITEHEAT_OVERRUN_ERROR 0x02
#define WHITEHEAT_PARITY_ERROR 0x04
#define WHITEHEAT_FRAMING_ERROR 0x08
#define WHITEHEAT_BREAK_ERROR 0x10
#define WHITEHEAT_OHFLOW 0x01 /* TX is stopped by CTS (waiting for CTS to go ON) */
#define WHITEHEAT_IHFLOW 0x02 /* remote TX is stopped by RTS */
#define WHITEHEAT_OSFLOW 0x04 /* TX is stopped by XOFF received (waiting for XON to occur) */
#define WHITEHEAT_ISFLOW 0x08 /* remote TX is stopped by XOFF transmitted */
#define WHITEHEAT_TX_DONE 0x80 /* TX has completed */
#define WHITEHEAT_MODEM_EVENT 0x01
#define WHITEHEAT_ERROR_EVENT 0x02
#define WHITEHEAT_FLOW_EVENT 0x04
#define WHITEHEAT_CONNECT_EVENT 0x08
/*
* WHITEHEAT_DO_TEST
*/
#define WHITEHEAT_TEST_UART_RW 0x01 /* read/write uart registers */
#define WHITEHEAT_TEST_UART_INTR 0x02 /* uart interrupt */
#define WHITEHEAT_TEST_SETUP_CONT 0x03 /* setup for PORT_CONT/PORT_DISCONT */
#define WHITEHEAT_TEST_PORT_CONT 0x04 /* port connect */
#define WHITEHEAT_TEST_PORT_DISCONT 0x05 /* port disconnect */
#define WHITEHEAT_TEST_UART_CLK_START 0x06 /* uart clock test start */
#define WHITEHEAT_TEST_UART_CLK_STOP 0x07 /* uart clock test stop */
#define WHITEHEAT_TEST_MODEM_FT 0x08 /* modem signals, requires a loopback cable/connector */
#define WHITEHEAT_TEST_ERASE_EEPROM 0x09 /* erase eeprom */
#define WHITEHEAT_TEST_READ_EEPROM 0x0a /* read eeprom */
#define WHITEHEAT_TEST_PROGRAM_EEPROM 0x0b /* program eeprom */
struct whiteheat_test {
__u8 port; /* port number (1 to n) */
__u8 test; /* see WHITEHEAT_TEST_* above*/
__u8 info[32]; /* additional info */
};
/*
* Replies from the firmware
*/
/*
* WHITEHEAT_STATUS
*/
#define WHITEHEAT_EVENT_MODEM 0x01 /* modem field is valid */
#define WHITEHEAT_EVENT_ERROR 0x02 /* error field is valid */
#define WHITEHEAT_EVENT_FLOW 0x04 /* flow field is valid */
#define WHITEHEAT_EVENT_CONNECT 0x08 /* connect field is valid */
#define WHITEHEAT_FLOW_NONE 0x00 /* no flow control active */
#define WHITEHEAT_FLOW_HARD_OUT 0x01 /* TX is stopped by CTS (waiting for CTS to go on) */
#define WHITEHEAT_FLOW_HARD_IN 0x02 /* remote TX is stopped by RTS */
#define WHITEHEAT_FLOW_SOFT_OUT 0x04 /* TX is stopped by XOFF received (waiting for XON) */
#define WHITEHEAT_FLOW_SOFT_IN 0x08 /* remote TX is stopped by XOFF transmitted */
#define WHITEHEAT_FLOW_TX_DONE 0x80 /* TX has completed */
struct whiteheat_status_info {
__u8 port; /* port number (1 to N) */
__u8 event; /* indicates which of the following bytes are the current event */
__u8 modem; /* modem signal status (copy of UART MSR register) */
__u8 error; /* PFO and RX break (copy of UART LSR register) */
__u8 flow; /* flow control state */
__u8 connect; /* connect state, non-zero value indicates connected */
__u8 event; /* indicates what the current event is, see WHITEHEAT_EVENT_* above */
__u8 modem; /* modem signal status (copy of uart's MSR register) */
__u8 error; /* line status (copy of uart's LSR register) */
__u8 flow; /* flow control state, see WHITEHEAT_FLOW_* above */
__u8 connect; /* 0 means not connected, non-zero means connected */
};
/* data returned from WHITEHEAT_EVENT command */
struct whiteheat_event {
__u8 port; /* port number (1 to N) */
__u8 event; /* indicates which of the following bytes are the current event */
__u8 info; /* either modem, error, flow, or connect information */
/*
* WHITEHEAT_GET_DTR_RTS
*/
struct whiteheat_dr_info {
__u8 mcr; /* copy of uart's MCR register */
};
/* data retured by the WHITEHEAT_GET_HW_INFO command */
/*
* WHITEHEAT_GET_HW_INFO
*/
struct whiteheat_hw_info {
__u8 hw_id; /* hardware id number, WhiteHEAT = 0 */
__u8 sw_major_rev; /* major version number */
......@@ -166,5 +253,30 @@ struct whiteheat_hw_info {
} hw_eeprom_info; /* EEPROM contents */
};
#endif
/*
* WHITEHEAT_EVENT
*/
struct whiteheat_event_info {
__u8 port; /* port number (1 to N) */
__u8 event; /* see whiteheat_status_info.event */
__u8 info; /* see whiteheat_status_info.modem, .error, .flow, .connect */
};
/*
* WHITEHEAT_DO_TEST
*/
#define WHITEHEAT_TEST_FAIL 0x00 /* test failed */
#define WHITEHEAT_TEST_UNKNOWN 0x01 /* unknown test requested */
#define WHITEHEAT_TEST_PASS 0xff /* test passed */
struct whiteheat_test_info {
__u8 port; /* port number (1 to N) */
__u8 test; /* indicates which test this is a response for, see WHITEHEAT_DO_TEST above */
__u8 status; /* see WHITEHEAT_TEST_* above */
__u8 results[32]; /* test-dependent results */
};
#endif
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -70,7 +70,7 @@ datafab_bulk_read(struct us_data *us, unsigned char *data, unsigned int len) {
unsigned int act_len; /* ignored */
if (len == 0)
return USB_STOR_TRANSPORT_GOOD;
return USB_STOR_XFER_GOOD;
US_DEBUGP("datafab_bulk_read: len = %d\n", len);
return usb_storage_raw_bulk(us, SCSI_DATA_READ, data, len, &act_len);
......@@ -82,7 +82,7 @@ datafab_bulk_write(struct us_data *us, unsigned char *data, unsigned int len) {
unsigned int act_len; /* ignored */
if (len == 0)
return USB_STOR_TRANSPORT_GOOD;
return USB_STOR_XFER_GOOD;
US_DEBUGP("datafab_bulk_write: len = %d\n", len);
return usb_storage_raw_bulk(us, SCSI_DATA_WRITE, data, len, &act_len);
......@@ -144,12 +144,12 @@ static int datafab_read_data(struct us_data *us,
// send the read command
result = datafab_bulk_write(us, command, sizeof(command));
if (result != USB_STOR_TRANSPORT_GOOD)
if (result != USB_STOR_XFER_GOOD)
goto leave;
// read the result
result = datafab_bulk_read(us, ptr, len);
if (result != USB_STOR_TRANSPORT_GOOD)
if (result != USB_STOR_XFER_GOOD)
goto leave;
sectors -= thistime;
......@@ -171,7 +171,7 @@ static int datafab_read_data(struct us_data *us,
leave:
if (use_sg)
kfree(buffer);
return result;
return USB_STOR_TRANSPORT_ERROR;
}
......@@ -243,17 +243,17 @@ static int datafab_write_data(struct us_data *us,
// send the command
result = datafab_bulk_write(us, command, sizeof(command));
if (result != USB_STOR_TRANSPORT_GOOD)
if (result != USB_STOR_XFER_GOOD)
goto leave;
// send the data
result = datafab_bulk_write(us, ptr, len);
if (result != USB_STOR_TRANSPORT_GOOD)
if (result != USB_STOR_XFER_GOOD)
goto leave;
// read the result
result = datafab_bulk_read(us, reply, sizeof(reply));
if (result != USB_STOR_TRANSPORT_GOOD)
if (result != USB_STOR_XFER_GOOD)
goto leave;
if (reply[0] != 0x50 && reply[1] != 0) {
......@@ -280,7 +280,7 @@ static int datafab_write_data(struct us_data *us,
leave:
if (use_sg)
kfree(buffer);
return result;
return USB_STOR_TRANSPORT_ERROR;
}
......@@ -308,11 +308,11 @@ static int datafab_determine_lun(struct us_data *us,
command[5] = 0xa0;
rc = datafab_bulk_write(us, command, 8);
if (rc != USB_STOR_TRANSPORT_GOOD)
return rc;
if (rc != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
rc = datafab_bulk_read(us, buf, sizeof(buf));
if (rc == USB_STOR_TRANSPORT_GOOD) {
if (rc == USB_STOR_XFER_GOOD) {
info->lun = 0;
return USB_STOR_TRANSPORT_GOOD;
}
......@@ -320,11 +320,11 @@ static int datafab_determine_lun(struct us_data *us,
command[5] = 0xb0;
rc = datafab_bulk_write(us, command, 8);
if (rc != USB_STOR_TRANSPORT_GOOD)
return rc;
if (rc != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
rc = datafab_bulk_read(us, buf, sizeof(buf));
if (rc == USB_STOR_TRANSPORT_GOOD) {
if (rc == USB_STOR_XFER_GOOD) {
info->lun = 1;
return USB_STOR_TRANSPORT_GOOD;
}
......@@ -332,7 +332,7 @@ static int datafab_determine_lun(struct us_data *us,
wait_ms(20);
}
return USB_STOR_TRANSPORT_FAILED;
return USB_STOR_TRANSPORT_ERROR;
}
static int datafab_id_device(struct us_data *us,
......@@ -358,22 +358,23 @@ static int datafab_id_device(struct us_data *us,
command[5] += (info->lun << 4);
rc = datafab_bulk_write(us, command, 8);
if (rc != USB_STOR_TRANSPORT_GOOD)
return rc;
if (rc != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
// we'll go ahead and extract the media capacity while we're here...
//
rc = datafab_bulk_read(us, reply, sizeof(reply));
if (rc == USB_STOR_TRANSPORT_GOOD) {
if (rc == USB_STOR_XFER_GOOD) {
// capacity is at word offset 57-58
//
info->sectors = ((u32)(reply[117]) << 24) |
((u32)(reply[116]) << 16) |
((u32)(reply[115]) << 8) |
((u32)(reply[114]) );
return USB_STOR_TRANSPORT_GOOD;
}
return rc;
return USB_STOR_TRANSPORT_ERROR;
}
......
......@@ -197,7 +197,7 @@ freecom_readdata (Scsi_Cmnd *srb, struct us_data *us,
/* has the current command been aborted? */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
US_DEBUGP("freecom_readdata(): transfer aborted\n");
return US_BULK_TRANSFER_ABORTED;
return USB_STOR_TRANSPORT_ABORTED;
}
return USB_STOR_TRANSPORT_ERROR;
......@@ -238,7 +238,7 @@ freecom_writedata (Scsi_Cmnd *srb, struct us_data *us,
/* has the current command been aborted? */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
US_DEBUGP("freecom_writedata(): transfer aborted\n");
return US_BULK_TRANSFER_ABORTED;
return USB_STOR_TRANSPORT_ABORTED;
}
return USB_STOR_TRANSPORT_ERROR;
......@@ -301,7 +301,7 @@ int freecom_transport(Scsi_Cmnd *srb, struct us_data *us)
/* we canceled this transfer */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
US_DEBUGP("freecom_transport(): transfer aborted\n");
return US_BULK_TRANSFER_ABORTED;
return USB_STOR_TRANSPORT_ABORTED;
}
return USB_STOR_TRANSPORT_ERROR;
......@@ -316,7 +316,7 @@ int freecom_transport(Scsi_Cmnd *srb, struct us_data *us)
/* we canceled this transfer */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
US_DEBUGP("freecom_transport(): transfer aborted\n");
return US_BULK_TRANSFER_ABORTED;
return USB_STOR_TRANSPORT_ABORTED;
}
US_DEBUG(pdump ((void *) fst, partial));
......@@ -354,7 +354,7 @@ int freecom_transport(Scsi_Cmnd *srb, struct us_data *us)
/* we canceled this transfer */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
US_DEBUGP("freecom_transport(): transfer aborted\n");
return US_BULK_TRANSFER_ABORTED;
return USB_STOR_TRANSPORT_ABORTED;
}
return USB_STOR_TRANSPORT_ERROR;
......@@ -369,7 +369,7 @@ int freecom_transport(Scsi_Cmnd *srb, struct us_data *us)
/* we canceled this transfer */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
US_DEBUGP("freecom_transport(): transfer aborted\n");
return US_BULK_TRANSFER_ABORTED;
return USB_STOR_TRANSPORT_ABORTED;
}
US_DEBUG(pdump ((void *) fst, partial));
......@@ -430,7 +430,7 @@ int freecom_transport(Scsi_Cmnd *srb, struct us_data *us)
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
US_DEBUGP ("freecom_transport: transfer aborted\n");
return US_BULK_TRANSFER_ABORTED;
return USB_STOR_TRANSPORT_ABORTED;
}
if (partial != 4 || result != 0)
return USB_STOR_TRANSPORT_ERROR;
......@@ -459,7 +459,7 @@ int freecom_transport(Scsi_Cmnd *srb, struct us_data *us)
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
US_DEBUGP ("freecom_transport: transfer aborted\n");
return US_BULK_TRANSFER_ABORTED;
return USB_STOR_TRANSPORT_ABORTED;
}
if (partial != 4 || result != 0)
return USB_STOR_TRANSPORT_ERROR;
......
......@@ -65,7 +65,7 @@ static inline int jumpshot_bulk_read(struct us_data *us,
unsigned int act_len; /* ignored */
if (len == 0)
return USB_STOR_TRANSPORT_GOOD;
return USB_STOR_XFER_GOOD;
US_DEBUGP("jumpshot_bulk_read: len = %d\n", len);
return usb_storage_raw_bulk(us, SCSI_DATA_READ, data, len, &act_len);
......@@ -79,7 +79,7 @@ static inline int jumpshot_bulk_write(struct us_data *us,
unsigned int act_len; /* ignored */
if (len == 0)
return USB_STOR_TRANSPORT_GOOD;
return USB_STOR_XFER_GOOD;
US_DEBUGP("jumpshot_bulk_write: len = %d\n", len);
return usb_storage_raw_bulk(us, SCSI_DATA_WRITE, data, len, &act_len);
......@@ -168,7 +168,7 @@ static int jumpshot_read_data(struct us_data *us,
// read the result
result = jumpshot_bulk_read(us, ptr, len);
if (result != USB_STOR_TRANSPORT_GOOD)
if (result != USB_STOR_XFER_GOOD)
goto leave;
US_DEBUGP("jumpshot_read_data: %d bytes\n", len);
......@@ -192,7 +192,7 @@ static int jumpshot_read_data(struct us_data *us,
leave:
if (use_sg)
kfree(buffer);
return result;
return USB_STOR_TRANSPORT_ERROR;
}
......@@ -253,7 +253,7 @@ static int jumpshot_write_data(struct us_data *us,
// send the data
result = jumpshot_bulk_write(us, ptr, len);
if (result != USB_STOR_TRANSPORT_GOOD)
if (result != USB_STOR_XFER_GOOD)
goto leave;
// read the result. apparently the bulk write can complete
......@@ -288,7 +288,7 @@ static int jumpshot_write_data(struct us_data *us,
leave:
if (use_sg)
kfree(buffer);
return result;
return USB_STOR_TRANSPORT_ERROR;
}
static int jumpshot_id_device(struct us_data *us,
......@@ -314,8 +314,8 @@ static int jumpshot_id_device(struct us_data *us,
// read the reply
rc = jumpshot_bulk_read(us, reply, sizeof(reply));
if (rc != USB_STOR_TRANSPORT_GOOD)
return rc;
if (rc != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
info->sectors = ((u32)(reply[117]) << 24) |
((u32)(reply[116]) << 16) |
......
......@@ -61,7 +61,7 @@ usb_storage_send_control(struct us_data *us,
/* did we abort this command? */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
US_DEBUGP("usb_stor_send_control(): transfer aborted\n");
return US_BULK_TRANSFER_ABORTED;
return USB_STOR_TRANSPORT_ABORTED;
}
// Check the return code for the command.
......@@ -70,7 +70,7 @@ usb_storage_send_control(struct us_data *us,
/* a stall indicates a protocol error */
if (result == -EPIPE) {
US_DEBUGP("-- Stall on control pipe\n");
return USB_STOR_TRANSPORT_FAILED;
return USB_STOR_TRANSPORT_ERROR;
}
/* Uh oh... serious problem here */
......@@ -100,14 +100,14 @@ usb_storage_raw_bulk(struct us_data *us, int direction, unsigned char *data,
" pipe 0x%x, stalled at %d bytes\n",
pipe, *act_len);
if (usb_stor_clear_halt(us, pipe) < 0)
return US_BULK_TRANSFER_FAILED;
/* return US_BULK_TRANSFER_SHORT; */
return USB_STOR_XFER_ERROR;
return USB_STOR_XFER_STALLED;
}
/* did we abort this command? */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
US_DEBUGP("usb_storage_raw_bulk(): transfer aborted\n");
return US_BULK_TRANSFER_ABORTED;
return USB_STOR_XFER_ABORTED;
}
if (result) {
......@@ -122,13 +122,13 @@ usb_storage_raw_bulk(struct us_data *us, int direction, unsigned char *data,
US_DEBUGP("raw_bulk(): unknown error %d\n",
result);
return US_BULK_TRANSFER_FAILED;
return USB_STOR_XFER_ERROR;
}
if (*act_len != len) {
US_DEBUGP("Warning: Transferred only %d of %d bytes\n",
*act_len, len);
return US_BULK_TRANSFER_SHORT;
return USB_STOR_XFER_SHORT;
}
#if 0
......@@ -137,7 +137,7 @@ usb_storage_raw_bulk(struct us_data *us, int direction, unsigned char *data,
*act_len, len);
#endif
return US_BULK_TRANSFER_GOOD;
return USB_STOR_XFER_GOOD;
}
int
......@@ -145,14 +145,14 @@ usb_storage_bulk_transport(struct us_data *us, int direction,
unsigned char *data, unsigned int len,
int use_sg) {
int result = USB_STOR_TRANSPORT_GOOD;
int result = USB_STOR_XFER_ERROR;
int transferred = 0;
int i;
struct scatterlist *sg;
unsigned int act_len;
if (len == 0)
return USB_STOR_TRANSPORT_GOOD;
return USB_STOR_XFER_GOOD;
#if DEBUG_PRCT
......@@ -196,7 +196,7 @@ usb_storage_bulk_transport(struct us_data *us, int direction,
result = usb_storage_raw_bulk(us, direction,
buf, length, &act_len);
if (result != US_BULK_TRANSFER_GOOD)
if (result != USB_STOR_XFER_GOOD)
break;
transferred += length;
}
......
......@@ -285,12 +285,14 @@ sddr09_request_sense(struct us_data *us, unsigned char *sensebuf, int buflen) {
}
result = usb_storage_raw_bulk(us, SCSI_DATA_READ, sensebuf, buflen, &act_len);
if (result != USB_STOR_TRANSPORT_GOOD)
if (result != USB_STOR_XFER_GOOD) {
US_DEBUGP("request sense bulk in failed\n");
else
return USB_STOR_TRANSPORT_ERROR;
}
else {
US_DEBUGP("request sense worked\n");
return result;
return USB_STOR_TRANSPORT_GOOD;
}
}
/*
......@@ -344,11 +346,12 @@ sddr09_readX(struct us_data *us, int x, unsigned long fromaddress,
result = usb_storage_bulk_transport(us, SCSI_DATA_READ,
buf, bulklen, use_sg);
if (result != USB_STOR_TRANSPORT_GOOD)
if (result != USB_STOR_XFER_GOOD) {
US_DEBUGP("Result for bulk_transport in sddr09_read2%d %d\n",
x, result);
return result;
return USB_STOR_TRANSPORT_ERROR;
}
return USB_STOR_TRANSPORT_GOOD;
}
/*
......@@ -510,11 +513,12 @@ sddr09_writeX(struct us_data *us,
result = usb_storage_bulk_transport(us, SCSI_DATA_WRITE,
buf, bulklen, use_sg);
if (result != USB_STOR_TRANSPORT_GOOD)
if (result != USB_STOR_XFER_GOOD) {
US_DEBUGP("Result for bulk_transport in sddr09_writeX %d\n",
result);
return result;
return USB_STOR_TRANSPORT_ERROR;
}
return USB_STOR_TRANSPORT_GOOD;
}
/* erase address, write same address */
......@@ -590,13 +594,14 @@ sddr09_read_sg_test_only(struct us_data *us) {
result = usb_storage_bulk_transport(us, SCSI_DATA_READ,
buf, bulklen, 0);
if (result != USB_STOR_TRANSPORT_GOOD)
kfree(buf);
if (result != USB_STOR_XFER_GOOD) {
US_DEBUGP("Result for bulk_transport in sddr09_read_sg %d\n",
result);
return USB_STOR_TRANSPORT_ERROR;
}
kfree(buf);
return result;
return USB_STOR_TRANSPORT_GOOD;
}
#endif
......@@ -629,7 +634,8 @@ sddr09_read_status(struct us_data *us, unsigned char *status) {
result = usb_storage_bulk_transport(us, SCSI_DATA_READ,
data, sizeof(data), 0);
*status = data[0];
return result;
return (result == USB_STOR_XFER_GOOD ?
USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR);
}
static int
......@@ -953,7 +959,8 @@ sddr09_read_deviceID(struct us_data *us, unsigned char *deviceID) {
for (i = 0; i < 4; i++)
deviceID[i] = content[i];
return result;
return (result == USB_STOR_XFER_GOOD ?
USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR);
}
static int
......@@ -1549,7 +1556,8 @@ int sddr09_transport(Scsi_Cmnd *srb, struct us_data *us)
srb->request_bufflen,
srb->use_sg);
return result;
return (result == USB_STOR_XFER_GOOD ?
USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR);
}
return USB_STOR_TRANSPORT_GOOD;
......
......@@ -101,16 +101,16 @@ static int sddr55_status(struct us_data *us)
US_DEBUGP("Result for send_command in status %d\n",
result);
if (result != US_BULK_TRANSFER_GOOD) {
if (result != USB_STOR_XFER_GOOD) {
set_sense_info (4, 0, 0); /* hardware error */
return result;
return USB_STOR_TRANSPORT_ERROR;
}
result = sddr55_bulk_transport(us,
SCSI_DATA_READ, status, 4);
/* expect to get short transfer if no card fitted */
if (result == US_BULK_TRANSFER_SHORT) {
if (result == USB_STOR_XFER_SHORT || result == USB_STOR_XFER_STALLED) {
/* had a short transfer, no card inserted, free map memory */
if (info->lba_to_pba)
kfree(info->lba_to_pba);
......@@ -123,12 +123,12 @@ static int sddr55_status(struct us_data *us)
info->force_read_only = 0;
set_sense_info (2, 0x3a, 0); /* not ready, medium not present */
return result;
return USB_STOR_TRANSPORT_FAILED;
}
if (result != US_BULK_TRANSFER_GOOD) {
if (result != USB_STOR_XFER_GOOD) {
set_sense_info (4, 0, 0); /* hardware error */
return result;
return USB_STOR_TRANSPORT_FAILED;
}
/* check write protect status */
......@@ -138,11 +138,12 @@ static int sddr55_status(struct us_data *us)
result = sddr55_bulk_transport(us,
SCSI_DATA_READ, status, 2);
if (result != US_BULK_TRANSFER_GOOD) {
if (result != USB_STOR_XFER_GOOD) {
set_sense_info (4, 0, 0); /* hardware error */
}
return result;
return (result == USB_STOR_XFER_GOOD ?
USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_FAILED);
}
......@@ -214,23 +215,29 @@ static int sddr55_read_data(struct us_data *us,
US_DEBUGP("Result for send_command in read_data %d\n",
result);
if (result != US_BULK_TRANSFER_GOOD)
if (result != USB_STOR_XFER_GOOD) {
result = USB_STOR_TRANSPORT_ERROR;
goto leave;
}
/* read data */
result = sddr55_bulk_transport(us,
SCSI_DATA_READ, ptr,
pages<<info->pageshift);
if (result != US_BULK_TRANSFER_GOOD)
if (result != USB_STOR_XFER_GOOD) {
result = USB_STOR_TRANSPORT_ERROR;
goto leave;
}
/* now read status */
result = sddr55_bulk_transport(us,
SCSI_DATA_READ, status, 2);
if (result != US_BULK_TRANSFER_GOOD)
if (result != USB_STOR_XFER_GOOD) {
result = USB_STOR_TRANSPORT_ERROR;
goto leave;
}
/* check status for error */
if (status[0] == 0xff && status[1] == 0x4) {
......@@ -247,6 +254,7 @@ static int sddr55_read_data(struct us_data *us,
}
us_copy_to_sgbuf_all(buffer, len, content, use_sg);
result = USB_STOR_TRANSPORT_GOOD;
leave:
if (use_sg)
......@@ -374,12 +382,13 @@ static int sddr55_write_data(struct us_data *us,
result = sddr55_bulk_transport(us,
SCSI_DATA_WRITE, command, 8);
if (result != US_BULK_TRANSFER_GOOD) {
if (result != USB_STOR_XFER_GOOD) {
US_DEBUGP("Result for send_command in write_data %d\n",
result);
/* set_sense_info is superfluous here? */
set_sense_info (3, 0x3, 0);/* peripheral write error */
result = USB_STOR_TRANSPORT_FAILED;
goto leave;
}
......@@ -388,24 +397,26 @@ static int sddr55_write_data(struct us_data *us,
SCSI_DATA_WRITE, ptr,
pages<<info->pageshift);
if (result != US_BULK_TRANSFER_GOOD) {
if (result != USB_STOR_XFER_GOOD) {
US_DEBUGP("Result for send_data in write_data %d\n",
result);
/* set_sense_info is superfluous here? */
set_sense_info (3, 0x3, 0);/* peripheral write error */
result = USB_STOR_TRANSPORT_FAILED;
goto leave;
}
/* now read status */
result = sddr55_bulk_transport(us, SCSI_DATA_READ, status, 6);
if (result != US_BULK_TRANSFER_GOOD) {
if (result != USB_STOR_XFER_GOOD) {
US_DEBUGP("Result for get_status in write_data %d\n",
result);
/* set_sense_info is superfluous here? */
set_sense_info (3, 0x3, 0);/* peripheral write error */
result = USB_STOR_TRANSPORT_FAILED;
goto leave;
}
......@@ -446,6 +457,7 @@ static int sddr55_write_data(struct us_data *us,
sectors -= pages >> info->smallpageshift;
ptr += (pages << info->pageshift);
}
result = USB_STOR_TRANSPORT_GOOD;
leave:
if (use_sg)
......@@ -468,14 +480,14 @@ static int sddr55_read_deviceID(struct us_data *us,
US_DEBUGP("Result of send_control for device ID is %d\n",
result);
if (result != US_BULK_TRANSFER_GOOD)
return result;
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
result = sddr55_bulk_transport(us,
SCSI_DATA_READ, content, 4);
if (result != US_BULK_TRANSFER_GOOD)
return result;
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
*manufacturerID = content[0];
*deviceID = content[1];
......@@ -485,7 +497,7 @@ static int sddr55_read_deviceID(struct us_data *us,
SCSI_DATA_READ, content, 2);
}
return result;
return USB_STOR_TRANSPORT_GOOD;
}
......@@ -510,7 +522,7 @@ static unsigned long sddr55_get_capacity(struct us_data *us) {
US_DEBUGP("Result of read_deviceID is %d\n",
result);
if (result != US_BULK_TRANSFER_GOOD)
if (result != USB_STOR_XFER_GOOD)
return 0;
US_DEBUGP("Device ID = %02X\n", deviceID);
......@@ -603,21 +615,21 @@ static int sddr55_read_map(struct us_data *us) {
result = sddr55_bulk_transport(us, SCSI_DATA_WRITE, command, 8);
if ( result != US_BULK_TRANSFER_GOOD) {
if ( result != USB_STOR_XFER_GOOD) {
kfree (buffer);
return -1;
}
result = sddr55_bulk_transport(us, SCSI_DATA_READ, buffer, numblocks * 2);
if ( result != US_BULK_TRANSFER_GOOD) {
if ( result != USB_STOR_XFER_GOOD) {
kfree (buffer);
return -1;
}
result = sddr55_bulk_transport(us, SCSI_DATA_READ, command, 2);
if ( result != US_BULK_TRANSFER_GOOD) {
if ( result != USB_STOR_XFER_GOOD) {
kfree (buffer);
return -1;
}
......
......@@ -153,7 +153,8 @@ int usbat_read_block(struct us_data *us,
result = usb_storage_bulk_transport(us, SCSI_DATA_READ, content, len, use_sg);
return result;
return (result == USB_STOR_XFER_GOOD ?
USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR);
}
/*
......@@ -234,8 +235,8 @@ int usbat_write_block(struct us_data *us,
result = usb_storage_bulk_transport(us, SCSI_DATA_WRITE, content, len, use_sg);
if (result != USB_STOR_TRANSPORT_GOOD)
return result;
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
return usbat_wait_not_busy(us, minutes);
}
......@@ -309,8 +310,8 @@ int usbat_rw_block_test(struct us_data *us,
SCSI_DATA_WRITE,
data, num_registers*2, 0);
if (result!=USB_STOR_TRANSPORT_GOOD)
return result;
if (result!=USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
}
......@@ -341,7 +342,8 @@ int usbat_rw_block_test(struct us_data *us,
* transferred.
*/
if (result == US_BULK_TRANSFER_SHORT) {
if (result == USB_STOR_XFER_SHORT ||
result == USB_STOR_XFER_STALLED) {
/*
* If we're reading and we stalled, then clear
......@@ -373,8 +375,8 @@ int usbat_rw_block_test(struct us_data *us,
US_DEBUGP("Redoing %s\n",
direction==SCSI_DATA_WRITE ? "write" : "read");
} else if (result != US_BULK_TRANSFER_GOOD)
return result;
} else if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
else
return usbat_wait_not_busy(us, minutes);
......@@ -425,8 +427,8 @@ int usbat_multiple_write(struct us_data *us,
result = usb_storage_bulk_transport(us,
SCSI_DATA_WRITE, data, num_registers*2, 0);
if (result != USB_STOR_TRANSPORT_GOOD)
return result;
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
return usbat_wait_not_busy(us, 0);
}
......
......@@ -572,36 +572,37 @@ int usb_stor_transfer_partial(struct us_data *us, char *buf, int length)
if (result == -EPIPE) {
US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
if (usb_stor_clear_halt(us, pipe) < 0)
return US_BULK_TRANSFER_FAILED;
return USB_STOR_XFER_ERROR;
return USB_STOR_XFER_STALLED;
}
/* did we abort this command? */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
US_DEBUGP("usb_stor_transfer_partial(): transfer aborted\n");
return US_BULK_TRANSFER_ABORTED;
}
/* did we send all the data? */
if (partial == length) {
US_DEBUGP("usb_stor_transfer_partial(): transfer complete\n");
return US_BULK_TRANSFER_GOOD;
return USB_STOR_XFER_ABORTED;
}
/* NAK - that means we've retried a few times already */
if (result == -ETIMEDOUT) {
US_DEBUGP("usb_stor_transfer_partial(): device NAKed\n");
return US_BULK_TRANSFER_FAILED;
return USB_STOR_XFER_ERROR;
}
/* the catch-all error case */
if (result) {
US_DEBUGP("usb_stor_transfer_partial(): unknown error\n");
return US_BULK_TRANSFER_FAILED;
return USB_STOR_XFER_ERROR;
}
/* did we send all the data? */
if (partial == length) {
US_DEBUGP("usb_stor_transfer_partial(): transfer complete\n");
return USB_STOR_XFER_GOOD;
}
/* no error code, so we must have transferred some data,
* just not all of it */
return US_BULK_TRANSFER_SHORT;
return USB_STOR_XFER_SHORT;
}
/*
......@@ -739,7 +740,7 @@ void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us)
* Also, if we have a short transfer on a command that can't have
* a short transfer, we're going to do this.
*/
if ((srb->result == US_BULK_TRANSFER_SHORT) &&
if ((srb->result == USB_STOR_XFER_SHORT) &&
!((srb->cmnd[0] == REQUEST_SENSE) ||
(srb->cmnd[0] == INQUIRY) ||
(srb->cmnd[0] == MODE_SENSE) ||
......@@ -995,13 +996,13 @@ int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us)
/* did we abort this command? */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
US_DEBUGP("usb_stor_control_msg(): transfer aborted\n");
return US_BULK_TRANSFER_ABORTED;
return USB_STOR_TRANSPORT_ABORTED;
}
/* a stall indicates a protocol error */
if (result == -EPIPE) {
US_DEBUGP("-- Stall on control pipe\n");
return USB_STOR_TRANSPORT_FAILED;
return USB_STOR_TRANSPORT_ERROR;
}
if (result < 0) {
......@@ -1017,13 +1018,13 @@ int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us)
US_DEBUGP("CBI data stage result is 0x%x\n", result);
/* report any errors */
if (result == US_BULK_TRANSFER_ABORTED) {
if (result == USB_STOR_XFER_ABORTED) {
clear_bit(US_FLIDX_IP_WANTED, &us->flags);
return USB_STOR_TRANSPORT_ABORTED;
}
if (result == US_BULK_TRANSFER_FAILED) {
if (result == USB_STOR_XFER_ERROR) {
clear_bit(US_FLIDX_IP_WANTED, &us->flags);
return USB_STOR_TRANSPORT_FAILED;
return USB_STOR_TRANSPORT_ERROR;
}
}
......@@ -1103,13 +1104,13 @@ int usb_stor_CB_transport(Scsi_Cmnd *srb, struct us_data *us)
/* did we abort this command? */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
US_DEBUGP("usb_stor_CB_transport(): transfer aborted\n");
return US_BULK_TRANSFER_ABORTED;
return USB_STOR_TRANSPORT_ABORTED;
}
/* a stall indicates a protocol error */
if (result == -EPIPE) {
US_DEBUGP("-- Stall on control pipe\n");
return USB_STOR_TRANSPORT_FAILED;
return USB_STOR_TRANSPORT_ERROR;
}
/* Uh oh... serious problem here */
......@@ -1124,11 +1125,11 @@ int usb_stor_CB_transport(Scsi_Cmnd *srb, struct us_data *us)
US_DEBUGP("CB data stage result is 0x%x\n", result);
/* report any errors */
if (result == US_BULK_TRANSFER_ABORTED) {
if (result == USB_STOR_XFER_ABORTED) {
return USB_STOR_TRANSPORT_ABORTED;
}
if (result == US_BULK_TRANSFER_FAILED) {
return USB_STOR_TRANSPORT_FAILED;
if (result == USB_STOR_XFER_ERROR) {
return USB_STOR_TRANSPORT_ERROR;
}
}
......@@ -1207,7 +1208,7 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
/* did we abort this command? */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
US_DEBUGP("usb_stor_Bulk_transport(): transfer aborted\n");
return US_BULK_TRANSFER_ABORTED;
return USB_STOR_TRANSPORT_ABORTED;
}
/* if we stall, we need to clear it before we go on */
......@@ -1218,7 +1219,7 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
/* did we abort this command? */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
US_DEBUGP("usb_stor_Bulk_transport(): transfer aborted\n");
return US_BULK_TRANSFER_ABORTED;
return USB_STOR_TRANSPORT_ABORTED;
}
if (result < 0)
return USB_STOR_TRANSPORT_ERROR;
......@@ -1237,7 +1238,7 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
US_DEBUGP("Bulk data transfer result 0x%x\n", result);
/* if it was aborted, we need to indicate that */
if (result == US_BULK_TRANSFER_ABORTED)
if (result == USB_STOR_XFER_ABORTED)
return USB_STOR_TRANSPORT_ABORTED;
}
}
......@@ -1257,7 +1258,7 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
/* did we abort this command? */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
US_DEBUGP("usb_stor_Bulk_transport(): transfer aborted\n");
return US_BULK_TRANSFER_ABORTED;
return USB_STOR_TRANSPORT_ABORTED;
}
/* did the attempt to read the CSW fail? */
......@@ -1268,7 +1269,7 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
/* did we abort this command? */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
US_DEBUGP("usb_stor_Bulk_transport(): transfer aborted\n");
return US_BULK_TRANSFER_ABORTED;
return USB_STOR_TRANSPORT_ABORTED;
}
if (result < 0)
return USB_STOR_TRANSPORT_ERROR;
......@@ -1281,7 +1282,7 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
/* did we abort this command? */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
US_DEBUGP("usb_stor_Bulk_transport(): transfer aborted\n");
return US_BULK_TRANSFER_ABORTED;
return USB_STOR_TRANSPORT_ABORTED;
}
/* if it fails again, we need a reset and return an error*/
......@@ -1292,7 +1293,7 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
/* did we abort this command? */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
US_DEBUGP("usb_stor_Bulk_transport(): transfer aborted\n");
return US_BULK_TRANSFER_ABORTED;
return USB_STOR_TRANSPORT_ABORTED;
}
return USB_STOR_TRANSPORT_ERROR;
}
......
......@@ -115,12 +115,13 @@ struct bulk_cs_wrap {
#define US_BULK_GET_MAX_LUN 0xfe
/*
* usb_stor_transfer() return codes
* usb_stor_transfer() return codes, in order of severity
*/
#define US_BULK_TRANSFER_GOOD 0 /* good transfer */
#define US_BULK_TRANSFER_SHORT 1 /* transfered less than expected */
#define US_BULK_TRANSFER_FAILED 2 /* transfer died in the middle */
#define US_BULK_TRANSFER_ABORTED 3 /* transfer canceled */
#define USB_STOR_XFER_GOOD 0 /* good transfer */
#define USB_STOR_XFER_SHORT 1 /* transfered less than expected */
#define USB_STOR_XFER_STALLED 2 /* endpoint stalled */
#define USB_STOR_XFER_ERROR 3 /* transfer died in the middle */
#define USB_STOR_XFER_ABORTED 4 /* transfer canceled */
/*
* Transport return codes
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment