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 + -
显示快捷键?