merge with mainline
This commit is contained in:
commit
d84666e6bb
37 changed files with 2533 additions and 641 deletions
|
@ -654,7 +654,8 @@ grub_ohci_transaction (grub_ohci_td_t td,
|
|||
|
||||
static grub_usb_err_t
|
||||
grub_ohci_transfer (grub_usb_controller_t dev,
|
||||
grub_usb_transfer_t transfer)
|
||||
grub_usb_transfer_t transfer, int timeout,
|
||||
grub_size_t *actual)
|
||||
{
|
||||
struct grub_ohci *o = (struct grub_ohci *) dev->data;
|
||||
grub_ohci_ed_t ed_virt;
|
||||
|
@ -680,6 +681,8 @@ grub_ohci_transfer (grub_usb_controller_t dev,
|
|||
int err_unrec = 0;
|
||||
grub_uint32_t intstatus;
|
||||
|
||||
*actual = 0;
|
||||
|
||||
/* Pre-set target for ED - we need it to find proper ED */
|
||||
/* Set the device address. */
|
||||
target = transfer->devaddr;
|
||||
|
@ -832,7 +835,7 @@ grub_ohci_transfer (grub_usb_controller_t dev,
|
|||
}
|
||||
|
||||
/* Safety measure to avoid a hang. */
|
||||
maxtime = grub_get_time_ms () + 1000;
|
||||
maxtime = grub_get_time_ms () + timeout;
|
||||
|
||||
/* Wait until the transfer is completed or STALLs. */
|
||||
do
|
||||
|
@ -986,6 +989,7 @@ grub_ohci_transfer (grub_usb_controller_t dev,
|
|||
transfer->last_trans = tderr_virt->tr_index;
|
||||
else
|
||||
transfer->last_trans = -1;
|
||||
*actual = transfer->size + 1;
|
||||
}
|
||||
|
||||
else if (err_halt) /* error, ED is halted by OHCI, i.e. can be modified */
|
||||
|
@ -1032,7 +1036,7 @@ grub_ohci_transfer (grub_usb_controller_t dev,
|
|||
{
|
||||
case 0:
|
||||
/* XXX: Should not happen! */
|
||||
grub_error (GRUB_ERR_IO, "OHCI without reporting the reason");
|
||||
grub_error (GRUB_ERR_IO, "OHCI failed without reporting the reason");
|
||||
err = GRUB_USB_ERR_INTERNAL;
|
||||
break;
|
||||
|
||||
|
@ -1078,12 +1082,14 @@ grub_ohci_transfer (grub_usb_controller_t dev,
|
|||
|
||||
case 9:
|
||||
/* XXX: Data underrun error. */
|
||||
err = GRUB_USB_ERR_DATA;
|
||||
grub_dprintf ("ohci", "Underrun, failed TD address: %p, index: %d\n",
|
||||
tderr_virt, tderr_virt->tr_index);
|
||||
grub_dprintf ("ohci", "Underrun, number of not transferred bytes: %d\n",
|
||||
1 + grub_le_to_cpu32 (tderr_virt->buffer_end)
|
||||
- grub_le_to_cpu32 (tderr_virt->buffer));
|
||||
if (transfer->last_trans == -1)
|
||||
break;
|
||||
*actual = transfer->transactions[transfer->last_trans].size
|
||||
- (grub_le_to_cpu32 (tderr_virt->buffer_end)
|
||||
- grub_le_to_cpu32 (tderr_virt->buffer))
|
||||
+ transfer->transactions[transfer->last_trans].preceding;
|
||||
break;
|
||||
|
||||
case 10:
|
||||
|
@ -1172,12 +1178,10 @@ grub_ohci_transfer (grub_usb_controller_t dev,
|
|||
transfer->last_trans = tderr_virt->tr_index;
|
||||
else
|
||||
transfer->last_trans = -1;
|
||||
|
||||
}
|
||||
|
||||
/* Set empty ED - set HEAD = TAIL = last (not processed) TD */
|
||||
ed_virt->td_head = grub_cpu_to_le32 ( grub_le_to_cpu32 (
|
||||
ed_virt->td_tail) & ~0xf);
|
||||
/* Set empty ED - set HEAD = TAIL = last (not processed) TD */
|
||||
ed_virt->td_head = grub_cpu_to_le32 (grub_le_to_cpu32 (ed_virt->td_tail) & ~0xf);
|
||||
|
||||
/* At this point always should be:
|
||||
* ED has skip bit set and halted or empty or after next SOF,
|
||||
|
|
125
grub-core/bus/usb/serial/common.c
Normal file
125
grub-core/bus/usb/serial/common.c
Normal file
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2000,2001,2002,2003,2004,2005,2007,2008,2009,2010 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/serial.h>
|
||||
#include <grub/usbserial.h>
|
||||
|
||||
void
|
||||
grub_usbserial_fini (struct grub_serial_port *port)
|
||||
{
|
||||
port->usbdev->config[port->configno].interf[port->interfno].detach_hook = 0;
|
||||
port->usbdev->config[port->configno].interf[port->interfno].attached = 0;
|
||||
}
|
||||
|
||||
void
|
||||
grub_usbserial_detach (grub_usb_device_t usbdev, int configno, int interfno)
|
||||
{
|
||||
static struct grub_serial_port *port;
|
||||
port = usbdev->config[configno].interf[interfno].detach_data;
|
||||
|
||||
grub_serial_unregister (port);
|
||||
}
|
||||
|
||||
static int usbnum = 0;
|
||||
|
||||
int
|
||||
grub_usbserial_attach (grub_usb_device_t usbdev, int configno, int interfno,
|
||||
struct grub_serial_driver *driver)
|
||||
{
|
||||
struct grub_serial_port *port;
|
||||
int j;
|
||||
struct grub_usb_desc_if *interf;
|
||||
|
||||
interf = usbdev->config[configno].interf[interfno].descif;
|
||||
|
||||
port = grub_malloc (sizeof (*port));
|
||||
if (!port)
|
||||
{
|
||||
grub_print_error ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
port->name = grub_xasprintf ("usb%d", usbnum++);
|
||||
if (!port->name)
|
||||
{
|
||||
grub_free (port);
|
||||
grub_print_error ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
port->usbdev = usbdev;
|
||||
port->driver = driver;
|
||||
for (j = 0; j < interf->endpointcnt; j++)
|
||||
{
|
||||
struct grub_usb_desc_endp *endp;
|
||||
endp = &usbdev->config[0].interf[interfno].descendp[j];
|
||||
|
||||
if ((endp->endp_addr & 128) && (endp->attrib & 3) == 2)
|
||||
{
|
||||
/* Bulk IN endpoint. */
|
||||
port->in_endp = endp;
|
||||
}
|
||||
else if (!(endp->endp_addr & 128) && (endp->attrib & 3) == 2)
|
||||
{
|
||||
/* Bulk OUT endpoint. */
|
||||
port->out_endp = endp;
|
||||
}
|
||||
}
|
||||
if (!port->out_endp || !port->in_endp)
|
||||
{
|
||||
grub_free (port->name);
|
||||
grub_free (port);
|
||||
return 0;
|
||||
}
|
||||
|
||||
port->configno = configno;
|
||||
port->interfno = interfno;
|
||||
|
||||
grub_serial_config_defaults (port);
|
||||
grub_serial_register (port);
|
||||
|
||||
port->usbdev->config[port->configno].interf[port->interfno].detach_hook
|
||||
= grub_usbserial_detach;
|
||||
port->usbdev->config[port->configno].interf[port->interfno].detach_data
|
||||
= port;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
grub_usbserial_fetch (struct grub_serial_port *port, grub_size_t header_size)
|
||||
{
|
||||
grub_usb_err_t err;
|
||||
grub_size_t actual;
|
||||
|
||||
if (port->bufstart < port->bufend)
|
||||
return port->buf[port->bufstart++];
|
||||
|
||||
err = grub_usb_bulk_read_extended (port->usbdev, port->in_endp->endp_addr,
|
||||
sizeof (port->buf), port->buf, 10,
|
||||
&actual);
|
||||
if (err != GRUB_USB_ERR_NONE)
|
||||
return -1;
|
||||
|
||||
port->bufstart = header_size;
|
||||
port->bufend = actual;
|
||||
if (port->bufstart >= port->bufend)
|
||||
return -1;
|
||||
|
||||
return port->buf[port->bufstart++];
|
||||
}
|
205
grub-core/bus/usb/serial/ftdi.c
Normal file
205
grub-core/bus/usb/serial/ftdi.c
Normal file
|
@ -0,0 +1,205 @@
|
|||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2000,2001,2002,2003,2004,2005,2007,2008,2009,2010 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/serial.h>
|
||||
#include <grub/types.h>
|
||||
#include <grub/dl.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/usb.h>
|
||||
#include <grub/usbserial.h>
|
||||
|
||||
enum
|
||||
{
|
||||
GRUB_FTDI_MODEM_CTRL = 0x01,
|
||||
GRUB_FTDI_FLOW_CTRL = 0x02,
|
||||
GRUB_FTDI_SPEED_CTRL = 0x03,
|
||||
GRUB_FTDI_DATA_CTRL = 0x04
|
||||
};
|
||||
|
||||
#define GRUB_FTDI_MODEM_CTRL_DTRRTS 3
|
||||
#define GRUB_FTDI_FLOW_CTRL_DTRRTS 3
|
||||
|
||||
/* Convert speed to divisor. */
|
||||
static grub_uint32_t
|
||||
get_divisor (unsigned int speed)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
/* The structure for speed vs. divisor. */
|
||||
struct divisor
|
||||
{
|
||||
unsigned int speed;
|
||||
grub_uint32_t div;
|
||||
};
|
||||
|
||||
/* The table which lists common configurations. */
|
||||
/* Computed with a division formula with 3MHz as base frequency. */
|
||||
static struct divisor divisor_tab[] =
|
||||
{
|
||||
{ 2400, 0x04e2 },
|
||||
{ 4800, 0x0271 },
|
||||
{ 9600, 0x4138 },
|
||||
{ 19200, 0x809c },
|
||||
{ 38400, 0xc04e },
|
||||
{ 57600, 0xc034 },
|
||||
{ 115200, 0x001a }
|
||||
};
|
||||
|
||||
/* Set the baud rate. */
|
||||
for (i = 0; i < ARRAY_SIZE (divisor_tab); i++)
|
||||
if (divisor_tab[i].speed == speed)
|
||||
return divisor_tab[i].div;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
real_config (struct grub_serial_port *port)
|
||||
{
|
||||
grub_uint32_t divisor;
|
||||
const grub_uint16_t parities[] = {
|
||||
[GRUB_SERIAL_PARITY_NONE] = 0x0000,
|
||||
[GRUB_SERIAL_PARITY_ODD] = 0x0100,
|
||||
[GRUB_SERIAL_PARITY_EVEN] = 0x0200
|
||||
};
|
||||
const grub_uint16_t stop_bits[] = {
|
||||
[GRUB_SERIAL_STOP_BITS_1] = 0x0000,
|
||||
[GRUB_SERIAL_STOP_BITS_2] = 0x1000,
|
||||
};
|
||||
|
||||
if (port->configured)
|
||||
return;
|
||||
|
||||
grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_VENDOR_OUT,
|
||||
GRUB_FTDI_MODEM_CTRL,
|
||||
GRUB_FTDI_MODEM_CTRL_DTRRTS, 0, 0, 0);
|
||||
|
||||
grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_VENDOR_OUT,
|
||||
GRUB_FTDI_FLOW_CTRL,
|
||||
GRUB_FTDI_FLOW_CTRL_DTRRTS, 0, 0, 0);
|
||||
|
||||
divisor = get_divisor (port->config.speed);
|
||||
grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_VENDOR_OUT,
|
||||
GRUB_FTDI_SPEED_CTRL,
|
||||
divisor & 0xffff, divisor >> 16, 0, 0);
|
||||
|
||||
grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_VENDOR_OUT,
|
||||
GRUB_FTDI_DATA_CTRL,
|
||||
parities[port->config.parity]
|
||||
| stop_bits[port->config.stop_bits]
|
||||
| port->config.word_len, 0, 0, 0);
|
||||
|
||||
port->configured = 1;
|
||||
}
|
||||
|
||||
/* Fetch a key. */
|
||||
static int
|
||||
ftdi_hw_fetch (struct grub_serial_port *port)
|
||||
{
|
||||
real_config (port);
|
||||
|
||||
return grub_usbserial_fetch (port, 2);
|
||||
}
|
||||
|
||||
/* Put a character. */
|
||||
static void
|
||||
ftdi_hw_put (struct grub_serial_port *port, const int c)
|
||||
{
|
||||
char cc = c;
|
||||
|
||||
real_config (port);
|
||||
|
||||
grub_usb_bulk_write (port->usbdev, port->out_endp->endp_addr, 1, &cc);
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
ftdi_hw_configure (struct grub_serial_port *port,
|
||||
struct grub_serial_config *config)
|
||||
{
|
||||
grub_uint16_t divisor;
|
||||
|
||||
divisor = get_divisor (config->speed);
|
||||
if (divisor == 0)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "bad speed");
|
||||
|
||||
if (config->parity != GRUB_SERIAL_PARITY_NONE
|
||||
&& config->parity != GRUB_SERIAL_PARITY_ODD
|
||||
&& config->parity != GRUB_SERIAL_PARITY_EVEN)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "unsupported parity");
|
||||
|
||||
if (config->stop_bits != GRUB_SERIAL_STOP_BITS_1
|
||||
&& config->stop_bits != GRUB_SERIAL_STOP_BITS_2)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "unsupported stop bits");
|
||||
|
||||
if (config->word_len < 5 || config->word_len > 8)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "unsupported word length");
|
||||
|
||||
port->config = *config;
|
||||
port->configured = 0;
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static struct grub_serial_driver grub_ftdi_driver =
|
||||
{
|
||||
.configure = ftdi_hw_configure,
|
||||
.fetch = ftdi_hw_fetch,
|
||||
.put = ftdi_hw_put,
|
||||
.fini = grub_usbserial_fini
|
||||
};
|
||||
|
||||
static const struct
|
||||
{
|
||||
grub_uint16_t vendor, product;
|
||||
} products[] =
|
||||
{
|
||||
{0x0403, 0x6001} /* QEMU virtual USBserial. */
|
||||
};
|
||||
|
||||
static int
|
||||
grub_ftdi_attach (grub_usb_device_t usbdev, int configno, int interfno)
|
||||
{
|
||||
unsigned j;
|
||||
|
||||
for (j = 0; j < ARRAY_SIZE (products); j++)
|
||||
if (usbdev->descdev.vendorid == products[j].vendor
|
||||
&& usbdev->descdev.prodid == products[j].product)
|
||||
break;
|
||||
if (j == ARRAY_SIZE (products))
|
||||
return 0;
|
||||
|
||||
return grub_usbserial_attach (usbdev, configno, interfno,
|
||||
&grub_ftdi_driver);
|
||||
}
|
||||
|
||||
static struct grub_usb_attach_desc attach_hook =
|
||||
{
|
||||
.class = 0xff,
|
||||
.hook = grub_ftdi_attach
|
||||
};
|
||||
|
||||
GRUB_MOD_INIT(usbserial_ftdi)
|
||||
{
|
||||
grub_usb_register_attach_hook_class (&attach_hook);
|
||||
}
|
||||
|
||||
GRUB_MOD_FINI(usbserial_ftdi)
|
||||
{
|
||||
grub_serial_unregister_driver (&grub_ftdi_driver);
|
||||
grub_usb_unregister_attach_hook_class (&attach_hook);
|
||||
}
|
218
grub-core/bus/usb/serial/pl2303.c
Normal file
218
grub-core/bus/usb/serial/pl2303.c
Normal file
|
@ -0,0 +1,218 @@
|
|||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2000,2001,2002,2003,2004,2005,2007,2008,2009,2010 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/serial.h>
|
||||
#include <grub/types.h>
|
||||
#include <grub/dl.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/usb.h>
|
||||
#include <grub/usbserial.h>
|
||||
|
||||
/* Convert speed to divisor. */
|
||||
static grub_uint32_t
|
||||
is_speed_supported (unsigned int speed)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned int supported[] = { 2400, 4800, 9600, 19200, 38400, 57600, 115200};
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE (supported); i++)
|
||||
if (supported[i] == speed)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define GRUB_PL2303_REQUEST_SET_CONFIG 0x20
|
||||
#define GRUB_PL2303_STOP_BITS_1 0x0
|
||||
#define GRUB_PL2303_STOP_BITS_2 0x2
|
||||
|
||||
#define GRUB_PL2303_PARITY_NONE 0
|
||||
#define GRUB_PL2303_PARITY_ODD 1
|
||||
#define GRUB_PL2303_PARITY_EVEN 2
|
||||
|
||||
struct grub_pl2303_config
|
||||
{
|
||||
grub_uint32_t speed;
|
||||
grub_uint8_t stop_bits;
|
||||
grub_uint8_t parity;
|
||||
grub_uint8_t word_len;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
static void
|
||||
real_config (struct grub_serial_port *port)
|
||||
{
|
||||
struct grub_pl2303_config config_pl2303;
|
||||
char xx;
|
||||
|
||||
if (port->configured)
|
||||
return;
|
||||
|
||||
grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_VENDOR_IN,
|
||||
1, 0x8484, 0, 1, &xx);
|
||||
grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_VENDOR_OUT,
|
||||
1, 0x0404, 0, 0, 0);
|
||||
|
||||
grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_VENDOR_IN,
|
||||
1, 0x8484, 0, 1, &xx);
|
||||
grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_VENDOR_IN,
|
||||
1, 0x8383, 0, 1, &xx);
|
||||
grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_VENDOR_IN,
|
||||
1, 0x8484, 0, 1, &xx);
|
||||
grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_VENDOR_OUT,
|
||||
1, 0x0404, 1, 0, 0);
|
||||
|
||||
grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_VENDOR_IN,
|
||||
1, 0x8484, 0, 1, &xx);
|
||||
grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_VENDOR_IN,
|
||||
1, 0x8383, 0, 1, &xx);
|
||||
|
||||
grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_VENDOR_OUT,
|
||||
1, 0, 1, 0, 0);
|
||||
grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_VENDOR_OUT,
|
||||
1, 1, 0, 0, 0);
|
||||
grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_VENDOR_OUT,
|
||||
1, 2, 0x44, 0, 0);
|
||||
grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_VENDOR_OUT,
|
||||
1, 8, 0, 0, 0);
|
||||
grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_VENDOR_OUT,
|
||||
1, 9, 0, 0, 0);
|
||||
|
||||
if (port->config.stop_bits == GRUB_SERIAL_STOP_BITS_2)
|
||||
config_pl2303.stop_bits = GRUB_PL2303_STOP_BITS_2;
|
||||
else
|
||||
config_pl2303.stop_bits = GRUB_PL2303_STOP_BITS_1;
|
||||
|
||||
switch (port->config.parity)
|
||||
{
|
||||
case GRUB_SERIAL_PARITY_NONE:
|
||||
config_pl2303.parity = GRUB_PL2303_PARITY_NONE;
|
||||
break;
|
||||
case GRUB_SERIAL_PARITY_ODD:
|
||||
config_pl2303.parity = GRUB_PL2303_PARITY_ODD;
|
||||
break;
|
||||
case GRUB_SERIAL_PARITY_EVEN:
|
||||
config_pl2303.parity = GRUB_PL2303_PARITY_EVEN;
|
||||
break;
|
||||
}
|
||||
|
||||
config_pl2303.word_len = port->config.word_len;
|
||||
config_pl2303.speed = port->config.speed;
|
||||
grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_CLASS_INTERFACE_OUT,
|
||||
GRUB_PL2303_REQUEST_SET_CONFIG, 0, 0,
|
||||
sizeof (config_pl2303), (char *) &config_pl2303);
|
||||
grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_CLASS_INTERFACE_OUT,
|
||||
0x22, 3, 0, 0, 0);
|
||||
|
||||
grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_VENDOR_OUT,
|
||||
1, 0, 0x61, 0, 0);
|
||||
port->configured = 1;
|
||||
}
|
||||
|
||||
/* Fetch a key. */
|
||||
static int
|
||||
pl2303_hw_fetch (struct grub_serial_port *port)
|
||||
{
|
||||
real_config (port);
|
||||
|
||||
return grub_usbserial_fetch (port, 0);
|
||||
}
|
||||
|
||||
/* Put a character. */
|
||||
static void
|
||||
pl2303_hw_put (struct grub_serial_port *port, const int c)
|
||||
{
|
||||
char cc = c;
|
||||
|
||||
real_config (port);
|
||||
|
||||
grub_usb_bulk_write (port->usbdev, port->out_endp->endp_addr, 1, &cc);
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
pl2303_hw_configure (struct grub_serial_port *port,
|
||||
struct grub_serial_config *config)
|
||||
{
|
||||
if (!is_speed_supported (config->speed))
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "bad speed");
|
||||
|
||||
if (config->parity != GRUB_SERIAL_PARITY_NONE
|
||||
&& config->parity != GRUB_SERIAL_PARITY_ODD
|
||||
&& config->parity != GRUB_SERIAL_PARITY_EVEN)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "unsupported parity");
|
||||
|
||||
if (config->stop_bits != GRUB_SERIAL_STOP_BITS_1
|
||||
&& config->stop_bits != GRUB_SERIAL_STOP_BITS_2)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "unsupported stop bits");
|
||||
|
||||
if (config->word_len < 5 || config->word_len > 8)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "unsupported word length");
|
||||
|
||||
port->config = *config;
|
||||
port->configured = 0;
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static struct grub_serial_driver grub_pl2303_driver =
|
||||
{
|
||||
.configure = pl2303_hw_configure,
|
||||
.fetch = pl2303_hw_fetch,
|
||||
.put = pl2303_hw_put,
|
||||
.fini = grub_usbserial_fini
|
||||
};
|
||||
|
||||
static const struct
|
||||
{
|
||||
grub_uint16_t vendor, product;
|
||||
} products[] =
|
||||
{
|
||||
{0x067b, 0x2303}
|
||||
};
|
||||
|
||||
static int
|
||||
grub_pl2303_attach (grub_usb_device_t usbdev, int configno, int interfno)
|
||||
{
|
||||
unsigned j;
|
||||
|
||||
for (j = 0; j < ARRAY_SIZE (products); j++)
|
||||
if (usbdev->descdev.vendorid == products[j].vendor
|
||||
&& usbdev->descdev.prodid == products[j].product)
|
||||
break;
|
||||
if (j == ARRAY_SIZE (products))
|
||||
return 0;
|
||||
|
||||
return grub_usbserial_attach (usbdev, configno, interfno,
|
||||
&grub_pl2303_driver);
|
||||
}
|
||||
|
||||
static struct grub_usb_attach_desc attach_hook =
|
||||
{
|
||||
.class = 0xff,
|
||||
.hook = grub_pl2303_attach
|
||||
};
|
||||
|
||||
GRUB_MOD_INIT(usbserial_pl2303)
|
||||
{
|
||||
grub_usb_register_attach_hook_class (&attach_hook);
|
||||
}
|
||||
|
||||
GRUB_MOD_FINI(usbserial_pl2303)
|
||||
{
|
||||
grub_serial_unregister_driver (&grub_pl2303_driver);
|
||||
grub_usb_unregister_attach_hook_class (&attach_hook);
|
||||
}
|
|
@ -333,9 +333,11 @@ grub_free_td (struct grub_uhci *u, grub_uhci_td_t td)
|
|||
|
||||
static void
|
||||
grub_free_queue (struct grub_uhci *u, grub_uhci_td_t td,
|
||||
grub_usb_transfer_t transfer)
|
||||
grub_usb_transfer_t transfer, grub_size_t *actual)
|
||||
{
|
||||
int i; /* Index of TD in transfer */
|
||||
|
||||
*actual = 0;
|
||||
|
||||
/* Free the TDs in this queue and set last_trans. */
|
||||
for (i=0; td; i++)
|
||||
|
@ -345,6 +347,8 @@ grub_free_queue (struct grub_uhci *u, grub_uhci_td_t td,
|
|||
/* Check state of TD and possibly set last_trans */
|
||||
if (transfer && (td->linkptr & 1))
|
||||
transfer->last_trans = i;
|
||||
|
||||
*actual += (td->ctrl_status + 1) & 0x7ff;
|
||||
|
||||
/* Unlink the queue. */
|
||||
tdprev = td;
|
||||
|
@ -436,7 +440,8 @@ grub_uhci_transaction (struct grub_uhci *u, unsigned int endp,
|
|||
|
||||
static grub_usb_err_t
|
||||
grub_uhci_transfer (grub_usb_controller_t dev,
|
||||
grub_usb_transfer_t transfer)
|
||||
grub_usb_transfer_t transfer,
|
||||
int timeout, grub_size_t *actual)
|
||||
{
|
||||
struct grub_uhci *u = (struct grub_uhci *) dev->data;
|
||||
grub_uhci_qh_t qh;
|
||||
|
@ -447,10 +452,12 @@ grub_uhci_transfer (grub_usb_controller_t dev,
|
|||
int i;
|
||||
grub_uint64_t endtime;
|
||||
|
||||
*actual = 0;
|
||||
|
||||
/* Allocate a queue head for the transfer queue. */
|
||||
qh = grub_alloc_qh (u, GRUB_USB_TRANSACTION_TYPE_CONTROL);
|
||||
if (! qh)
|
||||
return grub_errno;
|
||||
return GRUB_USB_ERR_INTERNAL;
|
||||
|
||||
grub_dprintf ("uhci", "transfer, iobase:%08x\n", u->iobase);
|
||||
|
||||
|
@ -468,7 +475,7 @@ grub_uhci_transfer (grub_usb_controller_t dev,
|
|||
td_prev->linkptr = 1;
|
||||
|
||||
if (td_first)
|
||||
grub_free_queue (u, td_first, NULL);
|
||||
grub_free_queue (u, td_first, NULL, actual);
|
||||
|
||||
return GRUB_USB_ERR_INTERNAL;
|
||||
}
|
||||
|
@ -496,7 +503,7 @@ grub_uhci_transfer (grub_usb_controller_t dev,
|
|||
|
||||
/* Wait until either the transaction completed or an error
|
||||
occurred. */
|
||||
endtime = grub_get_time_ms () + 1000;
|
||||
endtime = grub_get_time_ms () + timeout;
|
||||
for (;;)
|
||||
{
|
||||
grub_uhci_td_t errtd;
|
||||
|
@ -512,42 +519,37 @@ grub_uhci_transfer (grub_usb_controller_t dev,
|
|||
|
||||
grub_dprintf ("uhci", "t status=0x%02x\n", errtd->ctrl_status);
|
||||
|
||||
/* Check if the TD is not longer active. */
|
||||
if (! (errtd->ctrl_status & (1 << 23)))
|
||||
{
|
||||
grub_dprintf ("uhci", ">>t status=0x%02x\n", errtd->ctrl_status);
|
||||
/* Check if the endpoint is stalled. */
|
||||
if (errtd->ctrl_status & (1 << 22))
|
||||
err = GRUB_USB_ERR_STALL;
|
||||
|
||||
/* Check if the endpoint is stalled. */
|
||||
if (errtd->ctrl_status & (1 << 22))
|
||||
err = GRUB_USB_ERR_STALL;
|
||||
/* Check if an error related to the data buffer occurred. */
|
||||
if (errtd->ctrl_status & (1 << 21))
|
||||
err = GRUB_USB_ERR_DATA;
|
||||
|
||||
/* Check if an error related to the data buffer occurred. */
|
||||
if (errtd->ctrl_status & (1 << 21))
|
||||
err = GRUB_USB_ERR_DATA;
|
||||
/* Check if a babble error occurred. */
|
||||
if (errtd->ctrl_status & (1 << 20))
|
||||
err = GRUB_USB_ERR_BABBLE;
|
||||
|
||||
/* Check if a babble error occurred. */
|
||||
if (errtd->ctrl_status & (1 << 20))
|
||||
err = GRUB_USB_ERR_BABBLE;
|
||||
/* Check if a NAK occurred. */
|
||||
if (errtd->ctrl_status & (1 << 19))
|
||||
err = GRUB_USB_ERR_NAK;
|
||||
|
||||
/* Check if a NAK occurred. */
|
||||
if (errtd->ctrl_status & (1 << 19))
|
||||
err = GRUB_USB_ERR_NAK;
|
||||
/* Check if a timeout occurred. */
|
||||
if (errtd->ctrl_status & (1 << 18))
|
||||
err = GRUB_USB_ERR_TIMEOUT;
|
||||
|
||||
/* Check if a timeout occurred. */
|
||||
if (errtd->ctrl_status & (1 << 18))
|
||||
err = GRUB_USB_ERR_TIMEOUT;
|
||||
/* Check if a bitstuff error occurred. */
|
||||
if (errtd->ctrl_status & (1 << 17))
|
||||
err = GRUB_USB_ERR_BITSTUFF;
|
||||
|
||||
/* Check if a bitstuff error occurred. */
|
||||
if (errtd->ctrl_status & (1 << 17))
|
||||
err = GRUB_USB_ERR_BITSTUFF;
|
||||
if (err)
|
||||
goto fail;
|
||||
|
||||
if (err)
|
||||
goto fail;
|
||||
/* Fall through, no errors occurred, so the QH might be
|
||||
updated. */
|
||||
grub_dprintf ("uhci", "transaction fallthrough\n");
|
||||
|
||||
/* Fall through, no errors occurred, so the QH might be
|
||||
updated. */
|
||||
grub_dprintf ("uhci", "transaction fallthrough\n");
|
||||
}
|
||||
if (grub_get_time_ms () > endtime)
|
||||
{
|
||||
err = GRUB_USB_ERR_STALL;
|
||||
|
@ -567,7 +569,7 @@ grub_uhci_transfer (grub_usb_controller_t dev,
|
|||
/* Place the QH back in the free list and deallocate the associated
|
||||
TDs. */
|
||||
qh->elinkptr = 1;
|
||||
grub_free_queue (u, td_first, transfer);
|
||||
grub_free_queue (u, td_first, transfer, actual);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <grub/usb.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/list.h>
|
||||
#include <grub/term.h>
|
||||
|
||||
static grub_usb_controller_dev_t grub_usb_list;
|
||||
struct grub_usb_attach_desc *attach_hooks;
|
||||
|
@ -208,14 +209,23 @@ grub_usb_device_initialize (grub_usb_device_t dev)
|
|||
goto fail;
|
||||
|
||||
/* Skip the configuration descriptor. */
|
||||
pos = sizeof (struct grub_usb_desc_config);
|
||||
pos = dev->config[i].descconf->length;
|
||||
|
||||
/* Read all interfaces. */
|
||||
for (currif = 0; currif < dev->config[i].descconf->numif; currif++)
|
||||
{
|
||||
while (pos < config.totallen
|
||||
&& ((struct grub_usb_desc *)&data[pos])->type
|
||||
!= GRUB_USB_DESCRIPTOR_INTERFACE)
|
||||
pos += ((struct grub_usb_desc *)&data[pos])->length;
|
||||
dev->config[i].interf[currif].descif
|
||||
= (struct grub_usb_desc_if *) &data[pos];
|
||||
pos += sizeof (struct grub_usb_desc_if);
|
||||
pos += dev->config[i].interf[currif].descif->length;
|
||||
|
||||
while (pos < config.totallen
|
||||
&& ((struct grub_usb_desc *)&data[pos])->type
|
||||
!= GRUB_USB_DESCRIPTOR_ENDPOINT)
|
||||
pos += ((struct grub_usb_desc *)&data[pos])->length;
|
||||
|
||||
/* Point to the first endpoint. */
|
||||
dev->config[i].interf[currif].descendp
|
||||
|
@ -256,6 +266,24 @@ void grub_usb_device_attach (grub_usb_device_t dev)
|
|||
for (desc = attach_hooks; desc; desc = desc->next)
|
||||
if (interf->class == desc->class && desc->hook (dev, 0, i))
|
||||
dev->config[0].interf[i].attached = 1;
|
||||
|
||||
if (dev->config[0].interf[i].attached)
|
||||
continue;
|
||||
|
||||
switch (interf->class)
|
||||
{
|
||||
case GRUB_USB_CLASS_MASS_STORAGE:
|
||||
grub_dl_load ("usbms");
|
||||
break;
|
||||
case GRUB_USB_CLASS_HID:
|
||||
grub_dl_load ("usb_keyboard");
|
||||
break;
|
||||
case 0xff:
|
||||
/* FIXME: don't load useless modules. */
|
||||
grub_dl_load ("usbserial_ftdi");
|
||||
grub_dl_load ("usbserial_pl2303");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -306,3 +334,14 @@ grub_usb_unregister_attach_hook_class (struct grub_usb_attach_desc *desc)
|
|||
{
|
||||
grub_list_remove (GRUB_AS_LIST_P (&attach_hooks), GRUB_AS_LIST (desc));
|
||||
}
|
||||
|
||||
|
||||
GRUB_MOD_INIT(usb)
|
||||
{
|
||||
grub_term_poll_usb = grub_usb_poll_devices;
|
||||
}
|
||||
|
||||
GRUB_MOD_FINI(usb)
|
||||
{
|
||||
grub_term_poll_usb = NULL;
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ struct grub_usb_hub
|
|||
struct grub_usb_hub *next;
|
||||
grub_usb_controller_t controller;
|
||||
int nports;
|
||||
grub_usb_speed_t *speed;
|
||||
struct grub_usb_device **devices;
|
||||
grub_usb_device_t dev;
|
||||
};
|
||||
|
||||
|
@ -104,7 +104,7 @@ grub_usb_hub_add_dev (grub_usb_controller_t controller, grub_usb_speed_t speed)
|
|||
}
|
||||
|
||||
|
||||
static grub_err_t
|
||||
static grub_usb_err_t
|
||||
grub_usb_add_hub (grub_usb_device_t dev)
|
||||
{
|
||||
struct grub_usb_usb_hubdesc hubdesc;
|
||||
|
@ -112,6 +112,7 @@ grub_usb_add_hub (grub_usb_device_t dev)
|
|||
int i;
|
||||
grub_uint64_t timeout;
|
||||
grub_usb_device_t next_dev;
|
||||
grub_usb_device_t *attached_devices;
|
||||
|
||||
err = grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_IN
|
||||
| GRUB_USB_REQTYPE_CLASS
|
||||
|
@ -130,6 +131,13 @@ grub_usb_add_hub (grub_usb_device_t dev)
|
|||
grub_dprintf ("usb", "Hub set configuration\n");
|
||||
grub_usb_set_configuration (dev, 1);
|
||||
|
||||
attached_devices = grub_zalloc (hubdesc.portcnt
|
||||
* sizeof (attached_devices[0]));
|
||||
if (!attached_devices)
|
||||
return GRUB_USB_ERR_INTERNAL;
|
||||
dev->children = attached_devices;
|
||||
dev->nports = hubdesc.portcnt;
|
||||
|
||||
/* Power on all Hub ports. */
|
||||
for (i = 1; i <= hubdesc.portcnt; i++)
|
||||
{
|
||||
|
@ -236,6 +244,8 @@ grub_usb_add_hub (grub_usb_device_t dev)
|
|||
if (! next_dev)
|
||||
continue;
|
||||
|
||||
attached_devices[i - 1] = next_dev;
|
||||
|
||||
/* If the device is a Hub, scan it for more devices. */
|
||||
if (next_dev->descdev.class == 0x09)
|
||||
grub_usb_add_hub (next_dev);
|
||||
|
@ -246,27 +256,29 @@ grub_usb_add_hub (grub_usb_device_t dev)
|
|||
}
|
||||
|
||||
static void
|
||||
attach_root_port (grub_usb_controller_t controller, int portno,
|
||||
attach_root_port (struct grub_usb_hub *hub, int portno,
|
||||
grub_usb_speed_t speed)
|
||||
{
|
||||
grub_usb_device_t dev;
|
||||
grub_err_t err;
|
||||
|
||||
/* Disable the port. XXX: Why? */
|
||||
err = controller->dev->portstatus (controller, portno, 0);
|
||||
err = hub->controller->dev->portstatus (hub->controller, portno, 0);
|
||||
if (err)
|
||||
return;
|
||||
|
||||
/* Enable the port. */
|
||||
err = controller->dev->portstatus (controller, portno, 1);
|
||||
err = hub->controller->dev->portstatus (hub->controller, portno, 1);
|
||||
if (err)
|
||||
return;
|
||||
|
||||
/* Enable the port and create a device. */
|
||||
dev = grub_usb_hub_add_dev (controller, speed);
|
||||
dev = grub_usb_hub_add_dev (hub->controller, speed);
|
||||
if (! dev)
|
||||
return;
|
||||
|
||||
hub->devices[portno] = dev;
|
||||
|
||||
/* If the device is a Hub, scan it for more devices. */
|
||||
if (dev->descdev.class == 0x09)
|
||||
grub_usb_add_hub (dev);
|
||||
|
@ -297,8 +309,8 @@ grub_usb_root_hub (grub_usb_controller_t controller)
|
|||
|
||||
/* Query the number of ports the root Hub has. */
|
||||
hub->nports = controller->dev->hubports (controller);
|
||||
hub->speed = grub_malloc (sizeof (hub->speed[0]) * hub->nports);
|
||||
if (!hub->speed)
|
||||
hub->devices = grub_zalloc (sizeof (hub->devices[0]) * hub->nports);
|
||||
if (!hub->devices)
|
||||
{
|
||||
grub_free (hub->controller);
|
||||
grub_free (hub);
|
||||
|
@ -307,36 +319,54 @@ grub_usb_root_hub (grub_usb_controller_t controller)
|
|||
|
||||
for (i = 0; i < hub->nports; i++)
|
||||
{
|
||||
hub->speed[i] = controller->dev->detect_dev (hub->controller, i,
|
||||
&changed);
|
||||
grub_usb_speed_t speed;
|
||||
speed = controller->dev->detect_dev (hub->controller, i,
|
||||
&changed);
|
||||
|
||||
if (hub->speed[i] != GRUB_USB_SPEED_NONE)
|
||||
attach_root_port (hub->controller, i, hub->speed[i]);
|
||||
if (speed != GRUB_USB_SPEED_NONE)
|
||||
attach_root_port (hub, i, speed);
|
||||
}
|
||||
|
||||
return GRUB_USB_ERR_NONE;
|
||||
}
|
||||
|
||||
static void detach_device (grub_usb_device_t dev);
|
||||
|
||||
static void
|
||||
detach_device (grub_usb_device_t dev)
|
||||
{
|
||||
unsigned i;
|
||||
int k;
|
||||
if (!dev)
|
||||
return;
|
||||
if (dev->descdev.class == GRUB_USB_CLASS_HUB)
|
||||
{
|
||||
for (i = 0; i < dev->nports; i++)
|
||||
detach_device (dev->children[i]);
|
||||
grub_free (dev->children);
|
||||
}
|
||||
for (i = 0; i < ARRAY_SIZE (dev->config); i++)
|
||||
if (dev->config[i].descconf)
|
||||
for (k = 0; k < dev->config[i].descconf->numif; k++)
|
||||
{
|
||||
struct grub_usb_interface *inter = &dev->config[i].interf[k];
|
||||
if (inter && inter->detach_hook)
|
||||
inter->detach_hook (dev, i, k);
|
||||
}
|
||||
grub_usb_devs[dev->addr] = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
poll_nonroot_hub (grub_usb_device_t dev)
|
||||
{
|
||||
struct grub_usb_usb_hubdesc hubdesc;
|
||||
grub_err_t err;
|
||||
int i;
|
||||
unsigned i;
|
||||
grub_uint64_t timeout;
|
||||
grub_usb_device_t next_dev;
|
||||
|
||||
err = grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_IN
|
||||
| GRUB_USB_REQTYPE_CLASS
|
||||
| GRUB_USB_REQTYPE_TARGET_DEV),
|
||||
GRUB_USB_REQ_GET_DESCRIPTOR,
|
||||
(GRUB_USB_DESCRIPTOR_HUB << 8) | 0,
|
||||
0, sizeof (hubdesc), (char *) &hubdesc);
|
||||
if (err)
|
||||
return;
|
||||
|
||||
grub_usb_device_t *attached_devices = dev->children;
|
||||
|
||||
/* Iterate over the Hub ports. */
|
||||
for (i = 1; i <= hubdesc.portcnt; i++)
|
||||
for (i = 1; i <= dev->nports; i++)
|
||||
{
|
||||
grub_uint32_t status;
|
||||
|
||||
|
@ -350,6 +380,12 @@ poll_nonroot_hub (grub_usb_device_t dev)
|
|||
status. */
|
||||
if (err)
|
||||
continue;
|
||||
|
||||
if (status & GRUB_USB_HUB_STATUS_C_CONNECTED)
|
||||
{
|
||||
detach_device (attached_devices[i-1]);
|
||||
attached_devices[i - 1] = NULL;
|
||||
}
|
||||
|
||||
/* Connected and status of connection changed ? */
|
||||
if ((status & GRUB_USB_HUB_STATUS_CONNECTED)
|
||||
|
@ -417,6 +453,8 @@ poll_nonroot_hub (grub_usb_device_t dev)
|
|||
if (! next_dev)
|
||||
continue;
|
||||
|
||||
attached_devices[i - 1] = next_dev;
|
||||
|
||||
/* If the device is a Hub, scan it for more devices. */
|
||||
if (next_dev->descdev.class == 0x09)
|
||||
grub_usb_add_hub (next_dev);
|
||||
|
@ -434,26 +472,23 @@ grub_usb_poll_devices (void)
|
|||
|
||||
for (hub = hubs; hub; hub = hub->next)
|
||||
{
|
||||
int changed=0;
|
||||
/* Do we have to recheck number of ports? */
|
||||
/* No, it should be never changed, it should be constant. */
|
||||
for (i = 0; i < hub->nports; i++)
|
||||
{
|
||||
grub_usb_speed_t speed;
|
||||
int changed = 0;
|
||||
|
||||
speed = hub->controller->dev->detect_dev (hub->controller, i,
|
||||
&changed);
|
||||
|
||||
if (speed != GRUB_USB_SPEED_NONE)
|
||||
if (changed)
|
||||
{
|
||||
if (changed)
|
||||
attach_root_port (hub->controller, i, speed);
|
||||
detach_device (hub->devices[i]);
|
||||
hub->devices[i] = NULL;
|
||||
if (speed != GRUB_USB_SPEED_NONE)
|
||||
attach_root_port (hub, i, speed);
|
||||
}
|
||||
|
||||
/* XXX: There should be also handling
|
||||
* of disconnected devices. */
|
||||
|
||||
hub->speed[i] = speed;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -463,9 +498,7 @@ grub_usb_poll_devices (void)
|
|||
grub_usb_device_t dev = grub_usb_devs[i];
|
||||
|
||||
if (dev && dev->descdev.class == 0x09)
|
||||
{
|
||||
poll_nonroot_hub (dev);
|
||||
}
|
||||
poll_nonroot_hub (dev);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -43,6 +43,7 @@ grub_usb_control_msg (grub_usb_device_t dev,
|
|||
volatile char *data;
|
||||
grub_uint32_t data_addr;
|
||||
grub_size_t size = size0;
|
||||
grub_size_t actual;
|
||||
|
||||
/* FIXME: avoid allocation any kind of buffer in a first place. */
|
||||
data_chunk = grub_memalign_dma32 (128, size ? : 16);
|
||||
|
@ -132,6 +133,7 @@ grub_usb_control_msg (grub_usb_device_t dev,
|
|||
else
|
||||
tr->pid = GRUB_USB_TRANSFER_TYPE_OUT;
|
||||
tr->data = data_addr + i * max;
|
||||
tr->preceding = i * max;
|
||||
size -= max;
|
||||
}
|
||||
|
||||
|
@ -145,7 +147,8 @@ grub_usb_control_msg (grub_usb_device_t dev,
|
|||
|
||||
transfer->transactions[datablocks + 1].toggle = 1;
|
||||
|
||||
err = dev->controller.dev->transfer (&dev->controller, transfer);
|
||||
err = dev->controller.dev->transfer (&dev->controller, transfer,
|
||||
1000, &actual);
|
||||
grub_dprintf ("usb", "control: err=%d\n", err);
|
||||
|
||||
grub_free (transfer->transactions);
|
||||
|
@ -162,7 +165,8 @@ grub_usb_control_msg (grub_usb_device_t dev,
|
|||
static grub_usb_err_t
|
||||
grub_usb_bulk_readwrite (grub_usb_device_t dev,
|
||||
int endpoint, grub_size_t size0, char *data_in,
|
||||
grub_transfer_type_t type)
|
||||
grub_transfer_type_t type, int timeout,
|
||||
grub_size_t *actual)
|
||||
{
|
||||
int i;
|
||||
grub_usb_transfer_t transfer;
|
||||
|
@ -240,10 +244,12 @@ grub_usb_bulk_readwrite (grub_usb_device_t dev,
|
|||
toggle = toggle ? 0 : 1;
|
||||
tr->pid = type;
|
||||
tr->data = data_addr + i * max;
|
||||
tr->preceding = i * max;
|
||||
size -= tr->size;
|
||||
}
|
||||
|
||||
err = dev->controller.dev->transfer (&dev->controller, transfer);
|
||||
err = dev->controller.dev->transfer (&dev->controller, transfer, timeout,
|
||||
actual);
|
||||
/* We must remember proper toggle value even if some transactions
|
||||
* were not processed - correct value should be inversion of last
|
||||
* processed transaction (TD). */
|
||||
|
@ -268,14 +274,34 @@ grub_usb_err_t
|
|||
grub_usb_bulk_write (grub_usb_device_t dev,
|
||||
int endpoint, grub_size_t size, char *data)
|
||||
{
|
||||
return grub_usb_bulk_readwrite (dev, endpoint, size, data,
|
||||
GRUB_USB_TRANSFER_TYPE_OUT);
|
||||
grub_size_t actual;
|
||||
grub_usb_err_t err;
|
||||
|
||||
err = grub_usb_bulk_readwrite (dev, endpoint, size, data,
|
||||
GRUB_USB_TRANSFER_TYPE_OUT, 1000, &actual);
|
||||
if (!err && actual != size)
|
||||
err = GRUB_USB_ERR_DATA;
|
||||
return err;
|
||||
}
|
||||
|
||||
grub_usb_err_t
|
||||
grub_usb_bulk_read (grub_usb_device_t dev,
|
||||
int endpoint, grub_size_t size, char *data)
|
||||
{
|
||||
return grub_usb_bulk_readwrite (dev, endpoint, size, data,
|
||||
GRUB_USB_TRANSFER_TYPE_IN);
|
||||
grub_size_t actual;
|
||||
grub_usb_err_t err;
|
||||
err = grub_usb_bulk_readwrite (dev, endpoint, size, data,
|
||||
GRUB_USB_TRANSFER_TYPE_IN, 1000, &actual);
|
||||
if (!err && actual != size)
|
||||
err = GRUB_USB_ERR_DATA;
|
||||
return err;
|
||||
}
|
||||
|
||||
grub_usb_err_t
|
||||
grub_usb_bulk_read_extended (grub_usb_device_t dev,
|
||||
int endpoint, grub_size_t size, char *data,
|
||||
int timeout, grub_size_t *actual)
|
||||
{
|
||||
return grub_usb_bulk_readwrite (dev, endpoint, size, data,
|
||||
GRUB_USB_TRANSFER_TYPE_IN, timeout, actual);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue