PL2303 works and is configurable. But sometime input is lost

This commit is contained in:
Vladimir 'phcoder' Serbinenko 2010-07-18 23:12:08 +02:00
parent 9edd681bbc
commit 9685412782
2 changed files with 77 additions and 47 deletions

View file

@ -26,68 +26,100 @@
/* Convert speed to divisor. */ /* Convert speed to divisor. */
static grub_uint32_t static grub_uint32_t
get_divisor (unsigned int speed) is_speed_supported (unsigned int speed)
{ {
unsigned int i; unsigned int i;
unsigned int supported[] = { 2400, 4800, 9600, 19200, 38400, 57600, 115200};
/* The structure for speed vs. divisor. */ for (i = 0; i < ARRAY_SIZE (supported); i++)
struct divisor if (supported[i] == speed)
{ return 1;
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; return 0;
} }
#define GRUB_PL2303_REQUEST_CONFIG 1 #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 static void
real_config (struct grub_serial_port *port) real_config (struct grub_serial_port *port)
{ {
struct req20 struct grub_pl2303_config config_pl2303;
{ char xx;
char data[7];
} req20;
if (port->configured) if (port->configured)
return; 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, grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_VENDOR_OUT,
GRUB_PL2303_REQUEST_CONFIG, 0, 0x61, 0, 0); 1, 0x0404, 0, 0, 0);
grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_VENDOR_OUT,
GRUB_PL2303_REQUEST_CONFIG, 1, 0, 0, 0);
grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_VENDOR_OUT,
GRUB_PL2303_REQUEST_CONFIG, 2, 0x44, 0, 0);
grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_VENDOR_OUT,
GRUB_PL2303_REQUEST_CONFIG, 8, 0, 0, 0);
grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_VENDOR_OUT,
GRUB_PL2303_REQUEST_CONFIG, 9, 0, 0, 0);
grub_memset (&req20, 0, sizeof (req20)); grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_VENDOR_IN,
req20.data[6] = 8; 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_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_CLASS_INTERFACE_OUT,
0x20, 0, 0, sizeof (req20), (char *) &req20); 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, grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_CLASS_INTERFACE_OUT,
0x22, 3, 0, 0, 0); 0x22, 3, 0, 0, 0);
grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_VENDOR_OUT,
1, 0, 0x61, 0, 0);
port->configured = 1; port->configured = 1;
} }
@ -123,10 +155,7 @@ static grub_err_t
pl2303_hw_configure (struct grub_serial_port *port, pl2303_hw_configure (struct grub_serial_port *port,
struct grub_serial_config *config) struct grub_serial_config *config)
{ {
grub_uint16_t divisor; if (!is_speed_supported (config->speed))
divisor = get_divisor (config->speed);
if (divisor == 0)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "bad speed"); return grub_error (GRUB_ERR_BAD_ARGUMENT, "bad speed");
if (config->parity != GRUB_SERIAL_PARITY_NONE if (config->parity != GRUB_SERIAL_PARITY_NONE

View file

@ -51,7 +51,8 @@ typedef enum
enum enum
{ {
GRUB_USB_REQTYPE_CLASS_INTERFACE_OUT = 0x21, GRUB_USB_REQTYPE_CLASS_INTERFACE_OUT = 0x21,
GRUB_USB_REQTYPE_VENDOR_OUT = 0x40 GRUB_USB_REQTYPE_VENDOR_OUT = 0x40,
GRUB_USB_REQTYPE_VENDOR_IN = 0xc0
}; };
/* Call HOOK with each device, until HOOK returns non-zero. */ /* Call HOOK with each device, until HOOK returns non-zero. */