USB: cypress_m8: Limit baud rate to <=4800 for USB low speed devices

The cypress app note for the M8 states that for the USB low speed
version of the part, throughput is effectively limited to 800
bytes/sec.  So if we were to try a faster baud rate in such cases then
we risk overrun errors on receive.  Best to just identify this case
and limit the rate to 4800 baud or less (by ignoring any request to
set a faster rate).  The old baud rate setting code was somewhat
fragile; this change also hopefully makes it easier in the future to
better checking / limiting.

Signed-off-by: Mike Isely <isely@pobox.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
Mike Isely 2008-02-10 20:23:32 -06:00 committed by Greg Kroah-Hartman
parent 6768306c3d
commit 92983c2121
1 changed files with 59 additions and 45 deletions

View File

@ -291,6 +291,59 @@ static struct usb_serial_driver cypress_ca42v2_device = {
*****************************************************************************/
static int analyze_baud_rate(struct usb_serial_port *port, unsigned baud_mask)
{
int new_rate;
struct cypress_private *priv;
priv = usb_get_serial_port_data(port);
/*
* The general purpose firmware for the Cypress M8 allows for
* a maximum speed of 57600bps (I have no idea whether DeLorme
* chose to use the general purpose firmware or not), if you
* need to modify this speed setting for your own project
* please add your own chiptype and modify the code likewise.
* The Cypress HID->COM device will work successfully up to
* 115200bps (but the actual throughput is around 3kBps).
*/
new_rate = mask_to_rate(baud_mask);
if (new_rate < 0) {
dbg("%s - failed setting baud rate, untranslatable speed",
__func__);
return -1;
}
if (port->serial->dev->speed == USB_SPEED_LOW) {
/*
* Mike Isely <isely@pobox.com> 2-Feb-2008: The
* Cypress app note that describes this mechanism
* states the the low-speed part can't handle more
* than 800 bytes/sec, in which case 4800 baud is the
* safest speed for a part like that.
*/
if (new_rate > 4800) {
dbg("%s - failed setting baud rate, device incapable "
"speed %d", __func__, new_rate);
return -1;
}
}
switch (priv->chiptype) {
case CT_EARTHMATE:
if (new_rate <= 600) {
/* 300 and 600 baud rates are supported under
* the generic firmware, but are not used with
* NMEA and SiRF protocols */
dbg("%s - failed setting baud rate, unsupported speed "
"of %d on Earthmate GPS", __func__, new_rate);
return -1;
}
break;
default:
break;
}
return new_rate;
}
/* This function can either set or retrieve the current serial line settings */
static int cypress_serial_control (struct usb_serial_port *port, unsigned baud_mask, int data_bits, int stop_bits,
int parity_enable, int parity_type, int reset, int cypress_request_type)
@ -309,54 +362,15 @@ static int cypress_serial_control (struct usb_serial_port *port, unsigned baud_m
switch(cypress_request_type) {
case CYPRESS_SET_CONFIG:
/*
* The general purpose firmware for the Cypress M8 allows for a maximum speed
* of 57600bps (I have no idea whether DeLorme chose to use the general purpose
* firmware or not), if you need to modify this speed setting for your own
* project please add your own chiptype and modify the code likewise. The
* Cypress HID->COM device will work successfully up to 115200bps (but the
* actual throughput is around 3kBps).
*/
new_baudrate = priv->baud_rate;
if (baud_mask != priv->cbr_mask) {
dbg("%s - baud rate is changing", __FUNCTION__);
if ( priv->chiptype == CT_EARTHMATE ) {
/* 300 and 600 baud rates are supported under the generic firmware,
* but are not used with NMEA and SiRF protocols */
if ( (baud_mask == B300) || (baud_mask == B600) ) {
err("%s - failed setting baud rate, unsupported speed",
__FUNCTION__);
new_baudrate = priv->baud_rate;
} else if ( (new_baudrate = mask_to_rate(baud_mask)) == -1) {
err("%s - failed setting baud rate, unsupported speed",
__FUNCTION__);
new_baudrate = priv->baud_rate;
}
} else if (priv->chiptype == CT_CYPHIDCOM) {
if ( (new_baudrate = mask_to_rate(baud_mask)) == -1) {
err("%s - failed setting baud rate, unsupported speed",
__FUNCTION__);
new_baudrate = priv->baud_rate;
}
} else if (priv->chiptype == CT_CA42V2) {
if ( (new_baudrate = mask_to_rate(baud_mask)) == -1) {
err("%s - failed setting baud rate, unsupported speed",
__FUNCTION__);
new_baudrate = priv->baud_rate;
}
} else if (priv->chiptype == CT_GENERIC) {
if ( (new_baudrate = mask_to_rate(baud_mask)) == -1) {
err("%s - failed setting baud rate, unsupported speed",
__FUNCTION__);
new_baudrate = priv->baud_rate;
}
} else {
info("%s - please define your chiptype", __FUNCTION__);
new_baudrate = priv->baud_rate;
retval = analyze_baud_rate(port, baud_mask);
if (retval >= 0) {
new_baudrate = retval;
dbg("%s - New baud rate set to %d",
__func__, new_baudrate);
}
} else { /* baud rate not changing, keep the old */
new_baudrate = priv->baud_rate;
}
dbg("%s - baud rate is being sent as %d", __FUNCTION__, new_baudrate);