#include <stdint.h>
#include <scsi/sg.h>
#include <unistd.h>
#include <endian.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <err.h>
#include <stdio.h>
#include <string.h>
#define JQ6500_CM
struct jqcmd {
uint16_t j_cmd;
uint32_t j_off;
uint32_t j_foo;
uint32_t j_len;
uint16_t j_bar;
} __attribute__((packed));
#define BASE 0x40000
#define MAXSIZE 0x200000 - BASE /* 2MB - 256kB */
off_t
filesize(char *file)
{
int result;
struct stat buf;
result = stat(file, &buf);
if (result != 0)
err(1, "cannot stat %s", file);
return buf.st_size;
}
void
w32le(uint8_t **loc, uint32_t val)
{
memcpy(*loc, &htole32(val), 4);
(*loc) += 4;
}
int
main(int argc, char **argv)
{
uint8_t buf[MAXSIZE];
uint8_t *dir, *data;
int count, size, dev;
int i, len;
if (argc < 3) {
fprintf(stderr, "%s device mp3file ...\n", argv[0]);
return 1;
}
setbuf(stderr, NULL);
memset(buf, 0xff, MAXSIZE);
count = argc-2;
dir = buf;
size = (3 + 2 * count) * 4;
data = dir + size;
w32le(&dir, 1); /* Number of Subdirs */
w32le(&dir, BASE + 8); /* Offset of first subdir */
w32le(&dir, count); /* Number of files in subdir 1 */
for (i = 0; i < count; i++) {
int fd;
char *fname = argv[i+2];
len = filesize(fname);
size += len;
if (size >= MAXSIZE) {
fprintf(stderr, "length %d exceeds maximum of %d", size, MAXSIZE);
return 1;
}
fd = open(fname, O_RDONLY);
if (fd < 0)
err(1, "cannot open %s", fname);
if (read(fd, data, len) != len)
err(1, "cannot read %s", fname);
close(fd);
w32le(&dir, BASE + data - buf); /* File offset */
w32le(&dir, len); /* File length */
data += len;
}
#define ERASE 0xfbd8
#define WRITE 0xfbd9
#define BLKSZ 0x1000
#define TIMEOUT 30000
dev = open(argv[1], O_RDWR);
if (dev < 0)
err(1, "cannot open device %s", argv[1]);
for (i = 0; i < size; i += BLKSZ) {
struct jqcmd cmd;
struct sg_io_hdr hdr;
fprintf(stderr, "%06x / %06x\n", BASE + i, BASE + size);
memset(&cmd, 0, sizeof(cmd));
cmd.j_cmd = htobe16(ERASE);
cmd.j_off = htobe32(BASE + i);
//cmd.j_len = htobe32(BLKSZ);
memset(&hdr, 0, sizeof(hdr));
hdr.interface_id = 'S';
hdr.timeout = TIMEOUT;
hdr.cmdp = (unsigned char *) &cmd;
hdr.cmd_len = sizeof(cmd);
hdr.dxfer_direction = SG_DXFER_NONE;
if (ioctl(dev, SG_IO, &hdr) < 0)
err(1, "erase failed at offset %x", BASE + i);
memset(&cmd, 0, sizeof(cmd));
cmd.j_cmd = htobe16(WRITE);
cmd.j_off = htobe32(BASE + i);
cmd.j_len = htobe32(BLKSZ);
memset(&hdr, 0, sizeof(hdr));
hdr.interface_id = 'S';
hdr.timeout = TIMEOUT;
hdr.cmdp = (unsigned char *) &cmd;
hdr.cmd_len = sizeof(cmd);
hdr.dxfer_direction = SG_DXFER_TO_DEV;
hdr.dxferp = buf + i;
hdr.dxfer_len = BLKSZ;
if (ioctl(dev, SG_IO, &hdr) < 0)
err(1, "write failed at offset %x", BASE + i);
}
close(dev);
return 0;
}