1 /*-
2  * Copyright (c) 2003
3  *	John Wehle <john@feith.com>.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *	This product includes software developed by John Wehle.
16  * 4. The name of the author may not be used to endorse or promote products
17  *    derived from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  * DISCLAIMED.	IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
23  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  *
31  * Conexant MPEG-2 Codec firmware extraction program.
32  *
33  * Generates:
34  *
35  * - cxm_dec_fw.c and cxm_enc_fw.c from the
36  * Hauppauge PVR-250 / PVR-350 Microsoft Windows driver
37  * (i.e. hcwpvrp2.sys).
38  *
39  * - cxm_cx2584x_fw.c from the Hauppauge PVR-150 / PVR-500
40  * Microsoft Windows driver (i.e. HcwMakoC.ROM). (optional)
41  *
42  * This was written using the invaluable information
43  * compiled by The IvyTV Project (ivtv.sourceforge.net).
44  */
45 
46 #include <sys/types.h>
47 #include <sys/mman.h>
48 #include <sys/param.h>
49 #include <sys/stat.h>
50 
51 #include <err.h>
52 #include <fcntl.h>
53 #include <stdio.h>
54 #include <stdlib.h>
55 #include <string.h>
56 #include <unistd.h>
57 
58 const uint8_t decoder_magic[] = {
59 	0xa7, 0x03, 0x00, 0x00, 0x66, 0xbb, 0x55, 0xaa
60 };
61 const uint8_t encoder_magic[] = {
62 	0xa7, 0x0d, 0x00, 0x00, 0x66, 0xbb, 0x55, 0xaa
63 };
64 
65 static int
66 save_firmware(const char *name, const uint8_t *buf, size_t nbytes)
67 {
68 	FILE *ofp;
69 	char outfile[MAXPATHLEN];
70 	size_t i;
71 
72 	if (nbytes > (256 * 1024))
73 		nbytes = 256 * 1024;
74 
75 	if ((size_t)snprintf(outfile, sizeof(outfile), "%s.c", name) >=
76 	    sizeof(outfile))
77 		errx(1, "save_firmware -- firmware name is too long");
78 
79 	if (!(ofp = fopen(outfile, "w")))
80 		err(1, "save_firmware -- can't open output file <%s>",
81 		    outfile);
82 
83 	fprintf(ofp, "#include <sys/types.h>\n"
84 	    "\n"
85 	    "const uint8_t %s[] __attribute__ ((aligned(4))) = {",
86 	    name);
87 
88 	for (i = 0; i < nbytes; i++) {
89 		if (i)
90 			fputc(',', ofp);
91 		if ((i % 8) == 0)
92 			fputs("\n\t", ofp);
93 		else
94 			fputc(' ', ofp);
95 		fprintf(ofp, "0x%.2x", buf[i]);
96 	}
97 
98 	fprintf(ofp, "\n};\n");
99 
100 	if (ferror(ofp)) {
101 		fclose(ofp);
102 		return -1;
103 	}
104 
105 	fclose(ofp);
106 	return 0;
107 }
108 
109 
110 int
111 main(int argc, char **argv)
112 {
113 	uint8_t *end;
114 	uint8_t *ptr;
115 	uint8_t *start;
116 	int decoder_fw_saved = 0;
117 	int encoder_fw_saved = 0;
118 	int fd, i;
119 	struct stat statbuf;
120 
121 	if (argc != 2) {
122 		fprintf(stderr, "usage: cxm_extract_fw file\n");
123 		exit(1);
124 	}
125 
126 	for (i = 1; i <= (argc - 1); i++) {
127 		/*
128 		 * Open the file.
129 		 */
130 		if ((fd = open(argv[i], O_RDONLY)) < 0)
131 			err(1, "can't open %s for reading", argv[i]);
132 
133 		/*
134 		 * Determine how big it is.
135 		 */
136 		if (fstat(fd, &statbuf) < 0) {
137 			close(fd);
138 			err(1, "can't fstat %s", argv[i]);
139 		}
140 
141 		/*
142 		 * Map it into memory.
143 		 */
144 		if (!(start = (uint8_t *)mmap(NULL, (size_t) statbuf.st_size,
145 			    PROT_READ, MAP_SHARED, fd, (off_t) 0))) {
146 			close(fd);
147 			err(1, "can't mmap %s", argv[i]);
148 		}
149 		end = start + statbuf.st_size;
150 
151 		close(fd);
152 
153 		if (statbuf.st_size > 100000) {
154 			for (ptr = start; ptr != end; ptr++) {
155 				if ((size_t)(end - ptr) >= sizeof(decoder_magic) &&
156 				    memcmp(ptr, decoder_magic, sizeof(decoder_magic)) == 0) {
157 					if (!decoder_fw_saved) {
158 						if (save_firmware("cxm_dec_fw", ptr, end - ptr) < 0)
159 							errx(1, "save_firmware failed");
160 						decoder_fw_saved = 1;
161 					} else {
162 						errx(1, "multiple decoder images present");
163 					}
164 				}
165 				if ((size_t)(end - ptr) >= sizeof(encoder_magic) &&
166 				    memcmp(ptr, encoder_magic, sizeof(encoder_magic)) == 0) {
167 					if (!encoder_fw_saved) {
168 						if (save_firmware("cxm_enc_fw", ptr, end - ptr) < 0)
169 							errx(1, "save_firmware failed");
170 						encoder_fw_saved = 1;
171 					} else {
172 						errx(1, "multiple encoder images present");
173 					}
174 				}
175 			}
176 		} else {
177 			errx(1, "save_firmware failed");
178 		}
179 
180 		munmap((caddr_t)start, (size_t)statbuf.st_size);
181 
182 		if (!decoder_fw_saved)
183 			errx(1, "decoder image not present");
184 
185 		if (!encoder_fw_saved)
186 			errx(1, "encoder image not present");
187 
188 		if (!decoder_fw_saved || !encoder_fw_saved)
189 			exit(1);
190 	}
191 
192 	exit(0);
193 }
194