• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6.36/drivers/staging/wlan-ng/
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 */
126unsigned int ns3data;
127struct s3datarec s3data[S3DATA_MAX];
128
129/* Plug records */
130unsigned int ns3plug;
131struct s3plugrec s3plug[S3PLUG_MAX];
132
133/* CRC records */
134unsigned int ns3crc;
135struct s3crcrec s3crc[S3CRC_MAX];
136
137/* Info records */
138unsigned int ns3info;
139struct s3inforec s3info[S3INFO_MAX];
140
141/* S7 record (there _better_ be only one) */
142u32 startaddr;
143
144/* Load image chunks */
145unsigned int nfchunks;
146struct 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
154struct pda pda;
155hfa384x_compident_t nicid;
156hfa384x_caplevel_t rfid;
157hfa384x_caplevel_t macid;
158hfa384x_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----------------------------------------------------------------*/
204int prism2_fwtry(struct usb_device *udev, wlandevice_t *wlandev)
205{
206	const struct firmware *fw_entry = NULL;
207
208	printk(KERN_INFO "prism2_usb: Checking for firmware %s\n",
209	       PRISM2_USB_FWFILE);
210	if (request_ihex_firmware(&fw_entry, PRISM2_USB_FWFILE, &udev->dev) != 0) {
211		printk(KERN_INFO
212		       "prism2_usb: Firmware not available, but not essential\n");
213		printk(KERN_INFO
214		       "prism2_usb: can continue to use card anyway.\n");
215		return 1;
216	}
217
218	printk(KERN_INFO "prism2_usb: %s will be processed, size %zu\n",
219	       PRISM2_USB_FWFILE, fw_entry->size);
220	prism2_fwapply((const struct ihex_binrec *)fw_entry->data, wlandev);
221
222	release_firmware(fw_entry);
223	return 0;
224}
225
226/*----------------------------------------------------------------
227* prism2_fwapply
228*
229* Apply the firmware loaded into memory
230*
231* Arguments:
232*	rfptr	firmware image in kernel memory
233*	wlandev device
234*
235* Returns:
236*	0	- success
237*	~0	- failure
238----------------------------------------------------------------*/
239int prism2_fwapply(const struct ihex_binrec *rfptr, wlandevice_t *wlandev)
240{
241	signed int result = 0;
242	struct p80211msg_dot11req_mibget getmsg;
243	p80211itemd_t *item;
244	u32 *data;
245
246	/* Initialize the data structures */
247	ns3data = 0;
248	memset(s3data, 0, sizeof(s3data));
249	ns3plug = 0;
250	memset(s3plug, 0, sizeof(s3plug));
251	ns3crc = 0;
252	memset(s3crc, 0, sizeof(s3crc));
253	ns3info = 0;
254	memset(s3info, 0, sizeof(s3info));
255	startaddr = 0;
256
257	nfchunks = 0;
258	memset(fchunk, 0, sizeof(fchunk));
259	memset(&nicid, 0, sizeof(nicid));
260	memset(&rfid, 0, sizeof(rfid));
261	memset(&macid, 0, sizeof(macid));
262	memset(&priid, 0, sizeof(priid));
263
264	/* clear the pda and add an initial END record */
265	memset(&pda, 0, sizeof(pda));
266	pda.rec[0] = (hfa384x_pdrec_t *) pda.buf;
267	pda.rec[0]->len = cpu_to_le16(2);	/* len in words */
268	pda.rec[0]->code = cpu_to_le16(HFA384x_PDR_END_OF_PDA);
269	pda.nrec = 1;
270
271	/*-----------------------------------------------------*/
272	/* Put card into fwload state */
273	prism2sta_ifstate(wlandev, P80211ENUM_ifstate_fwload);
274
275	/* Build the PDA we're going to use. */
276	if (read_cardpda(&pda, wlandev)) {
277		printk(KERN_ERR "load_cardpda failed, exiting.\n");
278		return 1;
279	}
280
281	/* read the card's PRI-SUP */
282	memset(&getmsg, 0, sizeof(getmsg));
283	getmsg.msgcode = DIDmsg_dot11req_mibget;
284	getmsg.msglen = sizeof(getmsg);
285	strcpy(getmsg.devname, wlandev->name);
286
287	getmsg.mibattribute.did = DIDmsg_dot11req_mibget_mibattribute;
288	getmsg.mibattribute.status = P80211ENUM_msgitem_status_data_ok;
289	getmsg.resultcode.did = DIDmsg_dot11req_mibget_resultcode;
290	getmsg.resultcode.status = P80211ENUM_msgitem_status_no_value;
291
292	item = (p80211itemd_t *) getmsg.mibattribute.data;
293	item->did = DIDmib_p2_p2NIC_p2PRISupRange;
294	item->status = P80211ENUM_msgitem_status_no_value;
295
296	data = (u32 *) item->data;
297
298	/* DIDmsg_dot11req_mibget */
299	prism2mgmt_mibset_mibget(wlandev, &getmsg);
300	if (getmsg.resultcode.data != P80211ENUM_resultcode_success)
301		printk(KERN_ERR "Couldn't fetch PRI-SUP info\n");
302
303	/* Already in host order */
304	priid.role = *data++;
305	priid.id = *data++;
306	priid.variant = *data++;
307	priid.bottom = *data++;
308	priid.top = *data++;
309
310	/* Read the S3 file */
311	result = read_fwfile(rfptr);
312	if (result) {
313		printk(KERN_ERR "Failed to read the data exiting.\n");
314		return 1;
315	}
316
317	result = validate_identity();
318
319	if (result) {
320		printk(KERN_ERR "Incompatible firmware image.\n");
321		return 1;
322	}
323
324	if (startaddr == 0x00000000) {
325		printk(KERN_ERR "Can't RAM download a Flash image!\n");
326		return 1;
327	}
328
329	/* Make the image chunks */
330	result = mkimage(fchunk, &nfchunks);
331
332	/* Do any plugging */
333	result = plugimage(fchunk, nfchunks, s3plug, ns3plug, &pda);
334	if (result) {
335		printk(KERN_ERR "Failed to plug data.\n");
336		return 1;
337	}
338
339	/* Insert any CRCs */
340	if (crcimage(fchunk, nfchunks, s3crc, ns3crc)) {
341		printk(KERN_ERR "Failed to insert all CRCs\n");
342		return 1;
343	}
344
345	/* Write the image */
346	result = writeimage(wlandev, fchunk, nfchunks);
347	if (result) {
348		printk(KERN_ERR "Failed to ramwrite image data.\n");
349		return 1;
350	}
351
352	/* clear any allocated memory */
353	free_chunks(fchunk, &nfchunks);
354	free_srecs();
355
356	printk(KERN_INFO "prism2_usb: firmware loading finished.\n");
357
358	return result;
359}
360
361/*----------------------------------------------------------------
362* crcimage
363*
364* Adds a CRC16 in the two bytes prior to each block identified by
365* an S3 CRC record.  Currently, we don't actually do a CRC we just
366* insert the value 0xC0DE in hfa384x order.
367*
368* Arguments:
369*	fchunk		Array of image chunks
370*	nfchunks	Number of image chunks
371*	s3crc		Array of crc records
372*	ns3crc		Number of crc records
373*
374* Returns:
375*	0	success
376*	~0	failure
377----------------------------------------------------------------*/
378int crcimage(struct imgchunk *fchunk, unsigned int nfchunks,
379	     struct s3crcrec *s3crc, unsigned int ns3crc)
380{
381	int result = 0;
382	int i;
383	int c;
384	u32 crcstart;
385	u32 crcend;
386	u32 cstart = 0;
387	u32 cend;
388	u8 *dest;
389	u32 chunkoff;
390
391	for (i = 0; i < ns3crc; i++) {
392		if (!s3crc[i].dowrite)
393			continue;
394		crcstart = s3crc[i].addr;
395		crcend = s3crc[i].addr + s3crc[i].len;
396		/* Find chunk */
397		for (c = 0; c < nfchunks; c++) {
398			cstart = fchunk[c].addr;
399			cend = fchunk[c].addr + fchunk[c].len;
400			/* the line below does an address & len match search */
401			/* unfortunately, I've found that the len fields of */
402			/* some crc records don't match with the length of */
403			/* the actual data, so we're not checking right now */
404			/* if (crcstart-2 >= cstart && crcend <= cend) break; */
405
406			/* note the -2 below, it's to make sure the chunk has */
407			/* space for the CRC value */
408			if (crcstart - 2 >= cstart && crcstart < cend)
409				break;
410		}
411		if (c >= nfchunks) {
412			printk(KERN_ERR
413			       "Failed to find chunk for "
414			       "crcrec[%d], addr=0x%06x len=%d , "
415			       "aborting crc.\n",
416			       i, s3crc[i].addr, s3crc[i].len);
417			return 1;
418		}
419
420		/* Insert crc */
421		pr_debug("Adding crc @ 0x%06x\n", s3crc[i].addr - 2);
422		chunkoff = crcstart - cstart - 2;
423		dest = fchunk[c].data + chunkoff;
424		*dest = 0xde;
425		*(dest + 1) = 0xc0;
426
427	}
428	return result;
429}
430
431/*----------------------------------------------------------------
432* free_chunks
433*
434* Clears the chunklist data structures in preparation for a new file.
435*
436* Arguments:
437*	none
438*
439* Returns:
440*	nothing
441----------------------------------------------------------------*/
442void free_chunks(struct imgchunk *fchunk, unsigned int *nfchunks)
443{
444	int i;
445	for (i = 0; i < *nfchunks; i++) {
446		if (fchunk[i].data != NULL)
447			kfree(fchunk[i].data);
448	}
449	*nfchunks = 0;
450	memset(fchunk, 0, sizeof(*fchunk));
451
452}
453
454/*----------------------------------------------------------------
455* free_srecs
456*
457* Clears the srec data structures in preparation for a new file.
458*
459* Arguments:
460*	none
461*
462* Returns:
463*	nothing
464----------------------------------------------------------------*/
465void free_srecs(void)
466{
467	ns3data = 0;
468	memset(s3data, 0, sizeof(s3data));
469	ns3plug = 0;
470	memset(s3plug, 0, sizeof(s3plug));
471	ns3crc = 0;
472	memset(s3crc, 0, sizeof(s3crc));
473	ns3info = 0;
474	memset(s3info, 0, sizeof(s3info));
475	startaddr = 0;
476}
477
478/*----------------------------------------------------------------
479* mkimage
480*
481* Scans the currently loaded set of S records for data residing
482* in contiguous memory regions.  Each contiguous region is then
483* made into a 'chunk'.  This function assumes that we're building
484* a new chunk list.  Assumes the s3data items are in sorted order.
485*
486* Arguments:	none
487*
488* Returns:
489*	0	- success
490*	~0	- failure (probably an errno)
491----------------------------------------------------------------*/
492int mkimage(struct imgchunk *clist, unsigned int *ccnt)
493{
494	int result = 0;
495	int i;
496	int j;
497	int currchunk = 0;
498	u32 nextaddr = 0;
499	u32 s3start;
500	u32 s3end;
501	u32 cstart = 0;
502	u32 cend;
503	u32 coffset;
504
505	/* There may already be data in the chunklist */
506	*ccnt = 0;
507
508	/* Establish the location and size of each chunk */
509	for (i = 0; i < ns3data; i++) {
510		if (s3data[i].addr == nextaddr) {
511			/* existing chunk, grow it */
512			clist[currchunk].len += s3data[i].len;
513			nextaddr += s3data[i].len;
514		} else {
515			/* New chunk */
516			(*ccnt)++;
517			currchunk = *ccnt - 1;
518			clist[currchunk].addr = s3data[i].addr;
519			clist[currchunk].len = s3data[i].len;
520			nextaddr = s3data[i].addr + s3data[i].len;
521			/* Expand the chunk if there is a CRC record at */
522			/* their beginning bound */
523			for (j = 0; j < ns3crc; j++) {
524				if (s3crc[j].dowrite &&
525				    s3crc[j].addr == clist[currchunk].addr) {
526					clist[currchunk].addr -= 2;
527					clist[currchunk].len += 2;
528				}
529			}
530		}
531	}
532
533	/* We're currently assuming there aren't any overlapping chunks */
534	/*  if this proves false, we'll need to add code to coalesce. */
535
536	/* Allocate buffer space for chunks */
537	for (i = 0; i < *ccnt; i++) {
538		clist[i].data = kzalloc(clist[i].len, GFP_KERNEL);
539		if (clist[i].data == NULL) {
540			printk(KERN_ERR
541			       "failed to allocate image space, exitting.\n");
542			return 1;
543		}
544		pr_debug("chunk[%d]: addr=0x%06x len=%d\n",
545			 i, clist[i].addr, clist[i].len);
546	}
547
548	/* Copy srec data to chunks */
549	for (i = 0; i < ns3data; i++) {
550		s3start = s3data[i].addr;
551		s3end = s3start + s3data[i].len - 1;
552		for (j = 0; j < *ccnt; j++) {
553			cstart = clist[j].addr;
554			cend = cstart + clist[j].len - 1;
555			if (s3start >= cstart && s3end <= cend)
556				break;
557		}
558		if (((unsigned int)j) >= (*ccnt)) {
559			printk(KERN_ERR
560			       "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----------------------------------------------------------------*/
585int 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) == HFA384x_PDR_NICID) {
598			memcpy(&nicid, &pda->rec[pda->nrec]->data.nicid,
599			       sizeof(nicid));
600			nicid.id = le16_to_cpu(nicid.id);
601			nicid.variant = le16_to_cpu(nicid.variant);
602			nicid.major = le16_to_cpu(nicid.major);
603			nicid.minor = le16_to_cpu(nicid.minor);
604		}
605		if (le16_to_cpu(pda->rec[pda->nrec]->code) ==
606		    HFA384x_PDR_MFISUPRANGE) {
607			memcpy(&rfid, &pda->rec[pda->nrec]->data.mfisuprange,
608			       sizeof(rfid));
609			rfid.id = le16_to_cpu(rfid.id);
610			rfid.variant = le16_to_cpu(rfid.variant);
611			rfid.bottom = le16_to_cpu(rfid.bottom);
612			rfid.top = le16_to_cpu(rfid.top);
613		}
614		if (le16_to_cpu(pda->rec[pda->nrec]->code) ==
615		    HFA384x_PDR_CFISUPRANGE) {
616			memcpy(&macid, &pda->rec[pda->nrec]->data.cfisuprange,
617			       sizeof(macid));
618			macid.id = le16_to_cpu(macid.id);
619			macid.variant = le16_to_cpu(macid.variant);
620			macid.bottom = le16_to_cpu(macid.bottom);
621			macid.top = le16_to_cpu(macid.top);
622		}
623
624		(pda->nrec)++;
625		curroff += le16_to_cpu(pda16[curroff]) + 1;
626
627	}
628	if (curroff >= (HFA384x_PDA_LEN_MAX / 2)) {
629		printk(KERN_ERR
630		       "no end record found or invalid lengths in "
631		       "PDR data, exiting. %x %d\n", 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----------------------------------------------------------------*/
658int 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			printk(KERN_WARNING
688			       "warning: Failed to find PDR for "
689			       "plugrec 0x%04x.\n", s3plug[i].itemcode);
690			continue;	/* and move on to the next PDR */
691		}
692
693		/* Validate plug len against PDR len */
694		if (j != -1 && s3plug[i].len < le16_to_cpu(pda->rec[j]->len)) {
695			printk(KERN_ERR
696			       "error: Plug vs. PDR len mismatch for "
697			       "plugrec 0x%04x, abort plugging.\n",
698			       s3plug[i].itemcode);
699			result = 1;
700			continue;
701		}
702
703		/* Validate plug address against chunk data and identify chunk */
704		for (c = 0; c < nfchunks; c++) {
705			cstart = fchunk[c].addr;
706			cend = fchunk[c].addr + fchunk[c].len;
707			if (pstart >= cstart && pend <= cend)
708				break;
709		}
710		if (c >= nfchunks) {
711			printk(KERN_ERR
712			       "error: Failed to find image chunk for "
713			       "plugrec 0x%04x.\n", s3plug[i].itemcode);
714			result = 1;
715			continue;
716		}
717
718		/* Plug data */
719		chunkoff = pstart - cstart;
720		dest = fchunk[c].data + chunkoff;
721		pr_debug("Plugging item 0x%04x @ 0x%06x, len=%d, "
722			 "cnum=%d coff=0x%06x\n",
723			 s3plug[i].itemcode, pstart, s3plug[i].len,
724			 c, chunkoff);
725
726		if (j == -1) {	/* plug the filename */
727			memset(dest, 0, s3plug[i].len);
728			strncpy(dest, PRISM2_USB_FWFILE, s3plug[i].len - 1);
729		} else {	/* plug a PDR */
730			memcpy(dest, &(pda->rec[j]->data), s3plug[i].len);
731		}
732	}
733	return result;
734
735}
736
737/*----------------------------------------------------------------
738* read_cardpda
739*
740* Sends the command for the driver to read the pda from the card
741* named in the device variable.  Upon success, the card pda is
742* stored in the "cardpda" variables.  Note that the pda structure
743* is considered 'well formed' after this function.  That means
744* that the nrecs is valid, the rec array has been set up, and there's
745* a valid PDAEND record in the raw PDA data.
746*
747* Arguments:
748*	pda		pda structure
749*	wlandev		device
750*
751* Returns:
752*	0	- success
753*	~0	- failure (probably an errno)
754----------------------------------------------------------------*/
755int read_cardpda(struct pda *pda, wlandevice_t *wlandev)
756{
757	int result = 0;
758	struct p80211msg_p2req_readpda msg;
759
760	/* set up the msg */
761	msg.msgcode = DIDmsg_p2req_readpda;
762	msg.msglen = sizeof(msg);
763	strcpy(msg.devname, wlandev->name);
764	msg.pda.did = DIDmsg_p2req_readpda_pda;
765	msg.pda.len = HFA384x_PDA_LEN_MAX;
766	msg.pda.status = P80211ENUM_msgitem_status_no_value;
767	msg.resultcode.did = DIDmsg_p2req_readpda_resultcode;
768	msg.resultcode.len = sizeof(u32);
769	msg.resultcode.status = P80211ENUM_msgitem_status_no_value;
770
771	if (prism2mgmt_readpda(wlandev, &msg) != 0) {
772		/* prism2mgmt_readpda prints an errno if appropriate */
773		result = -1;
774	} else if (msg.resultcode.data == P80211ENUM_resultcode_success) {
775		memcpy(pda->buf, msg.pda.data, HFA384x_PDA_LEN_MAX);
776		result = mkpdrlist(pda);
777	} else {
778		/* resultcode must've been something other than success */
779		result = -1;
780	}
781
782	return result;
783}
784
785/*----------------------------------------------------------------
786* read_fwfile
787*
788* Reads the given fw file which should have been compiled from an srec
789* file. Each record in the fw file will either be a plain data record,
790* a start address record, or other records used for plugging.
791*
792* Note that data records are expected to be sorted into
793* ascending address order in the fw file.
794*
795* Note also that the start address record, originally an S7 record in
796* the srec file, is expected in the fw file to be like a data record but
797* with a certain address to make it identiable.
798*
799* Here's the SREC format that the fw should have come from:
800* S[37]nnaaaaaaaaddd...dddcc
801*
802*       nn - number of bytes starting with the address field
803* aaaaaaaa - address in readable (or big endian) format
804* dd....dd - 0-245 data bytes (two chars per byte)
805*       cc - checksum
806*
807* The S7 record's (there should be only one) address value gets
808* converted to an S3 record with address of 0xff400000, with the
809* start address being stored as a 4 byte data word. That address is
810* the start execution address used for RAM downloads.
811*
812* The S3 records have a collection of subformats indicated by the
813* value of aaaaaaaa:
814*   0xff000000 - Plug record, data field format:
815*                xxxxxxxxaaaaaaaassssssss
816*                x - PDR code number (little endian)
817*                a - Address in load image to plug (little endian)
818*                s - Length of plug data area (little endian)
819*
820*   0xff100000 - CRC16 generation record, data field format:
821*                aaaaaaaassssssssbbbbbbbb
822*                a - Start address for CRC calculation (little endian)
823*                s - Length of data to  calculate over (little endian)
824*                b - Boolean, true=write crc, false=don't write
825*
826*   0xff200000 - Info record, data field format:
827*                ssssttttdd..dd
828*                s - Size in words (little endian)
829*                t - Info type (little endian), see #defines and
830*                    struct s3inforec for details about types.
831*                d - (s - 1) little endian words giving the contents of
832*                    the given info type.
833*
834*   0xff400000 - Start address record, data field format:
835*                aaaaaaaa
836*                a - Address in load image to plug (little endian)
837*
838* Arguments:
839*	record	firmware image (ihex record structure) in kernel memory
840*
841* Returns:
842*	0	- success
843*	~0	- failure (probably an errno)
844----------------------------------------------------------------*/
845int read_fwfile(const struct ihex_binrec *record)
846{
847	int		i;
848	int		rcnt = 0;
849	u16		*tmpinfo;
850	u16		*ptr16;
851	u32		*ptr32, len, addr;
852
853	pr_debug("Reading fw file ...\n");
854
855	while (record) {
856
857		rcnt++;
858
859		len = be16_to_cpu(record->len);
860		addr = be32_to_cpu(record->addr);
861
862		/* Point into data for different word lengths */
863		ptr32 = (u32 *) record->data;
864		ptr16 = (u16 *) record->data;
865
866		/* parse what was an S3 srec and put it in the right array */
867		switch (addr) {
868		case S3ADDR_START:
869			startaddr = *ptr32;
870			pr_debug("  S7 start addr, record=%d "
871				      " addr=0x%08x\n",
872				      rcnt,
873				      startaddr);
874			break;
875		case S3ADDR_PLUG:
876			s3plug[ns3plug].itemcode = *ptr32;
877			s3plug[ns3plug].addr = *(ptr32 + 1);
878			s3plug[ns3plug].len = *(ptr32 + 2);
879
880			pr_debug("  S3 plugrec, record=%d "
881				      "itemcode=0x%08x addr=0x%08x len=%d\n",
882				      rcnt,
883				      s3plug[ns3plug].itemcode,
884				      s3plug[ns3plug].addr,
885				      s3plug[ns3plug].len);
886
887			ns3plug++;
888			if (ns3plug == S3PLUG_MAX) {
889				printk(KERN_ERR "S3 plugrec limit reached - aborting\n");
890				return 1;
891			}
892			break;
893		case S3ADDR_CRC:
894			s3crc[ns3crc].addr = *ptr32;
895			s3crc[ns3crc].len = *(ptr32 + 1);
896			s3crc[ns3crc].dowrite = *(ptr32 + 2);
897
898			pr_debug("  S3 crcrec, record=%d "
899				      "addr=0x%08x len=%d write=0x%08x\n",
900				      rcnt,
901				      s3crc[ns3crc].addr,
902				      s3crc[ns3crc].len,
903				      s3crc[ns3crc].dowrite);
904			ns3crc++;
905			if (ns3crc == S3CRC_MAX) {
906				printk(KERN_ERR "S3 crcrec limit reached - aborting\n");
907				return 1;
908			}
909			break;
910		case S3ADDR_INFO:
911			s3info[ns3info].len = *ptr16;
912			s3info[ns3info].type = *(ptr16 + 1);
913
914			pr_debug("  S3 inforec, record=%d "
915			      "len=0x%04x type=0x%04x\n",
916				      rcnt,
917				      s3info[ns3info].len,
918				      s3info[ns3info].type);
919			if (((s3info[ns3info].len - 1) * sizeof(u16)) > sizeof(s3info[ns3info].info)) {
920				printk(KERN_ERR " S3 inforec length too long - aborting\n");
921				return 1;
922			}
923
924			tmpinfo = (u16 *)&(s3info[ns3info].info.version);
925			pr_debug("            info=");
926			for (i = 0; i < s3info[ns3info].len - 1; i++) {
927				tmpinfo[i] = *(ptr16 + 2 + i);
928				pr_debug("%04x ", tmpinfo[i]);
929			}
930			pr_debug("\n");
931
932			ns3info++;
933			if (ns3info == S3INFO_MAX) {
934				printk(KERN_ERR "S3 inforec limit reached - aborting\n");
935				return 1;
936			}
937			break;
938		default:	/* Data record */
939			s3data[ns3data].addr = addr;
940			s3data[ns3data].len = len;
941			s3data[ns3data].data = (uint8_t *) record->data;
942			ns3data++;
943			if (ns3data == S3DATA_MAX) {
944				printk(KERN_ERR "S3 datarec limit reached - aborting\n");
945				return 1;
946			}
947			break;
948		}
949		record = ihex_next_binrec(record);
950	}
951	return 0;
952}
953
954/*----------------------------------------------------------------
955* writeimage
956*
957* Takes the chunks, builds p80211 messages and sends them down
958* to the driver for writing to the card.
959*
960* Arguments:
961*	wlandev		device
962*	fchunk		Array of image chunks
963*	nfchunks	Number of image chunks
964*
965* Returns:
966*	0	success
967*	~0	failure
968----------------------------------------------------------------*/
969int writeimage(wlandevice_t *wlandev, struct imgchunk *fchunk,
970	       unsigned int nfchunks)
971{
972	int result = 0;
973	struct p80211msg_p2req_ramdl_state rstatemsg;
974	struct p80211msg_p2req_ramdl_write rwritemsg;
975	struct p80211msg *msgp;
976	u32 resultcode;
977	int i;
978	int j;
979	unsigned int nwrites;
980	u32 curroff;
981	u32 currlen;
982	u32 currdaddr;
983
984	/* Initialize the messages */
985	memset(&rstatemsg, 0, sizeof(rstatemsg));
986	strcpy(rstatemsg.devname, wlandev->name);
987	rstatemsg.msgcode = DIDmsg_p2req_ramdl_state;
988	rstatemsg.msglen = sizeof(rstatemsg);
989	rstatemsg.enable.did = DIDmsg_p2req_ramdl_state_enable;
990	rstatemsg.exeaddr.did = DIDmsg_p2req_ramdl_state_exeaddr;
991	rstatemsg.resultcode.did = DIDmsg_p2req_ramdl_state_resultcode;
992	rstatemsg.enable.status = P80211ENUM_msgitem_status_data_ok;
993	rstatemsg.exeaddr.status = P80211ENUM_msgitem_status_data_ok;
994	rstatemsg.resultcode.status = P80211ENUM_msgitem_status_no_value;
995	rstatemsg.enable.len = sizeof(u32);
996	rstatemsg.exeaddr.len = sizeof(u32);
997	rstatemsg.resultcode.len = sizeof(u32);
998
999	memset(&rwritemsg, 0, sizeof(rwritemsg));
1000	strcpy(rwritemsg.devname, wlandev->name);
1001	rwritemsg.msgcode = DIDmsg_p2req_ramdl_write;
1002	rwritemsg.msglen = sizeof(rwritemsg);
1003	rwritemsg.addr.did = DIDmsg_p2req_ramdl_write_addr;
1004	rwritemsg.len.did = DIDmsg_p2req_ramdl_write_len;
1005	rwritemsg.data.did = DIDmsg_p2req_ramdl_write_data;
1006	rwritemsg.resultcode.did = DIDmsg_p2req_ramdl_write_resultcode;
1007	rwritemsg.addr.status = P80211ENUM_msgitem_status_data_ok;
1008	rwritemsg.len.status = P80211ENUM_msgitem_status_data_ok;
1009	rwritemsg.data.status = P80211ENUM_msgitem_status_data_ok;
1010	rwritemsg.resultcode.status = P80211ENUM_msgitem_status_no_value;
1011	rwritemsg.addr.len = sizeof(u32);
1012	rwritemsg.len.len = sizeof(u32);
1013	rwritemsg.data.len = WRITESIZE_MAX;
1014	rwritemsg.resultcode.len = sizeof(u32);
1015
1016	/* Send xxx_state(enable) */
1017	pr_debug("Sending dl_state(enable) message.\n");
1018	rstatemsg.enable.data = P80211ENUM_truth_true;
1019	rstatemsg.exeaddr.data = startaddr;
1020
1021	msgp = (struct p80211msg *) &rstatemsg;
1022	result = prism2mgmt_ramdl_state(wlandev, msgp);
1023	if (result) {
1024		printk(KERN_ERR
1025		       "writeimage state enable failed w/ result=%d, "
1026		       "aborting download\n", result);
1027		return result;
1028	}
1029	resultcode = rstatemsg.resultcode.data;
1030	if (resultcode != P80211ENUM_resultcode_success) {
1031		printk(KERN_ERR
1032		       "writeimage()->xxxdl_state msg indicates failure, "
1033		       "w/ resultcode=%d, aborting download.\n", resultcode);
1034		return 1;
1035	}
1036
1037	/* Now, loop through the data chunks and send WRITESIZE_MAX data */
1038	for (i = 0; i < nfchunks; i++) {
1039		nwrites = fchunk[i].len / WRITESIZE_MAX;
1040		nwrites += (fchunk[i].len % WRITESIZE_MAX) ? 1 : 0;
1041		curroff = 0;
1042		for (j = 0; j < nwrites; j++) {
1043			/* TODO Move this to a separate function */
1044			int lenleft = fchunk[i].len - (WRITESIZE_MAX * j);
1045			if (fchunk[i].len > WRITESIZE_MAX)
1046				currlen = WRITESIZE_MAX;
1047			else
1048				currlen = lenleft;
1049			curroff = j * WRITESIZE_MAX;
1050			currdaddr = fchunk[i].addr + curroff;
1051			/* Setup the message */
1052			rwritemsg.addr.data = currdaddr;
1053			rwritemsg.len.data = currlen;
1054			memcpy(rwritemsg.data.data,
1055			       fchunk[i].data + curroff, currlen);
1056
1057			/* Send flashdl_write(pda) */
1058			pr_debug
1059			    ("Sending xxxdl_write message addr=%06x len=%d.\n",
1060			     currdaddr, currlen);
1061
1062			msgp = (struct p80211msg *) &rwritemsg;
1063			result = prism2mgmt_ramdl_write(wlandev, msgp);
1064
1065			/* Check the results */
1066			if (result) {
1067				printk(KERN_ERR
1068				       "writeimage chunk write failed w/ result=%d, "
1069				       "aborting download\n", result);
1070				return result;
1071			}
1072			resultcode = rstatemsg.resultcode.data;
1073			if (resultcode != P80211ENUM_resultcode_success) {
1074				printk(KERN_ERR
1075				       "writeimage()->xxxdl_write msg indicates failure, "
1076				       "w/ resultcode=%d, aborting download.\n",
1077				       resultcode);
1078				return 1;
1079			}
1080
1081		}
1082	}
1083
1084	/* Send xxx_state(disable) */
1085	pr_debug("Sending dl_state(disable) message.\n");
1086	rstatemsg.enable.data = P80211ENUM_truth_false;
1087	rstatemsg.exeaddr.data = 0;
1088
1089	msgp = (struct p80211msg *) &rstatemsg;
1090	result = prism2mgmt_ramdl_state(wlandev, msgp);
1091	if (result) {
1092		printk(KERN_ERR
1093		       "writeimage state disable failed w/ result=%d, "
1094		       "aborting download\n", result);
1095		return result;
1096	}
1097	resultcode = rstatemsg.resultcode.data;
1098	if (resultcode != P80211ENUM_resultcode_success) {
1099		printk(KERN_ERR
1100		       "writeimage()->xxxdl_state msg indicates failure, "
1101		       "w/ resultcode=%d, aborting download.\n", resultcode);
1102		return 1;
1103	}
1104	return result;
1105}
1106
1107int validate_identity(void)
1108{
1109	int i;
1110	int result = 1;
1111	int trump = 0;
1112
1113	pr_debug("NIC ID: %#x v%d.%d.%d\n",
1114		 nicid.id, nicid.major, nicid.minor, nicid.variant);
1115	pr_debug("MFI ID: %#x v%d %d->%d\n",
1116		 rfid.id, rfid.variant, rfid.bottom, rfid.top);
1117	pr_debug("CFI ID: %#x v%d %d->%d\n",
1118		 macid.id, macid.variant, macid.bottom, macid.top);
1119	pr_debug("PRI ID: %#x v%d %d->%d\n",
1120		 priid.id, priid.variant, priid.bottom, priid.top);
1121
1122	for (i = 0; i < ns3info; i++) {
1123		switch (s3info[i].type) {
1124		case 1:
1125			pr_debug("Version:  ID %#x %d.%d.%d\n",
1126				 s3info[i].info.version.id,
1127				 s3info[i].info.version.major,
1128				 s3info[i].info.version.minor,
1129				 s3info[i].info.version.variant);
1130			break;
1131		case 2:
1132			pr_debug("Compat: Role %#x Id %#x v%d %d->%d\n",
1133				 s3info[i].info.compat.role,
1134				 s3info[i].info.compat.id,
1135				 s3info[i].info.compat.variant,
1136				 s3info[i].info.compat.bottom,
1137				 s3info[i].info.compat.top);
1138
1139			/* MAC compat range */
1140			if ((s3info[i].info.compat.role == 1) &&
1141			    (s3info[i].info.compat.id == 2)) {
1142				if (s3info[i].info.compat.variant !=
1143				    macid.variant) {
1144					result = 2;
1145				}
1146			}
1147
1148			/* PRI compat range */
1149			if ((s3info[i].info.compat.role == 1) &&
1150			    (s3info[i].info.compat.id == 3)) {
1151				if ((s3info[i].info.compat.bottom > priid.top)
1152				    || (s3info[i].info.compat.top <
1153					priid.bottom)) {
1154					result = 3;
1155				}
1156			}
1157			/* SEC compat range */
1158			if ((s3info[i].info.compat.role == 1) &&
1159			    (s3info[i].info.compat.id == 4)) {
1160			}
1161
1162			break;
1163		case 3:
1164			pr_debug("Seq: %#x\n", s3info[i].info.buildseq);
1165
1166			break;
1167		case 4:
1168			pr_debug("Platform:  ID %#x %d.%d.%d\n",
1169				 s3info[i].info.version.id,
1170				 s3info[i].info.version.major,
1171				 s3info[i].info.version.minor,
1172				 s3info[i].info.version.variant);
1173
1174			if (nicid.id != s3info[i].info.version.id)
1175				continue;
1176			if (nicid.major != s3info[i].info.version.major)
1177				continue;
1178			if (nicid.minor != s3info[i].info.version.minor)
1179				continue;
1180			if ((nicid.variant != s3info[i].info.version.variant) &&
1181			    (nicid.id != 0x8008))
1182				continue;
1183
1184			trump = 1;
1185			break;
1186		case 0x8001:
1187			pr_debug("name inforec len %d\n", s3info[i].len);
1188
1189			break;
1190		default:
1191			pr_debug("Unknown inforec type %d\n", s3info[i].type);
1192		}
1193	}
1194	/* walk through */
1195
1196	if (trump && (result != 2))
1197		result = 0;
1198	return result;
1199}
1200