mirror of
https://github.com/sjlongland/adv950.git
synced 2025-09-13 10:43:14 +10:00
This is a check-in of the Advantech ADV950 serial driver, used with the UNO-1150 series of industrial computers, as sourced from: http://support.advantech.com/support/DownloadSRDetail_New.aspx?SR_ID=1-GLBRCD&Doc_Source=Download This builds with kernel 3.0.1, but does not build with contemporary kernels (i.e. ones that are still in support). I suspect this is a hacked up version of Russel King's 8250 serial driver from 2001. First step, let's get it building against the current kernel (v4.10.1) and then we'll look at integrating this into 8250 proper.
1803 lines
48 KiB
C
1803 lines
48 KiB
C
//******************************************************************************
|
|
//
|
|
// Copyright (c) 2011 Advantech Industrial Automation Group.
|
|
//
|
|
// Oxford PCI-954/952/16C950 with Advantech RS232/422/485 capacities
|
|
//
|
|
// This program 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 2 of the License, or (at your option)
|
|
// any later version.
|
|
//
|
|
// This program 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
|
|
// this program; if not, write to the Free Software Foundation, Inc., 59
|
|
// Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
//
|
|
//
|
|
//
|
|
//******************************************************************************
|
|
|
|
//***********************************************************************
|
|
// File: 8250_pci.c
|
|
//
|
|
// PLEASE SEE 8250.c FOR DETAIL
|
|
//***********************************************************************
|
|
#include <linux/module.h>
|
|
#include <linux/init.h>
|
|
#include <linux/pci.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/string.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/tty.h>
|
|
#include <linux/serial.h>
|
|
#include <linux/serial_core.h>
|
|
#include <linux/8250_pci.h>
|
|
|
|
#include <asm/bitops.h>
|
|
#include <asm/byteorder.h>
|
|
#include <asm/serial.h>
|
|
#include <asm/io.h>
|
|
|
|
#include "8250.h"
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
* Advantech IAG PCI-954/16C950 cards
|
|
*
|
|
*/
|
|
#define ADVANTECH_16C950_VER "3.33"
|
|
#define ADVANTECH_16C950_DATE "11/07/2011"
|
|
#define PCI_VENDOR_ID_ADVANTECH 0x13fe
|
|
#define PCI_DEVICE_ID_ADVANTECH_PCI1600 0x1600 /* Internal */
|
|
#define PCI_DEVICE_ID_ADVANTECH_PCI1601 0x1601 /* Internal */
|
|
#define PCI_DEVICE_ID_ADVANTECH_PCI1602 0x1602 /* Internal */
|
|
#define PCI_DEVICE_ID_ADVANTECH_PCI1603 0x1603 /* Internal */
|
|
#define PCI_DEVICE_ID_ADVANTECH_PCI1604 0x1604 /* Internal */
|
|
#define PCI_DEVICE_ID_ADVANTECH_PCI16ff 0x16ff /* External */
|
|
#define PCI_DEVICE_ID_ADVANTECH_PCI1600_1601 0x1601
|
|
#define PCI_DEVICE_ID_ADVANTECH_PCI1600_1602 0x1602
|
|
#define PCI_DEVICE_ID_ADVANTECH_PCI1600_1610 0x1610
|
|
#define PCI_DEVICE_ID_ADVANTECH_PCI1600_1612 0x1612 /* Also for UNO-2059 */
|
|
#define PCI_DEVICE_ID_ADVANTECH_PCI1600_1620 0x1620
|
|
#define PCI_DEVICE_ID_ADVANTECH_PCI1600_1622 0x1622
|
|
#define PCI_DEVICE_ID_ADVANTECH_UNO2050 0x2050
|
|
#define PCI_DEVICE_ID_ADVANTECH_UNOB2201 0x2201 //2668
|
|
#define PCI_DEVICE_ID_ADVANTECH_UNOBF201 0xf201 //2668
|
|
#define PCI_DEVICE_ID_ADVANTECH_UNOBX201_2201 0x2201 //2668
|
|
#define PCI_DEVICE_ID_ADVANTECH_MIC3620 0x3620
|
|
#define PCI_DEVICE_ID_ADVANTECH_MIC3612 0X3612
|
|
#define PCI_DEVICE_ID_ADVANTECH_MIC3611 0X3611
|
|
//yongjun add 2006/11/08
|
|
#define PCI_DEVICE_ID_ADVANTECH_UNO2176 0x2176
|
|
#define PCI_DEVICE_ID_ADVANTECH_UNO2X76_2176 0x2176
|
|
//yongjun add end 2006/11/08
|
|
|
|
//jinxin added to support PCIe952/PCIe954/PCIe958
|
|
#define PCI_DEVICE_ID_ADVANTECH_PCIE952 0xA202
|
|
#define PCI_DEVICE_ID_ADVANTECH_PCIE954 0xA304
|
|
#define PCI_DEVICE_ID_ADVANTECH_PCIE958 0xA408
|
|
|
|
//james dai add 2007/5/28
|
|
//DEVICE ID
|
|
#define PCI_DEVICE_ID_ADVANTECH_PCM3614P 0x3614 //PCM-3614P
|
|
#define PCI_DEVICE_ID_ADVANTECH_PCM3641P 0x3641 //PCM-3641P
|
|
|
|
#define PCI_DEVICE_ID_ADVANTECH_PCM3618P 0x3618 //PCM-3618P
|
|
#define PCI_DEVICE_ID_ADVANTECH_PCMF618P 0xF618 //PCM-3618P
|
|
#define PCI_DEVICE_ID_ADVANTECH_PCM3681P 0x3681 //PCM-3681P
|
|
#define PCI_DEVICE_ID_ADVANTECH_PCMF681P 0xF681 //PCM-3681P
|
|
|
|
#define PCI_SUB_VENDOR_ID_ADVANTECH_PCM3614P 0x3614 //PCM-3614P
|
|
#define PCI_SUB_VENDOR_ID_ADVANTECH_PCM3618P 0x3618 //PCM-3618P
|
|
#define PCI_SUB_VENDOR_ID_ADVANTECH_PCM3641P 0x3641 //PCM-3641P
|
|
#define PCI_SUB_VENDOR_ID_ADVANTECH_PCM3681P 0x3681 //PCM-3681P
|
|
//james dai add end
|
|
//james dai add to support UNO-1150
|
|
#define PCI_DEVICE_ID_ADVANTECH_UNO1150 0x3610 //UNO-1150
|
|
//james dai add end
|
|
//james dai add 2008/07/20 to support MIC-3621
|
|
#define PCI_DEVICE_ID_ADVANTECH_MIC3621 0x3621 //PCM-3614P
|
|
#define PCI_SUB_VENDOR_ID_ADVANTECH_MIC3621 0x3621 //PCM-3614P
|
|
//james dai add end
|
|
#define PCI_DEVICE_ID_ADVANTECH_A001 0xA001
|
|
#define PCI_DEVICE_ID_ADVANTECH_A002 0xA002
|
|
#define PCI_DEVICE_ID_ADVANTECH_A004 0xA004
|
|
#define PCI_DEVICE_ID_ADVANTECH_A101 0xA101
|
|
#define PCI_DEVICE_ID_ADVANTECH_A102 0xA102
|
|
#define PCI_DEVICE_ID_ADVANTECH_A104 0xA104
|
|
|
|
#define PCI_DEVICE_ID_ADVANTECH_F001 0xF001
|
|
#define PCI_DEVICE_ID_ADVANTECH_F002 0xF002
|
|
#define PCI_DEVICE_ID_ADVANTECH_F004 0xF004
|
|
#define PCI_DEVICE_ID_ADVANTECH_F101 0xF101
|
|
#define PCI_DEVICE_ID_ADVANTECH_F102 0xF102
|
|
#define PCI_DEVICE_ID_ADVANTECH_F104 0xF104
|
|
|
|
int adv_register_serial(struct serial_struct *req);
|
|
void adv_unregister_serial(int line);
|
|
|
|
#define ACR_DTR_RS232 0x00
|
|
#define ACR_DTR_ACTIVE_LOW_RS485 0x10
|
|
#define ACR_DTR_ACTIVE_HIGH_RS485 0x18
|
|
|
|
#define UART_TYPE_AUTO 0
|
|
#define UART_TYPE_RS232 1
|
|
#define UART_TYPE_RS485 2
|
|
|
|
/*
|
|
* Definitions for PCI support.
|
|
*/
|
|
#define FL_BASE_MASK 0x0007
|
|
#define FL_BASE0 0x0000
|
|
#define FL_BASE1 0x0001
|
|
#define FL_BASE2 0x0002
|
|
#define FL_BASE3 0x0003
|
|
#define FL_BASE4 0x0004
|
|
#define FL_GET_BASE(x) (x & FL_BASE_MASK)
|
|
|
|
/* Use successive BARs (PCI base address registers),
|
|
else use offset into some specified BAR */
|
|
#define FL_BASE_BARS 0x0008
|
|
|
|
/* do not assign an irq */
|
|
#define FL_NOIRQ 0x0080
|
|
|
|
/* Use the Base address register size to cap number of ports */
|
|
#define FL_REGION_SZ_CAP 0x0100
|
|
|
|
static char * product_line[] = {"GENERAL","PCI","PCM","ADAM","APAX","BAS","UNO","TPC","EAMB"};
|
|
struct pci_board {
|
|
unsigned int flags;
|
|
unsigned int num_ports;
|
|
unsigned int base_baud;
|
|
unsigned int uart_offset;
|
|
unsigned int reg_shift;
|
|
unsigned int first_offset;
|
|
};
|
|
|
|
/*
|
|
* init function returns:
|
|
* > 0 - number of ports
|
|
* = 0 - use board->num_ports
|
|
* < 0 - error
|
|
*/
|
|
struct pci_serial_quirk {
|
|
u32 vendor;
|
|
u32 device;
|
|
u32 subvendor;
|
|
u32 subdevice;
|
|
int (*init)(struct pci_dev *dev);
|
|
int (*setup)(struct pci_dev *dev, struct pci_board *board,
|
|
struct serial_struct *req, int idx);
|
|
void (*exit)(struct pci_dev *dev);
|
|
};
|
|
|
|
#define PCI_NUM_BAR_RESOURCES 6
|
|
|
|
struct serial_private {
|
|
unsigned int nr;
|
|
void *remapped_bar[PCI_NUM_BAR_RESOURCES];
|
|
struct pci_serial_quirk *quirk;
|
|
int line[0];
|
|
};
|
|
|
|
static void moan_device(const char *str, struct pci_dev *dev)
|
|
{
|
|
printk(KERN_WARNING "%s: %s\n"
|
|
KERN_WARNING "Please send the output of lspci -vv, this\n"
|
|
KERN_WARNING "message (0x%04x,0x%04x,0x%04x,0x%04x), the\n"
|
|
KERN_WARNING "manufacturer and name of serial board or\n"
|
|
KERN_WARNING "modem board to rmk+serial@arm.linux.org.uk.\n",
|
|
pci_name(dev), str, dev->vendor, dev->device,
|
|
dev->subsystem_vendor, dev->subsystem_device);
|
|
}
|
|
|
|
static int
|
|
setup_port(struct pci_dev *dev, struct serial_struct *req,
|
|
int bar, int offset, int regshift)
|
|
{
|
|
struct serial_private *priv = pci_get_drvdata(dev);
|
|
unsigned long port, len;
|
|
|
|
if (bar >= PCI_NUM_BAR_RESOURCES)
|
|
return -EINVAL;
|
|
|
|
if (pci_resource_flags(dev, bar) & IORESOURCE_MEM) {
|
|
port = pci_resource_start(dev, bar);
|
|
len = pci_resource_len(dev, bar);
|
|
|
|
if (!priv->remapped_bar[bar])
|
|
{
|
|
priv->remapped_bar[bar] = ioremap(port, len);
|
|
}
|
|
if (!priv->remapped_bar[bar])
|
|
return -ENOMEM;
|
|
|
|
req->io_type = UPIO_MEM;
|
|
req->iomap_base = port + offset;
|
|
req->iomem_base = priv->remapped_bar[bar] + offset;
|
|
//printk(KERN_INFO "bar=0x%d, offset=0x%x, req->iomap_base=0x%x, req->iomem_base=0x%x, port =0x%x, len=0x%x,regshift=0x%x\n",
|
|
// bar, offset, req->iomap_base, req->iomem_base, port, len, regshift);
|
|
|
|
req->iomem_reg_shift = regshift;
|
|
} else {
|
|
port = pci_resource_start(dev, bar) + offset;
|
|
req->io_type = UPIO_PORT;
|
|
req->port = port;
|
|
if (HIGH_BITS_OFFSET)
|
|
req->port_high = port >> HIGH_BITS_OFFSET;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
pci_default_setup(struct pci_dev *dev, struct pci_board *board,
|
|
struct serial_struct *req, int idx)
|
|
{
|
|
unsigned int bar, offset = board->first_offset, maxnr;
|
|
|
|
bar = FL_GET_BASE(board->flags);
|
|
if (board->flags & FL_BASE_BARS)
|
|
bar += idx;
|
|
else
|
|
offset += idx * board->uart_offset;
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18)
|
|
maxnr = (pci_resource_len(dev, bar) - board->uart_offset) >>
|
|
(board->reg_shift + 3);
|
|
#else
|
|
maxnr = (pci_resource_len(dev, bar) - board->uart_offset) /
|
|
(8 << board->reg_shift);
|
|
#endif
|
|
if (board->flags & FL_REGION_SZ_CAP && idx >= maxnr)
|
|
return 1;
|
|
|
|
return setup_port(dev, req, bar, offset, board->reg_shift);
|
|
}
|
|
|
|
/*
|
|
* Advantech IAG PCI-954/16C950 cards
|
|
*/
|
|
static int
|
|
pci_advantech_setup(struct pci_dev *dev, struct pci_board *board,
|
|
struct serial_struct *req, int idx)
|
|
{
|
|
u32 bar, port485, offset485;
|
|
u32 remap, len;
|
|
u8 config485, activeType, configFunc, configType;
|
|
u16 config485_958;
|
|
struct pci_dev *cfgdev = NULL;
|
|
int base_idx=0;
|
|
int rc;
|
|
|
|
configFunc = 1; // Default configuration BAR is function 1
|
|
offset485 = 0x60; // Default offset to get RS232/422/485 configuration
|
|
bar = PCI_BASE_ADDRESS_0; // Default BAR is PCI_BASE_ADDRESS_0
|
|
activeType = ACR_DTR_ACTIVE_HIGH_RS485; // Default RS485 is active high
|
|
configType = UART_TYPE_AUTO; // Default UART type is auto detection
|
|
switch(dev->subsystem_vendor)
|
|
{
|
|
case PCI_DEVICE_ID_ADVANTECH_PCI1600_1601:
|
|
printk("PCI-1601");
|
|
break;
|
|
case PCI_DEVICE_ID_ADVANTECH_PCI1600_1602:
|
|
printk("PCI-1602");
|
|
break;
|
|
case PCI_DEVICE_ID_ADVANTECH_PCI1600_1610:
|
|
printk("PCI-1610");
|
|
break;
|
|
case PCI_DEVICE_ID_ADVANTECH_PCI1600_1612: /* Also for UNO-2059 */
|
|
printk("PCI-1612 / UNO-2059");
|
|
break;
|
|
case PCI_DEVICE_ID_ADVANTECH_PCI1600_1620:
|
|
printk("PCI-1620");
|
|
break;
|
|
case PCI_DEVICE_ID_ADVANTECH_PCI1600_1622:
|
|
printk("PCI-1622CU");
|
|
break;
|
|
case PCI_DEVICE_ID_ADVANTECH_UNO2050:
|
|
printk("UNO-2050");
|
|
offset485 = 0x18;
|
|
break;
|
|
case PCI_DEVICE_ID_ADVANTECH_UNOBX201_2201:
|
|
printk("UNOB-2201CB");
|
|
activeType = ACR_DTR_ACTIVE_LOW_RS485;
|
|
break;
|
|
//yongjun add 2006/11/10
|
|
case PCI_DEVICE_ID_ADVANTECH_UNO2X76_2176:
|
|
printk( "UNO-2176" );
|
|
activeType = ACR_DTR_ACTIVE_LOW_RS485;
|
|
break;
|
|
//yongjun add end 2006/11/10
|
|
case PCI_DEVICE_ID_ADVANTECH_MIC3612:
|
|
printk("MIC-3612");
|
|
configFunc = 0;
|
|
bar = PCI_BASE_ADDRESS_2;
|
|
break;
|
|
//James Dai add to support MIC3621
|
|
case PCI_DEVICE_ID_ADVANTECH_MIC3621:
|
|
printk("MIC-3621");
|
|
configFunc = 0;
|
|
bar = PCI_BASE_ADDRESS_2;
|
|
break;
|
|
//James Dai add end
|
|
case PCI_DEVICE_ID_ADVANTECH_MIC3620:
|
|
printk("MIC-3620");
|
|
configType = UART_TYPE_RS232;
|
|
break;
|
|
/* Joshua Lan add @05/11/07 */
|
|
case PCI_DEVICE_ID_ADVANTECH_MIC3611:
|
|
printk("MIC-3611");
|
|
configFunc = 0;
|
|
bar = PCI_BASE_ADDRESS_2;
|
|
configType = UART_TYPE_RS485;
|
|
break;
|
|
//james dai add @2007/5/27
|
|
case PCI_SUB_VENDOR_ID_ADVANTECH_PCM3614P:
|
|
printk( "PCM-3614P" );
|
|
activeType = ACR_DTR_ACTIVE_LOW_RS485;
|
|
break;
|
|
case PCI_SUB_VENDOR_ID_ADVANTECH_PCM3618P:
|
|
printk( "PCM-3618P" );
|
|
activeType = ACR_DTR_ACTIVE_LOW_RS485;
|
|
break;
|
|
case PCI_SUB_VENDOR_ID_ADVANTECH_PCM3641P:
|
|
printk( "PCM-3641P" );
|
|
configType = UART_TYPE_RS232;
|
|
break;
|
|
case PCI_SUB_VENDOR_ID_ADVANTECH_PCM3681P:
|
|
printk( "PCM-3681P" );
|
|
configType = UART_TYPE_RS232;
|
|
break;
|
|
//james dai add end
|
|
//james dai add add @2008/6/3
|
|
case PCI_DEVICE_ID_ADVANTECH_UNO1150:
|
|
printk( "UNO-1150" );
|
|
configFunc = 0;
|
|
base_idx = 2;
|
|
bar = PCI_BASE_ADDRESS_2;
|
|
offset485 = 0x10;
|
|
activeType = ACR_DTR_ACTIVE_LOW_RS485;
|
|
break;
|
|
//james dai add end
|
|
case PCI_VENDOR_ID_ADVANTECH:
|
|
switch(dev->device)
|
|
{
|
|
case PCI_DEVICE_ID_ADVANTECH_PCIE952:
|
|
printk( "PCIE952");
|
|
req->type |= 0x01;//this bit means to use new way to calculate baudrate
|
|
req->type |= 0x02;//have DMA
|
|
req->type |= 0x10;//is PCIe952/4/8
|
|
configFunc = 0;
|
|
|
|
base_idx = 13;//
|
|
bar = PCI_BASE_ADDRESS_0;//ok
|
|
offset485 = 0x100;//
|
|
activeType = ACR_DTR_ACTIVE_LOW_RS485;//
|
|
|
|
//configType = UART_TYPE_RS232;
|
|
break;
|
|
case PCI_DEVICE_ID_ADVANTECH_PCIE954:
|
|
printk( "PCIE954");
|
|
req->type |= 0x01;
|
|
req->type |= 0x02;
|
|
req->type |= 0x10;
|
|
configFunc = 0;
|
|
|
|
base_idx = 13;//
|
|
bar = PCI_BASE_ADDRESS_0;//ok
|
|
offset485 = 0x100;//
|
|
activeType = ACR_DTR_ACTIVE_LOW_RS485;//
|
|
|
|
//configType = UART_TYPE_RS232;
|
|
break;
|
|
case PCI_DEVICE_ID_ADVANTECH_PCIE958:
|
|
printk( "PCIE958");
|
|
req->type |= 0x01;
|
|
req->type |= 0x02;
|
|
req->type |= 0x10;
|
|
configFunc = 0;
|
|
|
|
base_idx = 13;//
|
|
bar = PCI_BASE_ADDRESS_0;//ok
|
|
offset485 = 0x100;//
|
|
activeType = ACR_DTR_ACTIVE_LOW_RS485;//
|
|
|
|
//configType = UART_TYPE_RS232;
|
|
break;
|
|
case PCI_DEVICE_ID_ADVANTECH_PCI1601:
|
|
printk("PCI-1601A/B/AU/BU");
|
|
configType = UART_TYPE_RS485;
|
|
break;
|
|
case PCI_DEVICE_ID_ADVANTECH_PCI1602:
|
|
printk("PCI-1602A/B/AU/BU/UP");
|
|
configType = UART_TYPE_RS485;
|
|
break;
|
|
case PCI_DEVICE_ID_ADVANTECH_PCI1603:
|
|
printk("PCI-1603");
|
|
configType = UART_TYPE_RS232;
|
|
break;
|
|
case PCI_DEVICE_ID_ADVANTECH_PCI1604:
|
|
printk("PCI-1604UP");
|
|
configType = UART_TYPE_RS232;
|
|
break;
|
|
|
|
}
|
|
break;
|
|
}
|
|
if (dev->device == PCI_DEVICE_ID_ADVANTECH_A001
|
|
|| dev->device == PCI_DEVICE_ID_ADVANTECH_A002
|
|
|| dev->device == PCI_DEVICE_ID_ADVANTECH_A004
|
|
|| dev->device == PCI_DEVICE_ID_ADVANTECH_A101
|
|
|| dev->device == PCI_DEVICE_ID_ADVANTECH_A102
|
|
|| dev->device == PCI_DEVICE_ID_ADVANTECH_A104
|
|
|| dev->device == PCI_DEVICE_ID_ADVANTECH_F001
|
|
|| dev->device == PCI_DEVICE_ID_ADVANTECH_F002
|
|
|| dev->device == PCI_DEVICE_ID_ADVANTECH_F004
|
|
|| dev->device == PCI_DEVICE_ID_ADVANTECH_F101
|
|
|| dev->device == PCI_DEVICE_ID_ADVANTECH_F102
|
|
|| dev->device == PCI_DEVICE_ID_ADVANTECH_F104)
|
|
{
|
|
activeType = ACR_DTR_ACTIVE_LOW_RS485;
|
|
if (dev->subsystem_vendor != PCI_VENDOR_ID_ADVANTECH)
|
|
{
|
|
printk("%s-%04x",product_line[dev->subsystem_vendor],dev->subsystem_device);
|
|
}
|
|
else
|
|
{
|
|
printk("Advantech General COM Port Device");
|
|
}
|
|
|
|
}
|
|
if(configType == UART_TYPE_RS232)
|
|
{
|
|
req->reserved_char[0] = ACR_DTR_RS232;
|
|
}
|
|
else if(configType == UART_TYPE_RS485)
|
|
{
|
|
req->reserved_char[0] = activeType;
|
|
}
|
|
else // UART_TYPE_AUTO
|
|
{
|
|
// find RS232/422/485 configuration BAR
|
|
do {
|
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14)
|
|
cfgdev = pci_find_device(PCI_VENDOR_ID_ADVANTECH,
|
|
PCI_ANY_ID, cfgdev);
|
|
#else
|
|
cfgdev = pci_get_device(PCI_VENDOR_ID_ADVANTECH,
|
|
PCI_ANY_ID, cfgdev);
|
|
#endif
|
|
|
|
if ((dev->bus->number == cfgdev->bus->number) &&
|
|
(PCI_SLOT(dev->devfn) == PCI_SLOT(cfgdev->devfn)) &&
|
|
(PCI_FUNC(cfgdev->devfn) == configFunc))
|
|
{
|
|
pci_read_config_dword(cfgdev, bar, &port485);
|
|
if((port485 & PCI_BASE_ADDRESS_SPACE) ==
|
|
PCI_BASE_ADDRESS_SPACE_IO)
|
|
{
|
|
rc = pci_enable_device(cfgdev);
|
|
if (rc)
|
|
return rc;
|
|
port485 &= PCI_BASE_ADDRESS_IO_MASK;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
} while(cfgdev != NULL);
|
|
|
|
// if cannot get RS232/422/485 configuration port
|
|
if(!cfgdev)
|
|
{
|
|
printk("%x: cannot get RS232/422/485 configuration!\n",
|
|
dev->subsystem_vendor);
|
|
return -ENODEV;
|
|
}
|
|
if(req->type & 0x10){
|
|
len = pci_resource_len(cfgdev, ((bar-0x10)/0x04));
|
|
if (pci_resource_flags(cfgdev, ((bar-0x10)/0x04)) & IORESOURCE_MEM) {
|
|
remap = (u32)ioremap(port485, len);
|
|
config485_958 = readw((void *)(remap + offset485 + idx*0x10));
|
|
//printk(KERN_INFO "configure register = %x\n", config485_958);
|
|
req->reserved_char[0] = (config485_958 & (0x01 << base_idx)) ?
|
|
activeType : ACR_DTR_RS232;
|
|
goto done;
|
|
}
|
|
else{
|
|
config485_958 = inw(port485 + offset485 + idx*0x10);
|
|
req->reserved_char[0] = (config485_958 & (0x01 << base_idx)) ?
|
|
activeType : ACR_DTR_RS232;
|
|
goto done;
|
|
}
|
|
}
|
|
// read RS232/422/485 configuration value
|
|
config485 = inb(port485 + offset485);
|
|
if(PCI_FUNC(dev->devfn) == 1) base_idx=4;
|
|
req->reserved_char[0] = (config485 & (0x01 << (base_idx+idx))) ?
|
|
activeType : ACR_DTR_RS232;
|
|
}
|
|
done:
|
|
printk(", function %d, port %d, %s",
|
|
PCI_FUNC(dev->devfn), idx,
|
|
(req->reserved_char[0] != ACR_DTR_RS232) ?
|
|
"RS422/485" : "RS232");
|
|
if(req->reserved_char[0] != ACR_DTR_RS232)
|
|
printk(", %s\n", (activeType == ACR_DTR_ACTIVE_HIGH_RS485) ?
|
|
"Active High" : "Active Low");
|
|
else
|
|
printk("\n");
|
|
|
|
return pci_default_setup(dev, board, req, idx);
|
|
}
|
|
|
|
|
|
/*
|
|
* Master list of serial port init/setup/exit quirks.
|
|
* This does not describe the general nature of the port.
|
|
* (ie, baud base, number and location of ports, etc)
|
|
*
|
|
* This list is ordered alphabetically by vendor then device.
|
|
* Specific entries must come before more generic entries.
|
|
*/
|
|
static struct pci_serial_quirk pci_serial_quirks[] = {
|
|
/*
|
|
* Advantech IAG PCI-954/16C950 cards
|
|
*/
|
|
{
|
|
.vendor = PCI_VENDOR_ID_ADVANTECH,
|
|
.device = PCI_DEVICE_ID_ADVANTECH_PCI1600,
|
|
.subvendor = PCI_DEVICE_ID_ADVANTECH_PCI1600_1601,
|
|
.subdevice = PCI_ANY_ID,
|
|
.setup = pci_advantech_setup,
|
|
},
|
|
{
|
|
.vendor = PCI_VENDOR_ID_ADVANTECH,
|
|
.device = PCI_DEVICE_ID_ADVANTECH_PCI1600,
|
|
.subvendor = PCI_DEVICE_ID_ADVANTECH_PCI1600_1602,
|
|
.subdevice = PCI_ANY_ID,
|
|
.setup = pci_advantech_setup,
|
|
},
|
|
{
|
|
.vendor = PCI_VENDOR_ID_ADVANTECH,
|
|
.device = PCI_DEVICE_ID_ADVANTECH_PCI1600,
|
|
.subvendor = PCI_DEVICE_ID_ADVANTECH_PCI1600_1610,
|
|
.subdevice = PCI_ANY_ID,
|
|
.setup = pci_advantech_setup,
|
|
},
|
|
{
|
|
.vendor = PCI_VENDOR_ID_ADVANTECH,
|
|
.device = PCI_DEVICE_ID_ADVANTECH_PCI1600,
|
|
.subvendor = PCI_DEVICE_ID_ADVANTECH_PCI1600_1612,
|
|
.subdevice = PCI_ANY_ID,
|
|
.setup = pci_advantech_setup,
|
|
},
|
|
{
|
|
.vendor = PCI_VENDOR_ID_ADVANTECH,
|
|
.device = PCI_DEVICE_ID_ADVANTECH_PCI1600,
|
|
.subvendor = PCI_DEVICE_ID_ADVANTECH_PCI1600_1620,
|
|
.subdevice = PCI_ANY_ID,
|
|
.setup = pci_advantech_setup,
|
|
},
|
|
{
|
|
.vendor = PCI_VENDOR_ID_ADVANTECH,
|
|
.device = PCI_DEVICE_ID_ADVANTECH_PCI16ff,
|
|
.subvendor = PCI_DEVICE_ID_ADVANTECH_PCI1600_1620,
|
|
.subdevice = PCI_ANY_ID,
|
|
.setup = pci_advantech_setup,
|
|
},
|
|
{
|
|
.vendor = PCI_VENDOR_ID_ADVANTECH,
|
|
.device = PCI_DEVICE_ID_ADVANTECH_PCI1600,
|
|
.subvendor = PCI_DEVICE_ID_ADVANTECH_PCI1600_1622,
|
|
.subdevice = PCI_ANY_ID,
|
|
.setup = pci_advantech_setup,
|
|
},
|
|
{
|
|
.vendor = PCI_VENDOR_ID_ADVANTECH,
|
|
.device = PCI_DEVICE_ID_ADVANTECH_PCI16ff,
|
|
.subvendor = PCI_DEVICE_ID_ADVANTECH_PCI1600_1622,
|
|
.subdevice = PCI_ANY_ID,
|
|
.setup = pci_advantech_setup,
|
|
},
|
|
{
|
|
.vendor = PCI_VENDOR_ID_ADVANTECH,
|
|
.device = PCI_DEVICE_ID_ADVANTECH_UNO2050,
|
|
.subvendor = PCI_DEVICE_ID_ADVANTECH_UNO2050,
|
|
.subdevice = PCI_ANY_ID,
|
|
.setup = pci_advantech_setup,
|
|
},
|
|
{
|
|
.vendor = PCI_VENDOR_ID_ADVANTECH,
|
|
.device = PCI_DEVICE_ID_ADVANTECH_UNOB2201,
|
|
.subvendor = PCI_DEVICE_ID_ADVANTECH_UNOBX201_2201,
|
|
.subdevice = PCI_ANY_ID,
|
|
.setup = pci_advantech_setup,
|
|
},
|
|
{
|
|
.vendor = PCI_VENDOR_ID_ADVANTECH,
|
|
.device = PCI_DEVICE_ID_ADVANTECH_UNOBF201,
|
|
.subvendor = PCI_DEVICE_ID_ADVANTECH_UNOBX201_2201,
|
|
.subdevice = PCI_ANY_ID,
|
|
.setup = pci_advantech_setup,
|
|
},
|
|
{
|
|
.vendor = PCI_VENDOR_ID_ADVANTECH,
|
|
.device = PCI_DEVICE_ID_ADVANTECH_MIC3612,
|
|
.subvendor = PCI_DEVICE_ID_ADVANTECH_MIC3612,
|
|
.subdevice = PCI_ANY_ID,
|
|
.setup = pci_advantech_setup,
|
|
},
|
|
// Joshua Lan add @2005/11/07
|
|
{
|
|
.vendor = PCI_VENDOR_ID_ADVANTECH,
|
|
.device = PCI_DEVICE_ID_ADVANTECH_MIC3611,
|
|
.subvendor = PCI_DEVICE_ID_ADVANTECH_MIC3611,
|
|
.subdevice = PCI_ANY_ID,
|
|
.setup = pci_advantech_setup,
|
|
},
|
|
{
|
|
.vendor = PCI_VENDOR_ID_ADVANTECH,
|
|
.device = PCI_DEVICE_ID_ADVANTECH_MIC3620,
|
|
.subvendor = PCI_DEVICE_ID_ADVANTECH_MIC3620,
|
|
.subdevice = PCI_ANY_ID,
|
|
.setup = pci_advantech_setup,
|
|
},
|
|
{
|
|
.vendor = PCI_VENDOR_ID_ADVANTECH,
|
|
.device = PCI_DEVICE_ID_ADVANTECH_PCI1601,
|
|
.subvendor = PCI_VENDOR_ID_ADVANTECH,
|
|
.subdevice = PCI_ANY_ID,
|
|
.setup = pci_advantech_setup,
|
|
},
|
|
{
|
|
.vendor = PCI_VENDOR_ID_ADVANTECH,
|
|
.device = PCI_DEVICE_ID_ADVANTECH_PCI1602,
|
|
.subvendor = PCI_VENDOR_ID_ADVANTECH,
|
|
.subdevice = PCI_ANY_ID,
|
|
.setup = pci_advantech_setup,
|
|
},
|
|
{
|
|
.vendor = PCI_VENDOR_ID_ADVANTECH,
|
|
.device = PCI_DEVICE_ID_ADVANTECH_PCI1603,
|
|
.subvendor = PCI_VENDOR_ID_ADVANTECH,
|
|
.subdevice = PCI_ANY_ID,
|
|
.setup = pci_advantech_setup,
|
|
},
|
|
{
|
|
.vendor = PCI_VENDOR_ID_ADVANTECH,
|
|
.device = PCI_DEVICE_ID_ADVANTECH_PCI1604,
|
|
.subvendor = PCI_VENDOR_ID_ADVANTECH,
|
|
.subdevice = PCI_ANY_ID,
|
|
.setup = pci_advantech_setup,
|
|
},
|
|
|
|
//yongjun add 2006/11/10
|
|
{
|
|
.vendor = PCI_VENDOR_ID_ADVANTECH,
|
|
.device = PCI_DEVICE_ID_ADVANTECH_UNO2176,
|
|
.subvendor = PCI_DEVICE_ID_ADVANTECH_UNO2X76_2176,
|
|
.subdevice = PCI_ANY_ID,
|
|
.setup = pci_advantech_setup,
|
|
},
|
|
//yongjun add end
|
|
//jinxin added to support PCIe952/PCIe954/PCIe958
|
|
{
|
|
.vendor = PCI_VENDOR_ID_ADVANTECH,
|
|
.device = PCI_DEVICE_ID_ADVANTECH_PCIE952,
|
|
.subvendor = PCI_VENDOR_ID_ADVANTECH,
|
|
.subdevice = PCI_DEVICE_ID_ADVANTECH_PCIE952,
|
|
.setup = pci_advantech_setup,
|
|
},
|
|
{
|
|
.vendor = PCI_VENDOR_ID_ADVANTECH,
|
|
.device = PCI_DEVICE_ID_ADVANTECH_PCIE954,
|
|
.subvendor = PCI_VENDOR_ID_ADVANTECH,
|
|
.subdevice = PCI_DEVICE_ID_ADVANTECH_PCIE954,
|
|
.setup = pci_advantech_setup,
|
|
},
|
|
{
|
|
.vendor = PCI_VENDOR_ID_ADVANTECH,
|
|
.device = PCI_DEVICE_ID_ADVANTECH_PCIE958,
|
|
.subvendor = PCI_VENDOR_ID_ADVANTECH,
|
|
.subdevice = PCI_DEVICE_ID_ADVANTECH_PCIE958,
|
|
.setup = pci_advantech_setup,
|
|
},
|
|
//james dai add 2007/5/27
|
|
{
|
|
.vendor = PCI_VENDOR_ID_ADVANTECH,
|
|
.device = PCI_DEVICE_ID_ADVANTECH_PCM3614P,
|
|
.subvendor = PCI_SUB_VENDOR_ID_ADVANTECH_PCM3614P,
|
|
.subdevice = PCI_ANY_ID,
|
|
.setup = pci_advantech_setup,
|
|
},
|
|
{
|
|
.vendor = PCI_VENDOR_ID_ADVANTECH,
|
|
.device = PCI_DEVICE_ID_ADVANTECH_PCM3618P,
|
|
.subvendor = PCI_SUB_VENDOR_ID_ADVANTECH_PCM3618P,
|
|
.subdevice = PCI_ANY_ID,
|
|
.setup = pci_advantech_setup,
|
|
},
|
|
{
|
|
.vendor = PCI_VENDOR_ID_ADVANTECH,
|
|
.device = PCI_DEVICE_ID_ADVANTECH_PCMF618P,
|
|
.subvendor = PCI_SUB_VENDOR_ID_ADVANTECH_PCM3618P,
|
|
.subdevice = PCI_ANY_ID,
|
|
.setup = pci_advantech_setup,
|
|
},
|
|
{
|
|
.vendor = PCI_VENDOR_ID_ADVANTECH,
|
|
.device = PCI_DEVICE_ID_ADVANTECH_PCM3641P,
|
|
.subvendor = PCI_SUB_VENDOR_ID_ADVANTECH_PCM3641P,
|
|
.subdevice = PCI_ANY_ID,
|
|
.setup = pci_advantech_setup,
|
|
},
|
|
{
|
|
.vendor = PCI_VENDOR_ID_ADVANTECH,
|
|
.device = PCI_DEVICE_ID_ADVANTECH_PCM3681P,
|
|
.subvendor = PCI_SUB_VENDOR_ID_ADVANTECH_PCM3681P,
|
|
.subdevice = PCI_ANY_ID,
|
|
.setup = pci_advantech_setup,
|
|
},
|
|
{
|
|
.vendor = PCI_VENDOR_ID_ADVANTECH,
|
|
.device = PCI_DEVICE_ID_ADVANTECH_PCMF681P,
|
|
.subvendor = PCI_SUB_VENDOR_ID_ADVANTECH_PCM3681P,
|
|
.subdevice = PCI_ANY_ID,
|
|
.setup = pci_advantech_setup,
|
|
},
|
|
//james dai add end
|
|
//james dai add to support UNO-1150 @2008/6/3
|
|
{
|
|
.vendor = PCI_VENDOR_ID_ADVANTECH,
|
|
.device = PCI_DEVICE_ID_ADVANTECH_UNO1150,
|
|
.subvendor = PCI_DEVICE_ID_ADVANTECH_UNO1150,
|
|
.subdevice = PCI_ANY_ID,
|
|
.setup = pci_advantech_setup,
|
|
},
|
|
//james dai add end
|
|
//james dai add to support UNO-1150 @2008/6/20
|
|
{
|
|
.vendor = PCI_VENDOR_ID_ADVANTECH,
|
|
.device = PCI_DEVICE_ID_ADVANTECH_MIC3621,
|
|
.subvendor = PCI_SUB_VENDOR_ID_ADVANTECH_MIC3621,
|
|
.subdevice = PCI_ANY_ID,
|
|
.setup = pci_advantech_setup,
|
|
},
|
|
//james dai add end
|
|
{
|
|
.vendor = PCI_VENDOR_ID_ADVANTECH,
|
|
.device = PCI_DEVICE_ID_ADVANTECH_A001,
|
|
.subvendor = PCI_ANY_ID,
|
|
.subdevice = PCI_ANY_ID,
|
|
.setup = pci_advantech_setup,
|
|
},
|
|
{
|
|
.vendor = PCI_VENDOR_ID_ADVANTECH,
|
|
.device = PCI_DEVICE_ID_ADVANTECH_A002,
|
|
.subvendor = PCI_ANY_ID,
|
|
.subdevice = PCI_ANY_ID,
|
|
.setup = pci_advantech_setup,
|
|
},
|
|
{
|
|
.vendor = PCI_VENDOR_ID_ADVANTECH,
|
|
.device = PCI_DEVICE_ID_ADVANTECH_A004,
|
|
.subvendor = PCI_ANY_ID,
|
|
.subdevice = PCI_ANY_ID,
|
|
.setup = pci_advantech_setup,
|
|
},
|
|
{
|
|
.vendor = PCI_VENDOR_ID_ADVANTECH,
|
|
.device = PCI_DEVICE_ID_ADVANTECH_A101,
|
|
.subvendor = PCI_ANY_ID,
|
|
.subdevice = PCI_ANY_ID,
|
|
.setup = pci_advantech_setup,
|
|
},
|
|
{
|
|
.vendor = PCI_VENDOR_ID_ADVANTECH,
|
|
.device = PCI_DEVICE_ID_ADVANTECH_A102,
|
|
.subvendor = PCI_ANY_ID,
|
|
.subdevice = PCI_ANY_ID,
|
|
.setup = pci_advantech_setup,
|
|
},
|
|
{
|
|
.vendor = PCI_VENDOR_ID_ADVANTECH,
|
|
.device = PCI_DEVICE_ID_ADVANTECH_A104,
|
|
.subvendor = PCI_ANY_ID,
|
|
.subdevice = PCI_ANY_ID,
|
|
.setup = pci_advantech_setup,
|
|
},
|
|
{
|
|
.vendor = PCI_VENDOR_ID_ADVANTECH,
|
|
.device = PCI_DEVICE_ID_ADVANTECH_F001,
|
|
.subvendor = PCI_ANY_ID,
|
|
.subdevice = PCI_ANY_ID,
|
|
.setup = pci_advantech_setup,
|
|
},
|
|
{
|
|
.vendor = PCI_VENDOR_ID_ADVANTECH,
|
|
.device = PCI_DEVICE_ID_ADVANTECH_F002,
|
|
.subvendor = PCI_ANY_ID,
|
|
.subdevice = PCI_ANY_ID,
|
|
.setup = pci_advantech_setup,
|
|
},
|
|
{
|
|
.vendor = PCI_VENDOR_ID_ADVANTECH,
|
|
.device = PCI_DEVICE_ID_ADVANTECH_F004,
|
|
.subvendor = PCI_ANY_ID,
|
|
.subdevice = PCI_ANY_ID,
|
|
.setup = pci_advantech_setup,
|
|
},
|
|
{
|
|
.vendor = PCI_VENDOR_ID_ADVANTECH,
|
|
.device = PCI_DEVICE_ID_ADVANTECH_F101,
|
|
.subvendor = PCI_ANY_ID,
|
|
.subdevice = PCI_ANY_ID,
|
|
.setup = pci_advantech_setup,
|
|
},
|
|
{
|
|
.vendor = PCI_VENDOR_ID_ADVANTECH,
|
|
.device = PCI_DEVICE_ID_ADVANTECH_F102,
|
|
.subvendor = PCI_ANY_ID,
|
|
.subdevice = PCI_ANY_ID,
|
|
.setup = pci_advantech_setup,
|
|
},
|
|
{
|
|
.vendor = PCI_VENDOR_ID_ADVANTECH,
|
|
.device = PCI_DEVICE_ID_ADVANTECH_F104,
|
|
.subvendor = PCI_ANY_ID,
|
|
.subdevice = PCI_ANY_ID,
|
|
.setup = pci_advantech_setup,
|
|
},
|
|
};
|
|
|
|
static inline int quirk_id_matches(u32 quirk_id, u32 dev_id)
|
|
{
|
|
return quirk_id == PCI_ANY_ID || quirk_id == dev_id;
|
|
}
|
|
|
|
static struct pci_serial_quirk *find_quirk(struct pci_dev *dev)
|
|
{
|
|
struct pci_serial_quirk *quirk;
|
|
|
|
for (quirk = pci_serial_quirks; ; quirk++)
|
|
if (quirk_id_matches(quirk->vendor, dev->vendor) &&
|
|
quirk_id_matches(quirk->device, dev->device) &&
|
|
quirk_id_matches(quirk->subvendor, dev->subsystem_vendor) &&
|
|
quirk_id_matches(quirk->subdevice, dev->subsystem_device))
|
|
break;
|
|
return quirk;
|
|
}
|
|
|
|
static _INLINE_ int
|
|
get_pci_irq(struct pci_dev *dev, struct pci_board *board, int idx)
|
|
{
|
|
if (board->flags & FL_NOIRQ)
|
|
return 0;
|
|
else
|
|
return dev->irq;
|
|
}
|
|
|
|
/*
|
|
* This is the configuration table for all of the PCI serial boards
|
|
* which we support. It is directly indexed by the pci_board_num_t enum
|
|
* value, which is encoded in the pci_device_id PCI probe table's
|
|
* driver_data member.
|
|
*
|
|
* The makeup of these names are:
|
|
* pbn_bn{_bt}_n_baud
|
|
*
|
|
* bn = PCI BAR number
|
|
* bt = Index using PCI BARs
|
|
* n = number of serial ports
|
|
* d = support dma or not
|
|
* baud = baud rate
|
|
*
|
|
* Please note: in theory if n = 1, _bt infix should make no difference.
|
|
* ie, pbn_b0_1_115200 is the same as pbn_b0_bt_1_115200
|
|
*/
|
|
enum pci_board_num_t {
|
|
pbn_default = 0,
|
|
|
|
pbn_b0_1_115200,
|
|
pbn_b0_2_115200,
|
|
pbn_b0_4_115200,
|
|
pbn_b0_5_115200,
|
|
|
|
pbn_b0_1_921600,
|
|
pbn_b0_2_921600,
|
|
pbn_b0_4_921600,
|
|
|
|
pbn_b0_2_d_921600,
|
|
pbn_b0_4_d_921600,
|
|
pbn_b0_8_d_921600,
|
|
|
|
pbn_b0_bt_1_115200,
|
|
pbn_b0_bt_2_115200,
|
|
pbn_b0_bt_8_115200,
|
|
|
|
pbn_b0_bt_1_460800,
|
|
pbn_b0_bt_2_460800,
|
|
pbn_b0_bt_4_460800,
|
|
|
|
pbn_b0_bt_1_921600,
|
|
pbn_b0_bt_2_921600,
|
|
pbn_b0_bt_4_921600,
|
|
pbn_b0_bt_8_921600,
|
|
|
|
pbn_b1_1_115200,
|
|
pbn_b1_2_115200,
|
|
pbn_b1_4_115200,
|
|
pbn_b1_8_115200,
|
|
|
|
pbn_b1_1_921600,
|
|
pbn_b1_2_921600,
|
|
pbn_b1_4_921600,
|
|
pbn_b1_8_921600,
|
|
|
|
pbn_b1_bt_2_921600,
|
|
|
|
pbn_b1_2_1382400,
|
|
pbn_b1_4_1382400,
|
|
pbn_b1_8_1382400,
|
|
|
|
pbn_b2_1_115200,
|
|
pbn_b2_8_115200,
|
|
|
|
pbn_b2_1_460800,
|
|
pbn_b2_4_460800,
|
|
pbn_b2_8_460800,
|
|
pbn_b2_16_460800,
|
|
|
|
pbn_b2_1_921600,
|
|
pbn_b2_4_921600,
|
|
pbn_b2_8_921600,
|
|
|
|
pbn_b2_bt_1_115200,
|
|
pbn_b2_bt_2_115200,
|
|
pbn_b2_bt_4_115200,
|
|
|
|
pbn_b2_bt_2_921600,
|
|
pbn_b2_bt_4_921600,
|
|
|
|
pbn_b3_4_115200,
|
|
pbn_b3_8_115200,
|
|
};
|
|
|
|
static struct pci_board pci_boards[] __devinitdata = {
|
|
[pbn_default] = {
|
|
.flags = FL_BASE0,
|
|
.num_ports = 1,
|
|
.base_baud = 115200,
|
|
.uart_offset = 8,
|
|
},
|
|
[pbn_b0_1_115200] = {
|
|
.flags = FL_BASE0,
|
|
.num_ports = 1,
|
|
.base_baud = 115200,
|
|
.uart_offset = 8,
|
|
},
|
|
[pbn_b0_2_115200] = {
|
|
.flags = FL_BASE0,
|
|
.num_ports = 2,
|
|
.base_baud = 115200,
|
|
.uart_offset = 8,
|
|
},
|
|
[pbn_b0_4_115200] = {
|
|
.flags = FL_BASE0,
|
|
.num_ports = 4,
|
|
.base_baud = 115200,
|
|
.uart_offset = 8,
|
|
},
|
|
[pbn_b0_5_115200] = {
|
|
.flags = FL_BASE0,
|
|
.num_ports = 5,
|
|
.base_baud = 115200,
|
|
.uart_offset = 8,
|
|
},
|
|
|
|
[pbn_b0_1_921600] = {
|
|
.flags = FL_BASE0,
|
|
.num_ports = 1,
|
|
.base_baud = 921600,
|
|
.uart_offset = 8,
|
|
},
|
|
[pbn_b0_2_921600] = {
|
|
.flags = FL_BASE0,
|
|
.num_ports = 2,
|
|
.base_baud = 921600,
|
|
.uart_offset = 8,
|
|
},
|
|
[pbn_b0_4_921600] = {
|
|
.flags = FL_BASE0,
|
|
.num_ports = 4,
|
|
.base_baud = 921600,
|
|
.uart_offset = 8,
|
|
},
|
|
|
|
[pbn_b0_2_d_921600] = {
|
|
.flags = FL_BASE0,
|
|
.num_ports = 2,
|
|
.base_baud = 921600,
|
|
.uart_offset = 0x200,
|
|
.first_offset = 0x1000,
|
|
},
|
|
[pbn_b0_4_d_921600] = {
|
|
.flags = FL_BASE0,
|
|
.num_ports = 4,
|
|
.base_baud = 921600,
|
|
.uart_offset = 0x200,
|
|
.first_offset = 0x1000,
|
|
},
|
|
|
|
[pbn_b0_8_d_921600] = {
|
|
.flags = FL_BASE0,
|
|
.num_ports = 8,
|
|
.base_baud = 921600,
|
|
.uart_offset = 0x200,
|
|
.first_offset = 0x1000,
|
|
},
|
|
[pbn_b0_bt_1_115200] = {
|
|
.flags = FL_BASE0|FL_BASE_BARS,
|
|
.num_ports = 1,
|
|
.base_baud = 115200,
|
|
.uart_offset = 8,
|
|
},
|
|
[pbn_b0_bt_2_115200] = {
|
|
.flags = FL_BASE0|FL_BASE_BARS,
|
|
.num_ports = 2,
|
|
.base_baud = 115200,
|
|
.uart_offset = 8,
|
|
},
|
|
[pbn_b0_bt_8_115200] = {
|
|
.flags = FL_BASE0|FL_BASE_BARS,
|
|
.num_ports = 8,
|
|
.base_baud = 115200,
|
|
.uart_offset = 8,
|
|
},
|
|
|
|
[pbn_b0_bt_1_460800] = {
|
|
.flags = FL_BASE0|FL_BASE_BARS,
|
|
.num_ports = 1,
|
|
.base_baud = 460800,
|
|
.uart_offset = 8,
|
|
},
|
|
[pbn_b0_bt_2_460800] = {
|
|
.flags = FL_BASE0|FL_BASE_BARS,
|
|
.num_ports = 2,
|
|
.base_baud = 460800,
|
|
.uart_offset = 8,
|
|
},
|
|
[pbn_b0_bt_4_460800] = {
|
|
.flags = FL_BASE0|FL_BASE_BARS,
|
|
.num_ports = 4,
|
|
.base_baud = 460800,
|
|
.uart_offset = 8,
|
|
},
|
|
|
|
[pbn_b0_bt_1_921600] = {
|
|
.flags = FL_BASE0|FL_BASE_BARS,
|
|
.num_ports = 1,
|
|
.base_baud = 921600,
|
|
.uart_offset = 8,
|
|
},
|
|
[pbn_b0_bt_2_921600] = {
|
|
.flags = FL_BASE0|FL_BASE_BARS,
|
|
.num_ports = 2,
|
|
.base_baud = 921600,
|
|
.uart_offset = 8,
|
|
},
|
|
[pbn_b0_bt_4_921600] = {
|
|
.flags = FL_BASE0|FL_BASE_BARS,
|
|
.num_ports = 4,
|
|
.base_baud = 921600,
|
|
.uart_offset = 8,
|
|
},
|
|
[pbn_b0_bt_8_921600] = {
|
|
.flags = FL_BASE0|FL_BASE_BARS,
|
|
.num_ports = 8,
|
|
.base_baud = 921600,
|
|
.uart_offset = 8,
|
|
},
|
|
|
|
[pbn_b1_1_115200] = {
|
|
.flags = FL_BASE1,
|
|
.num_ports = 1,
|
|
.base_baud = 115200,
|
|
.uart_offset = 8,
|
|
},
|
|
[pbn_b1_2_115200] = {
|
|
.flags = FL_BASE1,
|
|
.num_ports = 2,
|
|
.base_baud = 115200,
|
|
.uart_offset = 8,
|
|
},
|
|
[pbn_b1_4_115200] = {
|
|
.flags = FL_BASE1,
|
|
.num_ports = 4,
|
|
.base_baud = 115200,
|
|
.uart_offset = 8,
|
|
},
|
|
[pbn_b1_8_115200] = {
|
|
.flags = FL_BASE1,
|
|
.num_ports = 8,
|
|
.base_baud = 115200,
|
|
.uart_offset = 8,
|
|
},
|
|
|
|
[pbn_b1_1_921600] = {
|
|
.flags = FL_BASE1,
|
|
.num_ports = 1,
|
|
.base_baud = 921600,
|
|
.uart_offset = 8,
|
|
},
|
|
[pbn_b1_2_921600] = {
|
|
.flags = FL_BASE1,
|
|
.num_ports = 2,
|
|
.base_baud = 921600,
|
|
.uart_offset = 8,
|
|
},
|
|
[pbn_b1_4_921600] = {
|
|
.flags = FL_BASE1,
|
|
.num_ports = 4,
|
|
.base_baud = 921600,
|
|
.uart_offset = 8,
|
|
},
|
|
[pbn_b1_8_921600] = {
|
|
.flags = FL_BASE1,
|
|
.num_ports = 8,
|
|
.base_baud = 921600,
|
|
.uart_offset = 8,
|
|
},
|
|
|
|
[pbn_b1_bt_2_921600] = {
|
|
.flags = FL_BASE1|FL_BASE_BARS,
|
|
.num_ports = 2,
|
|
.base_baud = 921600,
|
|
.uart_offset = 8,
|
|
},
|
|
|
|
[pbn_b1_2_1382400] = {
|
|
.flags = FL_BASE1,
|
|
.num_ports = 2,
|
|
.base_baud = 1382400,
|
|
.uart_offset = 8,
|
|
},
|
|
[pbn_b1_4_1382400] = {
|
|
.flags = FL_BASE1,
|
|
.num_ports = 4,
|
|
.base_baud = 1382400,
|
|
.uart_offset = 8,
|
|
},
|
|
[pbn_b1_8_1382400] = {
|
|
.flags = FL_BASE1,
|
|
.num_ports = 8,
|
|
.base_baud = 1382400,
|
|
.uart_offset = 8,
|
|
},
|
|
|
|
[pbn_b2_1_115200] = {
|
|
.flags = FL_BASE2,
|
|
.num_ports = 1,
|
|
.base_baud = 115200,
|
|
.uart_offset = 8,
|
|
},
|
|
[pbn_b2_8_115200] = {
|
|
.flags = FL_BASE2,
|
|
.num_ports = 8,
|
|
.base_baud = 115200,
|
|
.uart_offset = 8,
|
|
},
|
|
|
|
[pbn_b2_1_460800] = {
|
|
.flags = FL_BASE2,
|
|
.num_ports = 1,
|
|
.base_baud = 460800,
|
|
.uart_offset = 8,
|
|
},
|
|
[pbn_b2_4_460800] = {
|
|
.flags = FL_BASE2,
|
|
.num_ports = 4,
|
|
.base_baud = 460800,
|
|
.uart_offset = 8,
|
|
},
|
|
[pbn_b2_8_460800] = {
|
|
.flags = FL_BASE2,
|
|
.num_ports = 8,
|
|
.base_baud = 460800,
|
|
.uart_offset = 8,
|
|
},
|
|
[pbn_b2_16_460800] = {
|
|
.flags = FL_BASE2,
|
|
.num_ports = 16,
|
|
.base_baud = 460800,
|
|
.uart_offset = 8,
|
|
},
|
|
|
|
[pbn_b2_1_921600] = {
|
|
.flags = FL_BASE2,
|
|
.num_ports = 1,
|
|
.base_baud = 921600,
|
|
.uart_offset = 8,
|
|
},
|
|
[pbn_b2_4_921600] = {
|
|
.flags = FL_BASE2,
|
|
.num_ports = 4,
|
|
.base_baud = 921600,
|
|
.uart_offset = 8,
|
|
},
|
|
[pbn_b2_8_921600] = {
|
|
.flags = FL_BASE2,
|
|
.num_ports = 8,
|
|
.base_baud = 921600,
|
|
.uart_offset = 8,
|
|
},
|
|
|
|
[pbn_b2_bt_1_115200] = {
|
|
.flags = FL_BASE2|FL_BASE_BARS,
|
|
.num_ports = 1,
|
|
.base_baud = 115200,
|
|
.uart_offset = 8,
|
|
},
|
|
[pbn_b2_bt_2_115200] = {
|
|
.flags = FL_BASE2|FL_BASE_BARS,
|
|
.num_ports = 2,
|
|
.base_baud = 115200,
|
|
.uart_offset = 8,
|
|
},
|
|
[pbn_b2_bt_4_115200] = {
|
|
.flags = FL_BASE2|FL_BASE_BARS,
|
|
.num_ports = 4,
|
|
.base_baud = 115200,
|
|
.uart_offset = 8,
|
|
},
|
|
|
|
[pbn_b2_bt_2_921600] = {
|
|
.flags = FL_BASE2|FL_BASE_BARS,
|
|
.num_ports = 2,
|
|
.base_baud = 921600,
|
|
.uart_offset = 8,
|
|
},
|
|
[pbn_b2_bt_4_921600] = {
|
|
.flags = FL_BASE2|FL_BASE_BARS,
|
|
.num_ports = 4,
|
|
.base_baud = 921600,
|
|
.uart_offset = 8,
|
|
},
|
|
|
|
[pbn_b3_4_115200] = {
|
|
.flags = FL_BASE3,
|
|
.num_ports = 4,
|
|
.base_baud = 115200,
|
|
.uart_offset = 8,
|
|
},
|
|
[pbn_b3_8_115200] = {
|
|
.flags = FL_BASE3,
|
|
.num_ports = 8,
|
|
.base_baud = 115200,
|
|
.uart_offset = 8,
|
|
},
|
|
};
|
|
|
|
/*
|
|
* Given a complete unknown PCI device, try to use some heuristics to
|
|
* guess what the configuration might be, based on the pitiful PCI
|
|
* serial specs. Returns 0 on success, 1 on failure.
|
|
*/
|
|
static int __devinit
|
|
serial_pci_guess_board(struct pci_dev *dev, struct pci_board *board)
|
|
{
|
|
int num_iomem, num_port, first_port = -1, i;
|
|
|
|
/*
|
|
* If it is not a communications device or the programming
|
|
* interface is greater than 6, give up.
|
|
*
|
|
* (Should we try to make guesses for multiport serial devices
|
|
* later?)
|
|
*/
|
|
if ((((dev->class >> 8) != PCI_CLASS_COMMUNICATION_SERIAL) &&
|
|
((dev->class >> 8) != PCI_CLASS_COMMUNICATION_MODEM)) ||
|
|
(dev->class & 0xff) > 6)
|
|
return -ENODEV;
|
|
|
|
num_iomem = num_port = 0;
|
|
for (i = 0; i < PCI_NUM_BAR_RESOURCES; i++) {
|
|
if (pci_resource_flags(dev, i) & IORESOURCE_IO) {
|
|
num_port++;
|
|
if (first_port == -1)
|
|
first_port = i;
|
|
}
|
|
if (pci_resource_flags(dev, i) & IORESOURCE_MEM)
|
|
num_iomem++;
|
|
}
|
|
|
|
/*
|
|
* If there is 1 or 0 iomem regions, and exactly one port,
|
|
* use it. We guess the number of ports based on the IO
|
|
* region size.
|
|
*/
|
|
if (num_iomem <= 1 && num_port == 1) {
|
|
board->flags = first_port;
|
|
board->num_ports = pci_resource_len(dev, first_port) / 8;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Now guess if we've got a board which indexes by BARs.
|
|
* Each IO BAR should be 8 bytes, and they should follow
|
|
* consecutively.
|
|
*/
|
|
first_port = -1;
|
|
num_port = 0;
|
|
for (i = 0; i < PCI_NUM_BAR_RESOURCES; i++) {
|
|
if (pci_resource_flags(dev, i) & IORESOURCE_IO &&
|
|
pci_resource_len(dev, i) == 8 &&
|
|
(first_port == -1 || (first_port + num_port) == i)) {
|
|
num_port++;
|
|
if (first_port == -1)
|
|
first_port = i;
|
|
}
|
|
}
|
|
|
|
if (num_port > 1) {
|
|
board->flags = first_port | FL_BASE_BARS;
|
|
board->num_ports = num_port;
|
|
return 0;
|
|
}
|
|
|
|
return -ENODEV;
|
|
}
|
|
|
|
static inline int
|
|
serial_pci_matches(struct pci_board *board, struct pci_board *guessed)
|
|
{
|
|
return
|
|
board->num_ports == guessed->num_ports &&
|
|
board->base_baud == guessed->base_baud &&
|
|
board->uart_offset == guessed->uart_offset &&
|
|
board->reg_shift == guessed->reg_shift &&
|
|
board->first_offset == guessed->first_offset;
|
|
}
|
|
|
|
/*
|
|
* Probe one serial board. Unfortunately, there is no rhyme nor reason
|
|
* to the arrangement of serial ports on a PCI card.
|
|
*/
|
|
static int __devinit
|
|
pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent)
|
|
{
|
|
struct serial_private *priv;
|
|
struct pci_board *board, tmp;
|
|
struct pci_serial_quirk *quirk;
|
|
struct serial_struct serial_req;
|
|
int base_baud, rc, nr_ports, i;
|
|
|
|
|
|
if (ent->driver_data >= ARRAY_SIZE(pci_boards)) {
|
|
printk(KERN_ERR "pci_init_one: invalid driver_data: %ld\n",
|
|
ent->driver_data);
|
|
return -EINVAL;
|
|
}
|
|
|
|
board = &pci_boards[ent->driver_data];
|
|
|
|
rc = pci_enable_device(dev);
|
|
if (rc)
|
|
return rc;
|
|
|
|
if (ent->driver_data == pbn_default) {
|
|
/*
|
|
* Use a copy of the pci_board entry for this;
|
|
* avoid changing entries in the table.
|
|
*/
|
|
memcpy(&tmp, board, sizeof(struct pci_board));
|
|
board = &tmp;
|
|
|
|
/*
|
|
* We matched one of our class entries. Try to
|
|
* determine the parameters of this board.
|
|
*/
|
|
rc = serial_pci_guess_board(dev, board);
|
|
if (rc)
|
|
goto disable;
|
|
} else {
|
|
/*
|
|
* We matched an explicit entry. If we are able to
|
|
* detect this boards settings with our heuristic,
|
|
* then we no longer need this entry.
|
|
*/
|
|
memcpy(&tmp, &pci_boards[pbn_default], sizeof(struct pci_board));
|
|
rc = serial_pci_guess_board(dev, &tmp);
|
|
if (rc == 0 && serial_pci_matches(board, &tmp))
|
|
moan_device("Redundant entry in serial pci_table.",
|
|
dev);
|
|
}
|
|
|
|
nr_ports = board->num_ports;
|
|
|
|
/*
|
|
* Find an init and setup quirks.
|
|
*/
|
|
quirk = find_quirk(dev);
|
|
|
|
/*
|
|
* Run the new-style initialization function.
|
|
* The initialization function returns:
|
|
* <0 - error
|
|
* 0 - use board->num_ports
|
|
* >0 - number of ports
|
|
*/
|
|
if (quirk->init) {
|
|
rc = quirk->init(dev);
|
|
if (rc < 0)
|
|
goto disable;
|
|
if (rc)
|
|
nr_ports = rc;
|
|
}
|
|
|
|
priv = kmalloc(sizeof(struct serial_private) +
|
|
sizeof(unsigned int) * nr_ports,
|
|
GFP_KERNEL);
|
|
if (!priv) {
|
|
rc = -ENOMEM;
|
|
goto deinit;
|
|
}
|
|
|
|
memset(priv, 0, sizeof(struct serial_private) +
|
|
sizeof(unsigned int) * nr_ports);
|
|
|
|
priv->quirk = quirk;
|
|
pci_set_drvdata(dev, priv);
|
|
|
|
base_baud = board->base_baud;
|
|
if (!base_baud) {
|
|
moan_device("Board entry does not specify baud rate.", dev);
|
|
base_baud = BASE_BAUD;
|
|
}
|
|
for (i = 0; i < nr_ports; i++) {
|
|
memset(&serial_req, 0, sizeof(serial_req));
|
|
//lipeng modify at 06/08/2006
|
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 15)
|
|
serial_req.flags = UPF_SKIP_TEST | UPF_AUTOPROBE |
|
|
//UPF_RESOURCES | UPF_SHARE_IRQ;
|
|
UPF_SHARE_IRQ;
|
|
#else
|
|
serial_req.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
|
|
#endif
|
|
//lipeng modify end
|
|
serial_req.baud_base = base_baud;
|
|
serial_req.irq = get_pci_irq(dev, board, i);
|
|
if (quirk->setup(dev, board, &serial_req, i))
|
|
break;
|
|
#ifdef SERIAL_DEBUG_PCI
|
|
printk("Setup PCI port: port %x, irq %d, type %d\n",
|
|
serial_req.port, serial_req.irq, serial_req.io_type);
|
|
#endif
|
|
|
|
priv->line[i] = adv_register_serial(&serial_req);
|
|
if (priv->line[i] < 0) {
|
|
printk(KERN_WARNING "Couldn't register serial port %s: %d\n", pci_name(dev), priv->line[i]);
|
|
break;
|
|
}
|
|
}
|
|
|
|
priv->nr = i;
|
|
|
|
return 0;
|
|
|
|
deinit:
|
|
if (quirk->exit)
|
|
quirk->exit(dev);
|
|
disable:
|
|
pci_disable_device(dev);
|
|
return rc;
|
|
}
|
|
|
|
static void __devexit pciserial_remove_one(struct pci_dev *dev)
|
|
{
|
|
struct serial_private *priv = pci_get_drvdata(dev);
|
|
|
|
pci_set_drvdata(dev, NULL);
|
|
|
|
if (priv) {
|
|
struct pci_serial_quirk *quirk;
|
|
int i;
|
|
|
|
for (i = 0; i < PCI_NUM_BAR_RESOURCES; i++) {
|
|
if (priv->remapped_bar[i])
|
|
iounmap(priv->remapped_bar[i]);
|
|
priv->remapped_bar[i] = NULL;
|
|
}
|
|
|
|
for (i = 0; i < priv->nr; i++)
|
|
adv_unregister_serial(priv->line[i]);
|
|
|
|
for (i = 0; i < PCI_NUM_BAR_RESOURCES; i++) {
|
|
if (priv->remapped_bar[i])
|
|
iounmap(priv->remapped_bar[i]);
|
|
priv->remapped_bar[i] = NULL;
|
|
}
|
|
|
|
/*
|
|
* Find the exit quirks.
|
|
*/
|
|
quirk = find_quirk(dev);
|
|
if (quirk->exit)
|
|
quirk->exit(dev);
|
|
|
|
pci_disable_device(dev);
|
|
|
|
kfree(priv);
|
|
}
|
|
}
|
|
//lipeng modify at 06/08/2006
|
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 15)
|
|
static int pciserial_suspend_one(struct pci_dev *dev, u32 state)
|
|
{
|
|
struct serial_private *priv = pci_get_drvdata(dev);
|
|
|
|
if (priv) {
|
|
int i;
|
|
|
|
for (i = 0; i < priv->nr; i++)
|
|
adv_serial8250_suspend_port(priv->line[i]);
|
|
}
|
|
return 0;
|
|
}
|
|
#else
|
|
static int pciserial_suspend_one(struct pci_dev *dev, pm_message_t state)
|
|
{
|
|
struct serial_private *priv = pci_get_drvdata(dev);
|
|
|
|
if (priv) {
|
|
int i;
|
|
|
|
for (i = 0; i < priv->nr; i++)
|
|
adv_serial8250_suspend_port(priv->line[i]);
|
|
}
|
|
return 0;
|
|
}
|
|
#endif
|
|
//lipeng modify end
|
|
static int pciserial_resume_one(struct pci_dev *dev)
|
|
{
|
|
struct serial_private *priv = pci_get_drvdata(dev);
|
|
|
|
if (priv) {
|
|
int i;
|
|
|
|
/*
|
|
* Ensure that the board is correctly configured.
|
|
*/
|
|
if (priv->quirk->init)
|
|
priv->quirk->init(dev);
|
|
|
|
for (i = 0; i < priv->nr; i++)
|
|
adv_serial8250_resume_port(priv->line[i]);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static struct pci_device_id adv_serial_pci_tbl[] = {
|
|
/*
|
|
* Advantech IAG PCI-954/16C950 cards
|
|
*/
|
|
{ PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCI1600,
|
|
PCI_DEVICE_ID_ADVANTECH_PCI1600_1601, PCI_ANY_ID, 0, 0,
|
|
pbn_b0_2_921600 },
|
|
{ PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCI1600,
|
|
PCI_DEVICE_ID_ADVANTECH_PCI1600_1602, PCI_ANY_ID, 0, 0,
|
|
pbn_b0_2_921600 },
|
|
{ PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCI1600,
|
|
PCI_DEVICE_ID_ADVANTECH_PCI1600_1610, PCI_ANY_ID, 0, 0,
|
|
pbn_b0_4_921600 },
|
|
{ PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCI1600,
|
|
PCI_DEVICE_ID_ADVANTECH_PCI1600_1612, PCI_ANY_ID, 0, 0,
|
|
pbn_b0_4_921600 },
|
|
{ PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCI1600,
|
|
PCI_DEVICE_ID_ADVANTECH_PCI1600_1620, PCI_ANY_ID, 0, 0,
|
|
pbn_b0_4_921600 },
|
|
{ PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCI16ff,
|
|
PCI_DEVICE_ID_ADVANTECH_PCI1600_1620, PCI_ANY_ID, 0, 0,
|
|
pbn_b0_4_921600 },
|
|
{ PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCI1600,
|
|
PCI_DEVICE_ID_ADVANTECH_PCI1600_1622, PCI_ANY_ID, 0, 0,
|
|
pbn_b0_4_921600 },
|
|
{ PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCI16ff,
|
|
PCI_DEVICE_ID_ADVANTECH_PCI1600_1622, PCI_ANY_ID, 0, 0,
|
|
pbn_b0_4_921600 },
|
|
{ PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_UNO2050,
|
|
PCI_DEVICE_ID_ADVANTECH_UNO2050, PCI_ANY_ID, 0, 0,
|
|
pbn_b0_2_921600 },
|
|
{ PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_UNOB2201,
|
|
PCI_DEVICE_ID_ADVANTECH_UNOBX201_2201, PCI_ANY_ID, 0, 0,
|
|
pbn_b0_4_921600 },
|
|
{ PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_UNOBF201,
|
|
PCI_DEVICE_ID_ADVANTECH_UNOBX201_2201, PCI_ANY_ID, 0, 0,
|
|
pbn_b0_4_921600 },
|
|
{ PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_MIC3612,
|
|
PCI_DEVICE_ID_ADVANTECH_MIC3612, PCI_ANY_ID, 0, 0,
|
|
pbn_b2_4_921600 },
|
|
{ PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_MIC3620,
|
|
PCI_DEVICE_ID_ADVANTECH_MIC3620, PCI_ANY_ID, 0, 0,
|
|
pbn_b2_8_921600 },
|
|
{ PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_MIC3611,
|
|
PCI_DEVICE_ID_ADVANTECH_MIC3611, PCI_ANY_ID, 0, 0,
|
|
pbn_b2_4_921600 },
|
|
{ PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCI1601,
|
|
PCI_VENDOR_ID_ADVANTECH, PCI_ANY_ID, 0, 0,
|
|
pbn_b0_bt_2_921600 },
|
|
{ PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCI1602,
|
|
PCI_VENDOR_ID_ADVANTECH, PCI_ANY_ID, 0, 0,
|
|
pbn_b0_bt_2_921600 },
|
|
{ PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCI1603,
|
|
PCI_VENDOR_ID_ADVANTECH, PCI_ANY_ID, 0, 0,
|
|
pbn_b0_bt_2_921600 },
|
|
{ PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCI1604,
|
|
PCI_VENDOR_ID_ADVANTECH, PCI_ANY_ID, 0, 0,
|
|
pbn_b0_bt_2_921600 },
|
|
//yongjun add
|
|
{ PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_UNO2176,
|
|
PCI_DEVICE_ID_ADVANTECH_UNO2X76_2176, PCI_ANY_ID, 0, 0,
|
|
pbn_b0_4_921600 },
|
|
//yongjun add end
|
|
//jinxin added to support PCIe952/PCIe954/PCIe958
|
|
{ PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCIE952,
|
|
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
|
|
pbn_b0_2_d_921600 },
|
|
{ PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCIE954,
|
|
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
|
|
pbn_b0_4_d_921600 },
|
|
{ PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCIE958,
|
|
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
|
|
pbn_b0_8_d_921600 },
|
|
//james dai add
|
|
//PCM-3614P 4 PORTS RS232/422/485
|
|
{ PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCM3614P,
|
|
PCI_SUB_VENDOR_ID_ADVANTECH_PCM3614P, PCI_ANY_ID, 0, 0,
|
|
pbn_b0_4_921600 },
|
|
//PCM-3618P 8 PORTS RS232/422/485
|
|
{ PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCM3618P,
|
|
PCI_SUB_VENDOR_ID_ADVANTECH_PCM3618P, PCI_ANY_ID, 0, 0,
|
|
pbn_b0_4_921600 },
|
|
{ PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCMF618P,
|
|
PCI_SUB_VENDOR_ID_ADVANTECH_PCM3618P, PCI_ANY_ID, 0, 0,
|
|
pbn_b0_4_921600 },
|
|
//PCM-3641P 4 PORTS RS232
|
|
{ PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCM3641P,
|
|
PCI_SUB_VENDOR_ID_ADVANTECH_PCM3641P, PCI_ANY_ID, 0, 0,
|
|
pbn_b0_4_921600 },
|
|
//PCM-3681P 8 PORTS RS232
|
|
{ PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCM3681P,
|
|
PCI_SUB_VENDOR_ID_ADVANTECH_PCM3681P, PCI_ANY_ID, 0, 0,
|
|
pbn_b0_4_921600},
|
|
{ PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCMF681P,
|
|
PCI_SUB_VENDOR_ID_ADVANTECH_PCM3681P, PCI_ANY_ID, 0, 0,
|
|
pbn_b0_4_921600 },
|
|
//james dai add end
|
|
//james dai add to support UNO-1150
|
|
{ PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_UNO1150,
|
|
PCI_DEVICE_ID_ADVANTECH_UNO1150, PCI_ANY_ID, 0, 0,
|
|
pbn_b0_bt_2_921600 },
|
|
//james dai add end
|
|
//james dai add to support MIC-3621
|
|
{ PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_MIC3621,
|
|
PCI_SUB_VENDOR_ID_ADVANTECH_MIC3621, PCI_ANY_ID, 0, 0,
|
|
pbn_b2_8_921600 },
|
|
//james dai add end
|
|
{ PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_A001,
|
|
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
|
|
pbn_b0_1_921600 },
|
|
{ PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_A002,
|
|
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
|
|
pbn_b0_2_921600 },
|
|
{ PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_A004,
|
|
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
|
|
pbn_b0_4_921600 },
|
|
{ PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_A101,
|
|
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
|
|
pbn_b0_bt_1_921600 },
|
|
{ PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_A102,
|
|
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
|
|
pbn_b0_bt_2_921600 },
|
|
{ PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_A104,
|
|
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
|
|
pbn_b0_bt_4_921600 },
|
|
{ PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_F001,
|
|
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
|
|
pbn_b0_1_921600 },
|
|
{ PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_F002,
|
|
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
|
|
pbn_b0_2_921600 },
|
|
{ PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_F004,
|
|
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
|
|
pbn_b0_4_921600 },
|
|
{ PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_F101,
|
|
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
|
|
pbn_b0_bt_1_921600 },
|
|
{ PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_F102,
|
|
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
|
|
pbn_b0_bt_2_921600 },
|
|
{ PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_F104,
|
|
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
|
|
pbn_b0_bt_4_921600 },
|
|
{ 0, }
|
|
};
|
|
|
|
static struct pci_driver serial_pci_driver = {
|
|
.name = "advserial",
|
|
.probe = pciserial_init_one,
|
|
.remove = __devexit_p(pciserial_remove_one),
|
|
.suspend = pciserial_suspend_one,
|
|
.resume = pciserial_resume_one,
|
|
.id_table = adv_serial_pci_tbl,
|
|
};
|
|
|
|
int adv_serial8250_init(void);
|
|
void adv_serial8250_exit(void);
|
|
static int __init adv_serial8250_pci_init(void)
|
|
{
|
|
printk("\n");
|
|
printk("==========================================================="
|
|
"====\n");
|
|
printk("Advantech PCI-954/952/16C950 Device Drivers. V%s [%s]\n",
|
|
ADVANTECH_16C950_VER, ADVANTECH_16C950_DATE);
|
|
printk("Supports: RS232/422/485 auto detection and setting\n");
|
|
printk("Devices: UNO: UNO2050 [COM3/COM4]\n");
|
|
printk(" UNO2059 [COM1~COM4]\n");
|
|
printk(" UNOB-2201CB [COM1~COM8]\n");
|
|
printk(" UNOB-2176 [COM1~COM4]\n");
|
|
printk(" UNO-1150 [COM2/COM3]\n");
|
|
printk(" UNO-2679 [COM3~COM6]\n");
|
|
printk(" UNO-4672 [COM3~COM10]\n");
|
|
printk(" ICOM: PCI-1601, PCI-1602\n"
|
|
" PCI-1603, PCI-1604\n"
|
|
" PCI-1610, PCI-1612\n"
|
|
" PCI-1620, PCI-1622\n");
|
|
printk(" MIC: MIC-3611, MIC-3612\n");
|
|
printk(" MIC-3620, MIC-3621\n");
|
|
printk(" PCM: PCM-3614P/I, PCM-3641P/I\n");
|
|
printk(" PCM-3618P/I, PCM-3681P/I\n");
|
|
printk(" General: A001, A002, A004\n");
|
|
printk(" A101, A102, A104\n");
|
|
printk(" F001, F002, F004\n");
|
|
printk(" F101, F102, F104\n");
|
|
printk(" A202, A304, A408\n");
|
|
printk("Advantech Industrial Automation Group.\n");
|
|
printk("==========================================================="
|
|
"====\n");
|
|
if(adv_serial8250_init() >= 0)
|
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 21)
|
|
return pci_module_init(&serial_pci_driver);
|
|
#else
|
|
return pci_register_driver(&serial_pci_driver);
|
|
#endif
|
|
else
|
|
{
|
|
printk("Failed to do adv_serial8250_init()\n");
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
static void __exit adv_serial8250_pci_exit(void)
|
|
{
|
|
pci_unregister_driver(&serial_pci_driver);
|
|
adv_serial8250_exit();
|
|
}
|
|
|
|
module_init(adv_serial8250_pci_init);
|
|
module_exit(adv_serial8250_pci_exit);
|
|
|
|
MODULE_LICENSE("GPL");
|
|
MODULE_DESCRIPTION("Advantech IAG PCI-954/16C950 serial probe module");
|
|
MODULE_DEVICE_TABLE(pci, adv_serial_pci_tbl);
|