hermes.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:14k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /* hermes.c
  2.  *
  3.  * Driver core for the "Hermes" wireless MAC controller, as used in
  4.  * the Lucent Orinoco and Cabletron RoamAbout cards. It should also
  5.  * work on the hfa3841 and hfa3842 MAC controller chips used in the
  6.  * Prism II chipsets.
  7.  *
  8.  * This is not a complete driver, just low-level access routines for
  9.  * the MAC controller itself.
  10.  *
  11.  * Based on the prism2 driver from Absolute Value Systems' linux-wlan
  12.  * project, the Linux wvlan_cs driver, Lucent's HCF-Light
  13.  * (wvlan_hcf.c) library, and the NetBSD wireless driver (in no
  14.  * particular order).
  15.  *
  16.  * Copyright (C) 2000, David Gibson, Linuxcare Australia <hermes@gibson.dropbear.id.au>
  17.  * Copyright (C) 2001, David Gibson, IBM <hermes@gibson.dropbear.id.au>
  18.  * 
  19.  * The contents of this file are subject to the Mozilla Public License
  20.  * Version 1.1 (the "License"); you may not use this file except in
  21.  * compliance with the License. You may obtain a copy of the License
  22.  * at http://www.mozilla.org/MPL/
  23.  *
  24.  * Software distributed under the License is distributed on an "AS IS"
  25.  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
  26.  * the License for the specific language governing rights and
  27.  * limitations under the License.
  28.  *
  29.  * Alternatively, the contents of this file may be used under the
  30.  * terms of the GNU General Public License version 2 (the "GPL"), in
  31.  * which case the provisions of the GPL are applicable instead of the
  32.  * above.  If you wish to allow the use of your version of this file
  33.  * only under the terms of the GPL and not to allow others to use your
  34.  * version of this file under the MPL, indicate your decision by
  35.  * deleting the provisions above and replace them with the notice and
  36.  * other provisions required by the GPL.  If you do not delete the
  37.  * provisions above, a recipient may use your version of this file
  38.  * under either the MPL or the GPL.
  39.  */
  40. #include <linux/config.h>
  41. #include <linux/module.h>
  42. #include <linux/types.h>
  43. #include <linux/threads.h>
  44. #include <linux/smp.h>
  45. #include <asm/io.h>
  46. #include <linux/ptrace.h>
  47. #include <linux/delay.h>
  48. #include <linux/init.h>
  49. #include <linux/kernel.h>
  50. #include <asm/errno.h>
  51. #include "hermes.h"
  52. static char version[] __initdata = "hermes.c: 5 Apr 2002 David Gibson <hermes@gibson.dropbear.id.au>";
  53. MODULE_DESCRIPTION("Low-level driver helper for Lucent Hermes chipset and Prism II HFA384x wireless MAC controller");
  54. MODULE_AUTHOR("David Gibson <hermes@gibson.dropbear.id.au>");
  55. #ifdef MODULE_LICENSE
  56. MODULE_LICENSE("Dual MPL/GPL");
  57. #endif
  58. /* These are maximum timeouts. Most often, card wil react much faster */
  59. #define CMD_BUSY_TIMEOUT (100) /* In iterations of ~1us */
  60. #define CMD_INIT_TIMEOUT (50000) /* in iterations of ~10us */
  61. #define CMD_COMPL_TIMEOUT (20000) /* in iterations of ~10us */
  62. #define ALLOC_COMPL_TIMEOUT (1000) /* in iterations of ~10us */
  63. /*
  64.  * Debugging helpers
  65.  */
  66. #undef HERMES_DEBUG
  67. #ifdef HERMES_DEBUG
  68. #include <stdarg.h>
  69. #define DMSG(stuff...) do {printk(KERN_DEBUG "hermes @ 0x%x: " , hw->iobase); 
  70. printk(stuff);} while (0)
  71. #define DEBUG(lvl, stuff...) if ( (lvl) <= HERMES_DEBUG) DMSG(stuff)
  72. #else /* ! HERMES_DEBUG */
  73. #define DEBUG(lvl, stuff...) do { } while (0)
  74. #endif /* ! HERMES_DEBUG */
  75. #define IO_TYPE(hw) ((hw)->io_space ? "IO " : "MEM ")
  76. /*
  77.  * Internal functions
  78.  */
  79. /* Issue a command to the chip. Waiting for it to complete is the caller's
  80.    problem.
  81.    Returns -EBUSY if the command register is busy, 0 on success.
  82.    Callable from any context.
  83. */
  84. static int hermes_issue_cmd(hermes_t *hw, u16 cmd, u16 param0)
  85. {
  86. int k = CMD_BUSY_TIMEOUT;
  87. u16 reg;
  88. /* First wait for the command register to unbusy */
  89. reg = hermes_read_regn(hw, CMD);
  90. while ( (reg & HERMES_CMD_BUSY) && k ) {
  91. k--;
  92. udelay(1);
  93. reg = hermes_read_regn(hw, CMD);
  94. }
  95. DEBUG(3, "hermes_issue_cmd: did %d retries.n", CMD_BUSY_TIMEOUT-k);
  96. if (reg & HERMES_CMD_BUSY) {
  97. return -EBUSY;
  98. }
  99. hermes_write_regn(hw, PARAM2, 0);
  100. hermes_write_regn(hw, PARAM1, 0);
  101. hermes_write_regn(hw, PARAM0, param0);
  102. hermes_write_regn(hw, CMD, cmd);
  103. return 0;
  104. }
  105. /*
  106.  * Function definitions
  107.  */
  108. void hermes_struct_init(hermes_t *hw, ulong address,
  109. int io_space, int reg_spacing)
  110. {
  111. hw->iobase = address;
  112. hw->io_space = io_space;
  113. hw->reg_spacing = reg_spacing;
  114. hw->inten = 0x0;
  115. #ifdef HERMES_DEBUG_BUFFER
  116. hw->dbufp = 0;
  117. memset(&hw->dbuf, 0xff, sizeof(hw->dbuf));
  118. memset(&hw->profile, 0, sizeof(hw->profile));
  119. #endif
  120. }
  121. int hermes_reset(hermes_t *hw)
  122. {
  123. u16 status, reg;
  124. int err = 0;
  125. int k;
  126. /* We don't want to be interrupted while resetting the chipset */
  127. hw->inten = 0x0;
  128. hermes_write_regn(hw, INTEN, 0);
  129. hermes_write_regn(hw, EVACK, 0xffff);
  130. /* Normally it's a "can't happen" for the command register to
  131.            be busy when we go to issue a command because we are
  132.            serializing all commands.  However we want to have some
  133.            chance of resetting the card even if it gets into a stupid
  134.            state, so we actually wait to see if the command register
  135.            will unbusy itself here. */
  136. k = CMD_BUSY_TIMEOUT;
  137. reg = hermes_read_regn(hw, CMD);
  138. while (k && (reg & HERMES_CMD_BUSY)) {
  139. if (reg == 0xffff) /* Special case - the card has probably been removed,
  140.       so don't wait for the timeout */
  141. return -ENODEV;
  142. k--;
  143. udelay(1);
  144. reg = hermes_read_regn(hw, CMD);
  145. }
  146. /* No need to explicitly handle the timeout - if we've timed
  147.    out hermes_issue_cmd() will probably return -EBUSY below */
  148. /* According to the documentation, EVSTAT may contain
  149.    obsolete event occurrence information.  We have to acknowledge
  150.    it by writing EVACK. */
  151. reg = hermes_read_regn(hw, EVSTAT);
  152. hermes_write_regn(hw, EVACK, reg);
  153. /* We don't use hermes_docmd_wait here, because the reset wipes
  154.    the magic constant in SWSUPPORT0 away, and it gets confused */
  155. err = hermes_issue_cmd(hw, HERMES_CMD_INIT, 0);
  156. if (err)
  157. return err;
  158. reg = hermes_read_regn(hw, EVSTAT);
  159. k = CMD_INIT_TIMEOUT;
  160. while ( (! (reg & HERMES_EV_CMD)) && k) {
  161. k--;
  162. udelay(10);
  163. reg = hermes_read_regn(hw, EVSTAT);
  164. }
  165. DEBUG(0, "Reset completed in %d iterationsn", CMD_INIT_TIMEOUT - k);
  166. hermes_write_regn(hw, SWSUPPORT0, HERMES_MAGIC);
  167. if (! hermes_present(hw)) {
  168. DEBUG(0, "hermes @ 0x%x: Card removed during reset.n",
  169.        hw->iobase);
  170. err = -ENODEV;
  171. goto out;
  172. }
  173. if (! (reg & HERMES_EV_CMD)) {
  174. printk(KERN_ERR "hermes @ %s0x%lx: " 
  175.        "Timeout waiting for card to reset (reg=0x%04x)!n",
  176.        IO_TYPE(hw), hw->iobase, reg);
  177. err = -ETIMEDOUT;
  178. goto out;
  179. }
  180. status = hermes_read_regn(hw, STATUS);
  181. hermes_write_regn(hw, EVACK, HERMES_EV_CMD);
  182. if (status & HERMES_STATUS_RESULT)
  183. err = -EIO;
  184.  out:
  185. return err;
  186. }
  187. /* Issue a command to the chip, and (busy!) wait for it to
  188.  * complete.
  189.  *
  190.  * Returns: < 0 on internal error, 0 on success, > 0 on error returned by the firmware
  191.  *
  192.  * Callable from any context, but locking is your problem. */
  193. int hermes_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0, hermes_response_t *resp)
  194. {
  195. int err;
  196. int k;
  197. u16 reg;
  198. u16 status;
  199. err = hermes_issue_cmd(hw, cmd, parm0);
  200. if (err) {
  201. if (! hermes_present(hw)) {
  202. printk(KERN_WARNING "hermes @ %s0x%lx: "
  203.        "Card removed while issuing command.n",
  204.        IO_TYPE(hw), hw->iobase);
  205. err = -ENODEV;
  206. } else 
  207. printk(KERN_ERR "hermes @ %s0x%lx: Error %d issuing command.n",
  208.        IO_TYPE(hw), hw->iobase, err);
  209. goto out;
  210. }
  211. reg = hermes_read_regn(hw, EVSTAT);
  212. k = CMD_COMPL_TIMEOUT;
  213. while ( (! (reg & HERMES_EV_CMD)) && k) {
  214. k--;
  215. udelay(10);
  216. reg = hermes_read_regn(hw, EVSTAT);
  217. }
  218. if (! hermes_present(hw)) {
  219. printk(KERN_WARNING "hermes @ %s0x%lx: "
  220.        "Card removed while waiting for command completion.n",
  221.        IO_TYPE(hw), hw->iobase);
  222. err = -ENODEV;
  223. goto out;
  224. }
  225. if (! (reg & HERMES_EV_CMD)) {
  226. printk(KERN_ERR "hermes @ %s0x%lx: "
  227.        "Timeout waiting for command completion.n",
  228.        IO_TYPE(hw), hw->iobase);
  229. err = -ETIMEDOUT;
  230. goto out;
  231. }
  232. status = hermes_read_regn(hw, STATUS);
  233. if (resp) {
  234. resp->status = status;
  235. resp->resp0 = hermes_read_regn(hw, RESP0);
  236. resp->resp1 = hermes_read_regn(hw, RESP1);
  237. resp->resp2 = hermes_read_regn(hw, RESP2);
  238. }
  239. hermes_write_regn(hw, EVACK, HERMES_EV_CMD);
  240. if (status & HERMES_STATUS_RESULT)
  241. err = -EIO;
  242.  out:
  243. return err;
  244. }
  245. int hermes_allocate(hermes_t *hw, u16 size, u16 *fid)
  246. {
  247. int err = 0;
  248. int k;
  249. u16 reg;
  250. if ( (size < HERMES_ALLOC_LEN_MIN) || (size > HERMES_ALLOC_LEN_MAX) )
  251. return -EINVAL;
  252. err = hermes_docmd_wait(hw, HERMES_CMD_ALLOC, size, NULL);
  253. if (err) {
  254. printk(KERN_WARNING "hermes @ %s0x%lx: "
  255.        "Frame allocation command failed (0x%X).n",
  256.        IO_TYPE(hw), hw->iobase, err);
  257. return err;
  258. }
  259. reg = hermes_read_regn(hw, EVSTAT);
  260. k = ALLOC_COMPL_TIMEOUT;
  261. while ( (! (reg & HERMES_EV_ALLOC)) && k) {
  262. k--;
  263. udelay(10);
  264. reg = hermes_read_regn(hw, EVSTAT);
  265. }
  266. if (! hermes_present(hw)) {
  267. printk(KERN_WARNING "hermes @ %s0x%lx: "
  268.        "Card removed waiting for frame allocation.n",
  269.        IO_TYPE(hw), hw->iobase);
  270. return -ENODEV;
  271. }
  272. if (! (reg & HERMES_EV_ALLOC)) {
  273. printk(KERN_ERR "hermes @ %s0x%lx: "
  274.        "Timeout waiting for frame allocationn",
  275.        IO_TYPE(hw), hw->iobase);
  276. return -ETIMEDOUT;
  277. }
  278. *fid = hermes_read_regn(hw, ALLOCFID);
  279. hermes_write_regn(hw, EVACK, HERMES_EV_ALLOC);
  280. return 0;
  281. }
  282. /* Set up a BAP to read a particular chunk of data from card's internal buffer.
  283.  *
  284.  * Returns: < 0 on internal failure (errno), 0 on success, >0 on error
  285.  * from firmware
  286.  *
  287.  * Callable from any context */
  288. static int hermes_bap_seek(hermes_t *hw, int bap, u16 id, u16 offset)
  289. {
  290. int sreg = bap ? HERMES_SELECT1 : HERMES_SELECT0;
  291. int oreg = bap ? HERMES_OFFSET1 : HERMES_OFFSET0;
  292. int k;
  293. u16 reg;
  294. /* Paranoia.. */
  295. if ( (offset > HERMES_BAP_OFFSET_MAX) || (offset % 2) )
  296. return -EINVAL;
  297. k = HERMES_BAP_BUSY_TIMEOUT;
  298. reg = hermes_read_reg(hw, oreg);
  299. while ((reg & HERMES_OFFSET_BUSY) && k) {
  300. k--;
  301. udelay(1);
  302. reg = hermes_read_reg(hw, oreg);
  303. }
  304. #ifdef HERMES_DEBUG_BUFFER
  305. hw->profile[HERMES_BAP_BUSY_TIMEOUT - k]++;
  306. if (k < HERMES_BAP_BUSY_TIMEOUT) {
  307. struct hermes_debug_entry *e = 
  308. &hw->dbuf[(hw->dbufp++) % HERMES_DEBUG_BUFSIZE];
  309. e->bap = bap;
  310. e->id = id;
  311. e->offset = offset;
  312. e->cycles = HERMES_BAP_BUSY_TIMEOUT - k;
  313. }
  314. #endif
  315. if (reg & HERMES_OFFSET_BUSY)
  316. return -ETIMEDOUT;
  317. /* Now we actually set up the transfer */
  318. hermes_write_reg(hw, sreg, id);
  319. hermes_write_reg(hw, oreg, offset);
  320. /* Wait for the BAP to be ready */
  321. k = HERMES_BAP_BUSY_TIMEOUT;
  322. reg = hermes_read_reg(hw, oreg);
  323. while ( (reg & (HERMES_OFFSET_BUSY | HERMES_OFFSET_ERR)) && k) {
  324. k--;
  325. udelay(1);
  326. reg = hermes_read_reg(hw, oreg);
  327. }
  328. if (reg & HERMES_OFFSET_BUSY) {
  329. DEBUG(1,"hermes_bap_seek: timeoutn");
  330. return -ETIMEDOUT;
  331. }
  332. if (reg & HERMES_OFFSET_ERR) {
  333. DEBUG(1,"hermes_bap_seek: BAP errorn");
  334. return -EIO;
  335. }
  336. return 0;
  337. }
  338. /* Read a block of data from the chip's buffer, via the
  339.  * BAP. Synchronization/serialization is the caller's problem.  len
  340.  * must be even.
  341.  *
  342.  * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware
  343.  */
  344. int hermes_bap_pread(hermes_t *hw, int bap, void *buf, int len,
  345.      u16 id, u16 offset)
  346. {
  347. int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
  348. int err = 0;
  349. if ( (len < 0) || (len % 2) )
  350. return -EINVAL;
  351. err = hermes_bap_seek(hw, bap, id, offset);
  352. if (err)
  353. goto out;
  354. /* Actually do the transfer */
  355. hermes_read_words(hw, dreg, buf, len/2);
  356.  out:
  357. return err;
  358. }
  359. /* Write a block of data to the chip's buffer, via the
  360.  * BAP. Synchronization/serialization is the caller's problem. len
  361.  * must be even.
  362.  *
  363.  * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware
  364.  */
  365. int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, int len,
  366.       u16 id, u16 offset)
  367. {
  368. int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
  369. int err = 0;
  370. if ( (len < 0) || (len % 2) )
  371. return -EINVAL;
  372. err = hermes_bap_seek(hw, bap, id, offset);
  373. if (err)
  374. goto out;
  375. /* Actually do the transfer */
  376. hermes_write_words(hw, dreg, buf, len/2);
  377.  out:
  378. return err;
  379. }
  380. /* Read a Length-Type-Value record from the card.
  381.  *
  382.  * If length is NULL, we ignore the length read from the card, and
  383.  * read the entire buffer regardless. This is useful because some of
  384.  * the configuration records appear to have incorrect lengths in
  385.  * practice.
  386.  *
  387.  * Callable from user or bh context.  */
  388. int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, int bufsize,
  389.     u16 *length, void *buf)
  390. {
  391. int err = 0;
  392. int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
  393. u16 rlength, rtype;
  394. if ( (bufsize < 0) || (bufsize % 2) )
  395. return -EINVAL;
  396. err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS, rid, NULL);
  397. if (err)
  398. goto out;
  399. err = hermes_bap_seek(hw, bap, rid, 0);
  400. if (err)
  401. goto out;
  402. rlength = hermes_read_reg(hw, dreg);
  403. rtype = hermes_read_reg(hw, dreg);
  404. if (length)
  405. *length = rlength;
  406. if (rtype != rid)
  407. printk(KERN_WARNING "hermes @ %s0x%lx: "
  408.        "hermes_read_ltv(): rid  (0x%04x) does not match type (0x%04x)n",
  409.        IO_TYPE(hw), hw->iobase, rid, rtype);
  410. if (HERMES_RECLEN_TO_BYTES(rlength) > bufsize)
  411. printk(KERN_WARNING "hermes @ %s0x%lx: "
  412.        "Truncating LTV record from %d to %d bytes. "
  413.        "(rid=0x%04x, len=0x%04x)n",
  414.        IO_TYPE(hw), hw->iobase,
  415.        HERMES_RECLEN_TO_BYTES(rlength), bufsize, rid, rlength);
  416. /* FIXME: we should read the min of the requested length and
  417.            the actual record length */
  418. hermes_read_words(hw, dreg, buf, bufsize / 2);
  419.  out:
  420. return err;
  421. }
  422. int hermes_write_ltv(hermes_t *hw, int bap, u16 rid, 
  423.      u16 length, const void *value)
  424. {
  425. int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
  426. int err = 0;
  427. int count;
  428. DEBUG(3, "write_ltv(): bap=%d rid=0x%04x length=%d (value=0x%04x)n",
  429.       bap, rid, length, * ((u16 *)value));
  430. err = hermes_bap_seek(hw, bap, rid, 0);
  431. if (err)
  432. goto out;
  433. hermes_write_reg(hw, dreg, length);
  434. hermes_write_reg(hw, dreg, rid);
  435. count = length - 1;
  436. hermes_write_words(hw, dreg, value, count);
  437. err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS | HERMES_CMD_WRITE, 
  438. rid, NULL);
  439.  out:
  440. return err;
  441. }
  442. EXPORT_SYMBOL(hermes_struct_init);
  443. EXPORT_SYMBOL(hermes_reset);
  444. EXPORT_SYMBOL(hermes_docmd_wait);
  445. EXPORT_SYMBOL(hermes_allocate);
  446. EXPORT_SYMBOL(hermes_bap_pread);
  447. EXPORT_SYMBOL(hermes_bap_pwrite);
  448. EXPORT_SYMBOL(hermes_read_ltv);
  449. EXPORT_SYMBOL(hermes_write_ltv);
  450. static int __init init_hermes(void)
  451. {
  452. printk(KERN_DEBUG "%sn", version);
  453. return 0;
  454. }
  455. module_init(init_hermes);