LCOV - code coverage report
Current view: top level - drivers/pnp - card.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 0 197 0.0 %
Date: 2022-03-28 15:32:58 Functions: 0 18 0.0 %
Branches: 0 66 0.0 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0
       2                 :            : /*
       3                 :            :  * card.c - contains functions for managing groups of PnP devices
       4                 :            :  *
       5                 :            :  * Copyright 2002 Adam Belay <ambx1@neo.rr.com>
       6                 :            :  */
       7                 :            : 
       8                 :            : #include <linux/module.h>
       9                 :            : #include <linux/mutex.h>
      10                 :            : #include <linux/ctype.h>
      11                 :            : #include <linux/slab.h>
      12                 :            : #include <linux/pnp.h>
      13                 :            : #include <linux/dma-mapping.h>
      14                 :            : #include "base.h"
      15                 :            : 
      16                 :            : LIST_HEAD(pnp_cards);
      17                 :            : static LIST_HEAD(pnp_card_drivers);
      18                 :            : 
      19                 :            : static const struct pnp_card_device_id *match_card(struct pnp_card_driver *drv,
      20                 :            :                                                    struct pnp_card *card)
      21                 :            : {
      22                 :            :         const struct pnp_card_device_id *drv_id = drv->id_table;
      23                 :            : 
      24                 :            :         while (*drv_id->id) {
      25                 :            :                 if (compare_pnp_id(card->id, drv_id->id)) {
      26                 :            :                         int i = 0;
      27                 :            : 
      28                 :            :                         for (;;) {
      29                 :            :                                 int found;
      30                 :            :                                 struct pnp_dev *dev;
      31                 :            : 
      32                 :            :                                 if (i == PNP_MAX_DEVICES ||
      33                 :            :                                     !*drv_id->devs[i].id)
      34                 :            :                                         return drv_id;
      35                 :            :                                 found = 0;
      36                 :            :                                 card_for_each_dev(card, dev) {
      37                 :            :                                         if (compare_pnp_id(dev->id,
      38                 :            :                                                    drv_id->devs[i].id)) {
      39                 :            :                                                 found = 1;
      40                 :            :                                                 break;
      41                 :            :                                         }
      42                 :            :                                 }
      43                 :            :                                 if (!found)
      44                 :            :                                         break;
      45                 :            :                                 i++;
      46                 :            :                         }
      47                 :            :                 }
      48                 :            :                 drv_id++;
      49                 :            :         }
      50                 :            :         return NULL;
      51                 :            : }
      52                 :            : 
      53                 :          0 : static void card_remove(struct pnp_dev *dev)
      54                 :            : {
      55                 :          0 :         dev->card_link = NULL;
      56                 :          0 : }
      57                 :            : 
      58                 :          0 : static void card_remove_first(struct pnp_dev *dev)
      59                 :            : {
      60                 :          0 :         struct pnp_card_driver *drv = to_pnp_card_driver(dev->driver);
      61                 :            : 
      62   [ #  #  #  # ]:          0 :         if (!dev->card || !drv)
      63                 :            :                 return;
      64         [ #  # ]:          0 :         if (drv->remove)
      65                 :          0 :                 drv->remove(dev->card_link);
      66                 :          0 :         drv->link.remove = &card_remove;
      67                 :          0 :         kfree(dev->card_link);
      68                 :          0 :         card_remove(dev);
      69                 :            : }
      70                 :            : 
      71                 :          0 : static int card_probe(struct pnp_card *card, struct pnp_card_driver *drv)
      72                 :            : {
      73                 :          0 :         const struct pnp_card_device_id *id;
      74                 :          0 :         struct pnp_card_link *clink;
      75                 :          0 :         struct pnp_dev *dev;
      76                 :            : 
      77         [ #  # ]:          0 :         if (!drv->probe)
      78                 :            :                 return 0;
      79                 :          0 :         id = match_card(drv, card);
      80         [ #  # ]:          0 :         if (!id)
      81                 :            :                 return 0;
      82                 :            : 
      83                 :          0 :         clink = pnp_alloc(sizeof(*clink));
      84         [ #  # ]:          0 :         if (!clink)
      85                 :            :                 return 0;
      86                 :          0 :         clink->card = card;
      87                 :          0 :         clink->driver = drv;
      88                 :          0 :         clink->pm_state = PMSG_ON;
      89                 :            : 
      90         [ #  # ]:          0 :         if (drv->probe(clink, id) >= 0)
      91                 :            :                 return 1;
      92                 :            : 
      93                 :            :         /* Recovery */
      94         [ #  # ]:          0 :         card_for_each_dev(card, dev) {
      95         [ #  # ]:          0 :                 if (dev->card_link == clink)
      96                 :          0 :                         pnp_release_card_device(dev);
      97                 :            :         }
      98                 :          0 :         kfree(clink);
      99                 :          0 :         return 0;
     100                 :            : }
     101                 :            : 
     102                 :            : /**
     103                 :            :  * pnp_add_card_id - adds an EISA id to the specified card
     104                 :            :  * @id: pointer to a pnp_id structure
     105                 :            :  * @card: pointer to the desired card
     106                 :            :  */
     107                 :            : static struct pnp_id *pnp_add_card_id(struct pnp_card *card, char *id)
     108                 :            : {
     109                 :            :         struct pnp_id *dev_id, *ptr;
     110                 :            : 
     111                 :            :         dev_id = kzalloc(sizeof(struct pnp_id), GFP_KERNEL);
     112                 :            :         if (!dev_id)
     113                 :            :                 return NULL;
     114                 :            : 
     115                 :            :         dev_id->id[0] = id[0];
     116                 :            :         dev_id->id[1] = id[1];
     117                 :            :         dev_id->id[2] = id[2];
     118                 :            :         dev_id->id[3] = tolower(id[3]);
     119                 :            :         dev_id->id[4] = tolower(id[4]);
     120                 :            :         dev_id->id[5] = tolower(id[5]);
     121                 :            :         dev_id->id[6] = tolower(id[6]);
     122                 :            :         dev_id->id[7] = '\0';
     123                 :            : 
     124                 :            :         dev_id->next = NULL;
     125                 :            :         ptr = card->id;
     126                 :            :         while (ptr && ptr->next)
     127                 :            :                 ptr = ptr->next;
     128                 :            :         if (ptr)
     129                 :            :                 ptr->next = dev_id;
     130                 :            :         else
     131                 :            :                 card->id = dev_id;
     132                 :            : 
     133                 :            :         return dev_id;
     134                 :            : }
     135                 :            : 
     136                 :          0 : static void pnp_free_card_ids(struct pnp_card *card)
     137                 :            : {
     138                 :          0 :         struct pnp_id *id;
     139                 :          0 :         struct pnp_id *next;
     140                 :            : 
     141                 :          0 :         id = card->id;
     142         [ #  # ]:          0 :         while (id) {
     143                 :          0 :                 next = id->next;
     144                 :          0 :                 kfree(id);
     145                 :          0 :                 id = next;
     146                 :            :         }
     147                 :            : }
     148                 :            : 
     149                 :          0 : static void pnp_release_card(struct device *dmdev)
     150                 :            : {
     151                 :          0 :         struct pnp_card *card = to_pnp_card(dmdev);
     152                 :            : 
     153                 :          0 :         pnp_free_card_ids(card);
     154                 :          0 :         kfree(card);
     155                 :          0 : }
     156                 :            : 
     157                 :          0 : struct pnp_card *pnp_alloc_card(struct pnp_protocol *protocol, int id, char *pnpid)
     158                 :            : {
     159                 :          0 :         struct pnp_card *card;
     160                 :          0 :         struct pnp_id *dev_id;
     161                 :            : 
     162                 :          0 :         card = kzalloc(sizeof(struct pnp_card), GFP_KERNEL);
     163         [ #  # ]:          0 :         if (!card)
     164                 :            :                 return NULL;
     165                 :            : 
     166                 :          0 :         card->protocol = protocol;
     167                 :          0 :         card->number = id;
     168                 :            : 
     169                 :          0 :         card->dev.parent = &card->protocol->dev;
     170                 :          0 :         dev_set_name(&card->dev, "%02x:%02x", card->protocol->number, card->number);
     171                 :            : 
     172                 :          0 :         card->dev.coherent_dma_mask = DMA_BIT_MASK(24);
     173                 :          0 :         card->dev.dma_mask = &card->dev.coherent_dma_mask;
     174                 :            : 
     175                 :          0 :         dev_id = pnp_add_card_id(card, pnpid);
     176         [ #  # ]:          0 :         if (!dev_id) {
     177                 :          0 :                 kfree(card);
     178                 :          0 :                 return NULL;
     179                 :            :         }
     180                 :            : 
     181                 :            :         return card;
     182                 :            : }
     183                 :            : 
     184                 :          0 : static ssize_t pnp_show_card_name(struct device *dmdev,
     185                 :            :                                   struct device_attribute *attr, char *buf)
     186                 :            : {
     187                 :          0 :         char *str = buf;
     188                 :          0 :         struct pnp_card *card = to_pnp_card(dmdev);
     189                 :            : 
     190                 :          0 :         str += sprintf(str, "%s\n", card->name);
     191                 :          0 :         return (str - buf);
     192                 :            : }
     193                 :            : 
     194                 :            : static DEVICE_ATTR(name, S_IRUGO, pnp_show_card_name, NULL);
     195                 :            : 
     196                 :          0 : static ssize_t pnp_show_card_ids(struct device *dmdev,
     197                 :            :                                  struct device_attribute *attr, char *buf)
     198                 :            : {
     199                 :          0 :         char *str = buf;
     200                 :          0 :         struct pnp_card *card = to_pnp_card(dmdev);
     201                 :          0 :         struct pnp_id *pos = card->id;
     202                 :            : 
     203         [ #  # ]:          0 :         while (pos) {
     204                 :          0 :                 str += sprintf(str, "%s\n", pos->id);
     205                 :          0 :                 pos = pos->next;
     206                 :            :         }
     207                 :          0 :         return (str - buf);
     208                 :            : }
     209                 :            : 
     210                 :            : static DEVICE_ATTR(card_id, S_IRUGO, pnp_show_card_ids, NULL);
     211                 :            : 
     212                 :          0 : static int pnp_interface_attach_card(struct pnp_card *card)
     213                 :            : {
     214                 :          0 :         int rc = device_create_file(&card->dev, &dev_attr_name);
     215                 :            : 
     216         [ #  # ]:          0 :         if (rc)
     217                 :            :                 return rc;
     218                 :            : 
     219                 :          0 :         rc = device_create_file(&card->dev, &dev_attr_card_id);
     220         [ #  # ]:          0 :         if (rc)
     221                 :          0 :                 goto err_name;
     222                 :            : 
     223                 :            :         return 0;
     224                 :            : 
     225                 :            : err_name:
     226                 :          0 :         device_remove_file(&card->dev, &dev_attr_name);
     227                 :          0 :         return rc;
     228                 :            : }
     229                 :            : 
     230                 :            : /**
     231                 :            :  * pnp_add_card - adds a PnP card to the PnP Layer
     232                 :            :  * @card: pointer to the card to add
     233                 :            :  */
     234                 :          0 : int pnp_add_card(struct pnp_card *card)
     235                 :            : {
     236                 :          0 :         int error;
     237                 :          0 :         struct list_head *pos, *temp;
     238                 :            : 
     239                 :          0 :         card->dev.bus = NULL;
     240                 :          0 :         card->dev.release = &pnp_release_card;
     241                 :          0 :         error = device_register(&card->dev);
     242         [ #  # ]:          0 :         if (error) {
     243                 :          0 :                 dev_err(&card->dev, "could not register (err=%d)\n", error);
     244                 :          0 :                 put_device(&card->dev);
     245                 :          0 :                 return error;
     246                 :            :         }
     247                 :            : 
     248                 :          0 :         pnp_interface_attach_card(card);
     249                 :          0 :         mutex_lock(&pnp_lock);
     250                 :          0 :         list_add_tail(&card->global_list, &pnp_cards);
     251                 :          0 :         list_add_tail(&card->protocol_list, &card->protocol->cards);
     252                 :          0 :         mutex_unlock(&pnp_lock);
     253                 :            : 
     254                 :            :         /* we wait until now to add devices in order to ensure the drivers
     255                 :            :          * will be able to use all of the related devices on the card
     256                 :            :          * without waiting an unreasonable length of time */
     257         [ #  # ]:          0 :         list_for_each(pos, &card->devices) {
     258                 :          0 :                 struct pnp_dev *dev = card_to_pnp_dev(pos);
     259                 :          0 :                 __pnp_add_device(dev);
     260                 :            :         }
     261                 :            : 
     262                 :            :         /* match with card drivers */
     263         [ #  # ]:          0 :         list_for_each_safe(pos, temp, &pnp_card_drivers) {
     264                 :          0 :                 struct pnp_card_driver *drv =
     265                 :          0 :                     list_entry(pos, struct pnp_card_driver,
     266                 :            :                                global_list);
     267                 :          0 :                 card_probe(card, drv);
     268                 :            :         }
     269                 :            :         return 0;
     270                 :            : }
     271                 :            : 
     272                 :            : /**
     273                 :            :  * pnp_remove_card - removes a PnP card from the PnP Layer
     274                 :            :  * @card: pointer to the card to remove
     275                 :            :  */
     276                 :          0 : void pnp_remove_card(struct pnp_card *card)
     277                 :            : {
     278                 :          0 :         struct list_head *pos, *temp;
     279                 :            : 
     280                 :          0 :         device_unregister(&card->dev);
     281                 :          0 :         mutex_lock(&pnp_lock);
     282                 :          0 :         list_del(&card->global_list);
     283                 :          0 :         list_del(&card->protocol_list);
     284                 :          0 :         mutex_unlock(&pnp_lock);
     285         [ #  # ]:          0 :         list_for_each_safe(pos, temp, &card->devices) {
     286                 :          0 :                 struct pnp_dev *dev = card_to_pnp_dev(pos);
     287                 :          0 :                 pnp_remove_card_device(dev);
     288                 :            :         }
     289                 :          0 : }
     290                 :            : 
     291                 :            : /**
     292                 :            :  * pnp_add_card_device - adds a device to the specified card
     293                 :            :  * @card: pointer to the card to add to
     294                 :            :  * @dev: pointer to the device to add
     295                 :            :  */
     296                 :          0 : int pnp_add_card_device(struct pnp_card *card, struct pnp_dev *dev)
     297                 :            : {
     298                 :          0 :         dev->dev.parent = &card->dev;
     299                 :          0 :         dev->card_link = NULL;
     300                 :          0 :         dev_set_name(&dev->dev, "%02x:%02x.%02x",
     301                 :          0 :                      dev->protocol->number, card->number, dev->number);
     302                 :          0 :         mutex_lock(&pnp_lock);
     303                 :          0 :         dev->card = card;
     304                 :          0 :         list_add_tail(&dev->card_list, &card->devices);
     305                 :          0 :         mutex_unlock(&pnp_lock);
     306                 :          0 :         return 0;
     307                 :            : }
     308                 :            : 
     309                 :            : /**
     310                 :            :  * pnp_remove_card_device- removes a device from the specified card
     311                 :            :  * @dev: pointer to the device to remove
     312                 :            :  */
     313                 :          0 : void pnp_remove_card_device(struct pnp_dev *dev)
     314                 :            : {
     315                 :          0 :         mutex_lock(&pnp_lock);
     316                 :          0 :         dev->card = NULL;
     317                 :          0 :         list_del(&dev->card_list);
     318                 :          0 :         mutex_unlock(&pnp_lock);
     319                 :          0 :         __pnp_remove_device(dev);
     320                 :          0 : }
     321                 :            : 
     322                 :            : /**
     323                 :            :  * pnp_request_card_device - Searches for a PnP device under the specified card
     324                 :            :  * @clink: pointer to the card link, cannot be NULL
     325                 :            :  * @id: pointer to a PnP ID structure that explains the rules for finding the device
     326                 :            :  * @from: Starting place to search from. If NULL it will start from the beginning.
     327                 :            :  */
     328                 :          0 : struct pnp_dev *pnp_request_card_device(struct pnp_card_link *clink,
     329                 :            :                                         const char *id, struct pnp_dev *from)
     330                 :            : {
     331                 :          0 :         struct list_head *pos;
     332                 :          0 :         struct pnp_dev *dev;
     333                 :          0 :         struct pnp_card_driver *drv;
     334                 :          0 :         struct pnp_card *card;
     335                 :            : 
     336         [ #  # ]:          0 :         if (!clink || !id)
     337                 :            :                 return NULL;
     338                 :            : 
     339                 :          0 :         card = clink->card;
     340                 :          0 :         drv = clink->driver;
     341         [ #  # ]:          0 :         if (!from) {
     342                 :          0 :                 pos = card->devices.next;
     343                 :            :         } else {
     344         [ #  # ]:          0 :                 if (from->card != card)
     345                 :            :                         return NULL;
     346                 :          0 :                 pos = from->card_list.next;
     347                 :            :         }
     348         [ #  # ]:          0 :         while (pos != &card->devices) {
     349                 :          0 :                 dev = card_to_pnp_dev(pos);
     350   [ #  #  #  # ]:          0 :                 if ((!dev->card_link) && compare_pnp_id(dev->id, id))
     351                 :          0 :                         goto found;
     352                 :          0 :                 pos = pos->next;
     353                 :            :         }
     354                 :            : 
     355                 :            :         return NULL;
     356                 :            : 
     357                 :            : found:
     358                 :          0 :         dev->card_link = clink;
     359                 :          0 :         dev->dev.driver = &drv->link.driver;
     360         [ #  # ]:          0 :         if (pnp_bus_type.probe(&dev->dev))
     361                 :          0 :                 goto err_out;
     362         [ #  # ]:          0 :         if (device_bind_driver(&dev->dev))
     363                 :          0 :                 goto err_out;
     364                 :            : 
     365                 :            :         return dev;
     366                 :            : 
     367                 :          0 : err_out:
     368                 :          0 :         dev->dev.driver = NULL;
     369                 :          0 :         dev->card_link = NULL;
     370                 :          0 :         return NULL;
     371                 :            : }
     372                 :            : 
     373                 :            : /**
     374                 :            :  * pnp_release_card_device - call this when the driver no longer needs the device
     375                 :            :  * @dev: pointer to the PnP device structure
     376                 :            :  */
     377                 :          0 : void pnp_release_card_device(struct pnp_dev *dev)
     378                 :            : {
     379                 :          0 :         struct pnp_card_driver *drv = dev->card_link->driver;
     380                 :            : 
     381                 :          0 :         drv->link.remove = &card_remove;
     382                 :          0 :         device_release_driver(&dev->dev);
     383                 :          0 :         drv->link.remove = &card_remove_first;
     384                 :          0 : }
     385                 :            : 
     386                 :            : /*
     387                 :            :  * suspend/resume callbacks
     388                 :            :  */
     389                 :          0 : static int card_suspend(struct pnp_dev *dev, pm_message_t state)
     390                 :            : {
     391                 :          0 :         struct pnp_card_link *link = dev->card_link;
     392                 :            : 
     393         [ #  # ]:          0 :         if (link->pm_state.event == state.event)
     394                 :            :                 return 0;
     395                 :          0 :         link->pm_state = state;
     396                 :          0 :         return link->driver->suspend(link, state);
     397                 :            : }
     398                 :            : 
     399                 :          0 : static int card_resume(struct pnp_dev *dev)
     400                 :            : {
     401                 :          0 :         struct pnp_card_link *link = dev->card_link;
     402                 :            : 
     403         [ #  # ]:          0 :         if (link->pm_state.event == PM_EVENT_ON)
     404                 :            :                 return 0;
     405                 :          0 :         link->pm_state = PMSG_ON;
     406                 :          0 :         link->driver->resume(link);
     407                 :          0 :         return 0;
     408                 :            : }
     409                 :            : 
     410                 :            : /**
     411                 :            :  * pnp_register_card_driver - registers a PnP card driver with the PnP Layer
     412                 :            :  * @drv: pointer to the driver to register
     413                 :            :  */
     414                 :          0 : int pnp_register_card_driver(struct pnp_card_driver *drv)
     415                 :            : {
     416                 :          0 :         int error;
     417                 :          0 :         struct list_head *pos, *temp;
     418                 :            : 
     419                 :          0 :         drv->link.name = drv->name;
     420                 :          0 :         drv->link.id_table = NULL;   /* this will disable auto matching */
     421                 :          0 :         drv->link.flags = drv->flags;
     422                 :          0 :         drv->link.probe = NULL;
     423                 :          0 :         drv->link.remove = &card_remove_first;
     424         [ #  # ]:          0 :         drv->link.suspend = drv->suspend ? card_suspend : NULL;
     425         [ #  # ]:          0 :         drv->link.resume = drv->resume ? card_resume : NULL;
     426                 :            : 
     427                 :          0 :         error = pnp_register_driver(&drv->link);
     428         [ #  # ]:          0 :         if (error < 0)
     429                 :            :                 return error;
     430                 :            : 
     431                 :          0 :         mutex_lock(&pnp_lock);
     432                 :          0 :         list_add_tail(&drv->global_list, &pnp_card_drivers);
     433                 :          0 :         mutex_unlock(&pnp_lock);
     434                 :            : 
     435         [ #  # ]:          0 :         list_for_each_safe(pos, temp, &pnp_cards) {
     436                 :          0 :                 struct pnp_card *card =
     437                 :          0 :                     list_entry(pos, struct pnp_card, global_list);
     438                 :          0 :                 card_probe(card, drv);
     439                 :            :         }
     440                 :            :         return 0;
     441                 :            : }
     442                 :            : 
     443                 :            : /**
     444                 :            :  * pnp_unregister_card_driver - unregisters a PnP card driver from the PnP Layer
     445                 :            :  * @drv: pointer to the driver to unregister
     446                 :            :  */
     447                 :          0 : void pnp_unregister_card_driver(struct pnp_card_driver *drv)
     448                 :            : {
     449                 :          0 :         mutex_lock(&pnp_lock);
     450                 :          0 :         list_del(&drv->global_list);
     451                 :          0 :         mutex_unlock(&pnp_lock);
     452                 :          0 :         pnp_unregister_driver(&drv->link);
     453                 :          0 : }
     454                 :            : 
     455                 :            : EXPORT_SYMBOL(pnp_request_card_device);
     456                 :            : EXPORT_SYMBOL(pnp_release_card_device);
     457                 :            : EXPORT_SYMBOL(pnp_register_card_driver);
     458                 :            : EXPORT_SYMBOL(pnp_unregister_card_driver);

Generated by: LCOV version 1.14