bridge_pcmcia_80211.c 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. /*
  2. * Broadcom 43xx PCMCIA-SSB bridge module
  3. *
  4. * Copyright (c) 2007 Michael Buesch <m@bues.ch>
  5. *
  6. * Licensed under the GNU/GPL. See COPYING for details.
  7. */
  8. #include "ssb_private.h"
  9. #include <linux/ssb/ssb.h>
  10. #include <linux/slab.h>
  11. #include <linux/module.h>
  12. #include <pcmcia/cistpl.h>
  13. #include <pcmcia/ciscode.h>
  14. #include <pcmcia/ds.h>
  15. #include <pcmcia/cisreg.h>
  16. static const struct pcmcia_device_id ssb_host_pcmcia_tbl[] = {
  17. PCMCIA_DEVICE_MANF_CARD(0x2D0, 0x448),
  18. PCMCIA_DEVICE_MANF_CARD(0x2D0, 0x476),
  19. PCMCIA_DEVICE_NULL,
  20. };
  21. MODULE_DEVICE_TABLE(pcmcia, ssb_host_pcmcia_tbl);
  22. static int ssb_host_pcmcia_probe(struct pcmcia_device *dev)
  23. {
  24. struct ssb_bus *ssb;
  25. int err = -ENOMEM;
  26. int res = 0;
  27. ssb = kzalloc(sizeof(*ssb), GFP_KERNEL);
  28. if (!ssb)
  29. goto out_error;
  30. err = -ENODEV;
  31. dev->config_flags |= CONF_ENABLE_IRQ;
  32. dev->resource[2]->flags |= WIN_ENABLE | WIN_DATA_WIDTH_16 |
  33. WIN_USE_WAIT;
  34. dev->resource[2]->start = 0;
  35. dev->resource[2]->end = SSB_CORE_SIZE;
  36. res = pcmcia_request_window(dev, dev->resource[2], 250);
  37. if (res != 0)
  38. goto err_kfree_ssb;
  39. res = pcmcia_map_mem_page(dev, dev->resource[2], 0);
  40. if (res != 0)
  41. goto err_disable;
  42. if (!dev->irq)
  43. goto err_disable;
  44. res = pcmcia_enable_device(dev);
  45. if (res != 0)
  46. goto err_disable;
  47. err = ssb_bus_pcmciabus_register(ssb, dev, dev->resource[2]->start);
  48. if (err)
  49. goto err_disable;
  50. dev->priv = ssb;
  51. return 0;
  52. err_disable:
  53. pcmcia_disable_device(dev);
  54. err_kfree_ssb:
  55. kfree(ssb);
  56. out_error:
  57. dev_err(&dev->dev, "Initialization failed (%d, %d)\n", res, err);
  58. return err;
  59. }
  60. static void ssb_host_pcmcia_remove(struct pcmcia_device *dev)
  61. {
  62. struct ssb_bus *ssb = dev->priv;
  63. ssb_bus_unregister(ssb);
  64. pcmcia_disable_device(dev);
  65. kfree(ssb);
  66. dev->priv = NULL;
  67. }
  68. #ifdef CONFIG_PM
  69. static int ssb_host_pcmcia_suspend(struct pcmcia_device *dev)
  70. {
  71. struct ssb_bus *ssb = dev->priv;
  72. return ssb_bus_suspend(ssb);
  73. }
  74. static int ssb_host_pcmcia_resume(struct pcmcia_device *dev)
  75. {
  76. struct ssb_bus *ssb = dev->priv;
  77. return ssb_bus_resume(ssb);
  78. }
  79. #else /* CONFIG_PM */
  80. # define ssb_host_pcmcia_suspend NULL
  81. # define ssb_host_pcmcia_resume NULL
  82. #endif /* CONFIG_PM */
  83. static struct pcmcia_driver ssb_host_pcmcia_driver = {
  84. .owner = THIS_MODULE,
  85. .name = "ssb-pcmcia",
  86. .id_table = ssb_host_pcmcia_tbl,
  87. .probe = ssb_host_pcmcia_probe,
  88. .remove = ssb_host_pcmcia_remove,
  89. .suspend = ssb_host_pcmcia_suspend,
  90. .resume = ssb_host_pcmcia_resume,
  91. };
  92. static int pcmcia_init_failed;
  93. /*
  94. * These are not module init/exit functions!
  95. * The module_pcmcia_driver() helper cannot be used here.
  96. */
  97. int ssb_host_pcmcia_init(void)
  98. {
  99. pcmcia_init_failed = pcmcia_register_driver(&ssb_host_pcmcia_driver);
  100. return pcmcia_init_failed;
  101. }
  102. void ssb_host_pcmcia_exit(void)
  103. {
  104. if (!pcmcia_init_failed)
  105. pcmcia_unregister_driver(&ssb_host_pcmcia_driver);
  106. }