Revision 384dce1e
b/hw/usb-musb.c | ||
---|---|---|
24 | 24 |
#include "qemu-timer.h" |
25 | 25 |
#include "usb.h" |
26 | 26 |
#include "irq.h" |
27 |
#include "hw.h" |
|
27 | 28 |
|
28 | 29 |
/* Common USB registers */ |
29 | 30 |
#define MUSB_HDRC_FADDR 0x00 /* 8-bit */ |
... | ... | |
248 | 249 |
#define MGC_M_ULPI_REGCTL_COMPLETE 0x02 |
249 | 250 |
#define MGC_M_ULPI_REGCTL_REG 0x01 |
250 | 251 |
|
252 |
/* #define MUSB_DEBUG */ |
|
253 |
|
|
254 |
#ifdef MUSB_DEBUG |
|
255 |
#define TRACE(fmt,...) fprintf(stderr, "%s@%d: " fmt "\n", __FUNCTION__, \ |
|
256 |
__LINE__, ##__VA_ARGS__) |
|
257 |
#else |
|
258 |
#define TRACE(...) |
|
259 |
#endif |
|
260 |
|
|
261 |
|
|
251 | 262 |
static void musb_attach(USBPort *port, USBDevice *dev); |
252 | 263 |
|
253 | 264 |
typedef struct { |
... | ... | |
263 | 274 |
uint8_t fifosize; |
264 | 275 |
int timeout[2]; /* Always in microframes */ |
265 | 276 |
|
266 |
uint32_t *buf[2];
|
|
277 |
uint8_t *buf[2];
|
|
267 | 278 |
int fifolen[2]; |
268 | 279 |
int fifostart[2]; |
269 | 280 |
int fifoaddr[2]; |
... | ... | |
299 | 310 |
int setup_len; |
300 | 311 |
int session; |
301 | 312 |
|
302 |
uint32_t buf[0x2000];
|
|
313 |
uint8_t buf[0x8000];
|
|
303 | 314 |
|
304 | 315 |
/* Duplicating the world since 2008!... probably we should have 32 |
305 | 316 |
* logical, single endpoints instead. */ |
... | ... | |
774 | 785 |
MUSBEndPoint *ep = s->ep + epnum; |
775 | 786 |
int pid; |
776 | 787 |
int total, valid = 0; |
777 |
|
|
788 |
TRACE("start %d, len %d", ep->fifostart[0], ep->fifolen[0] ); |
|
778 | 789 |
ep->fifostart[0] += ep->fifolen[0]; |
779 | 790 |
ep->fifolen[0] = 0; |
780 | 791 |
|
... | ... | |
789 | 800 |
} |
790 | 801 |
|
791 | 802 |
/* If the packet is not fully ready yet, wait for a next segment. */ |
792 |
if (epnum && (ep->fifostart[0] << 2) < total)
|
|
803 |
if (epnum && (ep->fifostart[0]) < total) |
|
793 | 804 |
return; |
794 | 805 |
|
795 | 806 |
if (!valid) |
796 |
total = ep->fifostart[0] << 2;
|
|
807 |
total = ep->fifostart[0]; |
|
797 | 808 |
|
798 | 809 |
pid = USB_TOKEN_OUT; |
799 | 810 |
if (!epnum && (ep->csr[0] & MGC_M_CSR0_H_SETUPPKT)) { |
800 | 811 |
pid = USB_TOKEN_SETUP; |
801 |
if (total != 8) |
|
802 |
printf("%s: illegal SETUPPKT length of %i bytes\n",
|
|
803 |
__FUNCTION__, total);
|
|
812 |
if (total != 8) {
|
|
813 |
TRACE("illegal SETUPPKT length of %i bytes", total);
|
|
814 |
}
|
|
804 | 815 |
/* Controller should retry SETUP packets three times on errors |
805 | 816 |
* but it doesn't make sense for us to do that. */ |
806 | 817 |
} |
... | ... | |
817 | 828 |
/* If we already have a packet, which didn't fit into the |
818 | 829 |
* 64 bytes of the FIFO, only move the FIFO start and return. (Obsolete) */ |
819 | 830 |
if (ep->packey[1].pid == USB_TOKEN_IN && ep->status[1] >= 0 && |
820 |
(ep->fifostart[1] << 2) + ep->rxcount <
|
|
831 |
(ep->fifostart[1]) + ep->rxcount < |
|
821 | 832 |
ep->packey[1].len) { |
822 |
ep->fifostart[1] += ep->rxcount >> 2; |
|
833 |
TRACE("0x%08x, %d", ep->fifostart[1], ep->rxcount ); |
|
834 |
ep->fifostart[1] += ep->rxcount; |
|
823 | 835 |
ep->fifolen[1] = 0; |
824 | 836 |
|
825 |
ep->rxcount = MIN(ep->packey[0].len - (ep->fifostart[1] << 2),
|
|
837 |
ep->rxcount = MIN(ep->packey[0].len - (ep->fifostart[1]), |
|
826 | 838 |
ep->maxp[1]); |
827 | 839 |
|
828 | 840 |
ep->csr[1] &= ~MGC_M_RXCSR_H_REQPKT; |
... | ... | |
872 | 884 |
total, musb_rx_packet_complete, 1); |
873 | 885 |
} |
874 | 886 |
|
887 |
static uint8_t musb_read_fifo(MUSBEndPoint *ep) |
|
888 |
{ |
|
889 |
uint8_t value; |
|
890 |
if (ep->fifolen[1] >= 64) { |
|
891 |
/* We have a FIFO underrun */ |
|
892 |
TRACE("EP%d FIFO is now empty, stop reading", ep->epnum); |
|
893 |
return 0x00000000; |
|
894 |
} |
|
895 |
/* In DMA mode clear RXPKTRDY and set REQPKT automatically |
|
896 |
* (if AUTOREQ is set) */ |
|
897 |
|
|
898 |
ep->csr[1] &= ~MGC_M_RXCSR_FIFOFULL; |
|
899 |
value=ep->buf[1][ep->fifostart[1] + ep->fifolen[1] ++]; |
|
900 |
TRACE("EP%d 0x%02x, %d", ep->epnum, value, ep->fifolen[1] ); |
|
901 |
return value; |
|
902 |
} |
|
903 |
|
|
904 |
static void musb_write_fifo(MUSBEndPoint *ep, uint8_t value) |
|
905 |
{ |
|
906 |
TRACE("EP%d = %02x", ep->epnum, value); |
|
907 |
if (ep->fifolen[0] >= 64) { |
|
908 |
/* We have a FIFO overrun */ |
|
909 |
TRACE("EP%d FIFO exceeded 64 bytes, stop feeding data", ep->epnum); |
|
910 |
return; |
|
911 |
} |
|
912 |
|
|
913 |
ep->buf[0][ep->fifostart[0] + ep->fifolen[0] ++] = value; |
|
914 |
ep->csr[0] |= MGC_M_TXCSR_FIFONOTEMPTY; |
|
915 |
} |
|
916 |
|
|
875 | 917 |
static void musb_ep_frame_cancel(MUSBEndPoint *ep, int dir) |
876 | 918 |
{ |
877 | 919 |
if (ep->intv_timer[dir]) |
... | ... | |
895 | 937 |
return s->ep[ep].hport[1]; |
896 | 938 |
|
897 | 939 |
default: |
898 |
printf("%s: unknown register at %02x\n", __FUNCTION__, addr);
|
|
940 |
TRACE("unknown register 0x%02x", addr);
|
|
899 | 941 |
return 0x00; |
900 | 942 |
}; |
901 | 943 |
} |
... | ... | |
905 | 947 |
MUSBState *s = (MUSBState *) opaque; |
906 | 948 |
|
907 | 949 |
switch (addr) { |
950 |
case MUSB_HDRC_TXFUNCADDR: |
|
951 |
s->ep[ep].faddr[0] = value; |
|
952 |
break; |
|
953 |
case MUSB_HDRC_RXFUNCADDR: |
|
954 |
s->ep[ep].faddr[1] = value; |
|
955 |
break; |
|
908 | 956 |
case MUSB_HDRC_TXHUBADDR: |
909 | 957 |
s->ep[ep].haddr[0] = value; |
910 | 958 |
break; |
... | ... | |
919 | 967 |
break; |
920 | 968 |
|
921 | 969 |
default: |
922 |
printf("%s: unknown register at %02x\n", __FUNCTION__, addr); |
|
970 |
TRACE("unknown register 0x%02x", addr); |
|
971 |
break; |
|
923 | 972 |
}; |
924 | 973 |
} |
925 | 974 |
|
... | ... | |
975 | 1024 |
return 0x00; |
976 | 1025 |
case MUSB_HDRC_FIFOSIZE: |
977 | 1026 |
return ep ? s->ep[ep].fifosize : s->ep[ep].config; |
1027 |
case MUSB_HDRC_RXCOUNT: |
|
1028 |
return s->ep[ep].rxcount; |
|
978 | 1029 |
|
979 | 1030 |
default: |
980 |
printf("%s: unknown register at %02x\n", __FUNCTION__, addr);
|
|
1031 |
TRACE("unknown register 0x%02x", addr);
|
|
981 | 1032 |
return 0x00; |
982 | 1033 |
}; |
983 | 1034 |
} |
... | ... | |
1004 | 1055 |
case (MUSB_HDRC_FIFOSIZE & ~1): |
1005 | 1056 |
break; |
1006 | 1057 |
case MUSB_HDRC_FIFOSIZE: |
1007 |
printf("%s: somebody messes with fifosize (now %i bytes)\n", |
|
1008 |
__FUNCTION__, value); |
|
1058 |
TRACE("somebody messes with fifosize (now %i bytes)", value); |
|
1009 | 1059 |
s->ep[ep].fifosize = value; |
1010 | 1060 |
break; |
1011 |
|
|
1012 | 1061 |
default: |
1013 |
printf("%s: unknown register at %02x\n", __FUNCTION__, addr); |
|
1062 |
TRACE("unknown register 0x%02x", addr); |
|
1063 |
break; |
|
1014 | 1064 |
}; |
1015 | 1065 |
} |
1016 | 1066 |
|
... | ... | |
1194 | 1244 |
ep = (addr >> 4) & 0xf; |
1195 | 1245 |
return musb_ep_readb(s, ep, addr & 0xf); |
1196 | 1246 |
|
1247 |
case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f): |
|
1248 |
ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf; |
|
1249 |
return musb_read_fifo(s->ep + ep); |
|
1250 |
|
|
1197 | 1251 |
default: |
1198 |
printf("%s: unknown register at %02x\n", __FUNCTION__, (int) addr);
|
|
1252 |
TRACE("unknown register 0x%02x", (int) addr);
|
|
1199 | 1253 |
return 0x00; |
1200 | 1254 |
}; |
1201 | 1255 |
} |
... | ... | |
1276 | 1330 |
musb_ep_writeb(s, ep, addr & 0xf, value); |
1277 | 1331 |
break; |
1278 | 1332 |
|
1333 |
case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f): |
|
1334 |
ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf; |
|
1335 |
musb_write_fifo(s->ep + ep, value & 0xff); |
|
1336 |
break; |
|
1337 |
|
|
1279 | 1338 |
default: |
1280 |
printf("%s: unknown register at %02x\n", __FUNCTION__, (int) addr); |
|
1339 |
TRACE("unknown register 0x%02x", (int) addr); |
|
1340 |
break; |
|
1281 | 1341 |
}; |
1282 | 1342 |
} |
1283 | 1343 |
|
... | ... | |
1326 | 1386 |
ep = (addr >> 4) & 0xf; |
1327 | 1387 |
return musb_ep_readh(s, ep, addr & 0xf); |
1328 | 1388 |
|
1389 |
case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f): |
|
1390 |
ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf; |
|
1391 |
return (musb_read_fifo(s->ep + ep) | musb_read_fifo(s->ep + ep) << 8); |
|
1392 |
|
|
1329 | 1393 |
default: |
1330 | 1394 |
return musb_readb(s, addr) | (musb_readb(s, addr | 1) << 8); |
1331 | 1395 |
}; |
... | ... | |
1353 | 1417 |
case MUSB_HDRC_TXFIFOADDR: |
1354 | 1418 |
s->ep[s->idx].fifoaddr[0] = value; |
1355 | 1419 |
s->ep[s->idx].buf[0] = |
1356 |
s->buf + ((value << 1) & (sizeof(s->buf) / 4 - 1));
|
|
1420 |
s->buf + ((value << 3) & 0x7ff );
|
|
1357 | 1421 |
break; |
1358 | 1422 |
case MUSB_HDRC_RXFIFOADDR: |
1359 | 1423 |
s->ep[s->idx].fifoaddr[1] = value; |
1360 | 1424 |
s->ep[s->idx].buf[1] = |
1361 |
s->buf + ((value << 1) & (sizeof(s->buf) / 4 - 1));
|
|
1425 |
s->buf + ((value << 3) & 0x7ff);
|
|
1362 | 1426 |
break; |
1363 | 1427 |
|
1364 | 1428 |
case MUSB_HDRC_EP_IDX ... (MUSB_HDRC_EP_IDX + 0xf): |
... | ... | |
1375 | 1439 |
musb_ep_writeh(s, ep, addr & 0xf, value); |
1376 | 1440 |
break; |
1377 | 1441 |
|
1442 |
case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f): |
|
1443 |
ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf; |
|
1444 |
musb_write_fifo(s->ep + ep, value & 0xff); |
|
1445 |
musb_write_fifo(s->ep + ep, (value >> 8) & 0xff); |
|
1446 |
break; |
|
1447 |
|
|
1378 | 1448 |
default: |
1379 | 1449 |
musb_writeb(s, addr, value & 0xff); |
1380 | 1450 |
musb_writeb(s, addr | 1, value >> 8); |
... | ... | |
1384 | 1454 |
static uint32_t musb_readw(void *opaque, target_phys_addr_t addr) |
1385 | 1455 |
{ |
1386 | 1456 |
MUSBState *s = (MUSBState *) opaque; |
1387 |
MUSBEndPoint *ep; |
|
1388 |
int epnum; |
|
1457 |
int ep; |
|
1389 | 1458 |
|
1390 | 1459 |
switch (addr) { |
1391 | 1460 |
case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f): |
1392 |
epnum = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf; |
|
1393 |
ep = s->ep + epnum; |
|
1394 |
|
|
1395 |
if (ep->fifolen[1] >= 16) { |
|
1396 |
/* We have a FIFO underrun */ |
|
1397 |
printf("%s: EP%i FIFO is now empty, stop reading\n", |
|
1398 |
__FUNCTION__, epnum); |
|
1399 |
return 0x00000000; |
|
1400 |
} |
|
1401 |
/* In DMA mode clear RXPKTRDY and set REQPKT automatically |
|
1402 |
* (if AUTOREQ is set) */ |
|
1403 |
|
|
1404 |
ep->csr[1] &= ~MGC_M_RXCSR_FIFOFULL; |
|
1405 |
return ep->buf[1][ep->fifostart[1] + ep->fifolen[1] ++]; |
|
1406 |
|
|
1461 |
ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf; |
|
1462 |
return ( musb_read_fifo(s->ep + ep) | |
|
1463 |
musb_read_fifo(s->ep + ep) << 8 | |
|
1464 |
musb_read_fifo(s->ep + ep) << 16 | |
|
1465 |
musb_read_fifo(s->ep + ep) << 24 ); |
|
1407 | 1466 |
default: |
1408 |
printf("%s: unknown register at %02x\n", __FUNCTION__, (int) addr);
|
|
1467 |
TRACE("unknown register 0x%02x", (int) addr);
|
|
1409 | 1468 |
return 0x00000000; |
1410 | 1469 |
}; |
1411 | 1470 |
} |
... | ... | |
1413 | 1472 |
static void musb_writew(void *opaque, target_phys_addr_t addr, uint32_t value) |
1414 | 1473 |
{ |
1415 | 1474 |
MUSBState *s = (MUSBState *) opaque; |
1416 |
MUSBEndPoint *ep; |
|
1417 |
int epnum; |
|
1475 |
int ep; |
|
1418 | 1476 |
|
1419 | 1477 |
switch (addr) { |
1420 | 1478 |
case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f): |
1421 |
epnum = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf; |
|
1422 |
ep = s->ep + epnum; |
|
1423 |
|
|
1424 |
if (ep->fifolen[0] >= 16) { |
|
1425 |
/* We have a FIFO overrun */ |
|
1426 |
printf("%s: EP%i FIFO exceeded 64 bytes, stop feeding data\n", |
|
1427 |
__FUNCTION__, epnum); |
|
1479 |
ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf; |
|
1480 |
musb_write_fifo(s->ep + ep, value & 0xff); |
|
1481 |
musb_write_fifo(s->ep + ep, (value >> 8 ) & 0xff); |
|
1482 |
musb_write_fifo(s->ep + ep, (value >> 16) & 0xff); |
|
1483 |
musb_write_fifo(s->ep + ep, (value >> 24) & 0xff); |
|
1428 | 1484 |
break; |
1429 |
} |
|
1430 |
|
|
1431 |
ep->buf[0][ep->fifostart[0] + ep->fifolen[0] ++] = value; |
|
1432 |
if (epnum) |
|
1433 |
ep->csr[0] |= MGC_M_TXCSR_FIFONOTEMPTY; |
|
1434 |
break; |
|
1435 |
|
|
1436 | 1485 |
default: |
1437 |
printf("%s: unknown register at %02x\n", __FUNCTION__, (int) addr); |
|
1486 |
TRACE("unknown register 0x%02x", (int) addr); |
|
1487 |
break; |
|
1438 | 1488 |
}; |
1439 | 1489 |
} |
1440 | 1490 |
|
Also available in: Unified diff