update rccd2 for end-system integraton
[tas2555sw-android/tas2555-util-stereo.git] / rccd2 / android_utils.c
1 #include <sys/types.h>\r
2 #include <sys/stat.h>\r
3 #include <sys/ioctl.h>\r
4 #include <linux/kdev_t.h>\r
5 #include <unistd.h>\r
6 #include <fcntl.h>\r
7 #include <time.h>\r
8 #include <errno.h>\r
9 #include "utils.h"\r
10 #include <stdlib.h>\r
11 #include <stdarg.h>\r
12 #include <stdio.h>\r
13 \r
14 #include "aic3xxx_cfw.h"\r
15 #include "utils.h"\r
16 #include "host_compile.h"\r
17 #include "android_utils.h"\r
18 \r
19 int dump_cmds = 0;\r
20 int mode = mode_undef;\r
21 \r
22 static int dev_fd, dev_no, modern;\r
23 \r
24 #define DEVICE_ID 98\r
25 \r
26 int regDumpId;\r
27 char regBuffer[512];\r
28 \r
29 //static char *device;\r
30 void diag(int lvl, char *fmt, ...)\r
31 {\r
32         va_list ap;\r
33         va_start(ap, fmt);\r
34 #ifdef ANDROID\r
35         __android_log_vprint(lvl, PROGRAM, fmt, ap);\r
36 #endif\r
37         va_end(ap);\r
38         if (getppid() != 1 && (lvl >= (ANDROID_LOG_ERROR - verbose))) {\r
39                 va_start(ap, fmt);\r
40                 vfprintf(stderr, fmt, ap);\r
41                 va_end(ap);\r
42                 fprintf(stderr, "\n");\r
43         }\r
44         if (lvl >= ANDROID_LOG_FATAL)\r
45                 exit(1);\r
46 }\r
47 \r
48 const struct { char *node; int cfwb; } devices[] = {\r
49         { "aic3xxx_cfw", 1 },\r
50         { "tiload", 0 },\r
51         { "tiload_node", 0 }\r
52 };\r
53 int open_device(char *device)\r
54 {\r
55         char dfile[64];\r
56         struct stat sbuf;\r
57         int i = 0, fd;\r
58         if (device)  {\r
59                 // Possible use on host\r
60                 DBGW("Device not null");\r
61                 if (stat(device, &sbuf) == 0) {\r
62                         strncpy(dfile, device, sizeof(dfile)-1);\r
63                         goto open;\r
64                 }\r
65                 DBGW("Could not locate device \"%s\"", device);\r
66                 // Switch exclusive to old style device if one is specified (rccd backwards-compatibilty)\r
67                 while (devices[i].cfwb)\r
68                         ++i;\r
69         }\r
70         for (; i < ARRAY_LEN(devices); ++i) {\r
71                 sprintf(dfile, "/dev/%s", devices[i].node);\r
72                 if (stat(dfile, &sbuf) == 0)\r
73                         goto open;\r
74                 DBGW("Missing device node \"%s\"\n\tLooking for %s in /proc/devices...", dfile, devices[i].node);\r
75                 FILE *fp = fopen("/proc/devices", "r");\r
76                 if (!fp)\r
77                         DBGF("Unable to read /proc/devices");\r
78                 char ln[4096];\r
79                 while (fgets(ln, sizeof(ln), fp)) {\r
80                         if (!strstr(ln, devices[i].node))\r
81                                 continue;\r
82                         ln[strlen(ln) - 1] = 0;\r
83                         DBGW("Found node entry \"%s\"", ln);\r
84                         int major = strtol(ln, NULL, 10);\r
85                         DBGW("\tMajor number = %d", major);\r
86                         if (mknod(dfile, S_IFCHR | 0777, MKDEV(major, 0)) < 0)\r
87                                 DBGF("Unable to\n\tmknod \"%s\" c %d 0", dfile, major);\r
88                         goto open;\r
89                 }\r
90         }\r
91         //This was DBGF  \r
92         DBGW("Unable find entry for codec diagnostic device.  Please check\n"\r
93                 "\tcat /proc/devices");\r
94 \r
95 \r
96         // CUstom code \r
97         //dfile = "/sdcard/RCCD2/Test.dev";\r
98         sprintf(dfile, "/sdcard/RCCD2/Test.dev");\r
99         i = 4;\r
100         DBGW("Device open is redirected to a file now - /sdcard/RCCD2/Test.dev");\r
101         goto open;\r
102 \r
103 \r
104         return -1;\r
105 open:\r
106         if ((fd = open(dfile, O_RDWR, 0)) < 0)\r
107                 DBGF("Unable to open device %s", dfile);\r
108         modern = devices[i].cfwb;\r
109         if (!modern) {\r
110                 // This stuff below is needed on the old tiload device \r
111                 // for purposes I don't fully understand\r
112                 char magic[4];\r
113                 ioctl(fd, _IOR(0xE0, 3, int), magic);\r
114         }\r
115         dev_fd = fd;\r
116         dev_no = i;\r
117         if (mode == mode_undef)\r
118                 mode = devices[i].cfwb ? mode_kernel : mode_user;\r
119         DBG("Opened device %s, mode:%s", dfile, modern ? "modern" : "legacy");\r
120         return fd;\r
121 }\r
122 \r
123 static int cbook = -1, cpage = -1, lock = 0;\r
124 \r
125 \r
126 static void  mread_reg(union cfw_register reg, u8 *buf, int n)\r
127 {\r
128         int ncmds = CFW_CMD_BURST_LEN(n);\r
129         int err, sz = CFW_BLOCK_SIZE(ncmds);\r
130         struct cfw_block *blk = ALLOC(sz);\r
131         blk->ncmds = ncmds;\r
132         blk->cmd[0].bhdr.cid = CFW_CMD_RBURST;\r
133         blk->cmd[0].bhdr.len = n;\r
134         blk->cmd[1].reg = reg;\r
135         if ((err = read(dev_fd, blk, sz)) != sz)\r
136                 DBGF("Device read error %d", err);\r
137         memcpy(buf, blk->cmd[1].burst.data, n);\r
138 }\r
139 \r
140 static void  mwrite_reg(union cfw_register reg, const u8 *buf, int n)\r
141 {\r
142         int ncmds = (n <= 3) ? n : CFW_CMD_BURST_LEN(n);\r
143         int i, err, sz = CFW_BLOCK_SIZE(ncmds);\r
144         struct cfw_block *blk = ALLOC(sz);\r
145         blk->ncmds = ncmds;\r
146         if (n <= 3) {\r
147                 for (i = 0; i < n; ++i) {\r
148                         blk->cmd[i].reg = reg;\r
149                         blk->cmd[i].reg.offset = reg.offset + i;\r
150                         blk->cmd[i].reg.data = buf[i + 1];\r
151                 }\r
152         }\r
153         else {\r
154                 blk->cmd[0].bhdr.cid = CFW_CMD_BURST;\r
155                 blk->cmd[0].bhdr.len = n;\r
156                 blk->cmd[1].reg = reg;\r
157                 memcpy(blk->cmd[1].burst.data, buf + 1, n);\r
158         }\r
159         if ((err = write(dev_fd, blk, sz)) != sz)\r
160                 DBGF("Device write error %d", err);\r
161 }\r
162 \r
163 \r
164 #define DREAD(reg, b, n) do { \\r
165         int err_ret__;                  \\r
166         DBGI("r 0x%02x 0x%02x, modern:%d", (b)[0], (n), modern); \\r
167         sprintf(regBuffer, "\nr %d %02x %02x%c", DEVICE_ID, (b)[0], (n),'\0'); \\r
168         write(regDumpId, &regBuffer, strlen(regBuffer)); \\r
169 if (modern) {\\r
170         mread_reg(reg, (b), n); \\r
171 }else if ((err_ret__ = read(dev_fd, b, n)) != n) \\r
172         DBGF("Device read error %d", err_ret__); \\r
173 } while (0)\r
174 #define DWRITE(reg, b, n) do { \\r
175         int err_ret__, i__;                  \\r
176         DBGI("w 0x%02x 0x%02x", (b)[0], (b)[1]); \\r
177         sprintf(regBuffer, "\nw %d %02x %02x%c", DEVICE_ID, (b)[0], (b)[1], '\0'); \\r
178         write(regDumpId, &regBuffer, strlen(regBuffer)); \\r
179 for (i__ = 2; i__ < n; ++i__) \\r
180 {DBGI("> 0x%02x", (b)[i__]); \\r
181         sprintf(regBuffer, " %02x%c", (b)[i__],'\0'); \\r
182         write(regDumpId, &regBuffer, strlen(regBuffer)); }\\r
183 if (modern) {\\r
184         mwrite_reg(reg, b, n); \\r
185 }else if ((err_ret__ = write(dev_fd, b, n)) != n) \\r
186         DBGF("Device write error %d", err_ret__); \\r
187 } while (0)\r
188 \r
189 static void cfw_lock(int l)\r
190 {\r
191         if (l && !lock) {\r
192                 // FIXME dummy\r
193                 lock = 1;\r
194         }\r
195         else if (!l && lock) {\r
196                 lock = 0;\r
197         }\r
198 }\r
199 static int restore_lock;\r
200 static void setpb(union cfw_register r)\r
201 {\r
202         DBG("Enter setpb");\r
203         u8 data[2];\r
204         restore_lock = lock;\r
205         cfw_lock(1);\r
206         DBG("Set Page/Book: (0x%02x,0x%02x)", r.book, r.page);\r
207         // if (cbook != r.book) {\r
208         if (1){\r
209                 //if (cpage != 0) {  \r
210                 if (1){\r
211                         data[0] = data[1] = 0;\r
212                         if (!modern)\r
213                                 DWRITE(r, data, 2);\r
214                         cpage = 0;\r
215                 }\r
216                 data[0] = 0x7F; data[1] = r.book;\r
217                 if (!modern)\r
218                         DWRITE(r, data, 2);\r
219                 cbook = r.book;\r
220                 DBG("Set Book: [0x%02x]", r.book);\r
221         }\r
222 \r
223         //if (cpage != r.page) {\r
224         if (1){ \r
225                 data[0] = 0; data[1] = r.page;\r
226                 if (!modern)\r
227                         DWRITE(r, data, 2);\r
228                 cpage = r.page;\r
229                 DBG("Set Page: [0x%02x]", r.page);\r
230         }\r
231         DBG("Exit setpb");\r
232 }\r
233 static void unsetpb(void)\r
234 {\r
235         DBG("Enter unsetpb");\r
236         cfw_lock(restore_lock);\r
237         DBG("Exit unsetpb");\r
238 }\r
239 \r
240 static u8 reg_read(union cfw_register reg)\r
241 {\r
242         u8 ret;\r
243         ret = reg.offset;\r
244         setpb(reg);\r
245         mread_reg(reg, &ret, 1);\r
246 \r
247         DREAD(reg, &ret, 1);\r
248         unsetpb();\r
249         return ret;\r
250 }\r
251 static void reg_write(union cfw_register reg)\r
252 {\r
253         u8 data[2];\r
254         data[0] = reg.offset;\r
255         data[1] = reg.data;\r
256         setpb(reg);\r
257         DWRITE(reg, data, 2);\r
258         unsetpb();\r
259 }\r
260 static void reg_wait(union cfw_register reg, u8 mask, u8 data)\r
261 {\r
262         u8 cur = reg_read(reg);\r
263         while ((cur & mask) != data) {\r
264                 usleep(2000);\r
265                 cur = reg_read(reg);\r
266         }\r
267 }\r
268 static int set_bits(u8 *data, u8 mask, u8 val)\r
269 {\r
270         u8 nd;\r
271         nd = ((*data&(~mask)) | (mask&val));\r
272         if (nd == *data)\r
273                 return 0;\r
274         *data = nd;\r
275         return 1;\r
276 }\r
277 static void cfw_op(unsigned char *var, struct cfw_cmd_op cmd)\r
278 {\r
279         u32 op1, op2;\r
280         u32 cid = cmd.cid;\r
281 \r
282         op1 = cmd.op1;\r
283         op2 = cmd.op2;\r
284         if (cid&CFW_CMD_OP1_ID)\r
285                 op1 = var[op1];\r
286         if (cid&CFW_CMD_OP2_ID)\r
287                 op2 = var[op2];\r
288         cid &= ~(CFW_CMD_OP1_ID | CFW_CMD_OP2_ID);\r
289 \r
290         switch (cid) {\r
291         case CFW_CMD_OP_ADD: var[cmd.dst] = op1 + op2; break;\r
292         case CFW_CMD_OP_SUB: var[cmd.dst] = op1 - op2; break;\r
293         case CFW_CMD_OP_MUL: var[cmd.dst] = op1*op2; break;\r
294         case CFW_CMD_OP_DIV: var[cmd.dst] = op1 / op2; break;\r
295         case CFW_CMD_OP_AND: var[cmd.dst] = op1 & op2; break;\r
296         case CFW_CMD_OP_OR: var[cmd.dst] = op1 | op2; break;\r
297         case CFW_CMD_OP_SHL: var[cmd.dst] = (op1 << op2); break;\r
298         case CFW_CMD_OP_SHR: var[cmd.dst] = (op1 >> op2); break;\r
299         case CFW_CMD_OP_RR:\r
300                 while (op2--) {\r
301                         var[cmd.dst] = (op1 >> 1) | ((op1 & 1) << 7);\r
302                 }\r
303                 break;\r
304         case CFW_CMD_OP_XOR: var[cmd.dst] = op1 ^ op2; break;\r
305         case CFW_CMD_OP_NOT: var[cmd.dst] = ~op1; break;\r
306         case CFW_CMD_OP_LNOT: var[cmd.dst] = !op1; break;\r
307         default: break;\r
308         }\r
309 }\r
310 \r
311 static int bulk_write(union cfw_register reg, int count, const u8 *buf)\r
312 {\r
313         setpb(reg);\r
314         DWRITE(reg, buf - 1, count + 1);\r
315         unsetpb();\r
316         return 0;\r
317 }\r
318 \r
319 static int bulk_read(union cfw_register reg, int count, u8 *buf)\r
320 {\r
321         int i;\r
322         if (reg.offset != buf[-1]) {\r
323                 DBGW("Mismatched register offset for read (%d != %d)",\r
324                         reg.offset, buf[-1]);\r
325         }\r
326         buf[0] = reg.offset;\r
327 \r
328         if (reg.offset == 0xFF && reg.book == 0xFF && reg.page == 0xFF)\r
329         {\r
330                 /* To handle Ping*/\r
331                 buf[0] = 0x7c;\r
332                 buf[1] = 00;\r
333                 buf[2] = 01;\r
334                 buf[3] = 02;\r
335 \r
336                 DBGI("..........PING.......");\r
337 \r
338         }\r
339         else\r
340         {\r
341 \r
342                 setpb(reg);\r
343                 //DBG("Commenting of DRED");\r
344                 DREAD(reg, buf, count);\r
345                 unsetpb();\r
346         }\r
347         DBGI("Reading from (%d,%d,%d)... %d bytes", reg.book, reg.page, reg.offset,\r
348                 count);\r
349         for (i = 0; i < count; i += 8) {\r
350                 switch (count - i) {\r
351                 case 1: DBGI("# 0x%02x", buf[i + 0]); break;\r
352                 case 2: DBGI("# 0x%02x 0x%02x", buf[i + 0], buf[i + 1]); break;\r
353                 case 3: DBGI("# 0x%02x 0x%02x 0x%02x", buf[i + 0], buf[i + 1], buf[i + 2]); break;\r
354                 case 4: DBGI("# 0x%02x 0x%02x 0x%02x 0x%02x", buf[i + 0], buf[i + 1], buf[i + 2], buf[i + 3]); break;\r
355                 case 5: DBGI("# 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x", buf[i + 0], buf[i + 1], buf[i + 2], buf[i + 3], buf[i + 4]); break;\r
356                 case 6: DBGI("# 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x", buf[i + 0], buf[i + 1], buf[i + 2], buf[i + 3], buf[i + 4], buf[i + 5]); break;\r
357                 case 7: DBGI("# 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x", buf[i + 0], buf[i + 1], buf[i + 2], buf[i + 3], buf[i + 4], buf[i + 5], buf[i + 6]); break;\r
358                 default:DBGI("# 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x", buf[i + 0], buf[i + 1], buf[i + 2], buf[i + 3], buf[i + 4], buf[i + 5], buf[i + 6], buf[i + 7]); break;\r
359                 }\r
360         }\r
361 \r
362 \r
363         return 0;\r
364 }\r
365 \r
366 static void run_block_slow(struct cfw_block *pb, u8 *var)\r
367 {\r
368         int pc = 0;\r
369         int cond = 0;\r
370         u8 data;\r
371 //      int i;\r
372         \r
373         DBG("%s: pb->ncmds=%d", __FUNCTION__, pb->ncmds);\r
374         while (pc < pb->ncmds) {\r
375                 union cfw_cmd *c = &(pb->cmd[pc]);\r
376                 if (c->cid != CFW_CMD_BRANCH_IM &&\r
377                         c->cid != CFW_CMD_BRANCH_ID &&\r
378                         c->cid != CFW_CMD_NOP)\r
379                         cond = 0;\r
380                 DBGI("%s: Case No %d:", __FUNCTION__, c->cid);\r
381                 switch (c->cid) {\r
382 \r
383                 case 0 ... (CFW_CMD_NOP - 1) :\r
384                         DBGI("CFW_CMD_NOP-1");\r
385                         reg_write(c->reg);\r
386                         pc += 1;\r
387                         break;\r
388                 case CFW_CMD_NOP:\r
389                         DBGI("CFW_CMD_NOP");\r
390                         pc += 1;\r
391                         break;\r
392                 case CFW_CMD_DELAY:\r
393                         DBGI("CFW_CMD_DELAY");\r
394                         usleep(c->delay.delay * 1000 + c->delay.delay_fine * 4);\r
395                         pc += 1;\r
396                         break;\r
397                 case CFW_CMD_UPDTBITS:\r
398                         DBGI("CFW_CMD_UPDTBITS");\r
399                         c[1].reg.data = reg_read(c[1].reg);\r
400                         set_bits(&data, c->bitop.mask, c[1].reg.data);\r
401                         reg_write(c[1].reg);\r
402                         pc += 2;\r
403                         break;\r
404                 case CFW_CMD_WAITBITS:\r
405                         DBGI("CFW_CMD_WAITBITS");\r
406                         reg_wait(c[1].reg, c->bitop.mask, c[1].reg.data);\r
407                         pc += 2;\r
408                         break;\r
409                 case CFW_CMD_LOCK:\r
410                         DBGI("CFW_CMD_LOCK");\r
411                         cfw_lock(c->lock.lock);\r
412                         pc += 1;\r
413                         break;\r
414                 case CFW_CMD_BURST:\r
415                         DBGI("CFW_CMD_BURST");\r
416                         bulk_write(c[1].reg, c->bhdr.len,\r
417                                 c[1].burst.data);\r
418                         pc += CFW_CMD_BURST_LEN(c->bhdr.len);\r
419                         break;\r
420                 case CFW_CMD_RBURST:\r
421                         DBGI("CFW_CMD_RBURST");\r
422                         bulk_read(c[1].reg, c->bhdr.len,\r
423                                 c[1].burst.data);\r
424                         pc += CFW_CMD_BURST_LEN(c->bhdr.len);\r
425                         break;\r
426                 case CFW_CMD_LOAD_VAR_IM:\r
427                         set_bits(&var[c->ldst.dvar],\r
428                                 c->ldst.mask, c->ldst.svar);\r
429                         pc += 1;\r
430                         break;\r
431                 case CFW_CMD_LOAD_VAR_ID:\r
432                         if (c->ldst.svar != c->ldst.dvar) {\r
433                                 set_bits(&var[c->ldst.dvar],\r
434                                         c->ldst.mask, var[c->ldst.svar]);\r
435                                 pc += 1;\r
436                         }\r
437                         else {\r
438                                 data = reg_read(c[1].reg);\r
439                                 set_bits(&var[c->ldst.dvar],\r
440                                         c->ldst.mask, data);\r
441                                 pc += 2;\r
442                         }\r
443                         break;\r
444                 case CFW_CMD_STORE_VAR:\r
445                         if (c->ldst.svar != c->ldst.dvar) {\r
446                                 c[1].reg.data = reg_read(c[1].reg);\r
447                                 set_bits(&(c[1].reg.data),\r
448                                         var[c->ldst.dvar],\r
449                                         var[c->ldst.svar]);\r
450                                 reg_write(c[1].reg);\r
451                         }\r
452                         else {\r
453                                 c[1].reg.data = reg_read(c[1].reg);\r
454                                 set_bits(&data, c->ldst.mask,\r
455                                         var[c->ldst.svar]);\r
456                                 reg_write(c[1].reg);\r
457                         }\r
458                         pc += 2;\r
459                         break;\r
460                 case CFW_CMD_COND:\r
461                         cond = var[c->cond.svar] & c->cond.mask;\r
462                         pc += 1;\r
463                         break;\r
464                 case CFW_CMD_BRANCH:\r
465                         pc = c->branch.address;\r
466                         break;\r
467                 case CFW_CMD_BRANCH_IM:\r
468                         if (c->branch.match == cond)\r
469                                 pc = c->branch.address;\r
470                         else\r
471                                 pc += 1;\r
472                         break;\r
473                 case CFW_CMD_BRANCH_ID:\r
474                         if (var[c->branch.match] == cond)\r
475                                 pc = c->branch.address;\r
476                         else\r
477                                 pc += 1;\r
478                         break;\r
479                 case CFW_CMD_PRINT:\r
480                 {\r
481                                                           union cfw_cmd *parglist = c + CFW_CMD_PRINT_ARG(c->print);\r
482 #ifdef ANDROID\r
483                                                           DBGI(c->print.fmt,\r
484                                                                   var[parglist->print_arg[0]],\r
485                                                                   var[parglist->print_arg[1]],\r
486                                                                   var[parglist->print_arg[2]],\r
487                                                                   var[parglist->print_arg[3]]);\r
488 #else\r
489                                                           printf(c->print.fmt,\r
490                                                                   var[parglist->print_arg[0]],\r
491                                                                   var[parglist->print_arg[1]],\r
492                                                                   var[parglist->print_arg[2]],\r
493                                                                   var[parglist->print_arg[3]]);\r
494 #endif\r
495                                                           pc += CFW_CMD_PRINT_LEN(c->print);\r
496                 }\r
497                         break;\r
498                 case CFW_CMD_OP_START ... CFW_CMD_OP_END:\r
499                         cfw_op(var, c->op);\r
500                         pc += 1;\r
501                         break;\r
502                 default:\r
503                         DBGW("Unknown cmd command %x. Skipped", c->cid);\r
504                         pc += 1;\r
505                         break;\r
506                 }\r
507         }\r
508 \r
509 }\r
510 \r
511 void run_block(struct cfw_block *pb, u8 *var)\r
512 {\r
513         char *filePath = "/sdcard/RCCD2/regDump.txt";\r
514         if (!modern || (mode != mode_kernel)) {\r
515                 DBGI("Calling run block slow");\r
516                 regDumpId = open(filePath, O_RDWR | O_APPEND | O_CREAT, 0644);\r
517                 run_block_slow(pb, var);\r
518                 close(regDumpId);\r
519                 return;\r
520         }\r
521         int r, n = CFW_BLOCK_SIZE(pb->ncmds);\r
522         DBGI("Calling write, ncmds %d, len %d, %x, size of union cfw_cmd %d ", n, CFW_BLOCK_SIZE(pb->ncmds - 1), pb->cmd[0].reg.data, sizeof(union cfw_cmd));\r
523         if ((r = write(dev_fd, pb, n)) != n)\r
524                 DBGF("Device write error %d", r);\r
525 \r
526 }\r