On Thu, Nov 29, 2012 at 09:03:00AM +1030, Jonathan Woithe wrote: > On Wed, Nov 28, 2012 at 09:30:10AM -0800, Greg KH wrote: > > On Thu, Nov 29, 2012 at 12:11:40AM +1030, Jonathan Woithe wrote: > > > On Wed, Nov 28, 2012 at 01:24:19PM +0000, Alan Cox wrote: > > > > Can we get a Signed-off-by: for the first patch so we can try and get it > > > > into 3.8 ? > > > > > > Sure. See below. The rest of the previous commit message was fine so I > > > haven't replicated it here. > > > > Please do, otherwise I have to hand-edit the patch to add it back, and > > odds are, I will get it wrong... > > No problem. See below. I took the opportunity to tweak the commit message > a touch. I am wondering (for documentation purposes) whether the quatech changes below made 3.8 or whether they'll appear in 3.9. I don't see them in linux-next or tty-next, but I'm still learning git and might have done something wrong while searching. jonathan > From: Alan Cox <alan@xxxxxxxxxxxxxxx> > > quatech: add the other serial identifiers and preliminary control code > > Jonathan Woithe posted an out of tree enabler/control module for these > cards. Lift the relevant identifiers and put them in the 8250_pci driver > along with code used to control custom registers on these cards. > > Signed-off-by: Alan Cox <alan@xxxxxxxxxxxxxxx> > Signed-off-by: Jonathan Woithe <jwoithe@xxxxxxxxxx> > > --- > diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c > index 17b7d26..43c6b4f 100644 > --- a/drivers/tty/serial/8250/8250_pci.c > +++ b/drivers/tty/serial/8250/8250_pci.c > @@ -1040,6 +1040,253 @@ static int pci_asix_setup(struct serial_private *priv, > return pci_default_setup(priv, board, port, idx); > } > > +/* Quatech devices have their own extra interface features */ > + > +struct quatech_feature { > + u16 devid; > + bool amcc; > +}; > + > +#define QPCR_TEST_FOR1 0x3F > +#define QPCR_TEST_GET1 0x00 > +#define QPCR_TEST_FOR2 0x40 > +#define QPCR_TEST_GET2 0x40 > +#define QPCR_TEST_FOR3 0x80 > +#define QPCR_TEST_GET3 0x40 > +#define QPCR_TEST_FOR4 0xC0 > +#define QPCR_TEST_GET4 0x80 > + > +#define QOPR_CLOCK_X1 0x0000 > +#define QOPR_CLOCK_X2 0x0001 > +#define QOPR_CLOCK_X4 0x0002 > +#define QOPR_CLOCK_X8 0x0003 > +#define QOPR_CLOCK_RATE_MASK 0x0003 > + > + > +static struct quatech_feature quatech_cards[] = { > + { PCI_DEVICE_ID_QUATECH_QSC100, 1 }, > + { PCI_DEVICE_ID_QUATECH_DSC100, 1 }, > + { PCI_DEVICE_ID_QUATECH_DSC100E, 0 }, > + { PCI_DEVICE_ID_QUATECH_DSC200, 1 }, > + { PCI_DEVICE_ID_QUATECH_DSC200E, 0 }, > + { PCI_DEVICE_ID_QUATECH_ESC100D, 1 }, > + { PCI_DEVICE_ID_QUATECH_ESC100M, 1 }, > + { PCI_DEVICE_ID_QUATECH_QSCP100, 1 }, > + { PCI_DEVICE_ID_QUATECH_DSCP100, 1 }, > + { PCI_DEVICE_ID_QUATECH_QSCP200, 1 }, > + { PCI_DEVICE_ID_QUATECH_DSCP200, 1 }, > + { PCI_DEVICE_ID_QUATECH_ESCLP100, 0 }, > + { PCI_DEVICE_ID_QUATECH_QSCLP100, 0 }, > + { PCI_DEVICE_ID_QUATECH_DSCLP100, 0 }, > + { PCI_DEVICE_ID_QUATECH_SSCLP100, 0 }, > + { PCI_DEVICE_ID_QUATECH_QSCLP200, 0 }, > + { PCI_DEVICE_ID_QUATECH_DSCLP200, 0 }, > + { PCI_DEVICE_ID_QUATECH_SSCLP200, 0 }, > + { PCI_DEVICE_ID_QUATECH_SPPXP_100, 0 }, > + { 0, } > +}; > + > +static int pci_quatech_amcc(u16 devid) > +{ > + struct quatech_feature *qf = &quatech_cards[0]; > + while (qf->devid) { > + if (qf->devid == devid) > + return qf->amcc; > + qf++; > + } > + pr_err("quatech: unknown port type '0x%04X'.\n", devid); > + return 0; > +}; > + > +static int pci_quatech_rqopr(struct uart_8250_port *port) > +{ > + unsigned long base = port->port.iobase; > + u8 LCR, val; > + > + LCR = inb(base + UART_LCR); > + outb(0xBF, base + UART_LCR); > + val = inb(base + UART_SCR); > + outb(LCR, base + UART_LCR); > + return val; > +} > + > +static void pci_quatech_wqopr(struct uart_8250_port *port, u8 qopr) > +{ > + unsigned long base = port->port.iobase; > + u8 LCR, val; > + > + LCR = inb(base + UART_LCR); > + outb(0xBF, base + UART_LCR); > + val = inb(base + UART_SCR); > + outb(qopr, base + UART_SCR); > + outb(LCR, base + UART_LCR); > +} > + > +static int pci_quatech_rqmcr(struct uart_8250_port *port) > +{ > + unsigned long base = port->port.iobase; > + u8 LCR, val, qmcr; > + > + LCR = inb(base + UART_LCR); > + outb(0xBF, base + UART_LCR); > + val = inb(base + UART_SCR); > + outb(val | 0x10, base + UART_SCR); > + qmcr = inb(base + UART_MCR); > + outb(val, base + UART_SCR); > + outb(LCR, base + UART_LCR); > + > + return qmcr; > +} > + > +static void pci_quatech_wqmcr(struct uart_8250_port *port, u8 qmcr) > +{ > + unsigned long base = port->port.iobase; > + u8 LCR, val; > + > + LCR = inb(base + UART_LCR); > + outb(0xBF, base + UART_LCR); > + val = inb(base + UART_SCR); > + outb(val | 0x10, base + UART_SCR); > + outb(qmcr, base + UART_MCR); > + outb(val, base + UART_SCR); > + outb(LCR, base + UART_LCR); > +} > + > +static int pci_quatech_has_qmcr(struct uart_8250_port *port) > +{ > + unsigned long base = port->port.iobase; > + u8 LCR, val; > + > + LCR = inb(base + UART_LCR); > + outb(0xBF, base + UART_LCR); > + val = inb(base + UART_SCR); > + if (val & 0x20) { > + outb(0x80, UART_LCR); > + if (!(inb(UART_SCR) & 0x20)) { > + outb(LCR, base + UART_LCR); > + return 1; > + } > + } > + return 0; > +} > + > +static int pci_quatech_test(struct uart_8250_port *port) > +{ > + u8 reg; > + u8 qopr = pci_quatech_rqopr(port); > + pci_quatech_wqopr(port, qopr & QPCR_TEST_FOR1); > + reg = pci_quatech_rqopr(port) & 0xC0; > + if (reg != QPCR_TEST_GET1) > + return -EINVAL; > + pci_quatech_wqopr(port, (qopr & QPCR_TEST_FOR1)|QPCR_TEST_FOR2); > + reg = pci_quatech_rqopr(port) & 0xC0; > + if (reg != QPCR_TEST_GET2) > + return -EINVAL; > + pci_quatech_wqopr(port, (qopr & QPCR_TEST_FOR1)|QPCR_TEST_FOR3); > + reg = pci_quatech_rqopr(port) & 0xC0; > + if (reg != QPCR_TEST_GET3) > + return -EINVAL; > + pci_quatech_wqopr(port, (qopr & QPCR_TEST_FOR1)|QPCR_TEST_FOR4); > + reg = pci_quatech_rqopr(port) & 0xC0; > + if (reg != QPCR_TEST_GET4) > + return -EINVAL; > + > + pci_quatech_wqopr(port, qopr); > + return 0; > +} > + > +static int pci_quatech_clock(struct uart_8250_port *port) > +{ > + u8 qopr, reg, set; > + unsigned long clock; > + > + if (pci_quatech_test(port) < 0) > + return 1843200; > + > + qopr = pci_quatech_rqopr(port); > + > + pci_quatech_wqopr(port, qopr & ~QOPR_CLOCK_X8); > + reg = pci_quatech_rqopr(port); > + if (reg & QOPR_CLOCK_X8) { > + clock = 1843200; > + goto out; > + } > + pci_quatech_wqopr(port, qopr | QOPR_CLOCK_X8); > + reg = pci_quatech_rqopr(port); > + if (!(reg & QOPR_CLOCK_X8)) { > + clock = 1843200; > + goto out; > + } > + reg &= QOPR_CLOCK_X8; > + if (reg == QOPR_CLOCK_X2) { > + clock = 3685400; > + set = QOPR_CLOCK_X2; > + } else if (reg == QOPR_CLOCK_X4) { > + clock = 7372800; > + set = QOPR_CLOCK_X4; > + } else if (reg == QOPR_CLOCK_X8) { > + clock = 14745600; > + set = QOPR_CLOCK_X8; > + } else { > + clock = 1843200; > + set = QOPR_CLOCK_X1; > + } > + qopr &= ~QOPR_CLOCK_RATE_MASK; > + qopr |= set; > + > +out: > + pci_quatech_wqopr(port, qopr); > + return clock; > +} > + > +static int pci_quatech_rs422(struct uart_8250_port *port) > +{ > + u8 qmcr; > + int rs422 = 0; > + > + if (!pci_quatech_has_qmcr(port)) > + return 0; > + qmcr = pci_quatech_rqmcr(port); > + pci_quatech_wqmcr(port, 0xFF); > + if (pci_quatech_rqmcr(port)) > + rs422 = 1; > + pci_quatech_wqmcr(port, qmcr); > + return rs422; > +} > + > +static int pci_quatech_init(struct pci_dev *dev) > +{ > + if (pci_quatech_amcc(dev->device)) { > + unsigned long base = pci_resource_start(dev, 0); > + if (base) { > + u32 tmp; > + outl(inl(base + 0x38), base + 0x38); > + tmp = inl(base + 0x3c); > + outl(tmp | 0x01000000, base + 0x3c); > + outl(tmp, base + 0x3c); > + } > + } > + return 0; > +} > + > +static int pci_quatech_setup(struct serial_private *priv, > + const struct pciserial_board *board, > + struct uart_8250_port *port, int idx) > +{ > + /* Needed by pci_quatech calls below */ > + port->port.iobase = pci_resource_start(priv->dev, FL_GET_BASE(board->flags)); > + /* Set up the clocking */ > + port->port.uartclk = pci_quatech_clock(port); > + /* For now just warn about RS422 */ > + if (pci_quatech_rs422(port)) > + pr_warn( "quatech: software control of RS422 features not currently supported.\n"); > + return pci_default_setup(priv, board, port, idx); > +} > + > +static void __devexit pci_quatech_exit(struct pci_dev *dev) > +{ > +} > + > static int pci_default_setup(struct serial_private *priv, > const struct pciserial_board *board, > struct uart_8250_port *port, int idx) > @@ -1503,6 +1750,16 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { > .setup = pci_default_setup, > .exit = __devexit_p(pci_plx9050_exit), > }, > + /* Quatech */ > + { > + .vendor = PCI_VENDOR_ID_QUATECH, > + .device = PCI_ANY_ID, > + .subvendor = PCI_ANY_ID, > + .subdevice = PCI_ANY_ID, > + .init = pci_quatech_init, > + .setup = pci_quatech_setup, > + .exit = __devexit_p(pci_quatech_exit), > + }, > /* > * SBS Technologies, Inc., PMC-OCTALPRO 232 > */ > @@ -3257,18 +3514,70 @@ static struct pci_device_id serial_pci_tbl[] = { > { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_ROMULUS, > 0x10b5, 0x106a, 0, 0, > pbn_plx_romulus }, > + /* > + * Quatech cards. These actually have configurable clocks but for > + * now we just use the default. > + * > + * 100 series are RS232, 200 series RS422, > + */ > { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSC100, > PCI_ANY_ID, PCI_ANY_ID, 0, 0, > pbn_b1_4_115200 }, > { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSC100, > PCI_ANY_ID, PCI_ANY_ID, 0, 0, > pbn_b1_2_115200 }, > + { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSC100E, > + PCI_ANY_ID, PCI_ANY_ID, 0, 0, > + pbn_b2_2_115200 }, > + { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSC200, > + PCI_ANY_ID, PCI_ANY_ID, 0, 0, > + pbn_b1_2_115200 }, > + { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSC200E, > + PCI_ANY_ID, PCI_ANY_ID, 0, 0, > + pbn_b2_2_115200 }, > + { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSC200, > + PCI_ANY_ID, PCI_ANY_ID, 0, 0, > + pbn_b1_4_115200 }, > { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESC100D, > PCI_ANY_ID, PCI_ANY_ID, 0, 0, > pbn_b1_8_115200 }, > { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESC100M, > PCI_ANY_ID, PCI_ANY_ID, 0, 0, > pbn_b1_8_115200 }, > + { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSCP100, > + PCI_ANY_ID, PCI_ANY_ID, 0, 0, > + pbn_b1_4_115200 }, > + { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSCP100, > + PCI_ANY_ID, PCI_ANY_ID, 0, 0, > + pbn_b1_2_115200 }, > + { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSCP200, > + PCI_ANY_ID, PCI_ANY_ID, 0, 0, > + pbn_b1_4_115200 }, > + { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSCP200, > + PCI_ANY_ID, PCI_ANY_ID, 0, 0, > + pbn_b1_2_115200 }, > + { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSCLP100, > + PCI_ANY_ID, PCI_ANY_ID, 0, 0, > + pbn_b2_4_115200 }, > + { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSCLP100, > + PCI_ANY_ID, PCI_ANY_ID, 0, 0, > + pbn_b2_2_115200 }, > + { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_SSCLP100, > + PCI_ANY_ID, PCI_ANY_ID, 0, 0, > + pbn_b2_1_115200 }, > + { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSCLP200, > + PCI_ANY_ID, PCI_ANY_ID, 0, 0, > + pbn_b2_4_115200 }, > + { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSCLP200, > + PCI_ANY_ID, PCI_ANY_ID, 0, 0, > + pbn_b2_2_115200 }, > + { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_SSCLP200, > + PCI_ANY_ID, PCI_ANY_ID, 0, 0, > + pbn_b2_1_115200 }, > + { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESCLP100, > + PCI_ANY_ID, PCI_ANY_ID, 0, 0, > + pbn_b0_8_115200 }, > + > { PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_OXSEMI_16PCI954, > PCI_VENDOR_ID_SPECIALIX, PCI_SUBDEVICE_ID_SPECIALIX_SPEED4, > 0, 0, > diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h > index 9d36b82..ce45006 100644 > --- a/include/linux/pci_ids.h > +++ b/include/linux/pci_ids.h > @@ -1867,8 +1867,23 @@ > #define PCI_VENDOR_ID_QUATECH 0x135C > #define PCI_DEVICE_ID_QUATECH_QSC100 0x0010 > #define PCI_DEVICE_ID_QUATECH_DSC100 0x0020 > +#define PCI_DEVICE_ID_QUATECH_DSC200 0x0030 > +#define PCI_DEVICE_ID_QUATECH_QSC200 0x0040 > #define PCI_DEVICE_ID_QUATECH_ESC100D 0x0050 > #define PCI_DEVICE_ID_QUATECH_ESC100M 0x0060 > +#define PCI_DEVICE_ID_QUATECH_QSCP100 0x0120 > +#define PCI_DEVICE_ID_QUATECH_DSCP100 0x0130 > +#define PCI_DEVICE_ID_QUATECH_QSCP200 0x0140 > +#define PCI_DEVICE_ID_QUATECH_DSCP200 0x0150 > +#define PCI_DEVICE_ID_QUATECH_QSCLP100 0x0170 > +#define PCI_DEVICE_ID_QUATECH_DSCLP100 0x0180 > +#define PCI_DEVICE_ID_QUATECH_DSC100E 0x0181 > +#define PCI_DEVICE_ID_QUATECH_SSCLP100 0x0190 > +#define PCI_DEVICE_ID_QUATECH_QSCLP200 0x01A0 > +#define PCI_DEVICE_ID_QUATECH_DSCLP200 0x01B0 > +#define PCI_DEVICE_ID_QUATECH_DSC200E 0x01B1 > +#define PCI_DEVICE_ID_QUATECH_SSCLP200 0x01C0 > +#define PCI_DEVICE_ID_QUATECH_ESCLP100 0x01E0 > #define PCI_DEVICE_ID_QUATECH_SPPXP_100 0x0278 > > #define PCI_VENDOR_ID_SEALEVEL 0x135e -- To unsubscribe from this list: send the line "unsubscribe linux-serial" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html