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