2 * Copyright (c) 2011, GraÅžvydas Ignotas
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the organization nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40 * BASE+1 ~ status: BAOSEI??
41 * /BUSY, ACK, PE, SLCT, ERROR, IRQ
42 * BASE+2 ~ control: ??MISIAS
43 * bidirrectMODE, IRQ_EN, /SLCT_IN, INIT, /AUTO_FD_XT, /STROBE
47 * TH, TR, TL, D3, D2, D1, D0
55 * 6 TL <-- 14 /AUTO_FD_XT
58 * 9 TR <-- 17 /SLCT_IN
60 * start: TH low/high, TL high
62 * TH low - lower nibble: MD ready to recv | MD sent to PC
63 * TL low - lower niblle: sent to MD | ready to recv from MD
64 * TH high - upper nibble: MD ready to recv | MD sent to PC
65 * TL high - upper nibble: sent | ready to recv from MD
68 #define ACK_TIMEOUT 2000000
71 #define PORT_STATUS 889
72 #define PORT_CONTROL 890
74 #define timediff(now, start) \
75 ((now.tv_sec - start.tv_sec) * 1000000 + now.tv_usec - start.tv_usec)
77 static void do_exit(const char *msg)
79 /* switch TL back to high */
80 outb(0xe0, PORT_CONTROL);
87 static void inthandler(int u)
92 static void wait_th_low(void)
94 struct timeval start, now;
96 gettimeofday(&start, NULL);
98 while (inb(PORT_STATUS) & 0x40) {
99 gettimeofday(&now, NULL);
100 if (timediff(now, start) > ACK_TIMEOUT)
101 do_exit("timeout waiting TH low\n");
105 static void wait_th_high(void)
107 struct timeval start, now;
109 gettimeofday(&start, NULL);
111 while (!(inb(PORT_STATUS) & 0x40)) {
112 gettimeofday(&now, NULL);
113 if (timediff(now, start) > ACK_TIMEOUT)
114 do_exit("timeout waiting TH high\n");
118 static unsigned int recv_byte(void)
122 outb(0xe2, PORT_CONTROL); /* TL low */
126 byte = inb(PORT_DATA) & 0x0f;
128 outb(0xe0, PORT_CONTROL); /* TL high */
132 byte |= inb(PORT_DATA) << 4;
137 static void send_byte(unsigned int byte)
141 outb(byte & 0x0f, PORT_DATA);
142 outb(0xc2, PORT_CONTROL); /* TL low */
146 outb((byte >> 4) & 0x0f, PORT_DATA);
147 outb(0xc0, PORT_CONTROL); /* TL high */
150 static void send_cmd(unsigned int cmd)
152 send_byte(CMD_PREFIX);
156 static void usage(const char *argv0)
158 fprintf(stderr, "usage:\n%s <cmd> [args]\n"
159 "\tsend <file> <addr> [size]\n"
160 "\trecv <file> <addr> <size>\n", argv0);
164 static unsigned int atoi_or_die(const char *a)
169 i = strtoul(a, &p, 0);
170 if (p == NULL || *p != 0) {
171 fprintf(stderr, "atoi: can't convert: %s\n", a);
178 int main(int argc, char *argv[])
180 unsigned int addr = 0, size = 0, i = 0;
188 data = malloc(0x1000000);
190 fprintf(stderr, "can't alloc %d bytes\n", 0x1000000);
194 /* parse args, read files.. */
195 if (strcmp(argv[1], "send") == 0)
197 if (argc != 4 && argc != 5)
200 file = fopen(argv[2], "rb");
202 fprintf(stderr, "can't open file: %s\n", argv[2]);
206 addr = atoi_or_die(argv[3]);
207 if (argv[4] == NULL) {
208 fseek(file, 0, SEEK_END);
210 fseek(file, 0, SEEK_SET);
213 size = atoi_or_die(argv[4]);
215 ret = fread(data, 1, size, file);
217 fprintf(stderr, "fread returned %d/%d\n", ret, size);
222 else if (strcmp(argv[1], "recv") == 0)
227 file = fopen(argv[2], "wb");
229 fprintf(stderr, "can't open file: %s\n", argv[2]);
233 addr = atoi_or_die(argv[3]);
234 size = atoi_or_die(argv[4]);
236 memset(data, 0, size);
241 ret = ioperm(PORT_DATA, 3, 1);
247 signal(SIGINT, inthandler);
249 printf("regs: %02x %02x %02x\n",
250 inb(PORT_DATA), inb(PORT_STATUS), inb(PORT_CONTROL));
251 outb(0xe8, PORT_CONTROL); /* TR low - request for transfer */
253 if (inb(PORT_STATUS) & 0x40)
254 printf("waiting for TH low..\n");
255 while (inb(PORT_STATUS) & 0x40)
258 outb(0xe0, PORT_CONTROL);
260 if (strcmp(argv[1], "send") == 0)
262 printf("send %06x %06x\n", addr, size);
263 send_cmd(CMD_MD_SEND);
264 send_byte((addr >> 16) & 0xff);
265 send_byte((addr >> 8) & 0xff);
266 send_byte((addr >> 0) & 0xff);
267 send_byte((size >> 16) & 0xff);
268 send_byte((size >> 8) & 0xff);
269 send_byte((size >> 0) & 0xff);
271 for (i = 0; i < size; i++)
273 if ((i & 0xff) == 0) {
274 printf("\b\b\b\b\b\b\b\b\b\b\b\b\b");
275 printf("%06x/%06x", i, size);
282 else if (strcmp(argv[1], "recv") == 0)
284 send_cmd(CMD_MD_RECV);
285 send_byte((addr >> 16) & 0xff);
286 send_byte((addr >> 8) & 0xff);
287 send_byte((addr >> 0) & 0xff);
288 send_byte((size >> 16) & 0xff);
289 send_byte((size >> 8) & 0xff);
290 send_byte((size >> 0) & 0xff);
291 outb(0xe0, PORT_CONTROL); /* TL high, recv mode */
293 for (i = 0; i < size; i++)
295 if ((i & 0xff) == 0) {
296 printf("\b\b\b\b\b\b\b\b\b\b\b\b\b");
297 printf("%06x/%06x", i, size);
301 data[i] = recv_byte();
304 fwrite(data, 1, size, file);
306 printf("\b\b\b\b\b\b\b\b\b\b\b\b\b");
307 printf("%06x/%06x\n", i, size);
310 /* switch TL back to high, disable outputs */
311 outb(0xe0, PORT_CONTROL);