root/drivers/misc/cb710/core.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. cb710_pci_update_config_reg
  2. cb710_pci_configure
  3. cb710_irq_handler
  4. cb710_release_slot
  5. cb710_register_slot
  6. cb710_unregister_slot
  7. cb710_set_irq_handler
  8. cb710_suspend
  9. cb710_resume
  10. cb710_probe
  11. cb710_remove_one
  12. cb710_init_module
  13. cb710_cleanup_module

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  *  cb710/core.c
   4  *
   5  *  Copyright by Michał Mirosław, 2008-2009
   6  */
   7 #include <linux/kernel.h>
   8 #include <linux/module.h>
   9 #include <linux/pci.h>
  10 #include <linux/spinlock.h>
  11 #include <linux/idr.h>
  12 #include <linux/cb710.h>
  13 #include <linux/gfp.h>
  14 
  15 static DEFINE_IDA(cb710_ida);
  16 
  17 void cb710_pci_update_config_reg(struct pci_dev *pdev,
  18         int reg, uint32_t mask, uint32_t xor)
  19 {
  20         u32 rval;
  21 
  22         pci_read_config_dword(pdev, reg, &rval);
  23         rval = (rval & mask) ^ xor;
  24         pci_write_config_dword(pdev, reg, rval);
  25 }
  26 EXPORT_SYMBOL_GPL(cb710_pci_update_config_reg);
  27 
  28 /* Some magic writes based on Windows driver init code */
  29 static int cb710_pci_configure(struct pci_dev *pdev)
  30 {
  31         unsigned int devfn = PCI_DEVFN(PCI_SLOT(pdev->devfn), 0);
  32         struct pci_dev *pdev0;
  33         u32 val;
  34 
  35         cb710_pci_update_config_reg(pdev, 0x48,
  36                 ~0x000000FF, 0x0000003F);
  37 
  38         pci_read_config_dword(pdev, 0x48, &val);
  39         if (val & 0x80000000)
  40                 return 0;
  41 
  42         pdev0 = pci_get_slot(pdev->bus, devfn);
  43         if (!pdev0)
  44                 return -ENODEV;
  45 
  46         if (pdev0->vendor == PCI_VENDOR_ID_ENE
  47             && pdev0->device == PCI_DEVICE_ID_ENE_720) {
  48                 cb710_pci_update_config_reg(pdev0, 0x8C,
  49                         ~0x00F00000, 0x00100000);
  50                 cb710_pci_update_config_reg(pdev0, 0xB0,
  51                         ~0x08000000, 0x08000000);
  52         }
  53 
  54         cb710_pci_update_config_reg(pdev0, 0x8C,
  55                 ~0x00000F00, 0x00000200);
  56         cb710_pci_update_config_reg(pdev0, 0x90,
  57                 ~0x00060000, 0x00040000);
  58 
  59         pci_dev_put(pdev0);
  60 
  61         return 0;
  62 }
  63 
  64 static irqreturn_t cb710_irq_handler(int irq, void *data)
  65 {
  66         struct cb710_chip *chip = data;
  67         struct cb710_slot *slot = &chip->slot[0];
  68         irqreturn_t handled = IRQ_NONE;
  69         unsigned nr;
  70 
  71         spin_lock(&chip->irq_lock); /* incl. smp_rmb() */
  72 
  73         for (nr = chip->slots; nr; ++slot, --nr) {
  74                 cb710_irq_handler_t handler_func = slot->irq_handler;
  75                 if (handler_func && handler_func(slot))
  76                         handled = IRQ_HANDLED;
  77         }
  78 
  79         spin_unlock(&chip->irq_lock);
  80 
  81         return handled;
  82 }
  83 
  84 static void cb710_release_slot(struct device *dev)
  85 {
  86 #ifdef CONFIG_CB710_DEBUG_ASSUMPTIONS
  87         struct cb710_slot *slot = cb710_pdev_to_slot(to_platform_device(dev));
  88         struct cb710_chip *chip = cb710_slot_to_chip(slot);
  89 
  90         /* slot struct can be freed now */
  91         atomic_dec(&chip->slot_refs_count);
  92 #endif
  93 }
  94 
  95 static int cb710_register_slot(struct cb710_chip *chip,
  96         unsigned slot_mask, unsigned io_offset, const char *name)
  97 {
  98         int nr = chip->slots;
  99         struct cb710_slot *slot = &chip->slot[nr];
 100         int err;
 101 
 102         dev_dbg(cb710_chip_dev(chip),
 103                 "register: %s.%d; slot %d; mask %d; IO offset: 0x%02X\n",
 104                 name, chip->platform_id, nr, slot_mask, io_offset);
 105 
 106         /* slot->irq_handler == NULL here; this needs to be
 107          * seen before platform_device_register() */
 108         ++chip->slots;
 109         smp_wmb();
 110 
 111         slot->iobase = chip->iobase + io_offset;
 112         slot->pdev.name = name;
 113         slot->pdev.id = chip->platform_id;
 114         slot->pdev.dev.parent = &chip->pdev->dev;
 115         slot->pdev.dev.release = cb710_release_slot;
 116 
 117         err = platform_device_register(&slot->pdev);
 118 
 119 #ifdef CONFIG_CB710_DEBUG_ASSUMPTIONS
 120         atomic_inc(&chip->slot_refs_count);
 121 #endif
 122 
 123         if (err) {
 124                 /* device_initialize() called from platform_device_register()
 125                  * wants this on error path */
 126                 platform_device_put(&slot->pdev);
 127 
 128                 /* slot->irq_handler == NULL here anyway, so no lock needed */
 129                 --chip->slots;
 130                 return err;
 131         }
 132 
 133         chip->slot_mask |= slot_mask;
 134 
 135         return 0;
 136 }
 137 
 138 static void cb710_unregister_slot(struct cb710_chip *chip,
 139         unsigned slot_mask)
 140 {
 141         int nr = chip->slots - 1;
 142 
 143         if (!(chip->slot_mask & slot_mask))
 144                 return;
 145 
 146         platform_device_unregister(&chip->slot[nr].pdev);
 147 
 148         /* complementary to spin_unlock() in cb710_set_irq_handler() */
 149         smp_rmb();
 150         BUG_ON(chip->slot[nr].irq_handler != NULL);
 151 
 152         /* slot->irq_handler == NULL here, so no lock needed */
 153         --chip->slots;
 154         chip->slot_mask &= ~slot_mask;
 155 }
 156 
 157 void cb710_set_irq_handler(struct cb710_slot *slot,
 158         cb710_irq_handler_t handler)
 159 {
 160         struct cb710_chip *chip = cb710_slot_to_chip(slot);
 161         unsigned long flags;
 162 
 163         spin_lock_irqsave(&chip->irq_lock, flags);
 164         slot->irq_handler = handler;
 165         spin_unlock_irqrestore(&chip->irq_lock, flags);
 166 }
 167 EXPORT_SYMBOL_GPL(cb710_set_irq_handler);
 168 
 169 #ifdef CONFIG_PM
 170 
 171 static int cb710_suspend(struct pci_dev *pdev, pm_message_t state)
 172 {
 173         struct cb710_chip *chip = pci_get_drvdata(pdev);
 174 
 175         devm_free_irq(&pdev->dev, pdev->irq, chip);
 176         pci_save_state(pdev);
 177         pci_disable_device(pdev);
 178         if (state.event & PM_EVENT_SLEEP)
 179                 pci_set_power_state(pdev, PCI_D3hot);
 180         return 0;
 181 }
 182 
 183 static int cb710_resume(struct pci_dev *pdev)
 184 {
 185         struct cb710_chip *chip = pci_get_drvdata(pdev);
 186         int err;
 187 
 188         pci_set_power_state(pdev, PCI_D0);
 189         pci_restore_state(pdev);
 190         err = pcim_enable_device(pdev);
 191         if (err)
 192                 return err;
 193 
 194         return devm_request_irq(&pdev->dev, pdev->irq,
 195                 cb710_irq_handler, IRQF_SHARED, KBUILD_MODNAME, chip);
 196 }
 197 
 198 #endif /* CONFIG_PM */
 199 
 200 static int cb710_probe(struct pci_dev *pdev,
 201         const struct pci_device_id *ent)
 202 {
 203         struct cb710_chip *chip;
 204         u32 val;
 205         int err;
 206         int n = 0;
 207 
 208         err = cb710_pci_configure(pdev);
 209         if (err)
 210                 return err;
 211 
 212         /* this is actually magic... */
 213         pci_read_config_dword(pdev, 0x48, &val);
 214         if (!(val & 0x80000000)) {
 215                 pci_write_config_dword(pdev, 0x48, val|0x71000000);
 216                 pci_read_config_dword(pdev, 0x48, &val);
 217         }
 218 
 219         dev_dbg(&pdev->dev, "PCI config[0x48] = 0x%08X\n", val);
 220         if (!(val & 0x70000000))
 221                 return -ENODEV;
 222         val = (val >> 28) & 7;
 223         if (val & CB710_SLOT_MMC)
 224                 ++n;
 225         if (val & CB710_SLOT_MS)
 226                 ++n;
 227         if (val & CB710_SLOT_SM)
 228                 ++n;
 229 
 230         chip = devm_kzalloc(&pdev->dev, struct_size(chip, slot, n),
 231                             GFP_KERNEL);
 232         if (!chip)
 233                 return -ENOMEM;
 234 
 235         err = pcim_enable_device(pdev);
 236         if (err)
 237                 return err;
 238 
 239         err = pcim_iomap_regions(pdev, 0x0001, KBUILD_MODNAME);
 240         if (err)
 241                 return err;
 242 
 243         spin_lock_init(&chip->irq_lock);
 244         chip->pdev = pdev;
 245         chip->iobase = pcim_iomap_table(pdev)[0];
 246 
 247         pci_set_drvdata(pdev, chip);
 248 
 249         err = devm_request_irq(&pdev->dev, pdev->irq,
 250                 cb710_irq_handler, IRQF_SHARED, KBUILD_MODNAME, chip);
 251         if (err)
 252                 return err;
 253 
 254         err = ida_alloc(&cb710_ida, GFP_KERNEL);
 255         if (err < 0)
 256                 return err;
 257         chip->platform_id = err;
 258 
 259         dev_info(&pdev->dev, "id %d, IO 0x%p, IRQ %d\n",
 260                 chip->platform_id, chip->iobase, pdev->irq);
 261 
 262         if (val & CB710_SLOT_MMC) {     /* MMC/SD slot */
 263                 err = cb710_register_slot(chip,
 264                         CB710_SLOT_MMC, 0x00, "cb710-mmc");
 265                 if (err)
 266                         return err;
 267         }
 268 
 269         if (val & CB710_SLOT_MS) {      /* MemoryStick slot */
 270                 err = cb710_register_slot(chip,
 271                         CB710_SLOT_MS, 0x40, "cb710-ms");
 272                 if (err)
 273                         goto unreg_mmc;
 274         }
 275 
 276         if (val & CB710_SLOT_SM) {      /* SmartMedia slot */
 277                 err = cb710_register_slot(chip,
 278                         CB710_SLOT_SM, 0x60, "cb710-sm");
 279                 if (err)
 280                         goto unreg_ms;
 281         }
 282 
 283         return 0;
 284 unreg_ms:
 285         cb710_unregister_slot(chip, CB710_SLOT_MS);
 286 unreg_mmc:
 287         cb710_unregister_slot(chip, CB710_SLOT_MMC);
 288 
 289 #ifdef CONFIG_CB710_DEBUG_ASSUMPTIONS
 290         BUG_ON(atomic_read(&chip->slot_refs_count) != 0);
 291 #endif
 292         return err;
 293 }
 294 
 295 static void cb710_remove_one(struct pci_dev *pdev)
 296 {
 297         struct cb710_chip *chip = pci_get_drvdata(pdev);
 298 
 299         cb710_unregister_slot(chip, CB710_SLOT_SM);
 300         cb710_unregister_slot(chip, CB710_SLOT_MS);
 301         cb710_unregister_slot(chip, CB710_SLOT_MMC);
 302 #ifdef CONFIG_CB710_DEBUG_ASSUMPTIONS
 303         BUG_ON(atomic_read(&chip->slot_refs_count) != 0);
 304 #endif
 305 
 306         ida_free(&cb710_ida, chip->platform_id);
 307 }
 308 
 309 static const struct pci_device_id cb710_pci_tbl[] = {
 310         { PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_CB710_FLASH,
 311                 PCI_ANY_ID, PCI_ANY_ID, },
 312         { 0, }
 313 };
 314 
 315 static struct pci_driver cb710_driver = {
 316         .name = KBUILD_MODNAME,
 317         .id_table = cb710_pci_tbl,
 318         .probe = cb710_probe,
 319         .remove = cb710_remove_one,
 320 #ifdef CONFIG_PM
 321         .suspend = cb710_suspend,
 322         .resume = cb710_resume,
 323 #endif
 324 };
 325 
 326 static int __init cb710_init_module(void)
 327 {
 328         return pci_register_driver(&cb710_driver);
 329 }
 330 
 331 static void __exit cb710_cleanup_module(void)
 332 {
 333         pci_unregister_driver(&cb710_driver);
 334         ida_destroy(&cb710_ida);
 335 }
 336 
 337 module_init(cb710_init_module);
 338 module_exit(cb710_cleanup_module);
 339 
 340 MODULE_AUTHOR("Michał Mirosław <mirq-linux@rere.qmqm.pl>");
 341 MODULE_DESCRIPTION("ENE CB710 memory card reader driver");
 342 MODULE_LICENSE("GPL");
 343 MODULE_DEVICE_TABLE(pci, cb710_pci_tbl);

/* [<][>][^][v][top][bottom][index][help] */