diff options
author | Karl Relton <karllinuxtest.relton@ntlworld.com> | 2009-08-19 03:06:39 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-09-15 15:01:35 -0400 |
commit | d89505998e007f88e08e84381dcc720a8990507d (patch) | |
tree | 2a38c5cf189079d0b3f8af84d833db36268b81a8 /drivers/staging | |
parent | c4004175eb51a40069b879d547e32fe8b4d6fde1 (diff) |
Staging: wlan-ng: Convert firmware loading to load binary ihex format
Convert prism2_usb firmware loading to load firmware in pre-compiled
binary 'ihex' format rather than ascii 'srec' format. This moves the
srec processing and sorting of records out of kernel space into a
pre-compiler. The driver now just works with the binary image, but
still does the 'pda plugging' of that image at runtime, as required
by the prism hardware.
Some Notes:
- The firmware is now expected to be in the same 'ihex' (.fw) format
used by other drivers.
- The now driver assumes the data records are already sorted into ascending
address order.
- Plug and crc records are still recognised by special address locations
as in original srec processing.
- The srec S7 start address record is assumed to have been converted
into a data record with another special address location (0xff400000),
with the original start address being stored as a 4 byte data word
(little endian).
Signed-off-by: Karl Relton <karllinuxtest.relton@ntlworld.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/staging')
-rw-r--r-- | drivers/staging/wlan-ng/prism2fw.c | 465 |
1 files changed, 131 insertions, 334 deletions
diff --git a/drivers/staging/wlan-ng/prism2fw.c b/drivers/staging/wlan-ng/prism2fw.c index c62b4759b3d..7d76a7f92a3 100644 --- a/drivers/staging/wlan-ng/prism2fw.c +++ b/drivers/staging/wlan-ng/prism2fw.c | |||
@@ -47,84 +47,28 @@ | |||
47 | 47 | ||
48 | /*================================================================*/ | 48 | /*================================================================*/ |
49 | /* System Includes */ | 49 | /* System Includes */ |
50 | #include <linux/sort.h> | 50 | #include <linux/ihex.h> |
51 | #include <linux/firmware.h> | ||
52 | 51 | ||
53 | /*================================================================*/ | 52 | /*================================================================*/ |
54 | /* Local Constants */ | 53 | /* Local Constants */ |
55 | 54 | ||
56 | #define PRISM2_USB_FWFILE "prism2_ru.hex" | 55 | #define PRISM2_USB_FWFILE "prism2_ru.fw" |
57 | 56 | ||
58 | #define S3DATA_MAX 5000 | 57 | #define S3DATA_MAX 5000 |
59 | #define S3PLUG_MAX 200 | 58 | #define S3PLUG_MAX 200 |
60 | #define S3CRC_MAX 200 | 59 | #define S3CRC_MAX 200 |
61 | #define S3INFO_MAX 50 | 60 | #define S3INFO_MAX 50 |
62 | #define SREC_LINE_MAX 264 | ||
63 | #define S3LEN_TXTOFFSET 2 | ||
64 | #define S3LEN_TXTLEN 2 | ||
65 | #define S3ADDR_TXTOFFSET 4 | ||
66 | #define S3ADDR_TXTLEN 8 | ||
67 | #define S3DATA_TXTOFFSET 12 | ||
68 | /*S3DATA_TXTLEN variable, depends on len field */ | ||
69 | /*S3CKSUM_TXTOFFSET variable, depends on len field */ | ||
70 | #define S3CKSUM_TXTLEN 2 | ||
71 | #define SERNUM_LEN_MAX 12 | ||
72 | |||
73 | #define S3PLUG_ITEMCODE_TXTOFFSET (S3DATA_TXTOFFSET) | ||
74 | #define S3PLUG_ITEMCODE_TXTLEN 8 | ||
75 | #define S3PLUG_ADDR_TXTOFFSET (S3DATA_TXTOFFSET+8) | ||
76 | #define S3PLUG_ADDR_TXTLEN 8 | ||
77 | #define S3PLUG_LEN_TXTOFFSET (S3DATA_TXTOFFSET+16) | ||
78 | #define S3PLUG_LEN_TXTLEN 8 | ||
79 | |||
80 | #define S3CRC_ADDR_TXTOFFSET (S3DATA_TXTOFFSET) | ||
81 | #define S3CRC_ADDR_TXTLEN 8 | ||
82 | #define S3CRC_LEN_TXTOFFSET (S3DATA_TXTOFFSET+8) | ||
83 | #define S3CRC_LEN_TXTLEN 8 | ||
84 | #define S3CRC_DOWRITE_TXTOFFSET (S3DATA_TXTOFFSET+16) | ||
85 | #define S3CRC_DOWRITE_TXTLEN 8 | ||
86 | |||
87 | #define S3INFO_LEN_TXTOFFSET (S3DATA_TXTOFFSET) | ||
88 | #define S3INFO_LEN_TXTLEN 4 | ||
89 | #define S3INFO_TYPE_TXTOFFSET (S3DATA_TXTOFFSET+4) | ||
90 | #define S3INFO_TYPE_TXTLEN 4 | ||
91 | #define S3INFO_DATA_TXTOFFSET (S3DATA_TXTOFFSET+8) | ||
92 | /* S3INFO_DATA_TXTLEN variable, depends on INFO_LEN field */ | ||
93 | 61 | ||
94 | #define S3ADDR_PLUG (0xff000000UL) | 62 | #define S3ADDR_PLUG (0xff000000UL) |
95 | #define S3ADDR_CRC (0xff100000UL) | 63 | #define S3ADDR_CRC (0xff100000UL) |
96 | #define S3ADDR_INFO (0xff200000UL) | 64 | #define S3ADDR_INFO (0xff200000UL) |
97 | 65 | #define S3ADDR_START (0xff400000UL) | |
98 | #define PDAFILE_LINE_MAX 1024 | ||
99 | 66 | ||
100 | #define CHUNKS_MAX 100 | 67 | #define CHUNKS_MAX 100 |
101 | 68 | ||
102 | #define WRITESIZE_MAX 4096 | 69 | #define WRITESIZE_MAX 4096 |
103 | 70 | ||
104 | /*================================================================*/ | 71 | /*================================================================*/ |
105 | /* Local Macros */ | ||
106 | |||
107 | #define bswap_16(x) \ | ||
108 | (__extension__ \ | ||
109 | ({ register unsigned short int __v, __x = (x); \ | ||
110 | __asm__ ("rorw $8, %w0" \ | ||
111 | : "=r" (__v) \ | ||
112 | : "0" (__x) \ | ||
113 | : "cc"); \ | ||
114 | __v; })) | ||
115 | |||
116 | #define bswap_32(x) \ | ||
117 | (__extension__ \ | ||
118 | ({ register unsigned int __v, __x = (x); \ | ||
119 | __asm__ ("rorw $8, %w0;" \ | ||
120 | "rorl $16, %0;" \ | ||
121 | "rorw $8, %w0" \ | ||
122 | : "=r" (__v) \ | ||
123 | : "0" (__x) \ | ||
124 | : "cc"); \ | ||
125 | __v; })) | ||
126 | |||
127 | /*================================================================*/ | ||
128 | /* Local Types */ | 72 | /* Local Types */ |
129 | 73 | ||
130 | typedef struct s3datarec { | 74 | typedef struct s3datarec { |
@@ -214,12 +158,11 @@ hfa384x_caplevel_t priid; | |||
214 | /*================================================================*/ | 158 | /*================================================================*/ |
215 | /* Local Function Declarations */ | 159 | /* Local Function Declarations */ |
216 | 160 | ||
217 | int prism2_fwapply(char *rfptr, int rfsize, wlandevice_t * wlandev); | 161 | int prism2_fwapply(const struct ihex_binrec *rfptr, wlandevice_t *wlandev); |
218 | int read_srecfile(char *rfptr, int rfsize); | 162 | int read_fwfile(const struct ihex_binrec *rfptr); |
219 | int mkimage(imgchunk_t *clist, unsigned int *ccnt); | 163 | int mkimage(imgchunk_t *clist, unsigned int *ccnt); |
220 | int read_cardpda(pda_t *pda, wlandevice_t *wlandev); | 164 | int read_cardpda(pda_t *pda, wlandevice_t *wlandev); |
221 | int mkpdrlist(pda_t *pda); | 165 | int mkpdrlist(pda_t *pda); |
222 | int s3datarec_compare(const void *p1, const void *p2); | ||
223 | int plugimage(imgchunk_t *fchunk, unsigned int nfchunks, | 166 | int plugimage(imgchunk_t *fchunk, unsigned int nfchunks, |
224 | s3plugrec_t *s3plug, unsigned int ns3plug, pda_t * pda); | 167 | s3plugrec_t *s3plug, unsigned int ns3plug, pda_t * pda); |
225 | int crcimage(imgchunk_t *fchunk, unsigned int nfchunks, | 168 | int crcimage(imgchunk_t *fchunk, unsigned int nfchunks, |
@@ -253,7 +196,7 @@ int prism2_fwtry(struct usb_device *udev, wlandevice_t *wlandev) | |||
253 | 196 | ||
254 | printk(KERN_INFO "prism2_usb: Checking for firmware %s\n", | 197 | printk(KERN_INFO "prism2_usb: Checking for firmware %s\n", |
255 | PRISM2_USB_FWFILE); | 198 | PRISM2_USB_FWFILE); |
256 | if (request_firmware(&fw_entry, PRISM2_USB_FWFILE, &udev->dev) != 0) { | 199 | if (request_ihex_firmware(&fw_entry, PRISM2_USB_FWFILE, &udev->dev) != 0) { |
257 | printk(KERN_INFO | 200 | printk(KERN_INFO |
258 | "prism2_usb: Firmware not available, but not essential\n"); | 201 | "prism2_usb: Firmware not available, but not essential\n"); |
259 | printk(KERN_INFO | 202 | printk(KERN_INFO |
@@ -263,7 +206,7 @@ int prism2_fwtry(struct usb_device *udev, wlandevice_t *wlandev) | |||
263 | 206 | ||
264 | printk(KERN_INFO "prism2_usb: %s will be processed, size %d\n", | 207 | printk(KERN_INFO "prism2_usb: %s will be processed, size %d\n", |
265 | PRISM2_USB_FWFILE, fw_entry->size); | 208 | PRISM2_USB_FWFILE, fw_entry->size); |
266 | prism2_fwapply((char *)fw_entry->data, fw_entry->size, wlandev); | 209 | prism2_fwapply((const struct ihex_binrec *)fw_entry->data, wlandev); |
267 | 210 | ||
268 | release_firmware(fw_entry); | 211 | release_firmware(fw_entry); |
269 | return 0; | 212 | return 0; |
@@ -276,14 +219,13 @@ int prism2_fwtry(struct usb_device *udev, wlandevice_t *wlandev) | |||
276 | * | 219 | * |
277 | * Arguments: | 220 | * Arguments: |
278 | * rfptr firmware image in kernel memory | 221 | * rfptr firmware image in kernel memory |
279 | * rfsize firmware size in kernel memory | ||
280 | * wlandev device | 222 | * wlandev device |
281 | * | 223 | * |
282 | * Returns: | 224 | * Returns: |
283 | * 0 - success | 225 | * 0 - success |
284 | * ~0 - failure | 226 | * ~0 - failure |
285 | ----------------------------------------------------------------*/ | 227 | ----------------------------------------------------------------*/ |
286 | int prism2_fwapply(char *rfptr, int rfsize, wlandevice_t *wlandev) | 228 | int prism2_fwapply(const struct ihex_binrec *rfptr, wlandevice_t *wlandev) |
287 | { | 229 | { |
288 | signed int result = 0; | 230 | signed int result = 0; |
289 | p80211msg_dot11req_mibget_t getmsg; | 231 | p80211msg_dot11req_mibget_t getmsg; |
@@ -356,13 +298,11 @@ int prism2_fwapply(char *rfptr, int rfsize, wlandevice_t *wlandev) | |||
356 | priid.top = *data++; | 298 | priid.top = *data++; |
357 | 299 | ||
358 | /* Read the S3 file */ | 300 | /* Read the S3 file */ |
359 | result = read_srecfile(rfptr, rfsize); | 301 | result = read_fwfile(rfptr); |
360 | if (result) { | 302 | if (result) { |
361 | printk(KERN_ERR "Failed to read the data exiting.\n"); | 303 | printk(KERN_ERR "Failed to read the data exiting.\n"); |
362 | return (1); | 304 | return (1); |
363 | } | 305 | } |
364 | /* Sort the S3 data records */ | ||
365 | sort(s3data, ns3data, sizeof(s3datarec_t), s3datarec_compare, NULL); | ||
366 | 306 | ||
367 | result = validate_identity(); | 307 | result = validate_identity(); |
368 | 308 | ||
@@ -516,10 +456,6 @@ void free_chunks(imgchunk_t *fchunk, unsigned int *nfchunks) | |||
516 | ----------------------------------------------------------------*/ | 456 | ----------------------------------------------------------------*/ |
517 | void free_srecs(void) | 457 | void free_srecs(void) |
518 | { | 458 | { |
519 | int i; | ||
520 | for (i = 0; i < ns3data; i++) { | ||
521 | kfree(s3data[i].data); | ||
522 | } | ||
523 | ns3data = 0; | 459 | ns3data = 0; |
524 | memset(s3data, 0, sizeof(s3data)); | 460 | memset(s3data, 0, sizeof(s3data)); |
525 | ns3plug = 0; | 461 | ns3plug = 0; |
@@ -598,10 +534,6 @@ int mkimage(imgchunk_t *clist, unsigned int *ccnt) | |||
598 | return (1); | 534 | return (1); |
599 | } | 535 | } |
600 | memset(clist[i].data, 0, clist[i].len); | 536 | memset(clist[i].data, 0, clist[i].len); |
601 | } | ||
602 | |||
603 | /* Display chunks */ | ||
604 | for (i = 0; i < *ccnt; i++) { | ||
605 | pr_debug("chunk[%d]: addr=0x%06x len=%d\n", | 537 | pr_debug("chunk[%d]: addr=0x%06x len=%d\n", |
606 | i, clist[i].addr, clist[i].len); | 538 | i, clist[i].addr, clist[i].len); |
607 | } | 539 | } |
@@ -856,44 +788,20 @@ int read_cardpda(pda_t *pda, wlandevice_t *wlandev) | |||
856 | } | 788 | } |
857 | 789 | ||
858 | /*---------------------------------------------------------------- | 790 | /*---------------------------------------------------------------- |
859 | * copy_line | 791 | * read_fwfile |
860 | * | 792 | * |
861 | * Copies a line of text, up to \n, \0, or SREC_LINE_MAX, or limit of | 793 | * Reads the given fw file which should have been compiled from an srec |
862 | * From array | 794 | * file. Each record in the fw file will either be a plain data record, |
795 | * a start address record, or other records used for plugging. | ||
863 | * | 796 | * |
864 | * Arguments: | 797 | * Note that data records are expected to be sorted into |
865 | * from From addr | 798 | * ascending address order in the fw file. |
866 | * to To addr | ||
867 | * limit Addr of last character in From array that can be copied | ||
868 | * | ||
869 | * Returns: | ||
870 | * Num characters copied | ||
871 | ----------------------------------------------------------------*/ | ||
872 | int copyline(char *from, char *to, char *limit) | ||
873 | { | ||
874 | int c = 0; | ||
875 | |||
876 | while ((c < SREC_LINE_MAX - 1) && (from + c <= limit) && | ||
877 | (from[c] != '\n') && (from[c] != '\0')) { | ||
878 | to[c] = from[c]; | ||
879 | c++; | ||
880 | } | ||
881 | |||
882 | to[c] = '\0'; | ||
883 | return (c < SREC_LINE_MAX - 1) ? c + 1 : c; | ||
884 | } | ||
885 | |||
886 | /*---------------------------------------------------------------- | ||
887 | * read_srecfile | ||
888 | * | 799 | * |
889 | * Reads the given srecord file and loads the records into the | 800 | * Note also that the start address record, originally an S7 record in |
890 | * s3xxx arrays. This function can be called repeatedly (once for | 801 | * the srec file, is expected in the fw file to be like a data record but |
891 | * each of a set of files), if necessary. This function performs | 802 | * with a certain address to make it identiable. |
892 | * no validation of the data except for the grossest of S-record | ||
893 | * line format checks. Don't forget that these will be DOS files... | ||
894 | * CR/LF at the end of each line. | ||
895 | * | 803 | * |
896 | * Here's the SREC format we're dealing with: | 804 | * Here's the SREC format that the fw should have come from: |
897 | * S[37]nnaaaaaaaaddd...dddcc | 805 | * S[37]nnaaaaaaaaddd...dddcc |
898 | * | 806 | * |
899 | * nn - number of bytes starting with the address field | 807 | * nn - number of bytes starting with the address field |
@@ -902,8 +810,9 @@ int copyline(char *from, char *to, char *limit) | |||
902 | * cc - checksum | 810 | * cc - checksum |
903 | * | 811 | * |
904 | * The S7 record's (there should be only one) address value gets | 812 | * The S7 record's (there should be only one) address value gets |
905 | * saved in startaddr. It's the start execution address used | 813 | * converted to an S3 record with address of 0xff400000, with the |
906 | * for RAM downloads. | 814 | * start address being stored as a 4 byte data word. That address is |
815 | * the start execution address used for RAM downloads. | ||
907 | * | 816 | * |
908 | * The S3 records have a collection of subformats indicated by the | 817 | * The S3 records have a collection of subformats indicated by the |
909 | * value of aaaaaaaa: | 818 | * value of aaaaaaaa: |
@@ -927,237 +836,124 @@ int copyline(char *from, char *to, char *limit) | |||
927 | * d - (s - 1) little endian words giving the contents of | 836 | * d - (s - 1) little endian words giving the contents of |
928 | * the given info type. | 837 | * the given info type. |
929 | * | 838 | * |
839 | * 0xff400000 - Start address record, data field format: | ||
840 | * aaaaaaaa | ||
841 | * a - Address in load image to plug (little endian) | ||
842 | * | ||
930 | * Arguments: | 843 | * Arguments: |
931 | * rfptr firmware image (s-record structure) in kernel memory | 844 | * record firmware image (ihex record structure) in kernel memory |
932 | * rfsize firmware size in kernel memory | ||
933 | * | 845 | * |
934 | * Returns: | 846 | * Returns: |
935 | * 0 - success | 847 | * 0 - success |
936 | * ~0 - failure (probably an errno) | 848 | * ~0 - failure (probably an errno) |
937 | ----------------------------------------------------------------*/ | 849 | ----------------------------------------------------------------*/ |
938 | int read_srecfile(char *rfptr, int rfsize) | 850 | int read_fwfile(const struct ihex_binrec *record) |
939 | { | 851 | { |
940 | int result = 0; | 852 | int i; |
941 | char buf[SREC_LINE_MAX]; | 853 | int rcnt = 0; |
942 | char tmpbuf[30]; | 854 | u16 *tmpinfo; |
943 | s3datarec_t tmprec; | 855 | u16 *ptr16; |
944 | int i, c; | 856 | u32 *ptr32, len, addr; |
945 | int line = 0; | ||
946 | u16 *tmpinfo; | ||
947 | char *endptr = rfptr + rfsize; | ||
948 | |||
949 | pr_debug("Reading S-record file ...\n"); | ||
950 | |||
951 | while ((c = copyline(rfptr, buf, endptr)) >= 12) { | ||
952 | rfptr = rfptr + c; | ||
953 | line++; | ||
954 | if (buf[0] != 'S') { | ||
955 | printk(KERN_ERR "%d warning: No initial \'S\'\n", line); | ||
956 | return 1; | ||
957 | } | ||
958 | if (buf[1] == '7') { /* S7 record, start address */ | ||
959 | buf[12] = '\0'; | ||
960 | startaddr = simple_strtoul(buf + 4, NULL, 16); | ||
961 | pr_debug(" S7 start addr, line=%d " | ||
962 | " addr=0x%08x\n", line, startaddr); | ||
963 | continue; | ||
964 | } else if (buf[1] == '3') { | ||
965 | /* Ok, it's an S3, parse and put it in the right array */ | ||
966 | /* Record Length field (we only want datalen) */ | ||
967 | memcpy(tmpbuf, buf + S3LEN_TXTOFFSET, S3LEN_TXTLEN); | ||
968 | tmpbuf[S3LEN_TXTLEN] = '\0'; | ||
969 | tmprec.len = simple_strtoul(tmpbuf, NULL, 16) - 4 - 1; /* 4=addr, 1=cksum */ | ||
970 | /* Address field */ | ||
971 | memcpy(tmpbuf, buf + S3ADDR_TXTOFFSET, S3ADDR_TXTLEN); | ||
972 | tmpbuf[S3ADDR_TXTLEN] = '\0'; | ||
973 | tmprec.addr = simple_strtoul(tmpbuf, NULL, 16); | ||
974 | /* Checksum field */ | ||
975 | tmprec.checksum = | ||
976 | simple_strtoul(buf + strlen(buf) - 2, NULL, 16); | ||
977 | |||
978 | switch (tmprec.addr) { | ||
979 | case S3ADDR_PLUG: | ||
980 | memcpy(tmpbuf, buf + S3PLUG_ITEMCODE_TXTOFFSET, | ||
981 | S3PLUG_ITEMCODE_TXTLEN); | ||
982 | tmpbuf[S3PLUG_ITEMCODE_TXTLEN] = '\0'; | ||
983 | s3plug[ns3plug].itemcode = | ||
984 | simple_strtoul(tmpbuf, NULL, 16); | ||
985 | s3plug[ns3plug].itemcode = | ||
986 | bswap_32(s3plug[ns3plug].itemcode); | ||
987 | |||
988 | memcpy(tmpbuf, buf + S3PLUG_ADDR_TXTOFFSET, | ||
989 | S3PLUG_ADDR_TXTLEN); | ||
990 | tmpbuf[S3PLUG_ADDR_TXTLEN] = '\0'; | ||
991 | s3plug[ns3plug].addr = | ||
992 | simple_strtoul(tmpbuf, NULL, 16); | ||
993 | s3plug[ns3plug].addr = | ||
994 | bswap_32(s3plug[ns3plug].addr); | ||
995 | |||
996 | memcpy(tmpbuf, buf + S3PLUG_LEN_TXTOFFSET, | ||
997 | S3PLUG_LEN_TXTLEN); | ||
998 | tmpbuf[S3PLUG_LEN_TXTLEN] = '\0'; | ||
999 | s3plug[ns3plug].len = | ||
1000 | simple_strtoul(tmpbuf, NULL, 16); | ||
1001 | s3plug[ns3plug].len = | ||
1002 | bswap_32(s3plug[ns3plug].len); | ||
1003 | |||
1004 | pr_debug(" S3 plugrec, line=%d " | ||
1005 | "itemcode=0x%04x addr=0x%08x len=%d\n", | ||
1006 | line, | ||
1007 | s3plug[ns3plug].itemcode, | ||
1008 | s3plug[ns3plug].addr, | ||
1009 | s3plug[ns3plug].len); | ||
1010 | |||
1011 | ns3plug++; | ||
1012 | if (ns3plug == S3PLUG_MAX) { | ||
1013 | printk(KERN_ERR | ||
1014 | "S3 plugrec limit reached - aborting\n"); | ||
1015 | return 1; | ||
1016 | } | ||
1017 | break; | ||
1018 | case S3ADDR_CRC: | ||
1019 | memcpy(tmpbuf, buf + S3CRC_ADDR_TXTOFFSET, | ||
1020 | S3CRC_ADDR_TXTLEN); | ||
1021 | tmpbuf[S3CRC_ADDR_TXTLEN] = '\0'; | ||
1022 | s3crc[ns3crc].addr = | ||
1023 | simple_strtoul(tmpbuf, NULL, 16); | ||
1024 | s3crc[ns3crc].addr = | ||
1025 | bswap_32(s3crc[ns3crc].addr); | ||
1026 | |||
1027 | memcpy(tmpbuf, buf + S3CRC_LEN_TXTOFFSET, | ||
1028 | S3CRC_LEN_TXTLEN); | ||
1029 | tmpbuf[S3CRC_LEN_TXTLEN] = '\0'; | ||
1030 | s3crc[ns3crc].len = | ||
1031 | simple_strtoul(tmpbuf, NULL, 16); | ||
1032 | s3crc[ns3crc].len = bswap_32(s3crc[ns3crc].len); | ||
1033 | |||
1034 | memcpy(tmpbuf, buf + S3CRC_DOWRITE_TXTOFFSET, | ||
1035 | S3CRC_DOWRITE_TXTLEN); | ||
1036 | tmpbuf[S3CRC_DOWRITE_TXTLEN] = '\0'; | ||
1037 | s3crc[ns3crc].dowrite = | ||
1038 | simple_strtoul(tmpbuf, NULL, 16); | ||
1039 | s3crc[ns3crc].dowrite = | ||
1040 | bswap_32(s3crc[ns3crc].dowrite); | ||
1041 | |||
1042 | pr_debug(" S3 crcrec, line=%d " | ||
1043 | "addr=0x%08x len=%d write=0x%08x\n", | ||
1044 | line, | ||
1045 | s3crc[ns3crc].addr, | ||
1046 | s3crc[ns3crc].len, | ||
1047 | s3crc[ns3crc].dowrite); | ||
1048 | ns3crc++; | ||
1049 | if (ns3crc == S3CRC_MAX) { | ||
1050 | printk(KERN_ERR | ||
1051 | "S3 crcrec limit reached - aborting\n"); | ||
1052 | return 1; | ||
1053 | } | ||
1054 | break; | ||
1055 | case S3ADDR_INFO: | ||
1056 | memcpy(tmpbuf, buf + S3INFO_LEN_TXTOFFSET, | ||
1057 | S3INFO_LEN_TXTLEN); | ||
1058 | tmpbuf[S3INFO_LEN_TXTLEN] = '\0'; | ||
1059 | s3info[ns3info].len = | ||
1060 | simple_strtoul(tmpbuf, NULL, 16); | ||
1061 | s3info[ns3info].len = | ||
1062 | bswap_16(s3info[ns3info].len); | ||
1063 | |||
1064 | memcpy(tmpbuf, buf + S3INFO_TYPE_TXTOFFSET, | ||
1065 | S3INFO_TYPE_TXTLEN); | ||
1066 | tmpbuf[S3INFO_TYPE_TXTLEN] = '\0'; | ||
1067 | s3info[ns3info].type = | ||
1068 | simple_strtoul(tmpbuf, NULL, 16); | ||
1069 | s3info[ns3info].type = | ||
1070 | bswap_16(s3info[ns3info].type); | ||
1071 | |||
1072 | pr_debug(" S3 inforec, line=%d " | ||
1073 | "len=0x%04x type=0x%04x\n", | ||
1074 | line, | ||
1075 | s3info[ns3info].len, | ||
1076 | s3info[ns3info].type); | ||
1077 | if (((s3info[ns3info].len - 1) * sizeof(u16)) > | ||
1078 | sizeof(s3info[ns3info].info)) { | ||
1079 | printk(KERN_ERR | ||
1080 | " S3 inforec length too long - aborting\n"); | ||
1081 | return 1; | ||
1082 | } | ||
1083 | 857 | ||
1084 | tmpinfo = | 858 | pr_debug("Reading fw file ...\n"); |
1085 | (u16 *) & (s3info[ns3info].info.version); | ||
1086 | for (i = 0; i < s3info[ns3info].len - 1; i++) { | ||
1087 | memcpy(tmpbuf, | ||
1088 | buf + S3INFO_DATA_TXTOFFSET + | ||
1089 | (i * 4), 4); | ||
1090 | tmpbuf[4] = '\0'; | ||
1091 | tmpinfo[i] = | ||
1092 | simple_strtoul(tmpbuf, NULL, 16); | ||
1093 | tmpinfo[i] = bswap_16(tmpinfo[i]); | ||
1094 | } | ||
1095 | pr_debug(" info="); | ||
1096 | for (i = 0; i < s3info[ns3info].len - 1; i++) { | ||
1097 | pr_debug("%04x ", tmpinfo[i]); | ||
1098 | } | ||
1099 | pr_debug("\n"); | ||
1100 | 859 | ||
1101 | ns3info++; | 860 | while (record) { |
1102 | if (ns3info == S3INFO_MAX) { | 861 | |
1103 | printk(KERN_ERR | 862 | rcnt++; |
1104 | "S3 inforec limit reached - aborting\n"); | 863 | |
1105 | return 1; | 864 | len = be16_to_cpu(record->len); |
1106 | } | 865 | addr = be32_to_cpu(record->addr); |
1107 | break; | 866 | |
1108 | default: /* Data record */ | 867 | /* Point into data for different word lengths */ |
1109 | s3data[ns3data].addr = tmprec.addr; | 868 | ptr32 = (u32 *) record->data; |
1110 | s3data[ns3data].len = tmprec.len; | 869 | ptr16 = (u16 *) record->data; |
1111 | s3data[ns3data].checksum = tmprec.checksum; | 870 | |
1112 | s3data[ns3data].data = | 871 | /* parse what was an S3 srec and put it in the right array */ |
1113 | kmalloc(tmprec.len, GFP_KERNEL); | 872 | switch(addr) { |
1114 | for (i = 0; i < tmprec.len; i++) { | 873 | case S3ADDR_START: |
1115 | memcpy(tmpbuf, | 874 | startaddr = *ptr32; |
1116 | buf + S3DATA_TXTOFFSET + (i * 2), | 875 | pr_debug(" S7 start addr, record=%d " |
1117 | 2); | 876 | " addr=0x%08x\n", |
1118 | tmpbuf[2] = '\0'; | 877 | rcnt, |
1119 | s3data[ns3data].data[i] = | 878 | startaddr); |
1120 | simple_strtoul(tmpbuf, NULL, 16); | 879 | break; |
1121 | } | 880 | case S3ADDR_PLUG: |
1122 | ns3data++; | 881 | s3plug[ns3plug].itemcode = *ptr32; |
1123 | if (ns3data == S3DATA_MAX) { | 882 | s3plug[ns3plug].addr = *(ptr32 + 1); |
1124 | printk(KERN_ERR | 883 | s3plug[ns3plug].len = *(ptr32 + 2); |
1125 | "S3 datarec limit reached - aborting\n"); | 884 | |
1126 | return 1; | 885 | pr_debug(" S3 plugrec, record=%d " |
1127 | } | 886 | "itemcode=0x%08x addr=0x%08x len=%d\n", |
1128 | break; | 887 | rcnt, |
888 | s3plug[ns3plug].itemcode, | ||
889 | s3plug[ns3plug].addr, | ||
890 | s3plug[ns3plug].len); | ||
891 | |||
892 | ns3plug++; | ||
893 | if ( ns3plug == S3PLUG_MAX ) { | ||
894 | printk(KERN_ERR "S3 plugrec limit reached - aborting\n"); | ||
895 | return 1; | ||
1129 | } | 896 | } |
1130 | } else { | 897 | break; |
1131 | printk(KERN_WARNING | 898 | case S3ADDR_CRC: |
1132 | "%d warning: Unknown S-record detected.\n", | 899 | s3crc[ns3crc].addr = *ptr32; |
1133 | line); | 900 | s3crc[ns3crc].len = *(ptr32 + 1); |
901 | s3crc[ns3crc].dowrite = *(ptr32 + 2); | ||
902 | |||
903 | pr_debug(" S3 crcrec, record=%d " | ||
904 | "addr=0x%08x len=%d write=0x%08x\n", | ||
905 | rcnt, | ||
906 | s3crc[ns3crc].addr, | ||
907 | s3crc[ns3crc].len, | ||
908 | s3crc[ns3crc].dowrite); | ||
909 | ns3crc++; | ||
910 | if ( ns3crc == S3CRC_MAX ) { | ||
911 | printk(KERN_ERR "S3 crcrec limit reached - aborting\n"); | ||
912 | return 1; | ||
913 | } | ||
914 | break; | ||
915 | case S3ADDR_INFO: | ||
916 | s3info[ns3info].len = *ptr16; | ||
917 | s3info[ns3info].type = *(ptr16 + 1); | ||
918 | |||
919 | pr_debug(" S3 inforec, record=%d " | ||
920 | "len=0x%04x type=0x%04x\n", | ||
921 | rcnt, | ||
922 | s3info[ns3info].len, | ||
923 | s3info[ns3info].type); | ||
924 | if ( ((s3info[ns3info].len - 1) * sizeof(u16)) > sizeof(s3info[ns3info].info) ) { | ||
925 | printk(KERN_ERR " S3 inforec length too long - aborting\n"); | ||
926 | return 1; | ||
927 | } | ||
928 | |||
929 | tmpinfo = (u16*)&(s3info[ns3info].info.version); | ||
930 | pr_debug(" info="); | ||
931 | for (i = 0; i < s3info[ns3info].len - 1; i++) { | ||
932 | tmpinfo[i] = *(ptr16 + 2 + i); | ||
933 | pr_debug("%04x ", tmpinfo[i]); | ||
934 | } | ||
935 | pr_debug("\n"); | ||
936 | |||
937 | ns3info++; | ||
938 | if ( ns3info == S3INFO_MAX ) { | ||
939 | printk(KERN_ERR "S3 inforec limit reached - aborting\n"); | ||
940 | return 1; | ||
941 | } | ||
942 | break; | ||
943 | default: /* Data record */ | ||
944 | s3data[ns3data].addr = addr; | ||
945 | s3data[ns3data].len = len; | ||
946 | s3data[ns3data].data = (uint8_t *) record->data; | ||
947 | ns3data++; | ||
948 | if ( ns3data == S3DATA_MAX ) { | ||
949 | printk(KERN_ERR "S3 datarec limit reached - aborting\n"); | ||
950 | return 1; | ||
951 | } | ||
952 | break; | ||
1134 | } | 953 | } |
954 | record = ihex_next_binrec(record); | ||
1135 | } | 955 | } |
1136 | return result; | 956 | return 0; |
1137 | } | ||
1138 | |||
1139 | /*---------------------------------------------------------------- | ||
1140 | * s3datarec_compare | ||
1141 | * | ||
1142 | * Comparison function for sort(). | ||
1143 | * | ||
1144 | * Arguments: | ||
1145 | * p1 ptr to the first item | ||
1146 | * p2 ptr to the second item | ||
1147 | * Returns: | ||
1148 | * 0 items are equal | ||
1149 | * <0 p1 < p2 | ||
1150 | * >0 p1 > p2 | ||
1151 | ----------------------------------------------------------------*/ | ||
1152 | int s3datarec_compare(const void *p1, const void *p2) | ||
1153 | { | ||
1154 | const s3datarec_t *s1 = p1; | ||
1155 | const s3datarec_t *s2 = p2; | ||
1156 | if (s1->addr == s2->addr) | ||
1157 | return 0; | ||
1158 | if (s1->addr < s2->addr) | ||
1159 | return -1; | ||
1160 | return 1; | ||
1161 | } | 957 | } |
1162 | 958 | ||
1163 | /*---------------------------------------------------------------- | 959 | /*---------------------------------------------------------------- |
@@ -1316,6 +1112,7 @@ int validate_identity(void) | |||
1316 | { | 1112 | { |
1317 | int i; | 1113 | int i; |
1318 | int result = 1; | 1114 | int result = 1; |
1115 | int trump = 0; | ||
1319 | 1116 | ||
1320 | pr_debug("NIC ID: %#x v%d.%d.%d\n", | 1117 | pr_debug("NIC ID: %#x v%d.%d.%d\n", |
1321 | nicid.id, nicid.major, nicid.minor, nicid.variant); | 1118 | nicid.id, nicid.major, nicid.minor, nicid.variant); |
@@ -1389,8 +1186,7 @@ int validate_identity(void) | |||
1389 | (nicid.id != 0x8008)) | 1186 | (nicid.id != 0x8008)) |
1390 | continue; | 1187 | continue; |
1391 | 1188 | ||
1392 | if (result != 2) | 1189 | trump = 1; |
1393 | result = 0; | ||
1394 | break; | 1190 | break; |
1395 | case 0x8001: | 1191 | case 0x8001: |
1396 | pr_debug("name inforec len %d\n", s3info[i].len); | 1192 | pr_debug("name inforec len %d\n", s3info[i].len); |
@@ -1402,5 +1198,6 @@ int validate_identity(void) | |||
1402 | } | 1198 | } |
1403 | // walk through | 1199 | // walk through |
1404 | 1200 | ||
1201 | if (trump && (result != 2)) result = 0; | ||
1405 | return result; | 1202 | return result; |
1406 | } | 1203 | } |