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