📄 serial_cs.c
字号:
i = CardServices(RequestIO, link->handle, &link->io); if (i == CS_SUCCESS) goto found_port; } next_entry: i = next_tuple(handle, &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(handle, &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 = CardServices(RequestIO, link->handle, &link->io); if (i == CS_SUCCESS) goto found_port; } } i = next_tuple(handle, &tuple, &parse); }found_port: if (i != CS_SUCCESS) { cs_error(link->handle, RequestIO, i); return -1; } i = CardServices(RequestIRQ, link->handle, &link->irq); if (i != CS_SUCCESS) { cs_error(link->handle, RequestIRQ, i); link->irq.AssignedIRQ = 0; } if (info->multi && (info->manfid == MANFID_3COM)) link->conf.ConfigIndex &= ~(0x08); i = CardServices(RequestConfiguration, link->handle, &link->conf); if (i != CS_SUCCESS) { cs_error(link->handle, RequestConfiguration, i); return -1; } return setup_serial(info, link->io.BasePort1, link->irq.AssignedIRQ);}static int multi_config(dev_link_t *link){ client_handle_t handle = link->handle; serial_info_t *info = link->priv; tuple_t tuple; u_char buf[256]; cisparse_t parse; cistpl_cftable_entry_t *cf = &parse.cftable_entry; int i, base2 = 0; 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(handle, &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 = CardServices(RequestIO, link->handle, &link->io); base2 = link->io.BasePort1 + 8; if (i == CS_SUCCESS) break; } i = next_tuple(handle, &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(handle, &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 = CardServices(RequestIO, link->handle, &link->io); base2 = link->io.BasePort2; if (i == CS_SUCCESS) break; } i = next_tuple(handle, &tuple, &parse); } } if (i != CS_SUCCESS) { cs_error(link->handle, RequestIO, i); return -1; } i = CardServices(RequestIRQ, link->handle, &link->irq); if (i != CS_SUCCESS) { cs_error(link->handle, RequestIRQ, i); link->irq.AssignedIRQ = 0; } /* Socket Dual IO: this enables irq's for second port */ if (info->multi && (info->manfid == MANFID_SOCKET)) { link->conf.Present |= PRESENT_EXT_STATUS; link->conf.ExtStatus = ESR_REQ_ATTN_ENA; } i = CardServices(RequestConfiguration, link->handle, &link->conf); if (i != CS_SUCCESS) { cs_error(link->handle, RequestConfiguration, i); return -1; } setup_serial(info, link->io.BasePort1, link->irq.AssignedIRQ); /* The Nokia cards are not really multiport cards */ if (info->manfid == MANFID_NOKIA) return 0; for (i = 0; i < info->multi-1; i++) setup_serial(info, base2+(8*i), link->irq.AssignedIRQ); return 0;}/*====================================================================== serial_config() is scheduled to run after a CARD_INSERTION event is received, to configure the PCMCIA socket, and to make the serial device available to the system.======================================================================*/#define CS_CHECK(fn, args...) \while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failedvoid serial_config(dev_link_t *link){ client_handle_t handle = link->handle; serial_info_t *info = link->priv; tuple_t tuple; u_short buf[128]; cisparse_t parse; cistpl_cftable_entry_t *cf = &parse.cftable_entry; int i, last_ret, last_fn; DEBUG(0, "serial_config(0x%p)\n", link); tuple.TupleData = (cisdata_t *)buf; tuple.TupleOffset = 0; tuple.TupleDataMax = 255; tuple.Attributes = 0; /* Get configuration register information */ tuple.DesiredTuple = CISTPL_CONFIG; last_ret = first_tuple(handle, &tuple, &parse); if (last_ret != CS_SUCCESS) { last_fn = ParseTuple; goto cs_failed; } link->conf.ConfigBase = parse.config.base; link->conf.Present = parse.config.rmask[0]; /* Configure card */ link->state |= DEV_CONFIG; /* Is this a compliant multifunction card? */ tuple.DesiredTuple = CISTPL_LONGLINK_MFC; tuple.Attributes = TUPLE_RETURN_COMMON | TUPLE_RETURN_LINK; info->multi = (first_tuple(handle, &tuple, &parse) == CS_SUCCESS); /* Is this a multiport card? */ tuple.DesiredTuple = CISTPL_MANFID; if (first_tuple(handle, &tuple, &parse) == CS_SUCCESS) { info->manfid = le16_to_cpu(buf[0]); for (i = 0; i < MULTI_COUNT; i++) if ((info->manfid == multi_id[i].manfid) && (le16_to_cpu(buf[1]) == multi_id[i].prodid)) break; if (i < MULTI_COUNT) info->multi = multi_id[i].multi; } /* Another check for dual-serial cards: look for either serial or multifunction cards that ask for appropriate IO port ranges */ tuple.DesiredTuple = CISTPL_FUNCID; if ((info->multi == 0) && ((first_tuple(handle, &tuple, &parse) != CS_SUCCESS) || (parse.funcid.func == CISTPL_FUNCID_MULTI) || (parse.funcid.func == CISTPL_FUNCID_SERIAL))) { tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; if (first_tuple(handle, &tuple, &parse) == CS_SUCCESS) { if ((cf->io.nwin == 1) && (cf->io.win[0].len % 8 == 0)) info->multi = cf->io.win[0].len >> 3; if ((cf->io.nwin == 2) && (cf->io.win[0].len == 8) && (cf->io.win[1].len == 8)) info->multi = 2; } } if (info->multi > 1) multi_config(link); else simple_config(link); if (info->ndev == 0) goto failed; if (info->manfid == MANFID_IBM) { conf_reg_t reg = { 0, CS_READ, 0x800, 0 }; CS_CHECK(AccessConfigurationRegister, link->handle, ®); reg.Action = CS_WRITE; reg.Value = reg.Value | 1; CS_CHECK(AccessConfigurationRegister, link->handle, ®); } link->dev = &info->node[0]; link->state &= ~DEV_CONFIG_PENDING; return;cs_failed: cs_error(link->handle, last_fn, last_ret);failed: serial_release((u_long)link);} /* serial_config *//*====================================================================== After a card is removed, serial_release() will unregister the net device, and release the PCMCIA configuration. ======================================================================*/void serial_release(u_long arg){ dev_link_t *link = (dev_link_t *)arg; serial_info_t *info = link->priv; int i; DEBUG(0, "serial_release(0x%p)\n", link); for (i = 0; i < info->ndev; i++) { unregister_serial(info->line[i]); } link->dev = NULL; if (!info->slave) { CardServices(ReleaseConfiguration, link->handle); CardServices(ReleaseIO, link->handle, &link->io); CardServices(ReleaseIRQ, link->handle, &link->irq); } link->state &= ~DEV_CONFIG;} /* serial_release *//*====================================================================== The card status event handler. Mostly, this schedules other stuff to run after an event is received. A CARD_REMOVAL event also sets some flags to discourage the serial drivers from talking to the ports. ======================================================================*/static int serial_event(event_t event, int priority, event_callback_args_t *args){ dev_link_t *link = args->client_data; serial_info_t *info = link->priv; DEBUG(1, "serial_event(0x%06x)\n", event); switch (event) { case CS_EVENT_CARD_REMOVAL: link->state &= ~DEV_PRESENT; if (link->state & DEV_CONFIG) mod_timer(&link->release, jiffies + HZ/20); break; case CS_EVENT_CARD_INSERTION: link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; serial_config(link); break; case CS_EVENT_PM_SUSPEND: link->state |= DEV_SUSPEND; /* Fall through... */ case CS_EVENT_RESET_PHYSICAL: if ((link->state & DEV_CONFIG) && !info->slave) CardServices(ReleaseConfiguration, link->handle); break; case CS_EVENT_PM_RESUME: link->state &= ~DEV_SUSPEND; /* Fall through... */ case CS_EVENT_CARD_RESET: if (DEV_OK(link) && !info->slave) CardServices(RequestConfiguration, link->handle, &link->conf); break; } return 0;} /* serial_event *//*====================================================================*/static int __init init_serial_cs(void){ servinfo_t serv; DEBUG(0, "%s\n", version); CardServices(GetCardServicesInfo, &serv); if (serv.Revision != CS_RELEASE_CODE) { printk(KERN_NOTICE "serial_cs: Card Services release " "does not match!\n"); return -1; } register_pccard_driver(&dev_info, &serial_attach, &serial_detach); return 0;}static void __exit exit_serial_cs(void){ DEBUG(0, "serial_cs: unloading\n"); unregister_pccard_driver(&dev_info); while (dev_list != NULL) serial_detach(dev_list);}module_init(init_serial_cs);module_exit(exit_serial_cs);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -