162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * PCMCIA high-level CIS access functions 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * The initial developer of the original code is David A. Hinds 662306a36Sopenharmony_ci * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds 762306a36Sopenharmony_ci * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Copyright (C) 1999 David A. Hinds 1062306a36Sopenharmony_ci * Copyright (C) 2004-2010 Dominik Brodowski 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <linux/slab.h> 1462306a36Sopenharmony_ci#include <linux/module.h> 1562306a36Sopenharmony_ci#include <linux/kernel.h> 1662306a36Sopenharmony_ci#include <linux/netdevice.h> 1762306a36Sopenharmony_ci#include <linux/etherdevice.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include <pcmcia/cisreg.h> 2062306a36Sopenharmony_ci#include <pcmcia/cistpl.h> 2162306a36Sopenharmony_ci#include <pcmcia/ss.h> 2262306a36Sopenharmony_ci#include <pcmcia/ds.h> 2362306a36Sopenharmony_ci#include "cs_internal.h" 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci/** 2762306a36Sopenharmony_ci * pccard_read_tuple() - internal CIS tuple access 2862306a36Sopenharmony_ci * @s: the struct pcmcia_socket where the card is inserted 2962306a36Sopenharmony_ci * @function: the device function we loop for 3062306a36Sopenharmony_ci * @code: which CIS code shall we look for? 3162306a36Sopenharmony_ci * @parse: buffer where the tuple shall be parsed (or NULL, if no parse) 3262306a36Sopenharmony_ci * 3362306a36Sopenharmony_ci * pccard_read_tuple() reads out one tuple and attempts to parse it 3462306a36Sopenharmony_ci */ 3562306a36Sopenharmony_ciint pccard_read_tuple(struct pcmcia_socket *s, unsigned int function, 3662306a36Sopenharmony_ci cisdata_t code, void *parse) 3762306a36Sopenharmony_ci{ 3862306a36Sopenharmony_ci tuple_t tuple; 3962306a36Sopenharmony_ci cisdata_t *buf; 4062306a36Sopenharmony_ci int ret; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci buf = kmalloc(256, GFP_KERNEL); 4362306a36Sopenharmony_ci if (buf == NULL) { 4462306a36Sopenharmony_ci dev_warn(&s->dev, "no memory to read tuple\n"); 4562306a36Sopenharmony_ci return -ENOMEM; 4662306a36Sopenharmony_ci } 4762306a36Sopenharmony_ci tuple.DesiredTuple = code; 4862306a36Sopenharmony_ci tuple.Attributes = 0; 4962306a36Sopenharmony_ci if (function == BIND_FN_ALL) 5062306a36Sopenharmony_ci tuple.Attributes = TUPLE_RETURN_COMMON; 5162306a36Sopenharmony_ci ret = pccard_get_first_tuple(s, function, &tuple); 5262306a36Sopenharmony_ci if (ret != 0) 5362306a36Sopenharmony_ci goto done; 5462306a36Sopenharmony_ci tuple.TupleData = buf; 5562306a36Sopenharmony_ci tuple.TupleOffset = 0; 5662306a36Sopenharmony_ci tuple.TupleDataMax = 255; 5762306a36Sopenharmony_ci ret = pccard_get_tuple_data(s, &tuple); 5862306a36Sopenharmony_ci if (ret != 0) 5962306a36Sopenharmony_ci goto done; 6062306a36Sopenharmony_ci ret = pcmcia_parse_tuple(&tuple, parse); 6162306a36Sopenharmony_cidone: 6262306a36Sopenharmony_ci kfree(buf); 6362306a36Sopenharmony_ci return ret; 6462306a36Sopenharmony_ci} 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci/** 6862306a36Sopenharmony_ci * pccard_loop_tuple() - loop over tuples in the CIS 6962306a36Sopenharmony_ci * @s: the struct pcmcia_socket where the card is inserted 7062306a36Sopenharmony_ci * @function: the device function we loop for 7162306a36Sopenharmony_ci * @code: which CIS code shall we look for? 7262306a36Sopenharmony_ci * @parse: buffer where the tuple shall be parsed (or NULL, if no parse) 7362306a36Sopenharmony_ci * @priv_data: private data to be passed to the loop_tuple function. 7462306a36Sopenharmony_ci * @loop_tuple: function to call for each CIS entry of type @function. IT 7562306a36Sopenharmony_ci * gets passed the raw tuple, the paresed tuple (if @parse is 7662306a36Sopenharmony_ci * set) and @priv_data. 7762306a36Sopenharmony_ci * 7862306a36Sopenharmony_ci * pccard_loop_tuple() loops over all CIS entries of type @function, and 7962306a36Sopenharmony_ci * calls the @loop_tuple function for each entry. If the call to @loop_tuple 8062306a36Sopenharmony_ci * returns 0, the loop exits. Returns 0 on success or errorcode otherwise. 8162306a36Sopenharmony_ci */ 8262306a36Sopenharmony_cistatic int pccard_loop_tuple(struct pcmcia_socket *s, unsigned int function, 8362306a36Sopenharmony_ci cisdata_t code, cisparse_t *parse, void *priv_data, 8462306a36Sopenharmony_ci int (*loop_tuple) (tuple_t *tuple, 8562306a36Sopenharmony_ci cisparse_t *parse, 8662306a36Sopenharmony_ci void *priv_data)) 8762306a36Sopenharmony_ci{ 8862306a36Sopenharmony_ci tuple_t tuple; 8962306a36Sopenharmony_ci cisdata_t *buf; 9062306a36Sopenharmony_ci int ret; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci buf = kzalloc(256, GFP_KERNEL); 9362306a36Sopenharmony_ci if (buf == NULL) { 9462306a36Sopenharmony_ci dev_warn(&s->dev, "no memory to read tuple\n"); 9562306a36Sopenharmony_ci return -ENOMEM; 9662306a36Sopenharmony_ci } 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci tuple.TupleData = buf; 9962306a36Sopenharmony_ci tuple.TupleDataMax = 255; 10062306a36Sopenharmony_ci tuple.TupleOffset = 0; 10162306a36Sopenharmony_ci tuple.DesiredTuple = code; 10262306a36Sopenharmony_ci tuple.Attributes = 0; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci ret = pccard_get_first_tuple(s, function, &tuple); 10562306a36Sopenharmony_ci while (!ret) { 10662306a36Sopenharmony_ci if (pccard_get_tuple_data(s, &tuple)) 10762306a36Sopenharmony_ci goto next_entry; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci if (parse) 11062306a36Sopenharmony_ci if (pcmcia_parse_tuple(&tuple, parse)) 11162306a36Sopenharmony_ci goto next_entry; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci ret = loop_tuple(&tuple, parse, priv_data); 11462306a36Sopenharmony_ci if (!ret) 11562306a36Sopenharmony_ci break; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_cinext_entry: 11862306a36Sopenharmony_ci ret = pccard_get_next_tuple(s, function, &tuple); 11962306a36Sopenharmony_ci } 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci kfree(buf); 12262306a36Sopenharmony_ci return ret; 12362306a36Sopenharmony_ci} 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci/* 12762306a36Sopenharmony_ci * pcmcia_io_cfg_data_width() - convert cfgtable to data path width parameter 12862306a36Sopenharmony_ci */ 12962306a36Sopenharmony_cistatic int pcmcia_io_cfg_data_width(unsigned int flags) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci if (!(flags & CISTPL_IO_8BIT)) 13262306a36Sopenharmony_ci return IO_DATA_PATH_WIDTH_16; 13362306a36Sopenharmony_ci if (!(flags & CISTPL_IO_16BIT)) 13462306a36Sopenharmony_ci return IO_DATA_PATH_WIDTH_8; 13562306a36Sopenharmony_ci return IO_DATA_PATH_WIDTH_AUTO; 13662306a36Sopenharmony_ci} 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_cistruct pcmcia_cfg_mem { 14062306a36Sopenharmony_ci struct pcmcia_device *p_dev; 14162306a36Sopenharmony_ci int (*conf_check) (struct pcmcia_device *p_dev, void *priv_data); 14262306a36Sopenharmony_ci void *priv_data; 14362306a36Sopenharmony_ci cisparse_t parse; 14462306a36Sopenharmony_ci cistpl_cftable_entry_t dflt; 14562306a36Sopenharmony_ci}; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci/* 14862306a36Sopenharmony_ci * pcmcia_do_loop_config() - internal helper for pcmcia_loop_config() 14962306a36Sopenharmony_ci * 15062306a36Sopenharmony_ci * pcmcia_do_loop_config() is the internal callback for the call from 15162306a36Sopenharmony_ci * pcmcia_loop_config() to pccard_loop_tuple(). Data is transferred 15262306a36Sopenharmony_ci * by a struct pcmcia_cfg_mem. 15362306a36Sopenharmony_ci */ 15462306a36Sopenharmony_cistatic int pcmcia_do_loop_config(tuple_t *tuple, cisparse_t *parse, void *priv) 15562306a36Sopenharmony_ci{ 15662306a36Sopenharmony_ci struct pcmcia_cfg_mem *cfg_mem = priv; 15762306a36Sopenharmony_ci struct pcmcia_device *p_dev = cfg_mem->p_dev; 15862306a36Sopenharmony_ci cistpl_cftable_entry_t *cfg = &parse->cftable_entry; 15962306a36Sopenharmony_ci cistpl_cftable_entry_t *dflt = &cfg_mem->dflt; 16062306a36Sopenharmony_ci unsigned int flags = p_dev->config_flags; 16162306a36Sopenharmony_ci unsigned int vcc = p_dev->socket->socket.Vcc; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci dev_dbg(&p_dev->dev, "testing configuration %x, autoconf %x\n", 16462306a36Sopenharmony_ci cfg->index, flags); 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci /* default values */ 16762306a36Sopenharmony_ci cfg_mem->p_dev->config_index = cfg->index; 16862306a36Sopenharmony_ci if (cfg->flags & CISTPL_CFTABLE_DEFAULT) 16962306a36Sopenharmony_ci cfg_mem->dflt = *cfg; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci /* check for matching Vcc? */ 17262306a36Sopenharmony_ci if (flags & CONF_AUTO_CHECK_VCC) { 17362306a36Sopenharmony_ci if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) { 17462306a36Sopenharmony_ci if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) 17562306a36Sopenharmony_ci return -ENODEV; 17662306a36Sopenharmony_ci } else if (dflt->vcc.present & (1 << CISTPL_POWER_VNOM)) { 17762306a36Sopenharmony_ci if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM] / 10000) 17862306a36Sopenharmony_ci return -ENODEV; 17962306a36Sopenharmony_ci } 18062306a36Sopenharmony_ci } 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci /* set Vpp? */ 18362306a36Sopenharmony_ci if (flags & CONF_AUTO_SET_VPP) { 18462306a36Sopenharmony_ci if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) 18562306a36Sopenharmony_ci p_dev->vpp = cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; 18662306a36Sopenharmony_ci else if (dflt->vpp1.present & (1 << CISTPL_POWER_VNOM)) 18762306a36Sopenharmony_ci p_dev->vpp = 18862306a36Sopenharmony_ci dflt->vpp1.param[CISTPL_POWER_VNOM] / 10000; 18962306a36Sopenharmony_ci } 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci /* enable audio? */ 19262306a36Sopenharmony_ci if ((flags & CONF_AUTO_AUDIO) && (cfg->flags & CISTPL_CFTABLE_AUDIO)) 19362306a36Sopenharmony_ci p_dev->config_flags |= CONF_ENABLE_SPKR; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci /* IO window settings? */ 19762306a36Sopenharmony_ci if (flags & CONF_AUTO_SET_IO) { 19862306a36Sopenharmony_ci cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io; 19962306a36Sopenharmony_ci int i = 0; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci p_dev->resource[0]->start = p_dev->resource[0]->end = 0; 20262306a36Sopenharmony_ci p_dev->resource[1]->start = p_dev->resource[1]->end = 0; 20362306a36Sopenharmony_ci if (io->nwin == 0) 20462306a36Sopenharmony_ci return -ENODEV; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; 20762306a36Sopenharmony_ci p_dev->resource[0]->flags |= 20862306a36Sopenharmony_ci pcmcia_io_cfg_data_width(io->flags); 20962306a36Sopenharmony_ci if (io->nwin > 1) { 21062306a36Sopenharmony_ci /* For multifunction cards, by convention, we 21162306a36Sopenharmony_ci * configure the network function with window 0, 21262306a36Sopenharmony_ci * and serial with window 1 */ 21362306a36Sopenharmony_ci i = (io->win[1].len > io->win[0].len); 21462306a36Sopenharmony_ci p_dev->resource[1]->flags = p_dev->resource[0]->flags; 21562306a36Sopenharmony_ci p_dev->resource[1]->start = io->win[1-i].base; 21662306a36Sopenharmony_ci p_dev->resource[1]->end = io->win[1-i].len; 21762306a36Sopenharmony_ci } 21862306a36Sopenharmony_ci p_dev->resource[0]->start = io->win[i].base; 21962306a36Sopenharmony_ci p_dev->resource[0]->end = io->win[i].len; 22062306a36Sopenharmony_ci p_dev->io_lines = io->flags & CISTPL_IO_LINES_MASK; 22162306a36Sopenharmony_ci } 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci /* MEM window settings? */ 22462306a36Sopenharmony_ci if (flags & CONF_AUTO_SET_IOMEM) { 22562306a36Sopenharmony_ci /* so far, we only set one memory window */ 22662306a36Sopenharmony_ci cistpl_mem_t *mem = (cfg->mem.nwin) ? &cfg->mem : &dflt->mem; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci p_dev->resource[2]->start = p_dev->resource[2]->end = 0; 22962306a36Sopenharmony_ci if (mem->nwin == 0) 23062306a36Sopenharmony_ci return -ENODEV; 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci p_dev->resource[2]->start = mem->win[0].host_addr; 23362306a36Sopenharmony_ci p_dev->resource[2]->end = mem->win[0].len; 23462306a36Sopenharmony_ci if (p_dev->resource[2]->end < 0x1000) 23562306a36Sopenharmony_ci p_dev->resource[2]->end = 0x1000; 23662306a36Sopenharmony_ci p_dev->card_addr = mem->win[0].card_addr; 23762306a36Sopenharmony_ci } 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci dev_dbg(&p_dev->dev, 24062306a36Sopenharmony_ci "checking configuration %x: %pr %pr %pr (%d lines)\n", 24162306a36Sopenharmony_ci p_dev->config_index, p_dev->resource[0], p_dev->resource[1], 24262306a36Sopenharmony_ci p_dev->resource[2], p_dev->io_lines); 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci return cfg_mem->conf_check(p_dev, cfg_mem->priv_data); 24562306a36Sopenharmony_ci} 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci/** 24862306a36Sopenharmony_ci * pcmcia_loop_config() - loop over configuration options 24962306a36Sopenharmony_ci * @p_dev: the struct pcmcia_device which we need to loop for. 25062306a36Sopenharmony_ci * @conf_check: function to call for each configuration option. 25162306a36Sopenharmony_ci * It gets passed the struct pcmcia_device and private data 25262306a36Sopenharmony_ci * being passed to pcmcia_loop_config() 25362306a36Sopenharmony_ci * @priv_data: private data to be passed to the conf_check function. 25462306a36Sopenharmony_ci * 25562306a36Sopenharmony_ci * pcmcia_loop_config() loops over all configuration options, and calls 25662306a36Sopenharmony_ci * the driver-specific conf_check() for each one, checking whether 25762306a36Sopenharmony_ci * it is a valid one. Returns 0 on success or errorcode otherwise. 25862306a36Sopenharmony_ci */ 25962306a36Sopenharmony_ciint pcmcia_loop_config(struct pcmcia_device *p_dev, 26062306a36Sopenharmony_ci int (*conf_check) (struct pcmcia_device *p_dev, 26162306a36Sopenharmony_ci void *priv_data), 26262306a36Sopenharmony_ci void *priv_data) 26362306a36Sopenharmony_ci{ 26462306a36Sopenharmony_ci struct pcmcia_cfg_mem *cfg_mem; 26562306a36Sopenharmony_ci int ret; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci cfg_mem = kzalloc(sizeof(struct pcmcia_cfg_mem), GFP_KERNEL); 26862306a36Sopenharmony_ci if (cfg_mem == NULL) 26962306a36Sopenharmony_ci return -ENOMEM; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci cfg_mem->p_dev = p_dev; 27262306a36Sopenharmony_ci cfg_mem->conf_check = conf_check; 27362306a36Sopenharmony_ci cfg_mem->priv_data = priv_data; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci ret = pccard_loop_tuple(p_dev->socket, p_dev->func, 27662306a36Sopenharmony_ci CISTPL_CFTABLE_ENTRY, &cfg_mem->parse, 27762306a36Sopenharmony_ci cfg_mem, pcmcia_do_loop_config); 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci kfree(cfg_mem); 28062306a36Sopenharmony_ci return ret; 28162306a36Sopenharmony_ci} 28262306a36Sopenharmony_ciEXPORT_SYMBOL(pcmcia_loop_config); 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_cistruct pcmcia_loop_mem { 28662306a36Sopenharmony_ci struct pcmcia_device *p_dev; 28762306a36Sopenharmony_ci void *priv_data; 28862306a36Sopenharmony_ci int (*loop_tuple) (struct pcmcia_device *p_dev, 28962306a36Sopenharmony_ci tuple_t *tuple, 29062306a36Sopenharmony_ci void *priv_data); 29162306a36Sopenharmony_ci}; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci/* 29462306a36Sopenharmony_ci * pcmcia_do_loop_tuple() - internal helper for pcmcia_loop_config() 29562306a36Sopenharmony_ci * 29662306a36Sopenharmony_ci * pcmcia_do_loop_tuple() is the internal callback for the call from 29762306a36Sopenharmony_ci * pcmcia_loop_tuple() to pccard_loop_tuple(). Data is transferred 29862306a36Sopenharmony_ci * by a struct pcmcia_cfg_mem. 29962306a36Sopenharmony_ci */ 30062306a36Sopenharmony_cistatic int pcmcia_do_loop_tuple(tuple_t *tuple, cisparse_t *parse, void *priv) 30162306a36Sopenharmony_ci{ 30262306a36Sopenharmony_ci struct pcmcia_loop_mem *loop = priv; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci return loop->loop_tuple(loop->p_dev, tuple, loop->priv_data); 30562306a36Sopenharmony_ci}; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci/** 30862306a36Sopenharmony_ci * pcmcia_loop_tuple() - loop over tuples in the CIS 30962306a36Sopenharmony_ci * @p_dev: the struct pcmcia_device which we need to loop for. 31062306a36Sopenharmony_ci * @code: which CIS code shall we look for? 31162306a36Sopenharmony_ci * @priv_data: private data to be passed to the loop_tuple function. 31262306a36Sopenharmony_ci * @loop_tuple: function to call for each CIS entry of type @function. IT 31362306a36Sopenharmony_ci * gets passed the raw tuple and @priv_data. 31462306a36Sopenharmony_ci * 31562306a36Sopenharmony_ci * pcmcia_loop_tuple() loops over all CIS entries of type @function, and 31662306a36Sopenharmony_ci * calls the @loop_tuple function for each entry. If the call to @loop_tuple 31762306a36Sopenharmony_ci * returns 0, the loop exits. Returns 0 on success or errorcode otherwise. 31862306a36Sopenharmony_ci */ 31962306a36Sopenharmony_ciint pcmcia_loop_tuple(struct pcmcia_device *p_dev, cisdata_t code, 32062306a36Sopenharmony_ci int (*loop_tuple) (struct pcmcia_device *p_dev, 32162306a36Sopenharmony_ci tuple_t *tuple, 32262306a36Sopenharmony_ci void *priv_data), 32362306a36Sopenharmony_ci void *priv_data) 32462306a36Sopenharmony_ci{ 32562306a36Sopenharmony_ci struct pcmcia_loop_mem loop = { 32662306a36Sopenharmony_ci .p_dev = p_dev, 32762306a36Sopenharmony_ci .loop_tuple = loop_tuple, 32862306a36Sopenharmony_ci .priv_data = priv_data}; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci return pccard_loop_tuple(p_dev->socket, p_dev->func, code, NULL, 33162306a36Sopenharmony_ci &loop, pcmcia_do_loop_tuple); 33262306a36Sopenharmony_ci} 33362306a36Sopenharmony_ciEXPORT_SYMBOL(pcmcia_loop_tuple); 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_cistruct pcmcia_loop_get { 33762306a36Sopenharmony_ci size_t len; 33862306a36Sopenharmony_ci cisdata_t **buf; 33962306a36Sopenharmony_ci}; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci/* 34262306a36Sopenharmony_ci * pcmcia_do_get_tuple() - internal helper for pcmcia_get_tuple() 34362306a36Sopenharmony_ci * 34462306a36Sopenharmony_ci * pcmcia_do_get_tuple() is the internal callback for the call from 34562306a36Sopenharmony_ci * pcmcia_get_tuple() to pcmcia_loop_tuple(). As we're only interested in 34662306a36Sopenharmony_ci * the first tuple, return 0 unconditionally. Create a memory buffer large 34762306a36Sopenharmony_ci * enough to hold the content of the tuple, and fill it with the tuple data. 34862306a36Sopenharmony_ci * The caller is responsible to free the buffer. 34962306a36Sopenharmony_ci */ 35062306a36Sopenharmony_cistatic int pcmcia_do_get_tuple(struct pcmcia_device *p_dev, tuple_t *tuple, 35162306a36Sopenharmony_ci void *priv) 35262306a36Sopenharmony_ci{ 35362306a36Sopenharmony_ci struct pcmcia_loop_get *get = priv; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci *get->buf = kzalloc(tuple->TupleDataLen, GFP_KERNEL); 35662306a36Sopenharmony_ci if (*get->buf) { 35762306a36Sopenharmony_ci get->len = tuple->TupleDataLen; 35862306a36Sopenharmony_ci memcpy(*get->buf, tuple->TupleData, tuple->TupleDataLen); 35962306a36Sopenharmony_ci } else 36062306a36Sopenharmony_ci dev_dbg(&p_dev->dev, "do_get_tuple: out of memory\n"); 36162306a36Sopenharmony_ci return 0; 36262306a36Sopenharmony_ci} 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci/** 36562306a36Sopenharmony_ci * pcmcia_get_tuple() - get first tuple from CIS 36662306a36Sopenharmony_ci * @p_dev: the struct pcmcia_device which we need to loop for. 36762306a36Sopenharmony_ci * @code: which CIS code shall we look for? 36862306a36Sopenharmony_ci * @buf: pointer to store the buffer to. 36962306a36Sopenharmony_ci * 37062306a36Sopenharmony_ci * pcmcia_get_tuple() gets the content of the first CIS entry of type @code. 37162306a36Sopenharmony_ci * It returns the buffer length (or zero). The caller is responsible to free 37262306a36Sopenharmony_ci * the buffer passed in @buf. 37362306a36Sopenharmony_ci */ 37462306a36Sopenharmony_cisize_t pcmcia_get_tuple(struct pcmcia_device *p_dev, cisdata_t code, 37562306a36Sopenharmony_ci unsigned char **buf) 37662306a36Sopenharmony_ci{ 37762306a36Sopenharmony_ci struct pcmcia_loop_get get = { 37862306a36Sopenharmony_ci .len = 0, 37962306a36Sopenharmony_ci .buf = buf, 38062306a36Sopenharmony_ci }; 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci *get.buf = NULL; 38362306a36Sopenharmony_ci pcmcia_loop_tuple(p_dev, code, pcmcia_do_get_tuple, &get); 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci return get.len; 38662306a36Sopenharmony_ci} 38762306a36Sopenharmony_ciEXPORT_SYMBOL(pcmcia_get_tuple); 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci#ifdef CONFIG_NET 39062306a36Sopenharmony_ci/* 39162306a36Sopenharmony_ci * pcmcia_do_get_mac() - internal helper for pcmcia_get_mac_from_cis() 39262306a36Sopenharmony_ci * 39362306a36Sopenharmony_ci * pcmcia_do_get_mac() is the internal callback for the call from 39462306a36Sopenharmony_ci * pcmcia_get_mac_from_cis() to pcmcia_loop_tuple(). We check whether the 39562306a36Sopenharmony_ci * tuple contains a proper LAN_NODE_ID of length 6, and copy the data 39662306a36Sopenharmony_ci * to struct net_device->dev_addr[i]. 39762306a36Sopenharmony_ci */ 39862306a36Sopenharmony_cistatic int pcmcia_do_get_mac(struct pcmcia_device *p_dev, tuple_t *tuple, 39962306a36Sopenharmony_ci void *priv) 40062306a36Sopenharmony_ci{ 40162306a36Sopenharmony_ci struct net_device *dev = priv; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci if (tuple->TupleData[0] != CISTPL_FUNCE_LAN_NODE_ID) 40462306a36Sopenharmony_ci return -EINVAL; 40562306a36Sopenharmony_ci if (tuple->TupleDataLen < ETH_ALEN + 2) { 40662306a36Sopenharmony_ci dev_warn(&p_dev->dev, "Invalid CIS tuple length for " 40762306a36Sopenharmony_ci "LAN_NODE_ID\n"); 40862306a36Sopenharmony_ci return -EINVAL; 40962306a36Sopenharmony_ci } 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci if (tuple->TupleData[1] != ETH_ALEN) { 41262306a36Sopenharmony_ci dev_warn(&p_dev->dev, "Invalid header for LAN_NODE_ID\n"); 41362306a36Sopenharmony_ci return -EINVAL; 41462306a36Sopenharmony_ci } 41562306a36Sopenharmony_ci eth_hw_addr_set(dev, &tuple->TupleData[2]); 41662306a36Sopenharmony_ci return 0; 41762306a36Sopenharmony_ci} 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci/** 42062306a36Sopenharmony_ci * pcmcia_get_mac_from_cis() - read out MAC address from CISTPL_FUNCE 42162306a36Sopenharmony_ci * @p_dev: the struct pcmcia_device for which we want the address. 42262306a36Sopenharmony_ci * @dev: a properly prepared struct net_device to store the info to. 42362306a36Sopenharmony_ci * 42462306a36Sopenharmony_ci * pcmcia_get_mac_from_cis() reads out the hardware MAC address from 42562306a36Sopenharmony_ci * CISTPL_FUNCE and stores it into struct net_device *dev->dev_addr which 42662306a36Sopenharmony_ci * must be set up properly by the driver (see examples!). 42762306a36Sopenharmony_ci */ 42862306a36Sopenharmony_ciint pcmcia_get_mac_from_cis(struct pcmcia_device *p_dev, struct net_device *dev) 42962306a36Sopenharmony_ci{ 43062306a36Sopenharmony_ci return pcmcia_loop_tuple(p_dev, CISTPL_FUNCE, pcmcia_do_get_mac, dev); 43162306a36Sopenharmony_ci} 43262306a36Sopenharmony_ciEXPORT_SYMBOL(pcmcia_get_mac_from_cis); 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci#endif /* CONFIG_NET */ 435