prism2fw.c 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236
  1. // SPDX-License-Identifier: (GPL-2.0 OR MPL-1.1)
  2. /* from src/prism2/download/prism2dl.c
  3. *
  4. * utility for downloading prism2 images moved into kernelspace
  5. *
  6. * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved.
  7. * --------------------------------------------------------------------
  8. *
  9. * linux-wlan
  10. *
  11. * The contents of this file are subject to the Mozilla Public
  12. * License Version 1.1 (the "License"); you may not use this file
  13. * except in compliance with the License. You may obtain a copy of
  14. * the License at http://www.mozilla.org/MPL/
  15. *
  16. * Software distributed under the License is distributed on an "AS
  17. * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  18. * implied. See the License for the specific language governing
  19. * rights and limitations under the License.
  20. *
  21. * Alternatively, the contents of this file may be used under the
  22. * terms of the GNU Public License version 2 (the "GPL"), in which
  23. * case the provisions of the GPL are applicable instead of the
  24. * above. If you wish to allow the use of your version of this file
  25. * only under the terms of the GPL and not to allow others to use
  26. * your version of this file under the MPL, indicate your decision
  27. * by deleting the provisions above and replace them with the notice
  28. * and other provisions required by the GPL. If you do not delete
  29. * the provisions above, a recipient may use your version of this
  30. * file under either the MPL or the GPL.
  31. *
  32. * --------------------------------------------------------------------
  33. *
  34. * Inquiries regarding the linux-wlan Open Source project can be
  35. * made directly to:
  36. *
  37. * AbsoluteValue Systems Inc.
  38. * info@linux-wlan.com
  39. * http://www.linux-wlan.com
  40. *
  41. * --------------------------------------------------------------------
  42. *
  43. * Portions of the development of this software were funded by
  44. * Intersil Corporation as part of PRISM(R) chipset product development.
  45. *
  46. * --------------------------------------------------------------------
  47. */
  48. /*================================================================*/
  49. /* System Includes */
  50. #include <linux/ihex.h>
  51. #include <linux/slab.h>
  52. /*================================================================*/
  53. /* Local Constants */
  54. #define PRISM2_USB_FWFILE "prism2_ru.fw"
  55. MODULE_FIRMWARE(PRISM2_USB_FWFILE);
  56. #define S3DATA_MAX 5000
  57. #define S3PLUG_MAX 200
  58. #define S3CRC_MAX 200
  59. #define S3INFO_MAX 50
  60. #define S3ADDR_PLUG (0xff000000UL)
  61. #define S3ADDR_CRC (0xff100000UL)
  62. #define S3ADDR_INFO (0xff200000UL)
  63. #define S3ADDR_START (0xff400000UL)
  64. #define CHUNKS_MAX 100
  65. #define WRITESIZE_MAX 4096
  66. /*================================================================*/
  67. /* Local Types */
  68. struct s3datarec {
  69. u32 len;
  70. u32 addr;
  71. u8 checksum;
  72. u8 *data;
  73. };
  74. struct s3plugrec {
  75. u32 itemcode;
  76. u32 addr;
  77. u32 len;
  78. };
  79. struct s3crcrec {
  80. u32 addr;
  81. u32 len;
  82. unsigned int dowrite;
  83. };
  84. struct s3inforec {
  85. u16 len;
  86. u16 type;
  87. union {
  88. struct hfa384x_compident version;
  89. struct hfa384x_caplevel compat;
  90. u16 buildseq;
  91. struct hfa384x_compident platform;
  92. } info;
  93. };
  94. struct pda {
  95. u8 buf[HFA384x_PDA_LEN_MAX];
  96. struct hfa384x_pdrec *rec[HFA384x_PDA_RECS_MAX];
  97. unsigned int nrec;
  98. };
  99. struct imgchunk {
  100. u32 addr; /* start address */
  101. u32 len; /* in bytes */
  102. u16 crc; /* CRC value (if it falls at a chunk boundary) */
  103. u8 *data;
  104. };
  105. /*================================================================*/
  106. /* Local Static Definitions */
  107. /*----------------------------------------------------------------*/
  108. /* s-record image processing */
  109. /* Data records */
  110. static unsigned int ns3data;
  111. static struct s3datarec *s3data;
  112. /* Plug records */
  113. static unsigned int ns3plug;
  114. static struct s3plugrec s3plug[S3PLUG_MAX];
  115. /* CRC records */
  116. static unsigned int ns3crc;
  117. static struct s3crcrec s3crc[S3CRC_MAX];
  118. /* Info records */
  119. static unsigned int ns3info;
  120. static struct s3inforec s3info[S3INFO_MAX];
  121. /* S7 record (there _better_ be only one) */
  122. static u32 startaddr;
  123. /* Load image chunks */
  124. static unsigned int nfchunks;
  125. static struct imgchunk fchunk[CHUNKS_MAX];
  126. /* Note that for the following pdrec_t arrays, the len and code */
  127. /* fields are stored in HOST byte order. The mkpdrlist() function */
  128. /* does the conversion. */
  129. /*----------------------------------------------------------------*/
  130. /* PDA, built from [card|newfile]+[addfile1+addfile2...] */
  131. static struct pda pda;
  132. static struct hfa384x_compident nicid;
  133. static struct hfa384x_caplevel rfid;
  134. static struct hfa384x_caplevel macid;
  135. static struct hfa384x_caplevel priid;
  136. /*================================================================*/
  137. /* Local Function Declarations */
  138. static int prism2_fwapply(const struct ihex_binrec *rfptr,
  139. struct wlandevice *wlandev);
  140. static int read_fwfile(const struct ihex_binrec *rfptr);
  141. static int mkimage(struct imgchunk *clist, unsigned int *ccnt);
  142. static int read_cardpda(struct pda *pda, struct wlandevice *wlandev);
  143. static int mkpdrlist(struct pda *pda);
  144. static int plugimage(struct imgchunk *fchunk, unsigned int nfchunks,
  145. struct s3plugrec *s3plug, unsigned int ns3plug,
  146. struct pda *pda);
  147. static int crcimage(struct imgchunk *fchunk, unsigned int nfchunks,
  148. struct s3crcrec *s3crc, unsigned int ns3crc);
  149. static int writeimage(struct wlandevice *wlandev, struct imgchunk *fchunk,
  150. unsigned int nfchunks);
  151. static void free_chunks(struct imgchunk *fchunk, unsigned int *nfchunks);
  152. static void free_srecs(void);
  153. static int validate_identity(void);
  154. /*================================================================*/
  155. /* Function Definitions */
  156. /*----------------------------------------------------------------
  157. * prism2_fwtry
  158. *
  159. * Try and get firmware into memory
  160. *
  161. * Arguments:
  162. * udev usb device structure
  163. * wlandev wlan device structure
  164. *
  165. * Returns:
  166. * 0 - success
  167. * ~0 - failure
  168. *----------------------------------------------------------------
  169. */
  170. static int prism2_fwtry(struct usb_device *udev, struct wlandevice *wlandev)
  171. {
  172. const struct firmware *fw_entry = NULL;
  173. netdev_info(wlandev->netdev, "prism2_usb: Checking for firmware %s\n",
  174. PRISM2_USB_FWFILE);
  175. if (request_ihex_firmware(&fw_entry,
  176. PRISM2_USB_FWFILE, &udev->dev) != 0) {
  177. netdev_info(wlandev->netdev,
  178. "prism2_usb: Firmware not available, but not essential\n");
  179. netdev_info(wlandev->netdev,
  180. "prism2_usb: can continue to use card anyway.\n");
  181. return 1;
  182. }
  183. netdev_info(wlandev->netdev,
  184. "prism2_usb: %s will be processed, size %zu\n",
  185. PRISM2_USB_FWFILE, fw_entry->size);
  186. prism2_fwapply((const struct ihex_binrec *)fw_entry->data, wlandev);
  187. release_firmware(fw_entry);
  188. return 0;
  189. }
  190. /*----------------------------------------------------------------
  191. * prism2_fwapply
  192. *
  193. * Apply the firmware loaded into memory
  194. *
  195. * Arguments:
  196. * rfptr firmware image in kernel memory
  197. * wlandev device
  198. *
  199. * Returns:
  200. * 0 - success
  201. * ~0 - failure
  202. *----------------------------------------------------------------
  203. */
  204. static int prism2_fwapply(const struct ihex_binrec *rfptr,
  205. struct wlandevice *wlandev)
  206. {
  207. signed int result = 0;
  208. struct p80211msg_dot11req_mibget getmsg;
  209. struct p80211itemd *item;
  210. u32 *data;
  211. /* Initialize the data structures */
  212. ns3data = 0;
  213. s3data = kcalloc(S3DATA_MAX, sizeof(*s3data), GFP_KERNEL);
  214. if (!s3data) {
  215. result = -ENOMEM;
  216. goto out;
  217. }
  218. ns3plug = 0;
  219. memset(s3plug, 0, sizeof(s3plug));
  220. ns3crc = 0;
  221. memset(s3crc, 0, sizeof(s3crc));
  222. ns3info = 0;
  223. memset(s3info, 0, sizeof(s3info));
  224. startaddr = 0;
  225. nfchunks = 0;
  226. memset(fchunk, 0, sizeof(fchunk));
  227. memset(&nicid, 0, sizeof(nicid));
  228. memset(&rfid, 0, sizeof(rfid));
  229. memset(&macid, 0, sizeof(macid));
  230. memset(&priid, 0, sizeof(priid));
  231. /* clear the pda and add an initial END record */
  232. memset(&pda, 0, sizeof(pda));
  233. pda.rec[0] = (struct hfa384x_pdrec *)pda.buf;
  234. pda.rec[0]->len = cpu_to_le16(2); /* len in words */
  235. pda.rec[0]->code = cpu_to_le16(HFA384x_PDR_END_OF_PDA);
  236. pda.nrec = 1;
  237. /*-----------------------------------------------------*/
  238. /* Put card into fwload state */
  239. prism2sta_ifstate(wlandev, P80211ENUM_ifstate_fwload);
  240. /* Build the PDA we're going to use. */
  241. if (read_cardpda(&pda, wlandev)) {
  242. netdev_err(wlandev->netdev, "load_cardpda failed, exiting.\n");
  243. result = 1;
  244. goto out;
  245. }
  246. /* read the card's PRI-SUP */
  247. memset(&getmsg, 0, sizeof(getmsg));
  248. getmsg.msgcode = DIDMSG_DOT11REQ_MIBGET;
  249. getmsg.msglen = sizeof(getmsg);
  250. strcpy(getmsg.devname, wlandev->name);
  251. getmsg.mibattribute.did = DIDMSG_DOT11REQ_MIBGET_MIBATTRIBUTE;
  252. getmsg.mibattribute.status = P80211ENUM_msgitem_status_data_ok;
  253. getmsg.resultcode.did = DIDMSG_DOT11REQ_MIBGET_RESULTCODE;
  254. getmsg.resultcode.status = P80211ENUM_msgitem_status_no_value;
  255. item = (struct p80211itemd *)getmsg.mibattribute.data;
  256. item->did = DIDMIB_P2_NIC_PRISUPRANGE;
  257. item->status = P80211ENUM_msgitem_status_no_value;
  258. data = (u32 *)item->data;
  259. /* DIDmsg_dot11req_mibget */
  260. prism2mgmt_mibset_mibget(wlandev, &getmsg);
  261. if (getmsg.resultcode.data != P80211ENUM_resultcode_success)
  262. netdev_err(wlandev->netdev, "Couldn't fetch PRI-SUP info\n");
  263. /* Already in host order */
  264. priid.role = *data++;
  265. priid.id = *data++;
  266. priid.variant = *data++;
  267. priid.bottom = *data++;
  268. priid.top = *data++;
  269. /* Read the S3 file */
  270. result = read_fwfile(rfptr);
  271. if (result) {
  272. netdev_err(wlandev->netdev,
  273. "Failed to read the data exiting.\n");
  274. goto out;
  275. }
  276. result = validate_identity();
  277. if (result) {
  278. netdev_err(wlandev->netdev, "Incompatible firmware image.\n");
  279. goto out;
  280. }
  281. if (startaddr == 0x00000000) {
  282. netdev_err(wlandev->netdev,
  283. "Can't RAM download a Flash image!\n");
  284. result = 1;
  285. goto out;
  286. }
  287. /* Make the image chunks */
  288. result = mkimage(fchunk, &nfchunks);
  289. if (result) {
  290. netdev_err(wlandev->netdev, "Failed to make image chunk.\n");
  291. goto free_chunks;
  292. }
  293. /* Do any plugging */
  294. result = plugimage(fchunk, nfchunks, s3plug, ns3plug, &pda);
  295. if (result) {
  296. netdev_err(wlandev->netdev, "Failed to plug data.\n");
  297. goto free_chunks;
  298. }
  299. /* Insert any CRCs */
  300. result = crcimage(fchunk, nfchunks, s3crc, ns3crc);
  301. if (result) {
  302. netdev_err(wlandev->netdev, "Failed to insert all CRCs\n");
  303. goto free_chunks;
  304. }
  305. /* Write the image */
  306. result = writeimage(wlandev, fchunk, nfchunks);
  307. if (result) {
  308. netdev_err(wlandev->netdev, "Failed to ramwrite image data.\n");
  309. goto free_chunks;
  310. }
  311. netdev_info(wlandev->netdev, "prism2_usb: firmware loading finished.\n");
  312. free_chunks:
  313. /* clear any allocated memory */
  314. free_chunks(fchunk, &nfchunks);
  315. free_srecs();
  316. out:
  317. return result;
  318. }
  319. /*----------------------------------------------------------------
  320. * crcimage
  321. *
  322. * Adds a CRC16 in the two bytes prior to each block identified by
  323. * an S3 CRC record. Currently, we don't actually do a CRC we just
  324. * insert the value 0xC0DE in hfa384x order.
  325. *
  326. * Arguments:
  327. * fchunk Array of image chunks
  328. * nfchunks Number of image chunks
  329. * s3crc Array of crc records
  330. * ns3crc Number of crc records
  331. *
  332. * Returns:
  333. * 0 success
  334. * ~0 failure
  335. *----------------------------------------------------------------
  336. */
  337. static int crcimage(struct imgchunk *fchunk, unsigned int nfchunks,
  338. struct s3crcrec *s3crc, unsigned int ns3crc)
  339. {
  340. int result = 0;
  341. int i;
  342. int c;
  343. u32 crcstart;
  344. u32 cstart = 0;
  345. u32 cend;
  346. u8 *dest;
  347. u32 chunkoff;
  348. for (i = 0; i < ns3crc; i++) {
  349. if (!s3crc[i].dowrite)
  350. continue;
  351. crcstart = s3crc[i].addr;
  352. /* Find chunk */
  353. for (c = 0; c < nfchunks; c++) {
  354. cstart = fchunk[c].addr;
  355. cend = fchunk[c].addr + fchunk[c].len;
  356. /* the line below does an address & len match search */
  357. /* unfortunately, I've found that the len fields of */
  358. /* some crc records don't match with the length of */
  359. /* the actual data, so we're not checking right now */
  360. /* if (crcstart-2 >= cstart && crcend <= cend) break; */
  361. /* note the -2 below, it's to make sure the chunk has */
  362. /* space for the CRC value */
  363. if (crcstart - 2 >= cstart && crcstart < cend)
  364. break;
  365. }
  366. if (c >= nfchunks) {
  367. pr_err("Failed to find chunk for crcrec[%d], addr=0x%06x len=%d , aborting crc.\n",
  368. i, s3crc[i].addr, s3crc[i].len);
  369. return 1;
  370. }
  371. /* Insert crc */
  372. pr_debug("Adding crc @ 0x%06x\n", s3crc[i].addr - 2);
  373. chunkoff = crcstart - cstart - 2;
  374. dest = fchunk[c].data + chunkoff;
  375. *dest = 0xde;
  376. *(dest + 1) = 0xc0;
  377. }
  378. return result;
  379. }
  380. /*----------------------------------------------------------------
  381. * free_chunks
  382. *
  383. * Clears the chunklist data structures in preparation for a new file.
  384. *
  385. * Arguments:
  386. * none
  387. *
  388. * Returns:
  389. * nothing
  390. *----------------------------------------------------------------
  391. */
  392. static void free_chunks(struct imgchunk *fchunk, unsigned int *nfchunks)
  393. {
  394. int i;
  395. for (i = 0; i < *nfchunks; i++)
  396. kfree(fchunk[i].data);
  397. *nfchunks = 0;
  398. memset(fchunk, 0, sizeof(*fchunk));
  399. }
  400. /*----------------------------------------------------------------
  401. * free_srecs
  402. *
  403. * Clears the srec data structures in preparation for a new file.
  404. *
  405. * Arguments:
  406. * none
  407. *
  408. * Returns:
  409. * nothing
  410. *----------------------------------------------------------------
  411. */
  412. static void free_srecs(void)
  413. {
  414. ns3data = 0;
  415. kfree(s3data);
  416. ns3plug = 0;
  417. memset(s3plug, 0, sizeof(s3plug));
  418. ns3crc = 0;
  419. memset(s3crc, 0, sizeof(s3crc));
  420. ns3info = 0;
  421. memset(s3info, 0, sizeof(s3info));
  422. startaddr = 0;
  423. }
  424. /*----------------------------------------------------------------
  425. * mkimage
  426. *
  427. * Scans the currently loaded set of S records for data residing
  428. * in contiguous memory regions. Each contiguous region is then
  429. * made into a 'chunk'. This function assumes that we're building
  430. * a new chunk list. Assumes the s3data items are in sorted order.
  431. *
  432. * Arguments: none
  433. *
  434. * Returns:
  435. * 0 - success
  436. * ~0 - failure (probably an errno)
  437. *----------------------------------------------------------------
  438. */
  439. static int mkimage(struct imgchunk *clist, unsigned int *ccnt)
  440. {
  441. int result = 0;
  442. int i;
  443. int j;
  444. int currchunk = 0;
  445. u32 nextaddr = 0;
  446. u32 s3start;
  447. u32 s3end;
  448. u32 cstart = 0;
  449. u32 cend;
  450. u32 coffset;
  451. /* There may already be data in the chunklist */
  452. *ccnt = 0;
  453. /* Establish the location and size of each chunk */
  454. for (i = 0; i < ns3data; i++) {
  455. if (s3data[i].addr == nextaddr) {
  456. /* existing chunk, grow it */
  457. clist[currchunk].len += s3data[i].len;
  458. nextaddr += s3data[i].len;
  459. } else {
  460. /* New chunk */
  461. (*ccnt)++;
  462. currchunk = *ccnt - 1;
  463. clist[currchunk].addr = s3data[i].addr;
  464. clist[currchunk].len = s3data[i].len;
  465. nextaddr = s3data[i].addr + s3data[i].len;
  466. /* Expand the chunk if there is a CRC record at */
  467. /* their beginning bound */
  468. for (j = 0; j < ns3crc; j++) {
  469. if (s3crc[j].dowrite &&
  470. s3crc[j].addr == clist[currchunk].addr) {
  471. clist[currchunk].addr -= 2;
  472. clist[currchunk].len += 2;
  473. }
  474. }
  475. }
  476. }
  477. /* We're currently assuming there aren't any overlapping chunks */
  478. /* if this proves false, we'll need to add code to coalesce. */
  479. /* Allocate buffer space for chunks */
  480. for (i = 0; i < *ccnt; i++) {
  481. clist[i].data = kzalloc(clist[i].len, GFP_KERNEL);
  482. if (!clist[i].data)
  483. return 1;
  484. pr_debug("chunk[%d]: addr=0x%06x len=%d\n",
  485. i, clist[i].addr, clist[i].len);
  486. }
  487. /* Copy srec data to chunks */
  488. for (i = 0; i < ns3data; i++) {
  489. s3start = s3data[i].addr;
  490. s3end = s3start + s3data[i].len - 1;
  491. for (j = 0; j < *ccnt; j++) {
  492. cstart = clist[j].addr;
  493. cend = cstart + clist[j].len - 1;
  494. if (s3start >= cstart && s3end <= cend)
  495. break;
  496. }
  497. if (((unsigned int)j) >= (*ccnt)) {
  498. pr_err("s3rec(a=0x%06x,l=%d), no chunk match, exiting.\n",
  499. s3start, s3data[i].len);
  500. return 1;
  501. }
  502. coffset = s3start - cstart;
  503. memcpy(clist[j].data + coffset, s3data[i].data, s3data[i].len);
  504. }
  505. return result;
  506. }
  507. /*----------------------------------------------------------------
  508. * mkpdrlist
  509. *
  510. * Reads a raw PDA and builds an array of pdrec_t structures.
  511. *
  512. * Arguments:
  513. * pda buffer containing raw PDA bytes
  514. * pdrec ptr to an array of pdrec_t's. Will be filled on exit.
  515. * nrec ptr to a variable that will contain the count of PDRs
  516. *
  517. * Returns:
  518. * 0 - success
  519. * ~0 - failure (probably an errno)
  520. *----------------------------------------------------------------
  521. */
  522. static int mkpdrlist(struct pda *pda)
  523. {
  524. __le16 *pda16 = (__le16 *)pda->buf;
  525. int curroff; /* in 'words' */
  526. pda->nrec = 0;
  527. curroff = 0;
  528. while (curroff < (HFA384x_PDA_LEN_MAX / 2 - 1) &&
  529. le16_to_cpu(pda16[curroff + 1]) != HFA384x_PDR_END_OF_PDA) {
  530. pda->rec[pda->nrec] = (struct hfa384x_pdrec *)&pda16[curroff];
  531. if (le16_to_cpu(pda->rec[pda->nrec]->code) ==
  532. HFA384x_PDR_NICID) {
  533. memcpy(&nicid, &pda->rec[pda->nrec]->data.nicid,
  534. sizeof(nicid));
  535. le16_to_cpus(&nicid.id);
  536. le16_to_cpus(&nicid.variant);
  537. le16_to_cpus(&nicid.major);
  538. le16_to_cpus(&nicid.minor);
  539. }
  540. if (le16_to_cpu(pda->rec[pda->nrec]->code) ==
  541. HFA384x_PDR_MFISUPRANGE) {
  542. memcpy(&rfid, &pda->rec[pda->nrec]->data.mfisuprange,
  543. sizeof(rfid));
  544. le16_to_cpus(&rfid.id);
  545. le16_to_cpus(&rfid.variant);
  546. le16_to_cpus(&rfid.bottom);
  547. le16_to_cpus(&rfid.top);
  548. }
  549. if (le16_to_cpu(pda->rec[pda->nrec]->code) ==
  550. HFA384x_PDR_CFISUPRANGE) {
  551. memcpy(&macid, &pda->rec[pda->nrec]->data.cfisuprange,
  552. sizeof(macid));
  553. le16_to_cpus(&macid.id);
  554. le16_to_cpus(&macid.variant);
  555. le16_to_cpus(&macid.bottom);
  556. le16_to_cpus(&macid.top);
  557. }
  558. (pda->nrec)++;
  559. curroff += le16_to_cpu(pda16[curroff]) + 1;
  560. }
  561. if (curroff >= (HFA384x_PDA_LEN_MAX / 2 - 1)) {
  562. pr_err("no end record found or invalid lengths in PDR data, exiting. %x %d\n",
  563. curroff, pda->nrec);
  564. return 1;
  565. }
  566. pda->rec[pda->nrec] = (struct hfa384x_pdrec *)&pda16[curroff];
  567. (pda->nrec)++;
  568. return 0;
  569. }
  570. /*----------------------------------------------------------------
  571. * plugimage
  572. *
  573. * Plugs the given image using the given plug records from the given
  574. * PDA and filename.
  575. *
  576. * Arguments:
  577. * fchunk Array of image chunks
  578. * nfchunks Number of image chunks
  579. * s3plug Array of plug records
  580. * ns3plug Number of plug records
  581. * pda Current pda data
  582. *
  583. * Returns:
  584. * 0 success
  585. * ~0 failure
  586. *----------------------------------------------------------------
  587. */
  588. static int plugimage(struct imgchunk *fchunk, unsigned int nfchunks,
  589. struct s3plugrec *s3plug, unsigned int ns3plug,
  590. struct pda *pda)
  591. {
  592. int result = 0;
  593. int i; /* plug index */
  594. int j; /* index of PDR or -1 if fname plug */
  595. int c; /* chunk index */
  596. u32 pstart;
  597. u32 pend;
  598. u32 cstart = 0;
  599. u32 cend;
  600. u32 chunkoff;
  601. u8 *dest;
  602. /* for each plug record */
  603. for (i = 0; i < ns3plug; i++) {
  604. pstart = s3plug[i].addr;
  605. pend = s3plug[i].addr + s3plug[i].len;
  606. /* find the matching PDR (or filename) */
  607. if (s3plug[i].itemcode != 0xffffffffUL) { /* not filename */
  608. for (j = 0; j < pda->nrec; j++) {
  609. if (s3plug[i].itemcode ==
  610. le16_to_cpu(pda->rec[j]->code))
  611. break;
  612. }
  613. } else {
  614. j = -1;
  615. }
  616. if (j >= pda->nrec && j != -1) { /* if no matching PDR, fail */
  617. pr_warn("warning: Failed to find PDR for plugrec 0x%04x.\n",
  618. s3plug[i].itemcode);
  619. continue; /* and move on to the next PDR */
  620. /* MSM: They swear that unless it's the MAC address,
  621. * the serial number, or the TX calibration records,
  622. * then there's reasonable defaults in the f/w
  623. * image. Therefore, missing PDRs in the card
  624. * should only be a warning, not fatal.
  625. * TODO: add fatals for the PDRs mentioned above.
  626. */
  627. }
  628. /* Validate plug len against PDR len */
  629. if (j != -1 && s3plug[i].len < le16_to_cpu(pda->rec[j]->len)) {
  630. pr_err("error: Plug vs. PDR len mismatch for plugrec 0x%04x, abort plugging.\n",
  631. s3plug[i].itemcode);
  632. result = 1;
  633. continue;
  634. }
  635. /*
  636. * Validate plug address against
  637. * chunk data and identify chunk
  638. */
  639. for (c = 0; c < nfchunks; c++) {
  640. cstart = fchunk[c].addr;
  641. cend = fchunk[c].addr + fchunk[c].len;
  642. if (pstart >= cstart && pend <= cend)
  643. break;
  644. }
  645. if (c >= nfchunks) {
  646. pr_err("error: Failed to find image chunk for plugrec 0x%04x.\n",
  647. s3plug[i].itemcode);
  648. result = 1;
  649. continue;
  650. }
  651. /* Plug data */
  652. chunkoff = pstart - cstart;
  653. dest = fchunk[c].data + chunkoff;
  654. pr_debug("Plugging item 0x%04x @ 0x%06x, len=%d, cnum=%d coff=0x%06x\n",
  655. s3plug[i].itemcode, pstart, s3plug[i].len,
  656. c, chunkoff);
  657. if (j == -1) { /* plug the filename */
  658. memset(dest, 0, s3plug[i].len);
  659. strncpy(dest, PRISM2_USB_FWFILE, s3plug[i].len - 1);
  660. } else { /* plug a PDR */
  661. memcpy(dest, &pda->rec[j]->data, s3plug[i].len);
  662. }
  663. }
  664. return result;
  665. }
  666. /*----------------------------------------------------------------
  667. * read_cardpda
  668. *
  669. * Sends the command for the driver to read the pda from the card
  670. * named in the device variable. Upon success, the card pda is
  671. * stored in the "cardpda" variables. Note that the pda structure
  672. * is considered 'well formed' after this function. That means
  673. * that the nrecs is valid, the rec array has been set up, and there's
  674. * a valid PDAEND record in the raw PDA data.
  675. *
  676. * Arguments:
  677. * pda pda structure
  678. * wlandev device
  679. *
  680. * Returns:
  681. * 0 - success
  682. * ~0 - failure (probably an errno)
  683. *----------------------------------------------------------------
  684. */
  685. static int read_cardpda(struct pda *pda, struct wlandevice *wlandev)
  686. {
  687. int result = 0;
  688. struct p80211msg_p2req_readpda *msg;
  689. msg = kzalloc(sizeof(*msg), GFP_KERNEL);
  690. if (!msg)
  691. return -ENOMEM;
  692. /* set up the msg */
  693. msg->msgcode = DIDMSG_P2REQ_READPDA;
  694. msg->msglen = sizeof(msg);
  695. strcpy(msg->devname, wlandev->name);
  696. msg->pda.did = DIDMSG_P2REQ_READPDA_PDA;
  697. msg->pda.len = HFA384x_PDA_LEN_MAX;
  698. msg->pda.status = P80211ENUM_msgitem_status_no_value;
  699. msg->resultcode.did = DIDMSG_P2REQ_READPDA_RESULTCODE;
  700. msg->resultcode.len = sizeof(u32);
  701. msg->resultcode.status = P80211ENUM_msgitem_status_no_value;
  702. if (prism2mgmt_readpda(wlandev, msg) != 0) {
  703. /* prism2mgmt_readpda prints an errno if appropriate */
  704. result = -1;
  705. } else if (msg->resultcode.data == P80211ENUM_resultcode_success) {
  706. memcpy(pda->buf, msg->pda.data, HFA384x_PDA_LEN_MAX);
  707. result = mkpdrlist(pda);
  708. } else {
  709. /* resultcode must've been something other than success */
  710. result = -1;
  711. }
  712. kfree(msg);
  713. return result;
  714. }
  715. /*----------------------------------------------------------------
  716. * read_fwfile
  717. *
  718. * Reads the given fw file which should have been compiled from an srec
  719. * file. Each record in the fw file will either be a plain data record,
  720. * a start address record, or other records used for plugging.
  721. *
  722. * Note that data records are expected to be sorted into
  723. * ascending address order in the fw file.
  724. *
  725. * Note also that the start address record, originally an S7 record in
  726. * the srec file, is expected in the fw file to be like a data record but
  727. * with a certain address to make it identifiable.
  728. *
  729. * Here's the SREC format that the fw should have come from:
  730. * S[37]nnaaaaaaaaddd...dddcc
  731. *
  732. * nn - number of bytes starting with the address field
  733. * aaaaaaaa - address in readable (or big endian) format
  734. * dd....dd - 0-245 data bytes (two chars per byte)
  735. * cc - checksum
  736. *
  737. * The S7 record's (there should be only one) address value gets
  738. * converted to an S3 record with address of 0xff400000, with the
  739. * start address being stored as a 4 byte data word. That address is
  740. * the start execution address used for RAM downloads.
  741. *
  742. * The S3 records have a collection of subformats indicated by the
  743. * value of aaaaaaaa:
  744. * 0xff000000 - Plug record, data field format:
  745. * xxxxxxxxaaaaaaaassssssss
  746. * x - PDR code number (little endian)
  747. * a - Address in load image to plug (little endian)
  748. * s - Length of plug data area (little endian)
  749. *
  750. * 0xff100000 - CRC16 generation record, data field format:
  751. * aaaaaaaassssssssbbbbbbbb
  752. * a - Start address for CRC calculation (little endian)
  753. * s - Length of data to calculate over (little endian)
  754. * b - Boolean, true=write crc, false=don't write
  755. *
  756. * 0xff200000 - Info record, data field format:
  757. * ssssttttdd..dd
  758. * s - Size in words (little endian)
  759. * t - Info type (little endian), see #defines and
  760. * struct s3inforec for details about types.
  761. * d - (s - 1) little endian words giving the contents of
  762. * the given info type.
  763. *
  764. * 0xff400000 - Start address record, data field format:
  765. * aaaaaaaa
  766. * a - Address in load image to plug (little endian)
  767. *
  768. * Arguments:
  769. * record firmware image (ihex record structure) in kernel memory
  770. *
  771. * Returns:
  772. * 0 - success
  773. * ~0 - failure (probably an errno)
  774. *----------------------------------------------------------------
  775. */
  776. static int read_fwfile(const struct ihex_binrec *record)
  777. {
  778. int i;
  779. int rcnt = 0;
  780. u16 *tmpinfo;
  781. u16 *ptr16;
  782. u32 *ptr32, len, addr;
  783. pr_debug("Reading fw file ...\n");
  784. while (record) {
  785. rcnt++;
  786. len = be16_to_cpu(record->len);
  787. addr = be32_to_cpu(record->addr);
  788. /* Point into data for different word lengths */
  789. ptr32 = (u32 *)record->data;
  790. ptr16 = (u16 *)record->data;
  791. /* parse what was an S3 srec and put it in the right array */
  792. switch (addr) {
  793. case S3ADDR_START:
  794. startaddr = *ptr32;
  795. pr_debug(" S7 start addr, record=%d addr=0x%08x\n",
  796. rcnt,
  797. startaddr);
  798. break;
  799. case S3ADDR_PLUG:
  800. s3plug[ns3plug].itemcode = *ptr32;
  801. s3plug[ns3plug].addr = *(ptr32 + 1);
  802. s3plug[ns3plug].len = *(ptr32 + 2);
  803. pr_debug(" S3 plugrec, record=%d itemcode=0x%08x addr=0x%08x len=%d\n",
  804. rcnt,
  805. s3plug[ns3plug].itemcode,
  806. s3plug[ns3plug].addr,
  807. s3plug[ns3plug].len);
  808. ns3plug++;
  809. if (ns3plug == S3PLUG_MAX) {
  810. pr_err("S3 plugrec limit reached - aborting\n");
  811. return 1;
  812. }
  813. break;
  814. case S3ADDR_CRC:
  815. s3crc[ns3crc].addr = *ptr32;
  816. s3crc[ns3crc].len = *(ptr32 + 1);
  817. s3crc[ns3crc].dowrite = *(ptr32 + 2);
  818. pr_debug(" S3 crcrec, record=%d addr=0x%08x len=%d write=0x%08x\n",
  819. rcnt,
  820. s3crc[ns3crc].addr,
  821. s3crc[ns3crc].len,
  822. s3crc[ns3crc].dowrite);
  823. ns3crc++;
  824. if (ns3crc == S3CRC_MAX) {
  825. pr_err("S3 crcrec limit reached - aborting\n");
  826. return 1;
  827. }
  828. break;
  829. case S3ADDR_INFO:
  830. s3info[ns3info].len = *ptr16;
  831. s3info[ns3info].type = *(ptr16 + 1);
  832. pr_debug(" S3 inforec, record=%d len=0x%04x type=0x%04x\n",
  833. rcnt,
  834. s3info[ns3info].len,
  835. s3info[ns3info].type);
  836. if (((s3info[ns3info].len - 1) * sizeof(u16)) >
  837. sizeof(s3info[ns3info].info)) {
  838. pr_err("S3 inforec length too long - aborting\n");
  839. return 1;
  840. }
  841. tmpinfo = (u16 *)&s3info[ns3info].info.version;
  842. pr_debug(" info=");
  843. for (i = 0; i < s3info[ns3info].len - 1; i++) {
  844. tmpinfo[i] = *(ptr16 + 2 + i);
  845. pr_debug("%04x ", tmpinfo[i]);
  846. }
  847. pr_debug("\n");
  848. ns3info++;
  849. if (ns3info == S3INFO_MAX) {
  850. pr_err("S3 inforec limit reached - aborting\n");
  851. return 1;
  852. }
  853. break;
  854. default: /* Data record */
  855. s3data[ns3data].addr = addr;
  856. s3data[ns3data].len = len;
  857. s3data[ns3data].data = (uint8_t *)record->data;
  858. ns3data++;
  859. if (ns3data == S3DATA_MAX) {
  860. pr_err("S3 datarec limit reached - aborting\n");
  861. return 1;
  862. }
  863. break;
  864. }
  865. record = ihex_next_binrec(record);
  866. }
  867. return 0;
  868. }
  869. /*----------------------------------------------------------------
  870. * writeimage
  871. *
  872. * Takes the chunks, builds p80211 messages and sends them down
  873. * to the driver for writing to the card.
  874. *
  875. * Arguments:
  876. * wlandev device
  877. * fchunk Array of image chunks
  878. * nfchunks Number of image chunks
  879. *
  880. * Returns:
  881. * 0 success
  882. * ~0 failure
  883. *----------------------------------------------------------------
  884. */
  885. static int writeimage(struct wlandevice *wlandev, struct imgchunk *fchunk,
  886. unsigned int nfchunks)
  887. {
  888. int result = 0;
  889. struct p80211msg_p2req_ramdl_state *rstmsg;
  890. struct p80211msg_p2req_ramdl_write *rwrmsg;
  891. u32 resultcode;
  892. int i;
  893. int j;
  894. unsigned int nwrites;
  895. u32 curroff;
  896. u32 currlen;
  897. u32 currdaddr;
  898. rstmsg = kzalloc(sizeof(*rstmsg), GFP_KERNEL);
  899. rwrmsg = kzalloc(sizeof(*rwrmsg), GFP_KERNEL);
  900. if (!rstmsg || !rwrmsg) {
  901. kfree(rstmsg);
  902. kfree(rwrmsg);
  903. netdev_err(wlandev->netdev,
  904. "%s: no memory for firmware download, aborting download\n",
  905. __func__);
  906. return -ENOMEM;
  907. }
  908. /* Initialize the messages */
  909. strcpy(rstmsg->devname, wlandev->name);
  910. rstmsg->msgcode = DIDMSG_P2REQ_RAMDL_STATE;
  911. rstmsg->msglen = sizeof(*rstmsg);
  912. rstmsg->enable.did = DIDMSG_P2REQ_RAMDL_STATE_ENABLE;
  913. rstmsg->exeaddr.did = DIDMSG_P2REQ_RAMDL_STATE_EXEADDR;
  914. rstmsg->resultcode.did = DIDMSG_P2REQ_RAMDL_STATE_RESULTCODE;
  915. rstmsg->enable.status = P80211ENUM_msgitem_status_data_ok;
  916. rstmsg->exeaddr.status = P80211ENUM_msgitem_status_data_ok;
  917. rstmsg->resultcode.status = P80211ENUM_msgitem_status_no_value;
  918. rstmsg->enable.len = sizeof(u32);
  919. rstmsg->exeaddr.len = sizeof(u32);
  920. rstmsg->resultcode.len = sizeof(u32);
  921. strcpy(rwrmsg->devname, wlandev->name);
  922. rwrmsg->msgcode = DIDMSG_P2REQ_RAMDL_WRITE;
  923. rwrmsg->msglen = sizeof(*rwrmsg);
  924. rwrmsg->addr.did = DIDMSG_P2REQ_RAMDL_WRITE_ADDR;
  925. rwrmsg->len.did = DIDMSG_P2REQ_RAMDL_WRITE_LEN;
  926. rwrmsg->data.did = DIDMSG_P2REQ_RAMDL_WRITE_DATA;
  927. rwrmsg->resultcode.did = DIDMSG_P2REQ_RAMDL_WRITE_RESULTCODE;
  928. rwrmsg->addr.status = P80211ENUM_msgitem_status_data_ok;
  929. rwrmsg->len.status = P80211ENUM_msgitem_status_data_ok;
  930. rwrmsg->data.status = P80211ENUM_msgitem_status_data_ok;
  931. rwrmsg->resultcode.status = P80211ENUM_msgitem_status_no_value;
  932. rwrmsg->addr.len = sizeof(u32);
  933. rwrmsg->len.len = sizeof(u32);
  934. rwrmsg->data.len = WRITESIZE_MAX;
  935. rwrmsg->resultcode.len = sizeof(u32);
  936. /* Send xxx_state(enable) */
  937. pr_debug("Sending dl_state(enable) message.\n");
  938. rstmsg->enable.data = P80211ENUM_truth_true;
  939. rstmsg->exeaddr.data = startaddr;
  940. result = prism2mgmt_ramdl_state(wlandev, rstmsg);
  941. if (result) {
  942. netdev_err(wlandev->netdev,
  943. "%s state enable failed w/ result=%d, aborting download\n",
  944. __func__, result);
  945. goto free_result;
  946. }
  947. resultcode = rstmsg->resultcode.data;
  948. if (resultcode != P80211ENUM_resultcode_success) {
  949. netdev_err(wlandev->netdev,
  950. "%s()->xxxdl_state msg indicates failure, w/ resultcode=%d, aborting download.\n",
  951. __func__, resultcode);
  952. result = 1;
  953. goto free_result;
  954. }
  955. /* Now, loop through the data chunks and send WRITESIZE_MAX data */
  956. for (i = 0; i < nfchunks; i++) {
  957. nwrites = fchunk[i].len / WRITESIZE_MAX;
  958. nwrites += (fchunk[i].len % WRITESIZE_MAX) ? 1 : 0;
  959. curroff = 0;
  960. for (j = 0; j < nwrites; j++) {
  961. /* TODO Move this to a separate function */
  962. int lenleft = fchunk[i].len - (WRITESIZE_MAX * j);
  963. if (fchunk[i].len > WRITESIZE_MAX)
  964. currlen = WRITESIZE_MAX;
  965. else
  966. currlen = lenleft;
  967. curroff = j * WRITESIZE_MAX;
  968. currdaddr = fchunk[i].addr + curroff;
  969. /* Setup the message */
  970. rwrmsg->addr.data = currdaddr;
  971. rwrmsg->len.data = currlen;
  972. memcpy(rwrmsg->data.data,
  973. fchunk[i].data + curroff, currlen);
  974. /* Send flashdl_write(pda) */
  975. pr_debug
  976. ("Sending xxxdl_write message addr=%06x len=%d.\n",
  977. currdaddr, currlen);
  978. result = prism2mgmt_ramdl_write(wlandev, rwrmsg);
  979. /* Check the results */
  980. if (result) {
  981. netdev_err(wlandev->netdev,
  982. "%s chunk write failed w/ result=%d, aborting download\n",
  983. __func__, result);
  984. goto free_result;
  985. }
  986. resultcode = rstmsg->resultcode.data;
  987. if (resultcode != P80211ENUM_resultcode_success) {
  988. pr_err("%s()->xxxdl_write msg indicates failure, w/ resultcode=%d, aborting download.\n",
  989. __func__, resultcode);
  990. result = 1;
  991. goto free_result;
  992. }
  993. }
  994. }
  995. /* Send xxx_state(disable) */
  996. pr_debug("Sending dl_state(disable) message.\n");
  997. rstmsg->enable.data = P80211ENUM_truth_false;
  998. rstmsg->exeaddr.data = 0;
  999. result = prism2mgmt_ramdl_state(wlandev, rstmsg);
  1000. if (result) {
  1001. netdev_err(wlandev->netdev,
  1002. "%s state disable failed w/ result=%d, aborting download\n",
  1003. __func__, result);
  1004. goto free_result;
  1005. }
  1006. resultcode = rstmsg->resultcode.data;
  1007. if (resultcode != P80211ENUM_resultcode_success) {
  1008. netdev_err(wlandev->netdev,
  1009. "%s()->xxxdl_state msg indicates failure, w/ resultcode=%d, aborting download.\n",
  1010. __func__, resultcode);
  1011. result = 1;
  1012. goto free_result;
  1013. }
  1014. free_result:
  1015. kfree(rstmsg);
  1016. kfree(rwrmsg);
  1017. return result;
  1018. }
  1019. static int validate_identity(void)
  1020. {
  1021. int i;
  1022. int result = 1;
  1023. int trump = 0;
  1024. pr_debug("NIC ID: %#x v%d.%d.%d\n",
  1025. nicid.id, nicid.major, nicid.minor, nicid.variant);
  1026. pr_debug("MFI ID: %#x v%d %d->%d\n",
  1027. rfid.id, rfid.variant, rfid.bottom, rfid.top);
  1028. pr_debug("CFI ID: %#x v%d %d->%d\n",
  1029. macid.id, macid.variant, macid.bottom, macid.top);
  1030. pr_debug("PRI ID: %#x v%d %d->%d\n",
  1031. priid.id, priid.variant, priid.bottom, priid.top);
  1032. for (i = 0; i < ns3info; i++) {
  1033. switch (s3info[i].type) {
  1034. case 1:
  1035. pr_debug("Version: ID %#x %d.%d.%d\n",
  1036. s3info[i].info.version.id,
  1037. s3info[i].info.version.major,
  1038. s3info[i].info.version.minor,
  1039. s3info[i].info.version.variant);
  1040. break;
  1041. case 2:
  1042. pr_debug("Compat: Role %#x Id %#x v%d %d->%d\n",
  1043. s3info[i].info.compat.role,
  1044. s3info[i].info.compat.id,
  1045. s3info[i].info.compat.variant,
  1046. s3info[i].info.compat.bottom,
  1047. s3info[i].info.compat.top);
  1048. /* MAC compat range */
  1049. if ((s3info[i].info.compat.role == 1) &&
  1050. (s3info[i].info.compat.id == 2)) {
  1051. if (s3info[i].info.compat.variant !=
  1052. macid.variant) {
  1053. result = 2;
  1054. }
  1055. }
  1056. /* PRI compat range */
  1057. if ((s3info[i].info.compat.role == 1) &&
  1058. (s3info[i].info.compat.id == 3)) {
  1059. if ((s3info[i].info.compat.bottom >
  1060. priid.top) ||
  1061. (s3info[i].info.compat.top <
  1062. priid.bottom)) {
  1063. result = 3;
  1064. }
  1065. }
  1066. /* SEC compat range */
  1067. if ((s3info[i].info.compat.role == 1) &&
  1068. (s3info[i].info.compat.id == 4)) {
  1069. /* FIXME: isn't something missing here? */
  1070. }
  1071. break;
  1072. case 3:
  1073. pr_debug("Seq: %#x\n", s3info[i].info.buildseq);
  1074. break;
  1075. case 4:
  1076. pr_debug("Platform: ID %#x %d.%d.%d\n",
  1077. s3info[i].info.version.id,
  1078. s3info[i].info.version.major,
  1079. s3info[i].info.version.minor,
  1080. s3info[i].info.version.variant);
  1081. if (nicid.id != s3info[i].info.version.id)
  1082. continue;
  1083. if (nicid.major != s3info[i].info.version.major)
  1084. continue;
  1085. if (nicid.minor != s3info[i].info.version.minor)
  1086. continue;
  1087. if ((nicid.variant != s3info[i].info.version.variant) &&
  1088. (nicid.id != 0x8008))
  1089. continue;
  1090. trump = 1;
  1091. break;
  1092. case 0x8001:
  1093. pr_debug("name inforec len %d\n", s3info[i].len);
  1094. break;
  1095. default:
  1096. pr_debug("Unknown inforec type %d\n", s3info[i].type);
  1097. }
  1098. }
  1099. /* walk through */
  1100. if (trump && (result != 2))
  1101. result = 0;
  1102. return result;
  1103. }