Showing error 885

User: Jiri Slaby
Error type: Resource Leak
Error type description: The code omits to put the resource to the system for reuse
File location: drivers/mmc/host/ricoh_mmc.c
Line in file: 142
Project: Linux Kernel
Project version: 2.6.28
Tools: Stanse (1.2)
Entered: 2011-11-07 22:41:42 UTC


Source:

  1/*
  2 *  ricoh_mmc.c - Dummy driver to disable the Rioch MMC controller.
  3 *
  4 *  Copyright (C) 2007 Philip Langdale, All Rights Reserved.
  5 *
  6 * This program is free software; you can redistribute it and/or modify
  7 * it under the terms of the GNU General Public License as published by
  8 * the Free Software Foundation; either version 2 of the License, or (at
  9 * your option) any later version.
 10 */
 11
 12/*
 13 * This is a conceptually ridiculous driver, but it is required by the way
 14 * the Ricoh multi-function R5C832 works. This chip implements firewire
 15 * and four different memory card controllers. Two of those controllers are
 16 * an SDHCI controller and a proprietary MMC controller. The linux SDHCI
 17 * driver supports MMC cards but the chip detects MMC cards in hardware
 18 * and directs them to the MMC controller - so the SDHCI driver never sees
 19 * them. To get around this, we must disable the useless MMC controller.
 20 * At that point, the SDHCI controller will start seeing them. As a bonus,
 21 * a detection event occurs immediately, even if the MMC card is already
 22 * in the reader.
 23 *
 24 * The relevant registers live on the firewire function, so this is unavoidably
 25 * ugly. Such is life.
 26 */
 27
 28#include <linux/pci.h>
 29
 30#define DRIVER_NAME "ricoh-mmc"
 31
 32static const struct pci_device_id pci_ids[] __devinitdata = {
 33        {
 34                .vendor                = PCI_VENDOR_ID_RICOH,
 35                .device                = PCI_DEVICE_ID_RICOH_R5C843,
 36                .subvendor        = PCI_ANY_ID,
 37                .subdevice        = PCI_ANY_ID,
 38        },
 39        { /* end: all zeroes */ },
 40};
 41
 42MODULE_DEVICE_TABLE(pci, pci_ids);
 43
 44static int ricoh_mmc_disable(struct pci_dev *fw_dev)
 45{
 46        u8 write_enable;
 47        u8 write_target;
 48        u8 disable;
 49
 50        if (fw_dev->device == PCI_DEVICE_ID_RICOH_RL5C476) {
 51                /* via RL5C476 */
 52
 53                pci_read_config_byte(fw_dev, 0xB7, &disable);
 54                if (disable & 0x02) {
 55                        printk(KERN_INFO DRIVER_NAME
 56                                ": Controller already disabled. " \
 57                                "Nothing to do.\n");
 58                        return -ENODEV;
 59                }
 60
 61                pci_read_config_byte(fw_dev, 0x8E, &write_enable);
 62                pci_write_config_byte(fw_dev, 0x8E, 0xAA);
 63                pci_read_config_byte(fw_dev, 0x8D, &write_target);
 64                pci_write_config_byte(fw_dev, 0x8D, 0xB7);
 65                pci_write_config_byte(fw_dev, 0xB7, disable | 0x02);
 66                pci_write_config_byte(fw_dev, 0x8E, write_enable);
 67                pci_write_config_byte(fw_dev, 0x8D, write_target);
 68        } else {
 69                /* via R5C832 */
 70
 71                pci_read_config_byte(fw_dev, 0xCB, &disable);
 72                if (disable & 0x02) {
 73                        printk(KERN_INFO DRIVER_NAME
 74                               ": Controller already disabled. " \
 75                                "Nothing to do.\n");
 76                        return -ENODEV;
 77                }
 78
 79                pci_read_config_byte(fw_dev, 0xCA, &write_enable);
 80                pci_write_config_byte(fw_dev, 0xCA, 0x57);
 81                pci_write_config_byte(fw_dev, 0xCB, disable | 0x02);
 82                pci_write_config_byte(fw_dev, 0xCA, write_enable);
 83        }
 84
 85        printk(KERN_INFO DRIVER_NAME
 86               ": Controller is now disabled.\n");
 87
 88        return 0;
 89}
 90
 91static int ricoh_mmc_enable(struct pci_dev *fw_dev)
 92{
 93        u8 write_enable;
 94        u8 write_target;
 95        u8 disable;
 96
 97        if (fw_dev->device == PCI_DEVICE_ID_RICOH_RL5C476) {
 98                /* via RL5C476 */
 99
100                pci_read_config_byte(fw_dev, 0x8E, &write_enable);
101                pci_write_config_byte(fw_dev, 0x8E, 0xAA);
102                pci_read_config_byte(fw_dev, 0x8D, &write_target);
103                pci_write_config_byte(fw_dev, 0x8D, 0xB7);
104                pci_read_config_byte(fw_dev, 0xB7, &disable);
105                pci_write_config_byte(fw_dev, 0xB7, disable & ~0x02);
106                pci_write_config_byte(fw_dev, 0x8E, write_enable);
107                pci_write_config_byte(fw_dev, 0x8D, write_target);
108        } else {
109                /* via R5C832 */
110
111                pci_read_config_byte(fw_dev, 0xCA, &write_enable);
112                pci_read_config_byte(fw_dev, 0xCB, &disable);
113                pci_write_config_byte(fw_dev, 0xCA, 0x57);
114                pci_write_config_byte(fw_dev, 0xCB, disable & ~0x02);
115                pci_write_config_byte(fw_dev, 0xCA, write_enable);
116        }
117
118        printk(KERN_INFO DRIVER_NAME
119               ": Controller is now re-enabled.\n");
120
121        return 0;
122}
123
124static int __devinit ricoh_mmc_probe(struct pci_dev *pdev,
125                                     const struct pci_device_id *ent)
126{
127        u8 rev;
128        u8 ctrlfound = 0;
129
130        struct pci_dev *fw_dev = NULL;
131
132        BUG_ON(pdev == NULL);
133        BUG_ON(ent == NULL);
134
135        pci_read_config_byte(pdev, PCI_CLASS_REVISION, &rev);
136
137        printk(KERN_INFO DRIVER_NAME
138                ": Ricoh MMC controller found at %s [%04x:%04x] (rev %x)\n",
139                pci_name(pdev), (int)pdev->vendor, (int)pdev->device,
140                (int)rev);
141
142        while ((fw_dev =
143                pci_get_device(PCI_VENDOR_ID_RICOH,
144                        PCI_DEVICE_ID_RICOH_RL5C476, fw_dev))) {
145                if (PCI_SLOT(pdev->devfn) == PCI_SLOT(fw_dev->devfn) &&
146                    pdev->bus == fw_dev->bus) {
147                        if (ricoh_mmc_disable(fw_dev) != 0)
148                                return -ENODEV;
149
150                        pci_set_drvdata(pdev, fw_dev);
151
152                        ++ctrlfound;
153                        break;
154                }
155        }
156
157        fw_dev = NULL;
158
159        while (!ctrlfound &&
160            (fw_dev = pci_get_device(PCI_VENDOR_ID_RICOH,
161                                        PCI_DEVICE_ID_RICOH_R5C832, fw_dev))) {
162                if (PCI_SLOT(pdev->devfn) == PCI_SLOT(fw_dev->devfn) &&
163                    pdev->bus == fw_dev->bus) {
164                        if (ricoh_mmc_disable(fw_dev) != 0)
165                                return -ENODEV;
166
167                        pci_set_drvdata(pdev, fw_dev);
168
169                        ++ctrlfound;
170                }
171        }
172
173        if (!ctrlfound) {
174                printk(KERN_WARNING DRIVER_NAME
175                       ": Main firewire function not found. Cannot disable controller.\n");
176                return -ENODEV;
177        }
178
179        return 0;
180}
181
182static void __devexit ricoh_mmc_remove(struct pci_dev *pdev)
183{
184        struct pci_dev *fw_dev = NULL;
185
186        fw_dev = pci_get_drvdata(pdev);
187        BUG_ON(fw_dev == NULL);
188
189        ricoh_mmc_enable(fw_dev);
190
191        pci_set_drvdata(pdev, NULL);
192}
193
194static int ricoh_mmc_suspend(struct pci_dev *pdev, pm_message_t state)
195{
196        struct pci_dev *fw_dev = NULL;
197
198        fw_dev = pci_get_drvdata(pdev);
199        BUG_ON(fw_dev == NULL);
200
201        printk(KERN_INFO DRIVER_NAME ": Suspending.\n");
202
203        ricoh_mmc_enable(fw_dev);
204
205        return 0;
206}
207
208static int ricoh_mmc_resume(struct pci_dev *pdev)
209{
210        struct pci_dev *fw_dev = NULL;
211
212        fw_dev = pci_get_drvdata(pdev);
213        BUG_ON(fw_dev == NULL);
214
215        printk(KERN_INFO DRIVER_NAME ": Resuming.\n");
216
217        ricoh_mmc_disable(fw_dev);
218
219        return 0;
220}
221
222static struct pci_driver ricoh_mmc_driver = {
223        .name =         DRIVER_NAME,
224        .id_table =        pci_ids,
225        .probe =         ricoh_mmc_probe,
226        .remove =        __devexit_p(ricoh_mmc_remove),
227        .suspend =        ricoh_mmc_suspend,
228        .resume =        ricoh_mmc_resume,
229};
230
231/*****************************************************************************\
232 *                                                                           *
233 * Driver init/exit                                                          *
234 *                                                                           *
235\*****************************************************************************/
236
237static int __init ricoh_mmc_drv_init(void)
238{
239        printk(KERN_INFO DRIVER_NAME
240                ": Ricoh MMC Controller disabling driver\n");
241        printk(KERN_INFO DRIVER_NAME ": Copyright(c) Philip Langdale\n");
242
243        return pci_register_driver(&ricoh_mmc_driver);
244}
245
246static void __exit ricoh_mmc_drv_exit(void)
247{
248        pci_unregister_driver(&ricoh_mmc_driver);
249}
250
251module_init(ricoh_mmc_drv_init);
252module_exit(ricoh_mmc_drv_exit);
253
254MODULE_AUTHOR("Philip Langdale <philipl@alumni.utexas.net>");
255MODULE_DESCRIPTION("Ricoh MMC Controller disabling driver");
256MODULE_LICENSE("GPL");
257