serial_cs.c
来自「linux 内核源代码」· C语言 代码 · 共 982 行 · 第 1/3 页
C
982 行
with Card Services.======================================================================*/static int serial_probe(struct pcmcia_device *link){ struct serial_info *info; DEBUG(0, "serial_attach()\n"); /* Create new serial device */ info = kzalloc(sizeof (*info), GFP_KERNEL); if (!info) return -ENOMEM; info->p_dev = link; link->priv = info; link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; link->io.NumPorts1 = 8; link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING; link->irq.IRQInfo1 = IRQ_LEVEL_ID; link->conf.Attributes = CONF_ENABLE_IRQ; if (do_sound) { link->conf.Attributes |= CONF_ENABLE_SPKR; link->conf.Status = CCSR_AUDIO_ENA; } link->conf.IntType = INT_MEMORY_AND_IO; return serial_config(link);}/*====================================================================== This deletes a driver "instance". The device is de-registered with Card Services. If it has been released, all local data structures are freed. Otherwise, the structures will be freed when the device is released.======================================================================*/static void serial_detach(struct pcmcia_device *link){ struct serial_info *info = link->priv; DEBUG(0, "serial_detach(0x%p)\n", link); /* * Ensure any outstanding scheduled tasks are completed. */ flush_scheduled_work(); /* * Ensure that the ports have been released. */ serial_remove(link); /* free bits */ kfree(info);}/*====================================================================*/static int setup_serial(struct pcmcia_device *handle, struct serial_info * info, kio_addr_t iobase, int irq){ struct uart_port port; int line; memset(&port, 0, sizeof (struct uart_port)); port.iobase = iobase; port.irq = irq; port.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ; port.uartclk = 1843200; port.dev = &handle_to_dev(handle); if (buggy_uart) port.flags |= UPF_BUGGY_UART; if (info->quirk && info->quirk->setup) info->quirk->setup(handle, &port); line = serial8250_register_port(&port); if (line < 0) { printk(KERN_NOTICE "serial_cs: serial8250_register_port() at " "0x%04lx, irq %d failed\n", (u_long)iobase, irq); return -EINVAL; } info->line[info->ndev] = line; sprintf(info->node[info->ndev].dev_name, "ttyS%d", line); info->node[info->ndev].major = TTY_MAJOR; info->node[info->ndev].minor = 0x40 + line; if (info->ndev > 0) info->node[info->ndev - 1].next = &info->node[info->ndev]; info->ndev++; return 0;}/*====================================================================*/static intfirst_tuple(struct pcmcia_device *handle, tuple_t * tuple, cisparse_t * parse){ int i; i = pcmcia_get_first_tuple(handle, tuple); if (i != CS_SUCCESS) return CS_NO_MORE_ITEMS; i = pcmcia_get_tuple_data(handle, tuple); if (i != CS_SUCCESS) return i; return pcmcia_parse_tuple(handle, tuple, parse);}static intnext_tuple(struct pcmcia_device *handle, tuple_t * tuple, cisparse_t * parse){ int i; i = pcmcia_get_next_tuple(handle, tuple); if (i != CS_SUCCESS) return CS_NO_MORE_ITEMS; i = pcmcia_get_tuple_data(handle, tuple); if (i != CS_SUCCESS) return i; return pcmcia_parse_tuple(handle, tuple, parse);}/*====================================================================*/static int simple_config(struct pcmcia_device *link){ static const kio_addr_t base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 }; static const int size_table[2] = { 8, 16 }; struct serial_info *info = link->priv; struct serial_cfg_mem *cfg_mem; tuple_t *tuple; u_char *buf; cisparse_t *parse; cistpl_cftable_entry_t *cf; config_info_t config; int i, j, try; int s; cfg_mem = kmalloc(sizeof(struct serial_cfg_mem), GFP_KERNEL); if (!cfg_mem) return -1; tuple = &cfg_mem->tuple; parse = &cfg_mem->parse; cf = &parse->cftable_entry; buf = cfg_mem->buf; /* If the card is already configured, look up the port and irq */ i = pcmcia_get_configuration_info(link, &config); if ((i == CS_SUCCESS) && (config.Attributes & CONF_VALID_CLIENT)) { kio_addr_t port = 0; if ((config.BasePort2 != 0) && (config.NumPorts2 == 8)) { port = config.BasePort2; info->slave = 1; } else if ((info->manfid == MANFID_OSITECH) && (config.NumPorts1 == 0x40)) { port = config.BasePort1 + 0x28; info->slave = 1; } if (info->slave) { kfree(cfg_mem); return setup_serial(link, info, port, config.AssignedIRQ); } } /* First pass: look for a config entry that looks normal. */ tuple->TupleData = (cisdata_t *) buf; tuple->TupleOffset = 0; tuple->TupleDataMax = 255; tuple->Attributes = 0; tuple->DesiredTuple = CISTPL_CFTABLE_ENTRY; /* Two tries: without IO aliases, then with aliases */ for (s = 0; s < 2; s++) { for (try = 0; try < 2; try++) { i = first_tuple(link, tuple, parse); while (i != CS_NO_MORE_ITEMS) { if (i != CS_SUCCESS) goto next_entry; if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM)) link->conf.Vpp = cf->vpp1.param[CISTPL_POWER_VNOM] / 10000; if ((cf->io.nwin > 0) && (cf->io.win[0].len == size_table[s]) && (cf->io.win[0].base != 0)) { link->conf.ConfigIndex = cf->index; link->io.BasePort1 = cf->io.win[0].base; link->io.IOAddrLines = (try == 0) ? 16 : cf->io.flags & CISTPL_IO_LINES_MASK; i = pcmcia_request_io(link, &link->io); if (i == CS_SUCCESS) goto found_port; }next_entry: i = next_tuple(link, tuple, parse); } } } /* Second pass: try to find an entry that isn't picky about its base address, then try to grab any standard serial port address, and finally try to get any free port. */ i = first_tuple(link, tuple, parse); while (i != CS_NO_MORE_ITEMS) { if ((i == CS_SUCCESS) && (cf->io.nwin > 0) && ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) { link->conf.ConfigIndex = cf->index; for (j = 0; j < 5; j++) { link->io.BasePort1 = base[j]; link->io.IOAddrLines = base[j] ? 16 : 3; i = pcmcia_request_io(link, &link->io); if (i == CS_SUCCESS) goto found_port; } } i = next_tuple(link, tuple, parse); } found_port: if (i != CS_SUCCESS) { printk(KERN_NOTICE "serial_cs: no usable port range found, giving up\n"); cs_error(link, RequestIO, i); kfree(cfg_mem); return -1; } i = pcmcia_request_irq(link, &link->irq); if (i != CS_SUCCESS) { cs_error(link, RequestIRQ, i); link->irq.AssignedIRQ = 0; } if (info->multi && (info->manfid == MANFID_3COM)) link->conf.ConfigIndex &= ~(0x08); /* * Apply any configuration quirks. */ if (info->quirk && info->quirk->config) info->quirk->config(link); i = pcmcia_request_configuration(link, &link->conf); if (i != CS_SUCCESS) { cs_error(link, RequestConfiguration, i); kfree(cfg_mem); return -1; } kfree(cfg_mem); return setup_serial(link, info, link->io.BasePort1, link->irq.AssignedIRQ);}static int multi_config(struct pcmcia_device * link){ struct serial_info *info = link->priv; struct serial_cfg_mem *cfg_mem; tuple_t *tuple; u_char *buf; cisparse_t *parse; cistpl_cftable_entry_t *cf; int i, rc, base2 = 0; cfg_mem = kmalloc(sizeof(struct serial_cfg_mem), GFP_KERNEL); if (!cfg_mem) return -1; tuple = &cfg_mem->tuple; parse = &cfg_mem->parse; cf = &parse->cftable_entry; buf = cfg_mem->buf; tuple->TupleData = (cisdata_t *) buf; tuple->TupleOffset = 0; tuple->TupleDataMax = 255; tuple->Attributes = 0; tuple->DesiredTuple = CISTPL_CFTABLE_ENTRY; /* First, look for a generic full-sized window */ link->io.NumPorts1 = info->multi * 8; i = first_tuple(link, tuple, parse); while (i != CS_NO_MORE_ITEMS) { /* The quad port cards have bad CIS's, so just look for a window larger than 8 ports and assume it will be right */ if ((i == CS_SUCCESS) && (cf->io.nwin == 1) && (cf->io.win[0].len > 8)) { link->conf.ConfigIndex = cf->index; link->io.BasePort1 = cf->io.win[0].base; link->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK; i = pcmcia_request_io(link, &link->io); base2 = link->io.BasePort1 + 8; if (i == CS_SUCCESS) break; } i = next_tuple(link, tuple, parse); } /* If that didn't work, look for two windows */ if (i != CS_SUCCESS) { link->io.NumPorts1 = link->io.NumPorts2 = 8; info->multi = 2; i = first_tuple(link, tuple, parse); while (i != CS_NO_MORE_ITEMS) { if ((i == CS_SUCCESS) && (cf->io.nwin == 2)) { link->conf.ConfigIndex = cf->index; link->io.BasePort1 = cf->io.win[0].base; link->io.BasePort2 = cf->io.win[1].base; link->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK; i = pcmcia_request_io(link, &link->io); base2 = link->io.BasePort2; if (i == CS_SUCCESS) break; } i = next_tuple(link, tuple, parse); } } if (i != CS_SUCCESS) { cs_error(link, RequestIO, i); rc = -1; goto free_cfg_mem; } i = pcmcia_request_irq(link, &link->irq); if (i != CS_SUCCESS) { printk(KERN_NOTICE "serial_cs: no usable port range found, giving up\n"); cs_error(link, RequestIRQ, i);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?