spectrum_cs.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661
  1. /*
  2. * Driver for 802.11b cards using RAM-loadable Symbol firmware, such as
  3. * Symbol Wireless Networker LA4137, CompactFlash cards by Socket
  4. * Communications and Intel PRO/Wireless 2011B.
  5. *
  6. * The driver implements Symbol firmware download. The rest is handled
  7. * in hermes.c and orinoco.c.
  8. *
  9. * Utilities for downloading the Symbol firmware are available at
  10. * http://sourceforge.net/projects/orinoco/
  11. *
  12. * Copyright (C) 2002-2005 Pavel Roskin <proski@gnu.org>
  13. * Portions based on orinoco_cs.c:
  14. * Copyright (C) David Gibson, Linuxcare Australia
  15. * Portions based on Spectrum24tDnld.c from original spectrum24 driver:
  16. * Copyright (C) Symbol Technologies.
  17. *
  18. * See copyright notice in file orinoco.c.
  19. */
  20. #define DRIVER_NAME "spectrum_cs"
  21. #define PFX DRIVER_NAME ": "
  22. #include <linux/module.h>
  23. #include <linux/kernel.h>
  24. #include <linux/init.h>
  25. #include <linux/delay.h>
  26. #include <linux/firmware.h>
  27. #include <pcmcia/cs_types.h>
  28. #include <pcmcia/cs.h>
  29. #include <pcmcia/cistpl.h>
  30. #include <pcmcia/cisreg.h>
  31. #include <pcmcia/ds.h>
  32. #include "orinoco.h"
  33. #include "hermes_dld.h"
  34. static const char primary_fw_name[] = "symbol_sp24t_prim_fw";
  35. static const char secondary_fw_name[] = "symbol_sp24t_sec_fw";
  36. /********************************************************************/
  37. /* Module stuff */
  38. /********************************************************************/
  39. MODULE_AUTHOR("Pavel Roskin <proski@gnu.org>");
  40. MODULE_DESCRIPTION("Driver for Symbol Spectrum24 Trilogy cards with firmware downloader");
  41. MODULE_LICENSE("Dual MPL/GPL");
  42. /* Module parameters */
  43. /* Some D-Link cards have buggy CIS. They do work at 5v properly, but
  44. * don't have any CIS entry for it. This workaround it... */
  45. static int ignore_cis_vcc; /* = 0 */
  46. module_param(ignore_cis_vcc, int, 0);
  47. MODULE_PARM_DESC(ignore_cis_vcc, "Allow voltage mismatch between card and socket");
  48. /********************************************************************/
  49. /* Data structures */
  50. /********************************************************************/
  51. /* PCMCIA specific device information (goes in the card field of
  52. * struct orinoco_private */
  53. struct orinoco_pccard {
  54. struct pcmcia_device *p_dev;
  55. dev_node_t node;
  56. };
  57. /********************************************************************/
  58. /* Function prototypes */
  59. /********************************************************************/
  60. static int spectrum_cs_config(struct pcmcia_device *link);
  61. static void spectrum_cs_release(struct pcmcia_device *link);
  62. /********************************************************************/
  63. /* Firmware downloader */
  64. /********************************************************************/
  65. /* Position of PDA in the adapter memory */
  66. #define EEPROM_ADDR 0x3000
  67. #define EEPROM_LEN 0x200
  68. #define PDA_OFFSET 0x100
  69. #define PDA_ADDR (EEPROM_ADDR + PDA_OFFSET)
  70. #define PDA_WORDS ((EEPROM_LEN - PDA_OFFSET) / 2)
  71. /* Constants for the CISREG_CCSR register */
  72. #define HCR_RUN 0x07 /* run firmware after reset */
  73. #define HCR_IDLE 0x0E /* don't run firmware after reset */
  74. #define HCR_MEM16 0x10 /* memory width bit, should be preserved */
  75. /* End markers */
  76. #define TEXT_END 0x1A /* End of text header */
  77. #define CS_CHECK(fn, ret) \
  78. do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
  79. /*
  80. * Reset the card using configuration registers COR and CCSR.
  81. * If IDLE is 1, stop the firmware, so that it can be safely rewritten.
  82. */
  83. static int
  84. spectrum_reset(struct pcmcia_device *link, int idle)
  85. {
  86. int last_ret, last_fn;
  87. conf_reg_t reg;
  88. u_int save_cor;
  89. /* Doing it if hardware is gone is guaranteed crash */
  90. if (!pcmcia_dev_present(link))
  91. return -ENODEV;
  92. /* Save original COR value */
  93. reg.Function = 0;
  94. reg.Action = CS_READ;
  95. reg.Offset = CISREG_COR;
  96. CS_CHECK(AccessConfigurationRegister,
  97. pcmcia_access_configuration_register(link, &reg));
  98. save_cor = reg.Value;
  99. /* Soft-Reset card */
  100. reg.Action = CS_WRITE;
  101. reg.Offset = CISREG_COR;
  102. reg.Value = (save_cor | COR_SOFT_RESET);
  103. CS_CHECK(AccessConfigurationRegister,
  104. pcmcia_access_configuration_register(link, &reg));
  105. udelay(1000);
  106. /* Read CCSR */
  107. reg.Action = CS_READ;
  108. reg.Offset = CISREG_CCSR;
  109. CS_CHECK(AccessConfigurationRegister,
  110. pcmcia_access_configuration_register(link, &reg));
  111. /*
  112. * Start or stop the firmware. Memory width bit should be
  113. * preserved from the value we've just read.
  114. */
  115. reg.Action = CS_WRITE;
  116. reg.Offset = CISREG_CCSR;
  117. reg.Value = (idle ? HCR_IDLE : HCR_RUN) | (reg.Value & HCR_MEM16);
  118. CS_CHECK(AccessConfigurationRegister,
  119. pcmcia_access_configuration_register(link, &reg));
  120. udelay(1000);
  121. /* Restore original COR configuration index */
  122. reg.Action = CS_WRITE;
  123. reg.Offset = CISREG_COR;
  124. reg.Value = (save_cor & ~COR_SOFT_RESET);
  125. CS_CHECK(AccessConfigurationRegister,
  126. pcmcia_access_configuration_register(link, &reg));
  127. udelay(1000);
  128. return 0;
  129. cs_failed:
  130. cs_error(link, last_fn, last_ret);
  131. return -ENODEV;
  132. }
  133. /*
  134. * Process a firmware image - stop the card, load the firmware, reset
  135. * the card and make sure it responds. For the secondary firmware take
  136. * care of the PDA - read it and then write it on top of the firmware.
  137. */
  138. static int
  139. spectrum_dl_image(hermes_t *hw, struct pcmcia_device *link,
  140. const unsigned char *image, const unsigned char *end,
  141. int secondary)
  142. {
  143. int ret;
  144. const unsigned char *ptr;
  145. const unsigned char *first_block;
  146. /* Plug Data Area (PDA) */
  147. __le16 pda[PDA_WORDS];
  148. /* Binary block begins after the 0x1A marker */
  149. ptr = image;
  150. while (*ptr++ != TEXT_END);
  151. first_block = ptr;
  152. /* Read the PDA from EEPROM */
  153. if (secondary) {
  154. ret = hermes_read_pda(hw, pda, PDA_ADDR, sizeof(pda), 1);
  155. if (ret)
  156. return ret;
  157. }
  158. /* Stop the firmware, so that it can be safely rewritten */
  159. ret = spectrum_reset(link, 1);
  160. if (ret)
  161. return ret;
  162. /* Program the adapter with new firmware */
  163. ret = hermes_program(hw, first_block, end);
  164. if (ret)
  165. return ret;
  166. /* Write the PDA to the adapter */
  167. if (secondary) {
  168. size_t len = hermes_blocks_length(first_block);
  169. ptr = first_block + len;
  170. ret = hermes_apply_pda(hw, ptr, pda);
  171. if (ret)
  172. return ret;
  173. }
  174. /* Run the firmware */
  175. ret = spectrum_reset(link, 0);
  176. if (ret)
  177. return ret;
  178. /* Reset hermes chip and make sure it responds */
  179. ret = hermes_init(hw);
  180. /* hermes_reset() should return 0 with the secondary firmware */
  181. if (secondary && ret != 0)
  182. return -ENODEV;
  183. /* And this should work with any firmware */
  184. if (!hermes_present(hw))
  185. return -ENODEV;
  186. return 0;
  187. }
  188. /*
  189. * Download the firmware into the card, this also does a PCMCIA soft
  190. * reset on the card, to make sure it's in a sane state.
  191. */
  192. static int
  193. spectrum_dl_firmware(hermes_t *hw, struct pcmcia_device *link)
  194. {
  195. int ret;
  196. const struct firmware *fw_entry;
  197. if (request_firmware(&fw_entry, primary_fw_name,
  198. &handle_to_dev(link)) != 0) {
  199. printk(KERN_ERR PFX "Cannot find firmware: %s\n",
  200. primary_fw_name);
  201. return -ENOENT;
  202. }
  203. /* Load primary firmware */
  204. ret = spectrum_dl_image(hw, link, fw_entry->data,
  205. fw_entry->data + fw_entry->size, 0);
  206. release_firmware(fw_entry);
  207. if (ret) {
  208. printk(KERN_ERR PFX "Primary firmware download failed\n");
  209. return ret;
  210. }
  211. if (request_firmware(&fw_entry, secondary_fw_name,
  212. &handle_to_dev(link)) != 0) {
  213. printk(KERN_ERR PFX "Cannot find firmware: %s\n",
  214. secondary_fw_name);
  215. return -ENOENT;
  216. }
  217. /* Load secondary firmware */
  218. ret = spectrum_dl_image(hw, link, fw_entry->data,
  219. fw_entry->data + fw_entry->size, 1);
  220. release_firmware(fw_entry);
  221. if (ret) {
  222. printk(KERN_ERR PFX "Secondary firmware download failed\n");
  223. }
  224. return ret;
  225. }
  226. /********************************************************************/
  227. /* Device methods */
  228. /********************************************************************/
  229. static int
  230. spectrum_cs_hard_reset(struct orinoco_private *priv)
  231. {
  232. struct orinoco_pccard *card = priv->card;
  233. struct pcmcia_device *link = card->p_dev;
  234. int err;
  235. if (!hermes_present(&priv->hw)) {
  236. /* The firmware needs to be reloaded */
  237. if (spectrum_dl_firmware(&priv->hw, link) != 0) {
  238. printk(KERN_ERR PFX "Firmware download failed\n");
  239. err = -ENODEV;
  240. }
  241. } else {
  242. /* Soft reset using COR and HCR */
  243. spectrum_reset(link, 0);
  244. }
  245. return 0;
  246. }
  247. /********************************************************************/
  248. /* PCMCIA stuff */
  249. /********************************************************************/
  250. /*
  251. * This creates an "instance" of the driver, allocating local data
  252. * structures for one device. The device is registered with Card
  253. * Services.
  254. *
  255. * The dev_link structure is initialized, but we don't actually
  256. * configure the card at this point -- we wait until we receive a card
  257. * insertion event. */
  258. static int
  259. spectrum_cs_probe(struct pcmcia_device *link)
  260. {
  261. struct net_device *dev;
  262. struct orinoco_private *priv;
  263. struct orinoco_pccard *card;
  264. dev = alloc_orinocodev(sizeof(*card), spectrum_cs_hard_reset);
  265. if (! dev)
  266. return -ENOMEM;
  267. priv = netdev_priv(dev);
  268. card = priv->card;
  269. /* Link both structures together */
  270. card->p_dev = link;
  271. link->priv = dev;
  272. /* Interrupt setup */
  273. link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
  274. link->irq.IRQInfo1 = IRQ_LEVEL_ID;
  275. link->irq.Handler = orinoco_interrupt;
  276. link->irq.Instance = dev;
  277. /* General socket configuration defaults can go here. In this
  278. * client, we assume very little, and rely on the CIS for
  279. * almost everything. In most clients, many details (i.e.,
  280. * number, sizes, and attributes of IO windows) are fixed by
  281. * the nature of the device, and can be hard-wired here. */
  282. link->conf.Attributes = 0;
  283. link->conf.IntType = INT_MEMORY_AND_IO;
  284. return spectrum_cs_config(link);
  285. } /* spectrum_cs_attach */
  286. /*
  287. * This deletes a driver "instance". The device is de-registered with
  288. * Card Services. If it has been released, all local data structures
  289. * are freed. Otherwise, the structures will be freed when the device
  290. * is released.
  291. */
  292. static void spectrum_cs_detach(struct pcmcia_device *link)
  293. {
  294. struct net_device *dev = link->priv;
  295. if (link->dev_node)
  296. unregister_netdev(dev);
  297. spectrum_cs_release(link);
  298. free_orinocodev(dev);
  299. } /* spectrum_cs_detach */
  300. /*
  301. * spectrum_cs_config() is scheduled to run after a CARD_INSERTION
  302. * event is received, to configure the PCMCIA socket, and to make the
  303. * device available to the system.
  304. */
  305. static int
  306. spectrum_cs_config(struct pcmcia_device *link)
  307. {
  308. struct net_device *dev = link->priv;
  309. struct orinoco_private *priv = netdev_priv(dev);
  310. struct orinoco_pccard *card = priv->card;
  311. hermes_t *hw = &priv->hw;
  312. int last_fn, last_ret;
  313. u_char buf[64];
  314. config_info_t conf;
  315. tuple_t tuple;
  316. cisparse_t parse;
  317. void __iomem *mem;
  318. /* Look up the current Vcc */
  319. CS_CHECK(GetConfigurationInfo,
  320. pcmcia_get_configuration_info(link, &conf));
  321. /*
  322. * In this loop, we scan the CIS for configuration table
  323. * entries, each of which describes a valid card
  324. * configuration, including voltage, IO window, memory window,
  325. * and interrupt settings.
  326. *
  327. * We make no assumptions about the card to be configured: we
  328. * use just the information available in the CIS. In an ideal
  329. * world, this would work for any PCMCIA card, but it requires
  330. * a complete and accurate CIS. In practice, a driver usually
  331. * "knows" most of these things without consulting the CIS,
  332. * and most client drivers will only use the CIS to fill in
  333. * implementation-defined details.
  334. */
  335. tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
  336. tuple.Attributes = 0;
  337. tuple.TupleData = buf;
  338. tuple.TupleDataMax = sizeof(buf);
  339. tuple.TupleOffset = 0;
  340. CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
  341. while (1) {
  342. cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
  343. cistpl_cftable_entry_t dflt = { .index = 0 };
  344. if ( (pcmcia_get_tuple_data(link, &tuple) != 0)
  345. || (pcmcia_parse_tuple(link, &tuple, &parse) != 0))
  346. goto next_entry;
  347. if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
  348. dflt = *cfg;
  349. if (cfg->index == 0)
  350. goto next_entry;
  351. link->conf.ConfigIndex = cfg->index;
  352. /* Use power settings for Vcc and Vpp if present */
  353. /* Note that the CIS values need to be rescaled */
  354. if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
  355. if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) {
  356. DEBUG(2, "spectrum_cs_config: Vcc mismatch (conf.Vcc = %d, CIS = %d)\n", conf.Vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000);
  357. if (!ignore_cis_vcc)
  358. goto next_entry;
  359. }
  360. } else if (dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) {
  361. if (conf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM] / 10000) {
  362. DEBUG(2, "spectrum_cs_config: Vcc mismatch (conf.Vcc = %d, CIS = %d)\n", conf.Vcc, dflt.vcc.param[CISTPL_POWER_VNOM] / 10000);
  363. if(!ignore_cis_vcc)
  364. goto next_entry;
  365. }
  366. }
  367. if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
  368. link->conf.Vpp =
  369. cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
  370. else if (dflt.vpp1.present & (1 << CISTPL_POWER_VNOM))
  371. link->conf.Vpp =
  372. dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000;
  373. /* Do we need to allocate an interrupt? */
  374. link->conf.Attributes |= CONF_ENABLE_IRQ;
  375. /* IO window settings */
  376. link->io.NumPorts1 = link->io.NumPorts2 = 0;
  377. if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
  378. cistpl_io_t *io =
  379. (cfg->io.nwin) ? &cfg->io : &dflt.io;
  380. link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
  381. if (!(io->flags & CISTPL_IO_8BIT))
  382. link->io.Attributes1 =
  383. IO_DATA_PATH_WIDTH_16;
  384. if (!(io->flags & CISTPL_IO_16BIT))
  385. link->io.Attributes1 =
  386. IO_DATA_PATH_WIDTH_8;
  387. link->io.IOAddrLines =
  388. io->flags & CISTPL_IO_LINES_MASK;
  389. link->io.BasePort1 = io->win[0].base;
  390. link->io.NumPorts1 = io->win[0].len;
  391. if (io->nwin > 1) {
  392. link->io.Attributes2 =
  393. link->io.Attributes1;
  394. link->io.BasePort2 = io->win[1].base;
  395. link->io.NumPorts2 = io->win[1].len;
  396. }
  397. /* This reserves IO space but doesn't actually enable it */
  398. if (pcmcia_request_io(link, &link->io) != 0)
  399. goto next_entry;
  400. }
  401. /* If we got this far, we're cool! */
  402. break;
  403. next_entry:
  404. pcmcia_disable_device(link);
  405. last_ret = pcmcia_get_next_tuple(link, &tuple);
  406. if (last_ret == CS_NO_MORE_ITEMS) {
  407. printk(KERN_ERR PFX "GetNextTuple(): No matching "
  408. "CIS configuration. Maybe you need the "
  409. "ignore_cis_vcc=1 parameter.\n");
  410. goto cs_failed;
  411. }
  412. }
  413. /*
  414. * Allocate an interrupt line. Note that this does not assign
  415. * a handler to the interrupt, unless the 'Handler' member of
  416. * the irq structure is initialized.
  417. */
  418. CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
  419. /* We initialize the hermes structure before completing PCMCIA
  420. * configuration just in case the interrupt handler gets
  421. * called. */
  422. mem = ioport_map(link->io.BasePort1, link->io.NumPorts1);
  423. if (!mem)
  424. goto cs_failed;
  425. hermes_struct_init(hw, mem, HERMES_16BIT_REGSPACING);
  426. /*
  427. * This actually configures the PCMCIA socket -- setting up
  428. * the I/O windows and the interrupt mapping, and putting the
  429. * card and host interface into "Memory and IO" mode.
  430. */
  431. CS_CHECK(RequestConfiguration,
  432. pcmcia_request_configuration(link, &link->conf));
  433. /* Ok, we have the configuration, prepare to register the netdev */
  434. dev->base_addr = link->io.BasePort1;
  435. dev->irq = link->irq.AssignedIRQ;
  436. card->node.major = card->node.minor = 0;
  437. /* Reset card and download firmware */
  438. if (spectrum_cs_hard_reset(priv) != 0) {
  439. goto failed;
  440. }
  441. SET_NETDEV_DEV(dev, &handle_to_dev(link));
  442. /* Tell the stack we exist */
  443. if (register_netdev(dev) != 0) {
  444. printk(KERN_ERR PFX "register_netdev() failed\n");
  445. goto failed;
  446. }
  447. /* At this point, the dev_node_t structure(s) needs to be
  448. * initialized and arranged in a linked list at link->dev_node. */
  449. strcpy(card->node.dev_name, dev->name);
  450. link->dev_node = &card->node; /* link->dev_node being non-NULL is also
  451. used to indicate that the
  452. net_device has been registered */
  453. /* Finally, report what we've done */
  454. printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s, irq %d, io "
  455. "0x%04x-0x%04x\n", dev->name, dev->dev.parent->bus_id,
  456. link->irq.AssignedIRQ, link->io.BasePort1,
  457. link->io.BasePort1 + link->io.NumPorts1 - 1);
  458. return 0;
  459. cs_failed:
  460. cs_error(link, last_fn, last_ret);
  461. failed:
  462. spectrum_cs_release(link);
  463. return -ENODEV;
  464. } /* spectrum_cs_config */
  465. /*
  466. * After a card is removed, spectrum_cs_release() will unregister the
  467. * device, and release the PCMCIA configuration. If the device is
  468. * still open, this will be postponed until it is closed.
  469. */
  470. static void
  471. spectrum_cs_release(struct pcmcia_device *link)
  472. {
  473. struct net_device *dev = link->priv;
  474. struct orinoco_private *priv = netdev_priv(dev);
  475. unsigned long flags;
  476. /* We're committed to taking the device away now, so mark the
  477. * hardware as unavailable */
  478. spin_lock_irqsave(&priv->lock, flags);
  479. priv->hw_unavailable++;
  480. spin_unlock_irqrestore(&priv->lock, flags);
  481. pcmcia_disable_device(link);
  482. if (priv->hw.iobase)
  483. ioport_unmap(priv->hw.iobase);
  484. } /* spectrum_cs_release */
  485. static int
  486. spectrum_cs_suspend(struct pcmcia_device *link)
  487. {
  488. struct net_device *dev = link->priv;
  489. struct orinoco_private *priv = netdev_priv(dev);
  490. int err = 0;
  491. /* Mark the device as stopped, to block IO until later */
  492. spin_lock(&priv->lock);
  493. err = __orinoco_down(dev);
  494. if (err)
  495. printk(KERN_WARNING "%s: Error %d downing interface\n",
  496. dev->name, err);
  497. netif_device_detach(dev);
  498. priv->hw_unavailable++;
  499. spin_unlock(&priv->lock);
  500. return err;
  501. }
  502. static int
  503. spectrum_cs_resume(struct pcmcia_device *link)
  504. {
  505. struct net_device *dev = link->priv;
  506. struct orinoco_private *priv = netdev_priv(dev);
  507. netif_device_attach(dev);
  508. priv->hw_unavailable--;
  509. schedule_work(&priv->reset_work);
  510. return 0;
  511. }
  512. /********************************************************************/
  513. /* Module initialization */
  514. /********************************************************************/
  515. /* Can't be declared "const" or the whole __initdata section will
  516. * become const */
  517. static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
  518. " (Pavel Roskin <proski@gnu.org>,"
  519. " David Gibson <hermes@gibson.dropbear.id.au>, et al)";
  520. static struct pcmcia_device_id spectrum_cs_ids[] = {
  521. PCMCIA_DEVICE_MANF_CARD(0x026c, 0x0001), /* Symbol Spectrum24 LA4137 */
  522. PCMCIA_DEVICE_MANF_CARD(0x0104, 0x0001), /* Socket Communications CF */
  523. PCMCIA_DEVICE_PROD_ID12("Intel", "PRO/Wireless LAN PC Card", 0x816cc815, 0x6fbf459a), /* 2011B, not 2011 */
  524. PCMCIA_DEVICE_NULL,
  525. };
  526. MODULE_DEVICE_TABLE(pcmcia, spectrum_cs_ids);
  527. static struct pcmcia_driver orinoco_driver = {
  528. .owner = THIS_MODULE,
  529. .drv = {
  530. .name = DRIVER_NAME,
  531. },
  532. .probe = spectrum_cs_probe,
  533. .remove = spectrum_cs_detach,
  534. .suspend = spectrum_cs_suspend,
  535. .resume = spectrum_cs_resume,
  536. .id_table = spectrum_cs_ids,
  537. };
  538. static int __init
  539. init_spectrum_cs(void)
  540. {
  541. printk(KERN_DEBUG "%s\n", version);
  542. return pcmcia_register_driver(&orinoco_driver);
  543. }
  544. static void __exit
  545. exit_spectrum_cs(void)
  546. {
  547. pcmcia_unregister_driver(&orinoco_driver);
  548. }
  549. module_init(init_spectrum_cs);
  550. module_exit(exit_spectrum_cs);