162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * card.c - contains functions for managing groups of PnP devices 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright 2002 Adam Belay <ambx1@neo.rr.com> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/module.h> 962306a36Sopenharmony_ci#include <linux/mutex.h> 1062306a36Sopenharmony_ci#include <linux/ctype.h> 1162306a36Sopenharmony_ci#include <linux/slab.h> 1262306a36Sopenharmony_ci#include <linux/pnp.h> 1362306a36Sopenharmony_ci#include <linux/dma-mapping.h> 1462306a36Sopenharmony_ci#include "base.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ciLIST_HEAD(pnp_cards); 1762306a36Sopenharmony_cistatic LIST_HEAD(pnp_card_drivers); 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_cistatic const struct pnp_card_device_id *match_card(struct pnp_card_driver *drv, 2062306a36Sopenharmony_ci struct pnp_card *card) 2162306a36Sopenharmony_ci{ 2262306a36Sopenharmony_ci const struct pnp_card_device_id *drv_id = drv->id_table; 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci while (*drv_id->id) { 2562306a36Sopenharmony_ci if (compare_pnp_id(card->id, drv_id->id)) { 2662306a36Sopenharmony_ci int i = 0; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci for (;;) { 2962306a36Sopenharmony_ci int found; 3062306a36Sopenharmony_ci struct pnp_dev *dev; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci if (i == PNP_MAX_DEVICES || 3362306a36Sopenharmony_ci !*drv_id->devs[i].id) 3462306a36Sopenharmony_ci return drv_id; 3562306a36Sopenharmony_ci found = 0; 3662306a36Sopenharmony_ci card_for_each_dev(card, dev) { 3762306a36Sopenharmony_ci if (compare_pnp_id(dev->id, 3862306a36Sopenharmony_ci drv_id->devs[i].id)) { 3962306a36Sopenharmony_ci found = 1; 4062306a36Sopenharmony_ci break; 4162306a36Sopenharmony_ci } 4262306a36Sopenharmony_ci } 4362306a36Sopenharmony_ci if (!found) 4462306a36Sopenharmony_ci break; 4562306a36Sopenharmony_ci i++; 4662306a36Sopenharmony_ci } 4762306a36Sopenharmony_ci } 4862306a36Sopenharmony_ci drv_id++; 4962306a36Sopenharmony_ci } 5062306a36Sopenharmony_ci return NULL; 5162306a36Sopenharmony_ci} 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistatic void card_remove(struct pnp_dev *dev) 5462306a36Sopenharmony_ci{ 5562306a36Sopenharmony_ci dev->card_link = NULL; 5662306a36Sopenharmony_ci} 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_cistatic void card_remove_first(struct pnp_dev *dev) 5962306a36Sopenharmony_ci{ 6062306a36Sopenharmony_ci struct pnp_card_driver *drv = to_pnp_card_driver(dev->driver); 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci if (!dev->card || !drv) 6362306a36Sopenharmony_ci return; 6462306a36Sopenharmony_ci if (drv->remove) 6562306a36Sopenharmony_ci drv->remove(dev->card_link); 6662306a36Sopenharmony_ci drv->link.remove = &card_remove; 6762306a36Sopenharmony_ci kfree(dev->card_link); 6862306a36Sopenharmony_ci card_remove(dev); 6962306a36Sopenharmony_ci} 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistatic int card_probe(struct pnp_card *card, struct pnp_card_driver *drv) 7262306a36Sopenharmony_ci{ 7362306a36Sopenharmony_ci const struct pnp_card_device_id *id; 7462306a36Sopenharmony_ci struct pnp_card_link *clink; 7562306a36Sopenharmony_ci struct pnp_dev *dev; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci if (!drv->probe) 7862306a36Sopenharmony_ci return 0; 7962306a36Sopenharmony_ci id = match_card(drv, card); 8062306a36Sopenharmony_ci if (!id) 8162306a36Sopenharmony_ci return 0; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci clink = kzalloc(sizeof(*clink), GFP_KERNEL); 8462306a36Sopenharmony_ci if (!clink) 8562306a36Sopenharmony_ci return 0; 8662306a36Sopenharmony_ci clink->card = card; 8762306a36Sopenharmony_ci clink->driver = drv; 8862306a36Sopenharmony_ci clink->pm_state = PMSG_ON; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci if (drv->probe(clink, id) >= 0) 9162306a36Sopenharmony_ci return 1; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci /* Recovery */ 9462306a36Sopenharmony_ci card_for_each_dev(card, dev) { 9562306a36Sopenharmony_ci if (dev->card_link == clink) 9662306a36Sopenharmony_ci pnp_release_card_device(dev); 9762306a36Sopenharmony_ci } 9862306a36Sopenharmony_ci kfree(clink); 9962306a36Sopenharmony_ci return 0; 10062306a36Sopenharmony_ci} 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci/** 10362306a36Sopenharmony_ci * pnp_add_card_id - adds an EISA id to the specified card 10462306a36Sopenharmony_ci * @id: pointer to a pnp_id structure 10562306a36Sopenharmony_ci * @card: pointer to the desired card 10662306a36Sopenharmony_ci */ 10762306a36Sopenharmony_cistatic struct pnp_id *pnp_add_card_id(struct pnp_card *card, char *id) 10862306a36Sopenharmony_ci{ 10962306a36Sopenharmony_ci struct pnp_id *dev_id, *ptr; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci dev_id = kzalloc(sizeof(struct pnp_id), GFP_KERNEL); 11262306a36Sopenharmony_ci if (!dev_id) 11362306a36Sopenharmony_ci return NULL; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci dev_id->id[0] = id[0]; 11662306a36Sopenharmony_ci dev_id->id[1] = id[1]; 11762306a36Sopenharmony_ci dev_id->id[2] = id[2]; 11862306a36Sopenharmony_ci dev_id->id[3] = tolower(id[3]); 11962306a36Sopenharmony_ci dev_id->id[4] = tolower(id[4]); 12062306a36Sopenharmony_ci dev_id->id[5] = tolower(id[5]); 12162306a36Sopenharmony_ci dev_id->id[6] = tolower(id[6]); 12262306a36Sopenharmony_ci dev_id->id[7] = '\0'; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci dev_id->next = NULL; 12562306a36Sopenharmony_ci ptr = card->id; 12662306a36Sopenharmony_ci while (ptr && ptr->next) 12762306a36Sopenharmony_ci ptr = ptr->next; 12862306a36Sopenharmony_ci if (ptr) 12962306a36Sopenharmony_ci ptr->next = dev_id; 13062306a36Sopenharmony_ci else 13162306a36Sopenharmony_ci card->id = dev_id; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci return dev_id; 13462306a36Sopenharmony_ci} 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_cistatic void pnp_free_card_ids(struct pnp_card *card) 13762306a36Sopenharmony_ci{ 13862306a36Sopenharmony_ci struct pnp_id *id; 13962306a36Sopenharmony_ci struct pnp_id *next; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci id = card->id; 14262306a36Sopenharmony_ci while (id) { 14362306a36Sopenharmony_ci next = id->next; 14462306a36Sopenharmony_ci kfree(id); 14562306a36Sopenharmony_ci id = next; 14662306a36Sopenharmony_ci } 14762306a36Sopenharmony_ci} 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_cistatic void pnp_release_card(struct device *dmdev) 15062306a36Sopenharmony_ci{ 15162306a36Sopenharmony_ci struct pnp_card *card = to_pnp_card(dmdev); 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci pnp_free_card_ids(card); 15462306a36Sopenharmony_ci kfree(card); 15562306a36Sopenharmony_ci} 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_cistruct pnp_card *pnp_alloc_card(struct pnp_protocol *protocol, int id, char *pnpid) 15862306a36Sopenharmony_ci{ 15962306a36Sopenharmony_ci struct pnp_card *card; 16062306a36Sopenharmony_ci struct pnp_id *dev_id; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci card = kzalloc(sizeof(struct pnp_card), GFP_KERNEL); 16362306a36Sopenharmony_ci if (!card) 16462306a36Sopenharmony_ci return NULL; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci card->protocol = protocol; 16762306a36Sopenharmony_ci card->number = id; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci card->dev.parent = &card->protocol->dev; 17062306a36Sopenharmony_ci dev_set_name(&card->dev, "%02x:%02x", card->protocol->number, card->number); 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci card->dev.coherent_dma_mask = DMA_BIT_MASK(24); 17362306a36Sopenharmony_ci card->dev.dma_mask = &card->dev.coherent_dma_mask; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci dev_id = pnp_add_card_id(card, pnpid); 17662306a36Sopenharmony_ci if (!dev_id) { 17762306a36Sopenharmony_ci kfree(card); 17862306a36Sopenharmony_ci return NULL; 17962306a36Sopenharmony_ci } 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci return card; 18262306a36Sopenharmony_ci} 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_cistatic ssize_t name_show(struct device *dmdev, 18562306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 18662306a36Sopenharmony_ci{ 18762306a36Sopenharmony_ci char *str = buf; 18862306a36Sopenharmony_ci struct pnp_card *card = to_pnp_card(dmdev); 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci str += sprintf(str, "%s\n", card->name); 19162306a36Sopenharmony_ci return (str - buf); 19262306a36Sopenharmony_ci} 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_cistatic DEVICE_ATTR_RO(name); 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_cistatic ssize_t card_id_show(struct device *dmdev, 19762306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 19862306a36Sopenharmony_ci{ 19962306a36Sopenharmony_ci char *str = buf; 20062306a36Sopenharmony_ci struct pnp_card *card = to_pnp_card(dmdev); 20162306a36Sopenharmony_ci struct pnp_id *pos = card->id; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci while (pos) { 20462306a36Sopenharmony_ci str += sprintf(str, "%s\n", pos->id); 20562306a36Sopenharmony_ci pos = pos->next; 20662306a36Sopenharmony_ci } 20762306a36Sopenharmony_ci return (str - buf); 20862306a36Sopenharmony_ci} 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_cistatic DEVICE_ATTR_RO(card_id); 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_cistatic int pnp_interface_attach_card(struct pnp_card *card) 21362306a36Sopenharmony_ci{ 21462306a36Sopenharmony_ci int rc = device_create_file(&card->dev, &dev_attr_name); 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci if (rc) 21762306a36Sopenharmony_ci return rc; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci rc = device_create_file(&card->dev, &dev_attr_card_id); 22062306a36Sopenharmony_ci if (rc) 22162306a36Sopenharmony_ci goto err_name; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci return 0; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_cierr_name: 22662306a36Sopenharmony_ci device_remove_file(&card->dev, &dev_attr_name); 22762306a36Sopenharmony_ci return rc; 22862306a36Sopenharmony_ci} 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci/** 23162306a36Sopenharmony_ci * pnp_add_card - adds a PnP card to the PnP Layer 23262306a36Sopenharmony_ci * @card: pointer to the card to add 23362306a36Sopenharmony_ci */ 23462306a36Sopenharmony_ciint pnp_add_card(struct pnp_card *card) 23562306a36Sopenharmony_ci{ 23662306a36Sopenharmony_ci int error; 23762306a36Sopenharmony_ci struct list_head *pos, *temp; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci card->dev.bus = NULL; 24062306a36Sopenharmony_ci card->dev.release = &pnp_release_card; 24162306a36Sopenharmony_ci error = device_register(&card->dev); 24262306a36Sopenharmony_ci if (error) { 24362306a36Sopenharmony_ci dev_err(&card->dev, "could not register (err=%d)\n", error); 24462306a36Sopenharmony_ci put_device(&card->dev); 24562306a36Sopenharmony_ci return error; 24662306a36Sopenharmony_ci } 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci pnp_interface_attach_card(card); 24962306a36Sopenharmony_ci mutex_lock(&pnp_lock); 25062306a36Sopenharmony_ci list_add_tail(&card->global_list, &pnp_cards); 25162306a36Sopenharmony_ci list_add_tail(&card->protocol_list, &card->protocol->cards); 25262306a36Sopenharmony_ci mutex_unlock(&pnp_lock); 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci /* we wait until now to add devices in order to ensure the drivers 25562306a36Sopenharmony_ci * will be able to use all of the related devices on the card 25662306a36Sopenharmony_ci * without waiting an unreasonable length of time */ 25762306a36Sopenharmony_ci list_for_each(pos, &card->devices) { 25862306a36Sopenharmony_ci struct pnp_dev *dev = card_to_pnp_dev(pos); 25962306a36Sopenharmony_ci __pnp_add_device(dev); 26062306a36Sopenharmony_ci } 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci /* match with card drivers */ 26362306a36Sopenharmony_ci list_for_each_safe(pos, temp, &pnp_card_drivers) { 26462306a36Sopenharmony_ci struct pnp_card_driver *drv = 26562306a36Sopenharmony_ci list_entry(pos, struct pnp_card_driver, 26662306a36Sopenharmony_ci global_list); 26762306a36Sopenharmony_ci card_probe(card, drv); 26862306a36Sopenharmony_ci } 26962306a36Sopenharmony_ci return 0; 27062306a36Sopenharmony_ci} 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci/** 27362306a36Sopenharmony_ci * pnp_remove_card - removes a PnP card from the PnP Layer 27462306a36Sopenharmony_ci * @card: pointer to the card to remove 27562306a36Sopenharmony_ci */ 27662306a36Sopenharmony_civoid pnp_remove_card(struct pnp_card *card) 27762306a36Sopenharmony_ci{ 27862306a36Sopenharmony_ci struct list_head *pos, *temp; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci device_unregister(&card->dev); 28162306a36Sopenharmony_ci mutex_lock(&pnp_lock); 28262306a36Sopenharmony_ci list_del(&card->global_list); 28362306a36Sopenharmony_ci list_del(&card->protocol_list); 28462306a36Sopenharmony_ci mutex_unlock(&pnp_lock); 28562306a36Sopenharmony_ci list_for_each_safe(pos, temp, &card->devices) { 28662306a36Sopenharmony_ci struct pnp_dev *dev = card_to_pnp_dev(pos); 28762306a36Sopenharmony_ci pnp_remove_card_device(dev); 28862306a36Sopenharmony_ci } 28962306a36Sopenharmony_ci} 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci/** 29262306a36Sopenharmony_ci * pnp_add_card_device - adds a device to the specified card 29362306a36Sopenharmony_ci * @card: pointer to the card to add to 29462306a36Sopenharmony_ci * @dev: pointer to the device to add 29562306a36Sopenharmony_ci */ 29662306a36Sopenharmony_ciint pnp_add_card_device(struct pnp_card *card, struct pnp_dev *dev) 29762306a36Sopenharmony_ci{ 29862306a36Sopenharmony_ci dev->dev.parent = &card->dev; 29962306a36Sopenharmony_ci dev->card_link = NULL; 30062306a36Sopenharmony_ci dev_set_name(&dev->dev, "%02x:%02x.%02x", 30162306a36Sopenharmony_ci dev->protocol->number, card->number, dev->number); 30262306a36Sopenharmony_ci mutex_lock(&pnp_lock); 30362306a36Sopenharmony_ci dev->card = card; 30462306a36Sopenharmony_ci list_add_tail(&dev->card_list, &card->devices); 30562306a36Sopenharmony_ci mutex_unlock(&pnp_lock); 30662306a36Sopenharmony_ci return 0; 30762306a36Sopenharmony_ci} 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci/** 31062306a36Sopenharmony_ci * pnp_remove_card_device- removes a device from the specified card 31162306a36Sopenharmony_ci * @dev: pointer to the device to remove 31262306a36Sopenharmony_ci */ 31362306a36Sopenharmony_civoid pnp_remove_card_device(struct pnp_dev *dev) 31462306a36Sopenharmony_ci{ 31562306a36Sopenharmony_ci mutex_lock(&pnp_lock); 31662306a36Sopenharmony_ci dev->card = NULL; 31762306a36Sopenharmony_ci list_del(&dev->card_list); 31862306a36Sopenharmony_ci mutex_unlock(&pnp_lock); 31962306a36Sopenharmony_ci __pnp_remove_device(dev); 32062306a36Sopenharmony_ci} 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci/** 32362306a36Sopenharmony_ci * pnp_request_card_device - Searches for a PnP device under the specified card 32462306a36Sopenharmony_ci * @clink: pointer to the card link, cannot be NULL 32562306a36Sopenharmony_ci * @id: pointer to a PnP ID structure that explains the rules for finding the device 32662306a36Sopenharmony_ci * @from: Starting place to search from. If NULL it will start from the beginning. 32762306a36Sopenharmony_ci */ 32862306a36Sopenharmony_cistruct pnp_dev *pnp_request_card_device(struct pnp_card_link *clink, 32962306a36Sopenharmony_ci const char *id, struct pnp_dev *from) 33062306a36Sopenharmony_ci{ 33162306a36Sopenharmony_ci struct list_head *pos; 33262306a36Sopenharmony_ci struct pnp_dev *dev; 33362306a36Sopenharmony_ci struct pnp_card_driver *drv; 33462306a36Sopenharmony_ci struct pnp_card *card; 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci if (!clink || !id) 33762306a36Sopenharmony_ci return NULL; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci card = clink->card; 34062306a36Sopenharmony_ci drv = clink->driver; 34162306a36Sopenharmony_ci if (!from) { 34262306a36Sopenharmony_ci pos = card->devices.next; 34362306a36Sopenharmony_ci } else { 34462306a36Sopenharmony_ci if (from->card != card) 34562306a36Sopenharmony_ci return NULL; 34662306a36Sopenharmony_ci pos = from->card_list.next; 34762306a36Sopenharmony_ci } 34862306a36Sopenharmony_ci while (pos != &card->devices) { 34962306a36Sopenharmony_ci dev = card_to_pnp_dev(pos); 35062306a36Sopenharmony_ci if ((!dev->card_link) && compare_pnp_id(dev->id, id)) 35162306a36Sopenharmony_ci goto found; 35262306a36Sopenharmony_ci pos = pos->next; 35362306a36Sopenharmony_ci } 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci return NULL; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_cifound: 35862306a36Sopenharmony_ci dev->card_link = clink; 35962306a36Sopenharmony_ci dev->dev.driver = &drv->link.driver; 36062306a36Sopenharmony_ci if (pnp_bus_type.probe(&dev->dev)) 36162306a36Sopenharmony_ci goto err_out; 36262306a36Sopenharmony_ci if (device_bind_driver(&dev->dev)) 36362306a36Sopenharmony_ci goto err_out; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci return dev; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_cierr_out: 36862306a36Sopenharmony_ci dev->dev.driver = NULL; 36962306a36Sopenharmony_ci dev->card_link = NULL; 37062306a36Sopenharmony_ci return NULL; 37162306a36Sopenharmony_ci} 37262306a36Sopenharmony_ciEXPORT_SYMBOL(pnp_request_card_device); 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci/** 37562306a36Sopenharmony_ci * pnp_release_card_device - call this when the driver no longer needs the device 37662306a36Sopenharmony_ci * @dev: pointer to the PnP device structure 37762306a36Sopenharmony_ci */ 37862306a36Sopenharmony_civoid pnp_release_card_device(struct pnp_dev *dev) 37962306a36Sopenharmony_ci{ 38062306a36Sopenharmony_ci struct pnp_card_driver *drv = dev->card_link->driver; 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci drv->link.remove = &card_remove; 38362306a36Sopenharmony_ci device_release_driver(&dev->dev); 38462306a36Sopenharmony_ci drv->link.remove = &card_remove_first; 38562306a36Sopenharmony_ci} 38662306a36Sopenharmony_ciEXPORT_SYMBOL(pnp_release_card_device); 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci/* 38962306a36Sopenharmony_ci * suspend/resume callbacks 39062306a36Sopenharmony_ci */ 39162306a36Sopenharmony_cistatic int card_suspend(struct pnp_dev *dev, pm_message_t state) 39262306a36Sopenharmony_ci{ 39362306a36Sopenharmony_ci struct pnp_card_link *link = dev->card_link; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci if (link->pm_state.event == state.event) 39662306a36Sopenharmony_ci return 0; 39762306a36Sopenharmony_ci link->pm_state = state; 39862306a36Sopenharmony_ci return link->driver->suspend(link, state); 39962306a36Sopenharmony_ci} 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_cistatic int card_resume(struct pnp_dev *dev) 40262306a36Sopenharmony_ci{ 40362306a36Sopenharmony_ci struct pnp_card_link *link = dev->card_link; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci if (link->pm_state.event == PM_EVENT_ON) 40662306a36Sopenharmony_ci return 0; 40762306a36Sopenharmony_ci link->pm_state = PMSG_ON; 40862306a36Sopenharmony_ci link->driver->resume(link); 40962306a36Sopenharmony_ci return 0; 41062306a36Sopenharmony_ci} 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci/** 41362306a36Sopenharmony_ci * pnp_register_card_driver - registers a PnP card driver with the PnP Layer 41462306a36Sopenharmony_ci * @drv: pointer to the driver to register 41562306a36Sopenharmony_ci */ 41662306a36Sopenharmony_ciint pnp_register_card_driver(struct pnp_card_driver *drv) 41762306a36Sopenharmony_ci{ 41862306a36Sopenharmony_ci int error; 41962306a36Sopenharmony_ci struct list_head *pos, *temp; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci drv->link.name = drv->name; 42262306a36Sopenharmony_ci drv->link.id_table = NULL; /* this will disable auto matching */ 42362306a36Sopenharmony_ci drv->link.flags = drv->flags; 42462306a36Sopenharmony_ci drv->link.probe = NULL; 42562306a36Sopenharmony_ci drv->link.remove = &card_remove_first; 42662306a36Sopenharmony_ci drv->link.suspend = drv->suspend ? card_suspend : NULL; 42762306a36Sopenharmony_ci drv->link.resume = drv->resume ? card_resume : NULL; 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci error = pnp_register_driver(&drv->link); 43062306a36Sopenharmony_ci if (error < 0) 43162306a36Sopenharmony_ci return error; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci mutex_lock(&pnp_lock); 43462306a36Sopenharmony_ci list_add_tail(&drv->global_list, &pnp_card_drivers); 43562306a36Sopenharmony_ci mutex_unlock(&pnp_lock); 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci list_for_each_safe(pos, temp, &pnp_cards) { 43862306a36Sopenharmony_ci struct pnp_card *card = 43962306a36Sopenharmony_ci list_entry(pos, struct pnp_card, global_list); 44062306a36Sopenharmony_ci card_probe(card, drv); 44162306a36Sopenharmony_ci } 44262306a36Sopenharmony_ci return 0; 44362306a36Sopenharmony_ci} 44462306a36Sopenharmony_ciEXPORT_SYMBOL(pnp_register_card_driver); 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci/** 44762306a36Sopenharmony_ci * pnp_unregister_card_driver - unregisters a PnP card driver from the PnP Layer 44862306a36Sopenharmony_ci * @drv: pointer to the driver to unregister 44962306a36Sopenharmony_ci */ 45062306a36Sopenharmony_civoid pnp_unregister_card_driver(struct pnp_card_driver *drv) 45162306a36Sopenharmony_ci{ 45262306a36Sopenharmony_ci mutex_lock(&pnp_lock); 45362306a36Sopenharmony_ci list_del(&drv->global_list); 45462306a36Sopenharmony_ci mutex_unlock(&pnp_lock); 45562306a36Sopenharmony_ci pnp_unregister_driver(&drv->link); 45662306a36Sopenharmony_ci} 45762306a36Sopenharmony_ciEXPORT_SYMBOL(pnp_unregister_card_driver); 458