Merge tag 'iwlwifi-next-for-kalle-2014-12-30' of https://git.kernel.org/pub/scm/linux...
[cascardo/linux.git] / drivers / fmc / fmc-match.c
1 /*
2  * Copyright (C) 2012 CERN (www.cern.ch)
3  * Author: Alessandro Rubini <rubini@gnudd.com>
4  *
5  * Released according to the GNU GPL, version 2 or any later version.
6  *
7  * This work is part of the White Rabbit project, a research effort led
8  * by CERN, the European Institute for Nuclear Research.
9  */
10 #include <linux/kernel.h>
11 #include <linux/slab.h>
12 #include <linux/fmc.h>
13 #include <linux/ipmi-fru.h>
14
15 /* The fru parser is both user and kernel capable: it needs alloc */
16 void *fru_alloc(size_t size)
17 {
18         return kzalloc(size, GFP_KERNEL);
19 }
20
21 /* The actual match function */
22 int fmc_match(struct device *dev, struct device_driver *drv)
23 {
24         struct fmc_driver *fdrv = to_fmc_driver(drv);
25         struct fmc_device *fdev = to_fmc_device(dev);
26         struct fmc_fru_id *fid;
27         int i, matched = 0;
28
29         /* This currently only matches the EEPROM (FRU id) */
30         fid = fdrv->id_table.fru_id;
31         if (!fid) {
32                 dev_warn(&fdev->dev, "Driver has no ID: matches all\n");
33                 matched = 1;
34         } else {
35                 if (!fdev->id.manufacturer || !fdev->id.product_name)
36                         return 0; /* the device has no FRU information */
37                 for (i = 0; i < fdrv->id_table.fru_id_nr; i++, fid++) {
38                         if (fid->manufacturer &&
39                             strcmp(fid->manufacturer, fdev->id.manufacturer))
40                                 continue;
41                         if (fid->product_name &&
42                             strcmp(fid->product_name, fdev->id.product_name))
43                                 continue;
44                         matched = 1;
45                         break;
46                 }
47         }
48
49         /* FIXME: match SDB contents */
50         return matched;
51 }
52
53 /* This function creates ID info for a newly registered device */
54 int fmc_fill_id_info(struct fmc_device *fmc)
55 {
56         struct fru_common_header *h;
57         struct fru_board_info_area *bia;
58         int ret, allocated = 0;
59
60         /* If we know the eeprom length, try to read it off the device */
61         if (fmc->eeprom_len && !fmc->eeprom) {
62                 fmc->eeprom = kzalloc(fmc->eeprom_len, GFP_KERNEL);
63                 if (!fmc->eeprom)
64                         return -ENOMEM;
65                 allocated = 1;
66                 ret = fmc->op->read_ee(fmc, 0, fmc->eeprom, fmc->eeprom_len);
67                 if (ret < 0)
68                         goto out;
69         }
70
71         /* If no eeprom, continue with other matches */
72         if (!fmc->eeprom)
73                 return 0;
74
75         dev_info(fmc->hwdev, "mezzanine %i\n", fmc->slot_id); /* header */
76
77         /* So we have the eeprom: parse the FRU part (if any) */
78         h = (void *)fmc->eeprom;
79         if (h->format != 1) {
80                 pr_info("      EEPROM has no FRU information\n");
81                 goto out;
82         }
83         if (!fru_header_cksum_ok(h)) {
84                 pr_info("      FRU: wrong header checksum\n");
85                 goto out;
86         }
87         bia = fru_get_board_area(h);
88         if (!fru_bia_cksum_ok(bia)) {
89                 pr_info("      FRU: wrong board area checksum\n");
90                 goto out;
91         }
92         fmc->id.manufacturer = fru_get_board_manufacturer(h);
93         fmc->id.product_name = fru_get_product_name(h);
94         pr_info("      Manufacturer: %s\n", fmc->id.manufacturer);
95         pr_info("      Product name: %s\n", fmc->id.product_name);
96
97         /* Create the short name (FIXME: look in sdb as well) */
98         fmc->mezzanine_name = kstrdup(fmc->id.product_name, GFP_KERNEL);
99
100 out:
101         if (allocated) {
102                 kfree(fmc->eeprom);
103                 fmc->eeprom = NULL;
104         }
105         return 0; /* no error: let other identification work */
106 }
107
108 /* Some ID data is allocated using fru_alloc() above, so release it */
109 void fmc_free_id_info(struct fmc_device *fmc)
110 {
111         kfree(fmc->mezzanine_name);
112         kfree(fmc->id.manufacturer);
113         kfree(fmc->id.product_name);
114 }