8250_pci.c
来自「linux 内核源代码」· C语言 代码 · 共 2,606 行 · 第 1/5 页
C
2,606 行
offset = board->uart_offset; bar = 0; break; case 2: bar = 1; break; case 3: offset = board->uart_offset; /* FALLTHROUGH */ case 4: /* BAR 2 */ case 5: /* BAR 3 */ case 6: /* BAR 4 */ case 7: /* BAR 5 */ bar = idx - 2; } return setup_port(priv, port, bar, offset, board->reg_shift);}/* * Some Titan cards are also a little weird */static inttitan_400l_800l_setup(struct serial_private *priv, struct pciserial_board *board, struct uart_port *port, int idx){ unsigned int bar, offset = board->first_offset; switch (idx) { case 0: bar = 1; break; case 1: bar = 2; break; default: bar = 4; offset = (idx - 2) * board->uart_offset; } return setup_port(priv, port, bar, offset, board->reg_shift);}static int pci_xircom_init(struct pci_dev *dev){ msleep(100); return 0;}static int pci_netmos_init(struct pci_dev *dev){ /* subdevice 0x00PS means <P> parallel, <S> serial */ unsigned int num_serial = dev->subsystem_device & 0xf; if (num_serial == 0) return -ENODEV; return num_serial;}/* * ITE support by Niels de Vos <niels.devos@wincor-nixdorf.com> * * These chips are available with optionally one parallel port and up to * two serial ports. Unfortunately they all have the same product id. * * Basic configuration is done over a region of 32 I/O ports. The base * ioport is called INTA or INTC, depending on docs/other drivers. * * The region of the 32 I/O ports is configured in POSIO0R... *//* registers */#define ITE_887x_MISCR 0x9c#define ITE_887x_INTCBAR 0x78#define ITE_887x_UARTBAR 0x7c#define ITE_887x_PS0BAR 0x10#define ITE_887x_POSIO0 0x60/* I/O space size */#define ITE_887x_IOSIZE 32/* I/O space size (bits 26-24; 8 bytes = 011b) */#define ITE_887x_POSIO_IOSIZE_8 (3 << 24)/* I/O space size (bits 26-24; 32 bytes = 101b) */#define ITE_887x_POSIO_IOSIZE_32 (5 << 24)/* Decoding speed (1 = slow, 2 = medium, 3 = fast) */#define ITE_887x_POSIO_SPEED (3 << 29)/* enable IO_Space bit */#define ITE_887x_POSIO_ENABLE (1 << 31)static int pci_ite887x_init(struct pci_dev *dev){ /* inta_addr are the configuration addresses of the ITE */ static const short inta_addr[] = { 0x2a0, 0x2c0, 0x220, 0x240, 0x1e0, 0x200, 0x280, 0 }; int ret, i, type; struct resource *iobase = NULL; u32 miscr, uartbar, ioport; /* search for the base-ioport */ i = 0; while (inta_addr[i] && iobase == NULL) { iobase = request_region(inta_addr[i], ITE_887x_IOSIZE, "ite887x"); if (iobase != NULL) { /* write POSIO0R - speed | size | ioport */ pci_write_config_dword(dev, ITE_887x_POSIO0, ITE_887x_POSIO_ENABLE | ITE_887x_POSIO_SPEED | ITE_887x_POSIO_IOSIZE_32 | inta_addr[i]); /* write INTCBAR - ioport */ pci_write_config_dword(dev, ITE_887x_INTCBAR, inta_addr[i]); ret = inb(inta_addr[i]); if (ret != 0xff) { /* ioport connected */ break; } release_region(iobase->start, ITE_887x_IOSIZE); iobase = NULL; } i++; } if (!inta_addr[i]) { printk(KERN_ERR "ite887x: could not find iobase\n"); return -ENODEV; } /* start of undocumented type checking (see parport_pc.c) */ type = inb(iobase->start + 0x18) & 0x0f; switch (type) { case 0x2: /* ITE8871 (1P) */ case 0xa: /* ITE8875 (1P) */ ret = 0; break; case 0xe: /* ITE8872 (2S1P) */ ret = 2; break; case 0x6: /* ITE8873 (1S) */ ret = 1; break; case 0x8: /* ITE8874 (2S) */ ret = 2; break; default: moan_device("Unknown ITE887x", dev); ret = -ENODEV; } /* configure all serial ports */ for (i = 0; i < ret; i++) { /* read the I/O port from the device */ pci_read_config_dword(dev, ITE_887x_PS0BAR + (0x4 * (i + 1)), &ioport); ioport &= 0x0000FF00; /* the actual base address */ pci_write_config_dword(dev, ITE_887x_POSIO0 + (0x4 * (i + 1)), ITE_887x_POSIO_ENABLE | ITE_887x_POSIO_SPEED | ITE_887x_POSIO_IOSIZE_8 | ioport); /* write the ioport to the UARTBAR */ pci_read_config_dword(dev, ITE_887x_UARTBAR, &uartbar); uartbar &= ~(0xffff << (16 * i)); /* clear half the reg */ uartbar |= (ioport << (16 * i)); /* set the ioport */ pci_write_config_dword(dev, ITE_887x_UARTBAR, uartbar); /* get current config */ pci_read_config_dword(dev, ITE_887x_MISCR, &miscr); /* disable interrupts (UARTx_Routing[3:0]) */ miscr &= ~(0xf << (12 - 4 * i)); /* activate the UART (UARTx_En) */ miscr |= 1 << (23 - i); /* write new config with activated UART */ pci_write_config_dword(dev, ITE_887x_MISCR, miscr); } if (ret <= 0) { /* the device has no UARTs if we get here */ release_region(iobase->start, ITE_887x_IOSIZE); } return ret;}static void __devexit pci_ite887x_exit(struct pci_dev *dev){ u32 ioport; /* the ioport is bit 0-15 in POSIO0R */ pci_read_config_dword(dev, ITE_887x_POSIO0, &ioport); ioport &= 0xffff; release_region(ioport, ITE_887x_IOSIZE);}static intpci_default_setup(struct serial_private *priv, struct pciserial_board *board, struct uart_port *port, 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; maxnr = (pci_resource_len(priv->dev, bar) - board->first_offset) >> (board->reg_shift + 3); if (board->flags & FL_REGION_SZ_CAP && idx >= maxnr) return 1; return setup_port(priv, port, bar, offset, board->reg_shift);}/* This should be in linux/pci_ids.h */#define PCI_VENDOR_ID_SBSMODULARIO 0x124B#define PCI_SUBVENDOR_ID_SBSMODULARIO 0x124B#define PCI_DEVICE_ID_OCTPRO 0x0001#define PCI_SUBDEVICE_ID_OCTPRO232 0x0108#define PCI_SUBDEVICE_ID_OCTPRO422 0x0208#define PCI_SUBDEVICE_ID_POCTAL232 0x0308#define PCI_SUBDEVICE_ID_POCTAL422 0x0408/* * 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[] = { /* * AFAVLAB cards - these may be called via parport_serial * It is not clear whether this applies to all products. */ { .vendor = PCI_VENDOR_ID_AFAVLAB, .device = PCI_ANY_ID, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .setup = afavlab_setup, }, /* * HP Diva */ { .vendor = PCI_VENDOR_ID_HP, .device = PCI_DEVICE_ID_HP_DIVA, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .init = pci_hp_diva_init, .setup = pci_hp_diva_setup, }, /* * Intel */ { .vendor = PCI_VENDOR_ID_INTEL, .device = PCI_DEVICE_ID_INTEL_80960_RP, .subvendor = 0xe4bf, .subdevice = PCI_ANY_ID, .init = pci_inteli960ni_init, .setup = pci_default_setup, }, /* * ITE */ { .vendor = PCI_VENDOR_ID_ITE, .device = PCI_DEVICE_ID_ITE_8872, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .init = pci_ite887x_init, .setup = pci_default_setup, .exit = __devexit_p(pci_ite887x_exit), }, /* * Panacom */ { .vendor = PCI_VENDOR_ID_PANACOM, .device = PCI_DEVICE_ID_PANACOM_QUADMODEM, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .init = pci_plx9050_init, .setup = pci_default_setup, .exit = __devexit_p(pci_plx9050_exit), }, { .vendor = PCI_VENDOR_ID_PANACOM, .device = PCI_DEVICE_ID_PANACOM_DUALMODEM, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .init = pci_plx9050_init, .setup = pci_default_setup, .exit = __devexit_p(pci_plx9050_exit), }, /* * PLX */ { .vendor = PCI_VENDOR_ID_PLX, .device = PCI_DEVICE_ID_PLX_9030, .subvendor = PCI_SUBVENDOR_ID_PERLE, .subdevice = PCI_ANY_ID, .setup = pci_default_setup, }, { .vendor = PCI_VENDOR_ID_PLX, .device = PCI_DEVICE_ID_PLX_9050, .subvendor = PCI_SUBVENDOR_ID_EXSYS, .subdevice = PCI_SUBDEVICE_ID_EXSYS_4055, .init = pci_plx9050_init, .setup = pci_default_setup, .exit = __devexit_p(pci_plx9050_exit), }, { .vendor = PCI_VENDOR_ID_PLX, .device = PCI_DEVICE_ID_PLX_9050, .subvendor = PCI_SUBVENDOR_ID_KEYSPAN, .subdevice = PCI_SUBDEVICE_ID_KEYSPAN_SX2, .init = pci_plx9050_init, .setup = pci_default_setup, .exit = __devexit_p(pci_plx9050_exit), }, { .vendor = PCI_VENDOR_ID_PLX, .device = PCI_DEVICE_ID_PLX_ROMULUS, .subvendor = PCI_VENDOR_ID_PLX, .subdevice = PCI_DEVICE_ID_PLX_ROMULUS, .init = pci_plx9050_init, .setup = pci_default_setup, .exit = __devexit_p(pci_plx9050_exit), }, /* * SBS Technologies, Inc., PMC-OCTALPRO 232 */ { .vendor = PCI_VENDOR_ID_SBSMODULARIO, .device = PCI_DEVICE_ID_OCTPRO, .subvendor = PCI_SUBVENDOR_ID_SBSMODULARIO, .subdevice = PCI_SUBDEVICE_ID_OCTPRO232, .init = sbs_init, .setup = sbs_setup, .exit = __devexit_p(sbs_exit), }, /* * SBS Technologies, Inc., PMC-OCTALPRO 422 */ { .vendor = PCI_VENDOR_ID_SBSMODULARIO, .device = PCI_DEVICE_ID_OCTPRO, .subvendor = PCI_SUBVENDOR_ID_SBSMODULARIO, .subdevice = PCI_SUBDEVICE_ID_OCTPRO422, .init = sbs_init, .setup = sbs_setup, .exit = __devexit_p(sbs_exit), }, /* * SBS Technologies, Inc., P-Octal 232 */ { .vendor = PCI_VENDOR_ID_SBSMODULARIO, .device = PCI_DEVICE_ID_OCTPRO, .subvendor = PCI_SUBVENDOR_ID_SBSMODULARIO, .subdevice = PCI_SUBDEVICE_ID_POCTAL232, .init = sbs_init, .setup = sbs_setup, .exit = __devexit_p(sbs_exit), }, /* * SBS Technologies, Inc., P-Octal 422 */ { .vendor = PCI_VENDOR_ID_SBSMODULARIO, .device = PCI_DEVICE_ID_OCTPRO, .subvendor = PCI_SUBVENDOR_ID_SBSMODULARIO, .subdevice = PCI_SUBDEVICE_ID_POCTAL422, .init = sbs_init, .setup = sbs_setup, .exit = __devexit_p(sbs_exit), }, /* * SIIG cards - these may be called via parport_serial */ { .vendor = PCI_VENDOR_ID_SIIG, .device = PCI_ANY_ID, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .init = pci_siig_init, .setup = pci_siig_setup, }, /* * Titan cards */ { .vendor = PCI_VENDOR_ID_TITAN, .device = PCI_DEVICE_ID_TITAN_400L, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .setup = titan_400l_800l_setup, }, { .vendor = PCI_VENDOR_ID_TITAN, .device = PCI_DEVICE_ID_TITAN_800L, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .setup = titan_400l_800l_setup, }, /* * Timedia cards */ { .vendor = PCI_VENDOR_ID_TIMEDIA, .device = PCI_DEVICE_ID_TIMEDIA_1889, .subvendor = PCI_VENDOR_ID_TIMEDIA, .subdevice = PCI_ANY_ID, .init = pci_timedia_init, .setup = pci_timedia_setup, }, { .vendor = PCI_VENDOR_ID_TIMEDIA, .device = PCI_ANY_ID, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .setup = pci_timedia_setup, }, /* * Xircom cards */ { .vendor = PCI_VENDOR_ID_XIRCOM, .device = PCI_DEVICE_ID_XIRCOM_X3201_MDM, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .init = pci_xircom_init, .setup = pci_default_setup, }, /* * Netmos cards - these may be called via parport_serial */ { .vendor = PCI_VENDOR_ID_NETMOS, .device = PCI_ANY_ID, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .init = pci_netmos_init, .setup = pci_default_setup, }, /* * Default "match everything" terminator entry */ { .vendor = PCI_ANY_ID, .device = PCI_ANY_ID, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .setup = pci_default_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 pciserial_board *board){ 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{_offsetinhex} * * bn = PCI BAR number * bt = Index using PCI BARs * n = number of serial ports * baud = baud rate * offsetinhex = offset for each sequential port (in hex) * * This table is sorted by (in order): bn, bt, baud, offsetindex, n. * * 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_8_115200, pbn_b0_1_921600, pbn_b0_2_921600, pbn_b0_4_921600,
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?