Commit 7808edcd authored by Nicos Gollan's avatar Nicos Gollan Committed by Greg Kroah-Hartman

Basic support for Moschip 9900 family I/O chips

Add I/O based support for serial and parallel ports of the following
chips:

Vendor: Moschip (0x9710)

Parts (device IDs)
* 9900 (0x9900)
* 9904 (0x9904
* 9901 (0x9912, also sold as 9912)
* 9922 (0x9922)

On all chips but the 9900, a single port is provided per PCI subdevice
(subvendor-ID 0xA000, subdevice-IDs 0x1000 for serial, 0x2000 for
parallel with proper class codes). In cascading configurations, the
9900 provides two devices per subdevice, with subvendor-ID 0xA000 and
subdevice-IDs 0x30ps where p is the number of parallel ports and s the
number of serial ports.

Basic testing was only done on the serial part of a 9912 to the point
where it can be used for a serial kernel console, and advanced features
are completely untested. It is possible to reduce functionality of the
chips by adding a configuration EEPROM, and the datasheet [1] is
inconsistent w.r.t subdevices in the 4s+2s1p and 2s1p+4s
configurations. The subdevice-ID 0x3012 should likely read 0x3011 with
a serial port in function 3, which would be consistent with the BAR
layouts. For now, the drivers ignore subdevices with ID 0x1000 and no
class code.

The parallel ports are integrated in parport_serial even for purely
parallel parts to reduce the footprint of the patch.

[1] http://www.moschip.com/data/products/MCS9900/MCS9900_Datasheet.pdfSigned-off-by: default avatarNicos Gollan <gtdev@spearhead.de>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 59c5f46f
...@@ -33,6 +33,9 @@ enum parport_pc_pci_cards { ...@@ -33,6 +33,9 @@ enum parport_pc_pci_cards {
netmos_9xx5_combo, netmos_9xx5_combo,
netmos_9855, netmos_9855,
netmos_9855_2p, netmos_9855_2p,
netmos_9900,
netmos_9900_2p,
netmos_99xx_1p,
avlab_1s1p, avlab_1s1p,
avlab_1s2p, avlab_1s2p,
avlab_2s1p, avlab_2s1p,
...@@ -72,22 +75,20 @@ static int __devinit netmos_parallel_init(struct pci_dev *dev, struct parport_pc ...@@ -72,22 +75,20 @@ static int __devinit netmos_parallel_init(struct pci_dev *dev, struct parport_pc
dev->subsystem_vendor == PCI_VENDOR_ID_IBM && dev->subsystem_vendor == PCI_VENDOR_ID_IBM &&
dev->subsystem_device == 0x0299) dev->subsystem_device == 0x0299)
return -ENODEV; return -ENODEV;
/*
* Netmos uses the subdevice ID to indicate the number of parallel if (dev->device == PCI_DEVICE_ID_NETMOS_9912) {
* and serial ports. The form is 0x00PS, where <P> is the number of par->numports = 1;
* parallel ports and <S> is the number of serial ports. } else {
*/ /*
par->numports = (dev->subsystem_device & 0xf0) >> 4; * Netmos uses the subdevice ID to indicate the number of parallel
if (par->numports > ARRAY_SIZE(par->addr)) * and serial ports. The form is 0x00PS, where <P> is the number of
par->numports = ARRAY_SIZE(par->addr); * parallel ports and <S> is the number of serial ports.
/* */
* This function is currently only called for cards with up to par->numports = (dev->subsystem_device & 0xf0) >> 4;
* one parallel port. if (par->numports > ARRAY_SIZE(par->addr))
* Parallel port BAR is either before or after serial ports BARS; par->numports = ARRAY_SIZE(par->addr);
* hence, lo should be either 0 or equal to the number of serial ports. }
*/
if (par->addr[0].lo != 0)
par->addr[0].lo = dev->subsystem_device & 0xf;
return 0; return 0;
} }
...@@ -97,6 +98,9 @@ static struct parport_pc_pci cards[] __devinitdata = { ...@@ -97,6 +98,9 @@ static struct parport_pc_pci cards[] __devinitdata = {
/* netmos_9xx5_combo */ { 1, { { 2, -1 }, }, netmos_parallel_init }, /* netmos_9xx5_combo */ { 1, { { 2, -1 }, }, netmos_parallel_init },
/* netmos_9855 */ { 1, { { 0, -1 }, }, netmos_parallel_init }, /* netmos_9855 */ { 1, { { 0, -1 }, }, netmos_parallel_init },
/* netmos_9855_2p */ { 2, { { 0, -1 }, { 2, -1 }, } }, /* netmos_9855_2p */ { 2, { { 0, -1 }, { 2, -1 }, } },
/* netmos_9900 */ {1, { { 3, 4 }, }, netmos_parallel_init },
/* netmos_9900_2p */ {2, { { 0, 1 }, { 3, 4 }, } },
/* netmos_99xx_1p */ {1, { { 0, 1 }, } },
/* avlab_1s1p */ { 1, { { 1, 2}, } }, /* avlab_1s1p */ { 1, { { 1, 2}, } },
/* avlab_1s2p */ { 2, { { 1, 2}, { 3, 4 },} }, /* avlab_1s2p */ { 2, { { 1, 2}, { 3, 4 },} },
/* avlab_2s1p */ { 1, { { 2, 3}, } }, /* avlab_2s1p */ { 1, { { 2, 3}, } },
...@@ -127,6 +131,14 @@ static struct pci_device_id parport_serial_pci_tbl[] = { ...@@ -127,6 +131,14 @@ static struct pci_device_id parport_serial_pci_tbl[] = {
0x1000, 0x0022, 0, 0, netmos_9855_2p }, 0x1000, 0x0022, 0, 0, netmos_9855_2p },
{ PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9855, { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9855,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9855 }, PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9855 },
{ PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9900,
0xA000, 0x3011, 0, 0, netmos_9900 },
{ PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9900,
0xA000, 0x3012, 0, 0, netmos_9900 },
{ PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9900,
0xA000, 0x3020, 0, 0, netmos_9900_2p },
{ PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9912,
0xA000, 0x2000, 0, 0, netmos_99xx_1p },
/* PCI_VENDOR_ID_AVLAB/Intek21 has another bunch of cards ...*/ /* PCI_VENDOR_ID_AVLAB/Intek21 has another bunch of cards ...*/
{ PCI_VENDOR_ID_AFAVLAB, 0x2110, { PCI_VENDOR_ID_AFAVLAB, 0x2110,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s1p }, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s1p },
...@@ -219,6 +231,24 @@ static struct pciserial_board pci_parport_serial_boards[] __devinitdata = { ...@@ -219,6 +231,24 @@ static struct pciserial_board pci_parport_serial_boards[] __devinitdata = {
.base_baud = 115200, .base_baud = 115200,
.uart_offset = 8, .uart_offset = 8,
}, },
[netmos_9900] = { /* n/t */
.flags = FL_BASE0 | FL_BASE_BARS,
.num_ports = 1,
.base_baud = 115200,
.uart_offset = 8,
},
[netmos_9900_2p] = { /* parallel only */ /* n/t */
.flags = FL_BASE0,
.num_ports = 0,
.base_baud = 115200,
.uart_offset = 8,
},
[netmos_99xx_1p] = { /* parallel only */ /* n/t */
.flags = FL_BASE0,
.num_ports = 0,
.base_baud = 115200,
.uart_offset = 8,
},
[avlab_1s1p] = { /* n/t */ [avlab_1s1p] = { /* n/t */
.flags = FL_BASE0 | FL_BASE_BARS, .flags = FL_BASE0 | FL_BASE_BARS,
.num_ports = 1, .num_ports = 1,
...@@ -285,6 +315,10 @@ static int __devinit serial_register (struct pci_dev *dev, ...@@ -285,6 +315,10 @@ static int __devinit serial_register (struct pci_dev *dev,
struct serial_private *serial; struct serial_private *serial;
board = &pci_parport_serial_boards[id->driver_data]; board = &pci_parport_serial_boards[id->driver_data];
if (board->num_ports == 0)
return 0;
serial = pciserial_init_ports(dev, board); serial = pciserial_init_ports(dev, board);
if (IS_ERR(serial)) if (IS_ERR(serial))
......
...@@ -56,6 +56,9 @@ struct serial_private { ...@@ -56,6 +56,9 @@ struct serial_private {
int line[0]; int line[0];
}; };
static int pci_default_setup(struct serial_private*,
const struct pciserial_board*, struct uart_port*, int);
static void moan_device(const char *str, struct pci_dev *dev) static void moan_device(const char *str, struct pci_dev *dev)
{ {
printk(KERN_WARNING printk(KERN_WARNING
...@@ -752,6 +755,62 @@ pci_ni8430_setup(struct serial_private *priv, ...@@ -752,6 +755,62 @@ pci_ni8430_setup(struct serial_private *priv,
return setup_port(priv, port, bar, offset, board->reg_shift); return setup_port(priv, port, bar, offset, board->reg_shift);
} }
static int pci_netmos_9900_setup(struct serial_private *priv,
const struct pciserial_board *board,
struct uart_port *port, int idx)
{
unsigned int bar;
if ((priv->dev->subsystem_device & 0xff00) == 0x3000) {
/* netmos apparently orders BARs by datasheet layout, so serial
* ports get BARs 0 and 3 (or 1 and 4 for memmapped)
*/
bar = 3 * idx;
return setup_port(priv, port, bar, 0, board->reg_shift);
} else {
return pci_default_setup(priv, board, port, idx);
}
}
/* the 99xx series comes with a range of device IDs and a variety
* of capabilities:
*
* 9900 has varying capabilities and can cascade to sub-controllers
* (cascading should be purely internal)
* 9904 is hardwired with 4 serial ports
* 9912 and 9922 are hardwired with 2 serial ports
*/
static int pci_netmos_9900_numports(struct pci_dev *dev)
{
unsigned int c = dev->class;
unsigned int pi;
unsigned short sub_serports;
pi = (c & 0xff);
if (pi == 2) {
return 1;
} else if ((pi == 0) &&
(dev->device == PCI_DEVICE_ID_NETMOS_9900)) {
/* two possibilities: 0x30ps encodes number of parallel and
* serial ports, or 0x1000 indicates *something*. This is not
* immediately obvious, since the 2s1p+4s configuration seems
* to offer all functionality on functions 0..2, while still
* advertising the same function 3 as the 4s+2s1p config.
*/
sub_serports = dev->subsystem_device & 0xf;
if (sub_serports > 0) {
return sub_serports;
} else {
printk(KERN_NOTICE "NetMos/Mostech serial driver ignoring port on ambiguous config.\n");
return 0;
}
}
moan_device("unknown NetMos/Mostech program interface", dev);
return 0;
}
static int pci_netmos_init(struct pci_dev *dev) static int pci_netmos_init(struct pci_dev *dev)
{ {
...@@ -761,12 +820,28 @@ static int pci_netmos_init(struct pci_dev *dev) ...@@ -761,12 +820,28 @@ static int pci_netmos_init(struct pci_dev *dev)
if ((dev->device == PCI_DEVICE_ID_NETMOS_9901) || if ((dev->device == PCI_DEVICE_ID_NETMOS_9901) ||
(dev->device == PCI_DEVICE_ID_NETMOS_9865)) (dev->device == PCI_DEVICE_ID_NETMOS_9865))
return 0; return 0;
if (dev->subsystem_vendor == PCI_VENDOR_ID_IBM && if (dev->subsystem_vendor == PCI_VENDOR_ID_IBM &&
dev->subsystem_device == 0x0299) dev->subsystem_device == 0x0299)
return 0; return 0;
switch (dev->device) { /* FALLTHROUGH on all */
case PCI_DEVICE_ID_NETMOS_9904:
case PCI_DEVICE_ID_NETMOS_9912:
case PCI_DEVICE_ID_NETMOS_9922:
case PCI_DEVICE_ID_NETMOS_9900:
num_serial = pci_netmos_9900_numports(dev);
break;
default:
if (num_serial == 0 ) {
moan_device("unknown NetMos/Mostech device", dev);
}
}
if (num_serial == 0) if (num_serial == 0)
return -ENODEV; return -ENODEV;
return num_serial; return num_serial;
} }
...@@ -1417,7 +1492,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { ...@@ -1417,7 +1492,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.subvendor = PCI_ANY_ID, .subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID, .subdevice = PCI_ANY_ID,
.init = pci_netmos_init, .init = pci_netmos_init,
.setup = pci_default_setup, .setup = pci_netmos_9900_setup,
}, },
/* /*
* For Oxford Semiconductor Tornado based devices * For Oxford Semiconductor Tornado based devices
...@@ -1644,6 +1719,7 @@ enum pci_board_num_t { ...@@ -1644,6 +1719,7 @@ enum pci_board_num_t {
pbn_ADDIDATA_PCIe_8_3906250, pbn_ADDIDATA_PCIe_8_3906250,
pbn_ce4100_1_115200, pbn_ce4100_1_115200,
pbn_omegapci, pbn_omegapci,
pbn_NETMOS9900_2s_115200,
}; };
/* /*
...@@ -2345,6 +2421,11 @@ static struct pciserial_board pci_boards[] __devinitdata = { ...@@ -2345,6 +2421,11 @@ static struct pciserial_board pci_boards[] __devinitdata = {
.base_baud = 115200, .base_baud = 115200,
.uart_offset = 0x200, .uart_offset = 0x200,
}, },
[pbn_NETMOS9900_2s_115200] = {
.flags = FL_BASE0,
.num_ports = 2,
.base_baud = 115200,
},
}; };
static const struct pci_device_id softmodem_blacklist[] = { static const struct pci_device_id softmodem_blacklist[] = {
...@@ -3826,6 +3907,27 @@ static struct pci_device_id serial_pci_tbl[] = { ...@@ -3826,6 +3907,27 @@ static struct pci_device_id serial_pci_tbl[] = {
0xA000, 0x1000, 0xA000, 0x1000,
0, 0, pbn_b0_1_115200 }, 0, 0, pbn_b0_1_115200 },
/* the 9901 is a rebranded 9912 */
{ PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9912,
0xA000, 0x1000,
0, 0, pbn_b0_1_115200 },
{ PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9922,
0xA000, 0x1000,
0, 0, pbn_b0_1_115200 },
{ PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9904,
0xA000, 0x1000,
0, 0, pbn_b0_1_115200 },
{ PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9900,
0xA000, 0x1000,
0, 0, pbn_b0_1_115200 },
{ PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9900,
0xA000, 0x3002,
0, 0, pbn_NETMOS9900_2s_115200 },
/* /*
* Best Connectivity PCI Multi I/O cards * Best Connectivity PCI Multi I/O cards
*/ */
......
...@@ -2821,7 +2821,11 @@ ...@@ -2821,7 +2821,11 @@
#define PCI_DEVICE_ID_NETMOS_9845 0x9845 #define PCI_DEVICE_ID_NETMOS_9845 0x9845
#define PCI_DEVICE_ID_NETMOS_9855 0x9855 #define PCI_DEVICE_ID_NETMOS_9855 0x9855
#define PCI_DEVICE_ID_NETMOS_9865 0x9865 #define PCI_DEVICE_ID_NETMOS_9865 0x9865
#define PCI_DEVICE_ID_NETMOS_9900 0x9900
#define PCI_DEVICE_ID_NETMOS_9901 0x9901 #define PCI_DEVICE_ID_NETMOS_9901 0x9901
#define PCI_DEVICE_ID_NETMOS_9904 0x9904
#define PCI_DEVICE_ID_NETMOS_9912 0x9912
#define PCI_DEVICE_ID_NETMOS_9922 0x9922
#define PCI_VENDOR_ID_3COM_2 0xa727 #define PCI_VENDOR_ID_3COM_2 0xa727
......
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