/* * pcmcia_device_query -- determine information about a pcmcia device */ static int pcmcia_device_query(struct pcmcia_device *p_dev) { cistpl_manfid_t manf_id; cistpl_funcid_t func_id; cistpl_vers_1_t vers1; unsigned int i; if (!pccard_read_tuple(p_dev->socket, p_dev->func, CISTPL_MANFID, &manf_id)) { p_dev->manf_id = manf_id.manf; p_dev->card_id = manf_id.card; p_dev->has_manf_id = 1; p_dev->has_card_id = 1; } if (!pccard_read_tuple(p_dev->socket, p_dev->func, CISTPL_FUNCID, &func_id)) { p_dev->func_id = func_id.func; p_dev->has_func_id = 1; } else { /* rule of thumb: cards with no FUNCID, but with * common memory device geometry information, are * probably memory cards (from pcmcia-cs) */ cistpl_device_geo_t devgeo; if (!pccard_read_tuple(p_dev->socket, p_dev->func, CISTPL_DEVICE_GEO, &devgeo)) { ds_dbg(0, "mem device geometry probably means " "FUNCID_MEMORY\n"); p_dev->func_id = CISTPL_FUNCID_MEMORY; p_dev->has_func_id = 1; } } if (!pccard_read_tuple(p_dev->socket, p_dev->func, CISTPL_VERS_1, &vers1)) { for (i=0; i < vers1.ns; i++) { char *tmp; unsigned int length; tmp = vers1.str + vers1.ofs[i]; length = strlen(tmp) + 1; if ((length < 3) || (length > 255)) continue; p_dev->prod_id[i] = kmalloc(sizeof(char) * length, GFP_KERNEL); if (!p_dev->prod_id[i]) continue; p_dev->prod_id[i] = strncpy(p_dev->prod_id[i], tmp, length); } } return 0; }
static int pcmcia_card_add(struct pcmcia_socket *s) { cisinfo_t cisinfo; cistpl_longlink_mfc_t mfc; unsigned int no_funcs, i; int ret = 0; if (!(s->resource_setup_done)) return -EAGAIN; /* try again, but later... */ if (pcmcia_validate_mem(s)) return -EAGAIN; /* try again, but later... */ ret = pccard_validate_cis(s, BIND_FN_ALL, &cisinfo); if (ret || !cisinfo.Chains) { ds_dbg(0, "invalid CIS or invalid resources\n"); return -ENODEV; } if (!pccard_read_tuple(s, BIND_FN_ALL, CISTPL_LONGLINK_MFC, &mfc)) no_funcs = mfc.nfn; else no_funcs = 1; for (i=0; i < no_funcs; i++) pcmcia_device_add(s, i); return (ret); }
static int pcmcia_device_probe(struct device * dev) { struct pcmcia_device *p_dev; struct pcmcia_driver *p_drv; struct pcmcia_device_id *did; struct pcmcia_socket *s; int ret = 0; dev = get_device(dev); if (!dev) return -ENODEV; p_dev = to_pcmcia_dev(dev); p_drv = to_pcmcia_drv(dev->driver); s = p_dev->socket; if ((!p_drv->probe) || (!try_module_get(p_drv->owner))) { ret = -EINVAL; goto put_dev; } p_dev->state &= ~CLIENT_UNBOUND; /* set up the device configuration, if it hasn't been done before */ if (!s->functions) { cistpl_longlink_mfc_t mfc; if (pccard_read_tuple(s, p_dev->func, CISTPL_LONGLINK_MFC, &mfc) == CS_SUCCESS) s->functions = mfc.nfn; else s->functions = 1; s->config = kzalloc(sizeof(config_t) * s->functions, GFP_KERNEL); if (!s->config) { ret = -ENOMEM; goto put_module; } } ret = p_drv->probe(p_dev); if (ret) goto put_module; /* handle pseudo multifunction devices: * there are at most two pseudo multifunction devices. * if we're matching against the first, schedule a * call which will then check whether there are two * pseudo devices, and if not, add the second one. */ did = (struct pcmcia_device_id *) p_dev->dev.driver_data; if (did && (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) && (p_dev->socket->device_count == 1) && (p_dev->device_no == 0)) pcmcia_add_pseudo_device(p_dev->socket); put_module: if (ret) module_put(p_drv->owner); put_dev: if (ret) put_device(dev); return (ret); }