18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * PCMCIA high-level CIS access functions
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * The initial developer of the original code is David A. Hinds
68c2ecf20Sopenharmony_ci * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
78c2ecf20Sopenharmony_ci * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * Copyright (C) 1999	     David A. Hinds
108c2ecf20Sopenharmony_ci * Copyright (C) 2004-2010   Dominik Brodowski
118c2ecf20Sopenharmony_ci */
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include <linux/slab.h>
148c2ecf20Sopenharmony_ci#include <linux/module.h>
158c2ecf20Sopenharmony_ci#include <linux/kernel.h>
168c2ecf20Sopenharmony_ci#include <linux/netdevice.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#include <pcmcia/cisreg.h>
198c2ecf20Sopenharmony_ci#include <pcmcia/cistpl.h>
208c2ecf20Sopenharmony_ci#include <pcmcia/ss.h>
218c2ecf20Sopenharmony_ci#include <pcmcia/ds.h>
228c2ecf20Sopenharmony_ci#include "cs_internal.h"
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci/**
268c2ecf20Sopenharmony_ci * pccard_read_tuple() - internal CIS tuple access
278c2ecf20Sopenharmony_ci * @s:		the struct pcmcia_socket where the card is inserted
288c2ecf20Sopenharmony_ci * @function:	the device function we loop for
298c2ecf20Sopenharmony_ci * @code:	which CIS code shall we look for?
308c2ecf20Sopenharmony_ci * @parse:	buffer where the tuple shall be parsed (or NULL, if no parse)
318c2ecf20Sopenharmony_ci *
328c2ecf20Sopenharmony_ci * pccard_read_tuple() reads out one tuple and attempts to parse it
338c2ecf20Sopenharmony_ci */
348c2ecf20Sopenharmony_ciint pccard_read_tuple(struct pcmcia_socket *s, unsigned int function,
358c2ecf20Sopenharmony_ci		cisdata_t code, void *parse)
368c2ecf20Sopenharmony_ci{
378c2ecf20Sopenharmony_ci	tuple_t tuple;
388c2ecf20Sopenharmony_ci	cisdata_t *buf;
398c2ecf20Sopenharmony_ci	int ret;
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci	buf = kmalloc(256, GFP_KERNEL);
428c2ecf20Sopenharmony_ci	if (buf == NULL) {
438c2ecf20Sopenharmony_ci		dev_warn(&s->dev, "no memory to read tuple\n");
448c2ecf20Sopenharmony_ci		return -ENOMEM;
458c2ecf20Sopenharmony_ci	}
468c2ecf20Sopenharmony_ci	tuple.DesiredTuple = code;
478c2ecf20Sopenharmony_ci	tuple.Attributes = 0;
488c2ecf20Sopenharmony_ci	if (function == BIND_FN_ALL)
498c2ecf20Sopenharmony_ci		tuple.Attributes = TUPLE_RETURN_COMMON;
508c2ecf20Sopenharmony_ci	ret = pccard_get_first_tuple(s, function, &tuple);
518c2ecf20Sopenharmony_ci	if (ret != 0)
528c2ecf20Sopenharmony_ci		goto done;
538c2ecf20Sopenharmony_ci	tuple.TupleData = buf;
548c2ecf20Sopenharmony_ci	tuple.TupleOffset = 0;
558c2ecf20Sopenharmony_ci	tuple.TupleDataMax = 255;
568c2ecf20Sopenharmony_ci	ret = pccard_get_tuple_data(s, &tuple);
578c2ecf20Sopenharmony_ci	if (ret != 0)
588c2ecf20Sopenharmony_ci		goto done;
598c2ecf20Sopenharmony_ci	ret = pcmcia_parse_tuple(&tuple, parse);
608c2ecf20Sopenharmony_cidone:
618c2ecf20Sopenharmony_ci	kfree(buf);
628c2ecf20Sopenharmony_ci	return ret;
638c2ecf20Sopenharmony_ci}
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci/**
678c2ecf20Sopenharmony_ci * pccard_loop_tuple() - loop over tuples in the CIS
688c2ecf20Sopenharmony_ci * @s:		the struct pcmcia_socket where the card is inserted
698c2ecf20Sopenharmony_ci * @function:	the device function we loop for
708c2ecf20Sopenharmony_ci * @code:	which CIS code shall we look for?
718c2ecf20Sopenharmony_ci * @parse:	buffer where the tuple shall be parsed (or NULL, if no parse)
728c2ecf20Sopenharmony_ci * @priv_data:	private data to be passed to the loop_tuple function.
738c2ecf20Sopenharmony_ci * @loop_tuple:	function to call for each CIS entry of type @function. IT
748c2ecf20Sopenharmony_ci *		gets passed the raw tuple, the paresed tuple (if @parse is
758c2ecf20Sopenharmony_ci *		set) and @priv_data.
768c2ecf20Sopenharmony_ci *
778c2ecf20Sopenharmony_ci * pccard_loop_tuple() loops over all CIS entries of type @function, and
788c2ecf20Sopenharmony_ci * calls the @loop_tuple function for each entry. If the call to @loop_tuple
798c2ecf20Sopenharmony_ci * returns 0, the loop exits. Returns 0 on success or errorcode otherwise.
808c2ecf20Sopenharmony_ci */
818c2ecf20Sopenharmony_cistatic int pccard_loop_tuple(struct pcmcia_socket *s, unsigned int function,
828c2ecf20Sopenharmony_ci			     cisdata_t code, cisparse_t *parse, void *priv_data,
838c2ecf20Sopenharmony_ci			     int (*loop_tuple) (tuple_t *tuple,
848c2ecf20Sopenharmony_ci					 cisparse_t *parse,
858c2ecf20Sopenharmony_ci					 void *priv_data))
868c2ecf20Sopenharmony_ci{
878c2ecf20Sopenharmony_ci	tuple_t tuple;
888c2ecf20Sopenharmony_ci	cisdata_t *buf;
898c2ecf20Sopenharmony_ci	int ret;
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	buf = kzalloc(256, GFP_KERNEL);
928c2ecf20Sopenharmony_ci	if (buf == NULL) {
938c2ecf20Sopenharmony_ci		dev_warn(&s->dev, "no memory to read tuple\n");
948c2ecf20Sopenharmony_ci		return -ENOMEM;
958c2ecf20Sopenharmony_ci	}
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	tuple.TupleData = buf;
988c2ecf20Sopenharmony_ci	tuple.TupleDataMax = 255;
998c2ecf20Sopenharmony_ci	tuple.TupleOffset = 0;
1008c2ecf20Sopenharmony_ci	tuple.DesiredTuple = code;
1018c2ecf20Sopenharmony_ci	tuple.Attributes = 0;
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	ret = pccard_get_first_tuple(s, function, &tuple);
1048c2ecf20Sopenharmony_ci	while (!ret) {
1058c2ecf20Sopenharmony_ci		if (pccard_get_tuple_data(s, &tuple))
1068c2ecf20Sopenharmony_ci			goto next_entry;
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci		if (parse)
1098c2ecf20Sopenharmony_ci			if (pcmcia_parse_tuple(&tuple, parse))
1108c2ecf20Sopenharmony_ci				goto next_entry;
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci		ret = loop_tuple(&tuple, parse, priv_data);
1138c2ecf20Sopenharmony_ci		if (!ret)
1148c2ecf20Sopenharmony_ci			break;
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_cinext_entry:
1178c2ecf20Sopenharmony_ci		ret = pccard_get_next_tuple(s, function, &tuple);
1188c2ecf20Sopenharmony_ci	}
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	kfree(buf);
1218c2ecf20Sopenharmony_ci	return ret;
1228c2ecf20Sopenharmony_ci}
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci/**
1268c2ecf20Sopenharmony_ci * pcmcia_io_cfg_data_width() - convert cfgtable to data path width parameter
1278c2ecf20Sopenharmony_ci */
1288c2ecf20Sopenharmony_cistatic int pcmcia_io_cfg_data_width(unsigned int flags)
1298c2ecf20Sopenharmony_ci{
1308c2ecf20Sopenharmony_ci	if (!(flags & CISTPL_IO_8BIT))
1318c2ecf20Sopenharmony_ci		return IO_DATA_PATH_WIDTH_16;
1328c2ecf20Sopenharmony_ci	if (!(flags & CISTPL_IO_16BIT))
1338c2ecf20Sopenharmony_ci		return IO_DATA_PATH_WIDTH_8;
1348c2ecf20Sopenharmony_ci	return IO_DATA_PATH_WIDTH_AUTO;
1358c2ecf20Sopenharmony_ci}
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_cistruct pcmcia_cfg_mem {
1398c2ecf20Sopenharmony_ci	struct pcmcia_device *p_dev;
1408c2ecf20Sopenharmony_ci	int (*conf_check) (struct pcmcia_device *p_dev, void *priv_data);
1418c2ecf20Sopenharmony_ci	void *priv_data;
1428c2ecf20Sopenharmony_ci	cisparse_t parse;
1438c2ecf20Sopenharmony_ci	cistpl_cftable_entry_t dflt;
1448c2ecf20Sopenharmony_ci};
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci/**
1478c2ecf20Sopenharmony_ci * pcmcia_do_loop_config() - internal helper for pcmcia_loop_config()
1488c2ecf20Sopenharmony_ci *
1498c2ecf20Sopenharmony_ci * pcmcia_do_loop_config() is the internal callback for the call from
1508c2ecf20Sopenharmony_ci * pcmcia_loop_config() to pccard_loop_tuple(). Data is transferred
1518c2ecf20Sopenharmony_ci * by a struct pcmcia_cfg_mem.
1528c2ecf20Sopenharmony_ci */
1538c2ecf20Sopenharmony_cistatic int pcmcia_do_loop_config(tuple_t *tuple, cisparse_t *parse, void *priv)
1548c2ecf20Sopenharmony_ci{
1558c2ecf20Sopenharmony_ci	struct pcmcia_cfg_mem *cfg_mem = priv;
1568c2ecf20Sopenharmony_ci	struct pcmcia_device *p_dev = cfg_mem->p_dev;
1578c2ecf20Sopenharmony_ci	cistpl_cftable_entry_t *cfg = &parse->cftable_entry;
1588c2ecf20Sopenharmony_ci	cistpl_cftable_entry_t *dflt = &cfg_mem->dflt;
1598c2ecf20Sopenharmony_ci	unsigned int flags = p_dev->config_flags;
1608c2ecf20Sopenharmony_ci	unsigned int vcc = p_dev->socket->socket.Vcc;
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	dev_dbg(&p_dev->dev, "testing configuration %x, autoconf %x\n",
1638c2ecf20Sopenharmony_ci		cfg->index, flags);
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	/* default values */
1668c2ecf20Sopenharmony_ci	cfg_mem->p_dev->config_index = cfg->index;
1678c2ecf20Sopenharmony_ci	if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
1688c2ecf20Sopenharmony_ci		cfg_mem->dflt = *cfg;
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	/* check for matching Vcc? */
1718c2ecf20Sopenharmony_ci	if (flags & CONF_AUTO_CHECK_VCC) {
1728c2ecf20Sopenharmony_ci		if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
1738c2ecf20Sopenharmony_ci			if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000)
1748c2ecf20Sopenharmony_ci				return -ENODEV;
1758c2ecf20Sopenharmony_ci		} else if (dflt->vcc.present & (1 << CISTPL_POWER_VNOM)) {
1768c2ecf20Sopenharmony_ci			if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM] / 10000)
1778c2ecf20Sopenharmony_ci				return -ENODEV;
1788c2ecf20Sopenharmony_ci		}
1798c2ecf20Sopenharmony_ci	}
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	/* set Vpp? */
1828c2ecf20Sopenharmony_ci	if (flags & CONF_AUTO_SET_VPP) {
1838c2ecf20Sopenharmony_ci		if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
1848c2ecf20Sopenharmony_ci			p_dev->vpp = cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
1858c2ecf20Sopenharmony_ci		else if (dflt->vpp1.present & (1 << CISTPL_POWER_VNOM))
1868c2ecf20Sopenharmony_ci			p_dev->vpp =
1878c2ecf20Sopenharmony_ci				dflt->vpp1.param[CISTPL_POWER_VNOM] / 10000;
1888c2ecf20Sopenharmony_ci	}
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	/* enable audio? */
1918c2ecf20Sopenharmony_ci	if ((flags & CONF_AUTO_AUDIO) && (cfg->flags & CISTPL_CFTABLE_AUDIO))
1928c2ecf20Sopenharmony_ci		p_dev->config_flags |= CONF_ENABLE_SPKR;
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	/* IO window settings? */
1968c2ecf20Sopenharmony_ci	if (flags & CONF_AUTO_SET_IO) {
1978c2ecf20Sopenharmony_ci		cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
1988c2ecf20Sopenharmony_ci		int i = 0;
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci		p_dev->resource[0]->start = p_dev->resource[0]->end = 0;
2018c2ecf20Sopenharmony_ci		p_dev->resource[1]->start = p_dev->resource[1]->end = 0;
2028c2ecf20Sopenharmony_ci		if (io->nwin == 0)
2038c2ecf20Sopenharmony_ci			return -ENODEV;
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci		p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
2068c2ecf20Sopenharmony_ci		p_dev->resource[0]->flags |=
2078c2ecf20Sopenharmony_ci					pcmcia_io_cfg_data_width(io->flags);
2088c2ecf20Sopenharmony_ci		if (io->nwin > 1) {
2098c2ecf20Sopenharmony_ci			/* For multifunction cards, by convention, we
2108c2ecf20Sopenharmony_ci			 * configure the network function with window 0,
2118c2ecf20Sopenharmony_ci			 * and serial with window 1 */
2128c2ecf20Sopenharmony_ci			i = (io->win[1].len > io->win[0].len);
2138c2ecf20Sopenharmony_ci			p_dev->resource[1]->flags = p_dev->resource[0]->flags;
2148c2ecf20Sopenharmony_ci			p_dev->resource[1]->start = io->win[1-i].base;
2158c2ecf20Sopenharmony_ci			p_dev->resource[1]->end = io->win[1-i].len;
2168c2ecf20Sopenharmony_ci		}
2178c2ecf20Sopenharmony_ci		p_dev->resource[0]->start = io->win[i].base;
2188c2ecf20Sopenharmony_ci		p_dev->resource[0]->end = io->win[i].len;
2198c2ecf20Sopenharmony_ci		p_dev->io_lines = io->flags & CISTPL_IO_LINES_MASK;
2208c2ecf20Sopenharmony_ci	}
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	/* MEM window settings? */
2238c2ecf20Sopenharmony_ci	if (flags & CONF_AUTO_SET_IOMEM) {
2248c2ecf20Sopenharmony_ci		/* so far, we only set one memory window */
2258c2ecf20Sopenharmony_ci		cistpl_mem_t *mem = (cfg->mem.nwin) ? &cfg->mem : &dflt->mem;
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci		p_dev->resource[2]->start = p_dev->resource[2]->end = 0;
2288c2ecf20Sopenharmony_ci		if (mem->nwin == 0)
2298c2ecf20Sopenharmony_ci			return -ENODEV;
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci		p_dev->resource[2]->start = mem->win[0].host_addr;
2328c2ecf20Sopenharmony_ci		p_dev->resource[2]->end = mem->win[0].len;
2338c2ecf20Sopenharmony_ci		if (p_dev->resource[2]->end < 0x1000)
2348c2ecf20Sopenharmony_ci			p_dev->resource[2]->end = 0x1000;
2358c2ecf20Sopenharmony_ci		p_dev->card_addr = mem->win[0].card_addr;
2368c2ecf20Sopenharmony_ci	}
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	dev_dbg(&p_dev->dev,
2398c2ecf20Sopenharmony_ci		"checking configuration %x: %pr %pr %pr (%d lines)\n",
2408c2ecf20Sopenharmony_ci		p_dev->config_index, p_dev->resource[0], p_dev->resource[1],
2418c2ecf20Sopenharmony_ci		p_dev->resource[2], p_dev->io_lines);
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	return cfg_mem->conf_check(p_dev, cfg_mem->priv_data);
2448c2ecf20Sopenharmony_ci}
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci/**
2478c2ecf20Sopenharmony_ci * pcmcia_loop_config() - loop over configuration options
2488c2ecf20Sopenharmony_ci * @p_dev:	the struct pcmcia_device which we need to loop for.
2498c2ecf20Sopenharmony_ci * @conf_check:	function to call for each configuration option.
2508c2ecf20Sopenharmony_ci *		It gets passed the struct pcmcia_device and private data
2518c2ecf20Sopenharmony_ci *		being passed to pcmcia_loop_config()
2528c2ecf20Sopenharmony_ci * @priv_data:	private data to be passed to the conf_check function.
2538c2ecf20Sopenharmony_ci *
2548c2ecf20Sopenharmony_ci * pcmcia_loop_config() loops over all configuration options, and calls
2558c2ecf20Sopenharmony_ci * the driver-specific conf_check() for each one, checking whether
2568c2ecf20Sopenharmony_ci * it is a valid one. Returns 0 on success or errorcode otherwise.
2578c2ecf20Sopenharmony_ci */
2588c2ecf20Sopenharmony_ciint pcmcia_loop_config(struct pcmcia_device *p_dev,
2598c2ecf20Sopenharmony_ci		       int	(*conf_check)	(struct pcmcia_device *p_dev,
2608c2ecf20Sopenharmony_ci						 void *priv_data),
2618c2ecf20Sopenharmony_ci		       void *priv_data)
2628c2ecf20Sopenharmony_ci{
2638c2ecf20Sopenharmony_ci	struct pcmcia_cfg_mem *cfg_mem;
2648c2ecf20Sopenharmony_ci	int ret;
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	cfg_mem = kzalloc(sizeof(struct pcmcia_cfg_mem), GFP_KERNEL);
2678c2ecf20Sopenharmony_ci	if (cfg_mem == NULL)
2688c2ecf20Sopenharmony_ci		return -ENOMEM;
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	cfg_mem->p_dev = p_dev;
2718c2ecf20Sopenharmony_ci	cfg_mem->conf_check = conf_check;
2728c2ecf20Sopenharmony_ci	cfg_mem->priv_data = priv_data;
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	ret = pccard_loop_tuple(p_dev->socket, p_dev->func,
2758c2ecf20Sopenharmony_ci				CISTPL_CFTABLE_ENTRY, &cfg_mem->parse,
2768c2ecf20Sopenharmony_ci				cfg_mem, pcmcia_do_loop_config);
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	kfree(cfg_mem);
2798c2ecf20Sopenharmony_ci	return ret;
2808c2ecf20Sopenharmony_ci}
2818c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pcmcia_loop_config);
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_cistruct pcmcia_loop_mem {
2858c2ecf20Sopenharmony_ci	struct pcmcia_device *p_dev;
2868c2ecf20Sopenharmony_ci	void *priv_data;
2878c2ecf20Sopenharmony_ci	int (*loop_tuple) (struct pcmcia_device *p_dev,
2888c2ecf20Sopenharmony_ci			   tuple_t *tuple,
2898c2ecf20Sopenharmony_ci			   void *priv_data);
2908c2ecf20Sopenharmony_ci};
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci/**
2938c2ecf20Sopenharmony_ci * pcmcia_do_loop_tuple() - internal helper for pcmcia_loop_config()
2948c2ecf20Sopenharmony_ci *
2958c2ecf20Sopenharmony_ci * pcmcia_do_loop_tuple() is the internal callback for the call from
2968c2ecf20Sopenharmony_ci * pcmcia_loop_tuple() to pccard_loop_tuple(). Data is transferred
2978c2ecf20Sopenharmony_ci * by a struct pcmcia_cfg_mem.
2988c2ecf20Sopenharmony_ci */
2998c2ecf20Sopenharmony_cistatic int pcmcia_do_loop_tuple(tuple_t *tuple, cisparse_t *parse, void *priv)
3008c2ecf20Sopenharmony_ci{
3018c2ecf20Sopenharmony_ci	struct pcmcia_loop_mem *loop = priv;
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	return loop->loop_tuple(loop->p_dev, tuple, loop->priv_data);
3048c2ecf20Sopenharmony_ci};
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci/**
3078c2ecf20Sopenharmony_ci * pcmcia_loop_tuple() - loop over tuples in the CIS
3088c2ecf20Sopenharmony_ci * @p_dev:	the struct pcmcia_device which we need to loop for.
3098c2ecf20Sopenharmony_ci * @code:	which CIS code shall we look for?
3108c2ecf20Sopenharmony_ci * @priv_data:	private data to be passed to the loop_tuple function.
3118c2ecf20Sopenharmony_ci * @loop_tuple:	function to call for each CIS entry of type @function. IT
3128c2ecf20Sopenharmony_ci *		gets passed the raw tuple and @priv_data.
3138c2ecf20Sopenharmony_ci *
3148c2ecf20Sopenharmony_ci * pcmcia_loop_tuple() loops over all CIS entries of type @function, and
3158c2ecf20Sopenharmony_ci * calls the @loop_tuple function for each entry. If the call to @loop_tuple
3168c2ecf20Sopenharmony_ci * returns 0, the loop exits. Returns 0 on success or errorcode otherwise.
3178c2ecf20Sopenharmony_ci */
3188c2ecf20Sopenharmony_ciint pcmcia_loop_tuple(struct pcmcia_device *p_dev, cisdata_t code,
3198c2ecf20Sopenharmony_ci		      int (*loop_tuple) (struct pcmcia_device *p_dev,
3208c2ecf20Sopenharmony_ci					 tuple_t *tuple,
3218c2ecf20Sopenharmony_ci					 void *priv_data),
3228c2ecf20Sopenharmony_ci		      void *priv_data)
3238c2ecf20Sopenharmony_ci{
3248c2ecf20Sopenharmony_ci	struct pcmcia_loop_mem loop = {
3258c2ecf20Sopenharmony_ci		.p_dev = p_dev,
3268c2ecf20Sopenharmony_ci		.loop_tuple = loop_tuple,
3278c2ecf20Sopenharmony_ci		.priv_data = priv_data};
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	return pccard_loop_tuple(p_dev->socket, p_dev->func, code, NULL,
3308c2ecf20Sopenharmony_ci				 &loop, pcmcia_do_loop_tuple);
3318c2ecf20Sopenharmony_ci}
3328c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pcmcia_loop_tuple);
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_cistruct pcmcia_loop_get {
3368c2ecf20Sopenharmony_ci	size_t len;
3378c2ecf20Sopenharmony_ci	cisdata_t **buf;
3388c2ecf20Sopenharmony_ci};
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci/**
3418c2ecf20Sopenharmony_ci * pcmcia_do_get_tuple() - internal helper for pcmcia_get_tuple()
3428c2ecf20Sopenharmony_ci *
3438c2ecf20Sopenharmony_ci * pcmcia_do_get_tuple() is the internal callback for the call from
3448c2ecf20Sopenharmony_ci * pcmcia_get_tuple() to pcmcia_loop_tuple(). As we're only interested in
3458c2ecf20Sopenharmony_ci * the first tuple, return 0 unconditionally. Create a memory buffer large
3468c2ecf20Sopenharmony_ci * enough to hold the content of the tuple, and fill it with the tuple data.
3478c2ecf20Sopenharmony_ci * The caller is responsible to free the buffer.
3488c2ecf20Sopenharmony_ci */
3498c2ecf20Sopenharmony_cistatic int pcmcia_do_get_tuple(struct pcmcia_device *p_dev, tuple_t *tuple,
3508c2ecf20Sopenharmony_ci			       void *priv)
3518c2ecf20Sopenharmony_ci{
3528c2ecf20Sopenharmony_ci	struct pcmcia_loop_get *get = priv;
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	*get->buf = kzalloc(tuple->TupleDataLen, GFP_KERNEL);
3558c2ecf20Sopenharmony_ci	if (*get->buf) {
3568c2ecf20Sopenharmony_ci		get->len = tuple->TupleDataLen;
3578c2ecf20Sopenharmony_ci		memcpy(*get->buf, tuple->TupleData, tuple->TupleDataLen);
3588c2ecf20Sopenharmony_ci	} else
3598c2ecf20Sopenharmony_ci		dev_dbg(&p_dev->dev, "do_get_tuple: out of memory\n");
3608c2ecf20Sopenharmony_ci	return 0;
3618c2ecf20Sopenharmony_ci}
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci/**
3648c2ecf20Sopenharmony_ci * pcmcia_get_tuple() - get first tuple from CIS
3658c2ecf20Sopenharmony_ci * @p_dev:	the struct pcmcia_device which we need to loop for.
3668c2ecf20Sopenharmony_ci * @code:	which CIS code shall we look for?
3678c2ecf20Sopenharmony_ci * @buf:        pointer to store the buffer to.
3688c2ecf20Sopenharmony_ci *
3698c2ecf20Sopenharmony_ci * pcmcia_get_tuple() gets the content of the first CIS entry of type @code.
3708c2ecf20Sopenharmony_ci * It returns the buffer length (or zero). The caller is responsible to free
3718c2ecf20Sopenharmony_ci * the buffer passed in @buf.
3728c2ecf20Sopenharmony_ci */
3738c2ecf20Sopenharmony_cisize_t pcmcia_get_tuple(struct pcmcia_device *p_dev, cisdata_t code,
3748c2ecf20Sopenharmony_ci			unsigned char **buf)
3758c2ecf20Sopenharmony_ci{
3768c2ecf20Sopenharmony_ci	struct pcmcia_loop_get get = {
3778c2ecf20Sopenharmony_ci		.len = 0,
3788c2ecf20Sopenharmony_ci		.buf = buf,
3798c2ecf20Sopenharmony_ci	};
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	*get.buf = NULL;
3828c2ecf20Sopenharmony_ci	pcmcia_loop_tuple(p_dev, code, pcmcia_do_get_tuple, &get);
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci	return get.len;
3858c2ecf20Sopenharmony_ci}
3868c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pcmcia_get_tuple);
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci/**
3908c2ecf20Sopenharmony_ci * pcmcia_do_get_mac() - internal helper for pcmcia_get_mac_from_cis()
3918c2ecf20Sopenharmony_ci *
3928c2ecf20Sopenharmony_ci * pcmcia_do_get_mac() is the internal callback for the call from
3938c2ecf20Sopenharmony_ci * pcmcia_get_mac_from_cis() to pcmcia_loop_tuple(). We check whether the
3948c2ecf20Sopenharmony_ci * tuple contains a proper LAN_NODE_ID of length 6, and copy the data
3958c2ecf20Sopenharmony_ci * to struct net_device->dev_addr[i].
3968c2ecf20Sopenharmony_ci */
3978c2ecf20Sopenharmony_cistatic int pcmcia_do_get_mac(struct pcmcia_device *p_dev, tuple_t *tuple,
3988c2ecf20Sopenharmony_ci			     void *priv)
3998c2ecf20Sopenharmony_ci{
4008c2ecf20Sopenharmony_ci	struct net_device *dev = priv;
4018c2ecf20Sopenharmony_ci	int i;
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci	if (tuple->TupleData[0] != CISTPL_FUNCE_LAN_NODE_ID)
4048c2ecf20Sopenharmony_ci		return -EINVAL;
4058c2ecf20Sopenharmony_ci	if (tuple->TupleDataLen < ETH_ALEN + 2) {
4068c2ecf20Sopenharmony_ci		dev_warn(&p_dev->dev, "Invalid CIS tuple length for "
4078c2ecf20Sopenharmony_ci			"LAN_NODE_ID\n");
4088c2ecf20Sopenharmony_ci		return -EINVAL;
4098c2ecf20Sopenharmony_ci	}
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci	if (tuple->TupleData[1] != ETH_ALEN) {
4128c2ecf20Sopenharmony_ci		dev_warn(&p_dev->dev, "Invalid header for LAN_NODE_ID\n");
4138c2ecf20Sopenharmony_ci		return -EINVAL;
4148c2ecf20Sopenharmony_ci	}
4158c2ecf20Sopenharmony_ci	for (i = 0; i < 6; i++)
4168c2ecf20Sopenharmony_ci		dev->dev_addr[i] = tuple->TupleData[i+2];
4178c2ecf20Sopenharmony_ci	return 0;
4188c2ecf20Sopenharmony_ci}
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci/**
4218c2ecf20Sopenharmony_ci * pcmcia_get_mac_from_cis() - read out MAC address from CISTPL_FUNCE
4228c2ecf20Sopenharmony_ci * @p_dev:	the struct pcmcia_device for which we want the address.
4238c2ecf20Sopenharmony_ci * @dev:	a properly prepared struct net_device to store the info to.
4248c2ecf20Sopenharmony_ci *
4258c2ecf20Sopenharmony_ci * pcmcia_get_mac_from_cis() reads out the hardware MAC address from
4268c2ecf20Sopenharmony_ci * CISTPL_FUNCE and stores it into struct net_device *dev->dev_addr which
4278c2ecf20Sopenharmony_ci * must be set up properly by the driver (see examples!).
4288c2ecf20Sopenharmony_ci */
4298c2ecf20Sopenharmony_ciint pcmcia_get_mac_from_cis(struct pcmcia_device *p_dev, struct net_device *dev)
4308c2ecf20Sopenharmony_ci{
4318c2ecf20Sopenharmony_ci	return pcmcia_loop_tuple(p_dev, CISTPL_FUNCE, pcmcia_do_get_mac, dev);
4328c2ecf20Sopenharmony_ci}
4338c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pcmcia_get_mac_from_cis);
4348c2ecf20Sopenharmony_ci
435