Compare commits
9 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
9ba08bec0f | ||
|
cb9fe32b8c | ||
|
bc58c3874f | ||
|
7fa64ca726 | ||
|
8e3d855eac | ||
|
b6e6f8ca44 | ||
|
f808bbc8e0 | ||
|
894f641639 | ||
|
8cebe92a4d |
349
CheatCode.c
349
CheatCode.c
@ -271,177 +271,178 @@ unsigned char kenobigcDBG[4288] =
|
|||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||||
};
|
};
|
||||||
unsigned char kenobigc[2736] =
|
|
||||||
{
|
//unsigned char kenobigc[2736] =
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x21, 0x60, 0x00, 0x00, 0x00, 0x00,
|
//{
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x21, 0x60, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x94, 0x21, 0xff, 0x58, 0x90, 0x01, 0x00, 0x08,
|
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x7c, 0x08, 0x02, 0xa6, 0x90, 0x01, 0x00, 0xac, 0x7c, 0x00, 0x00, 0x26, 0x90, 0x01, 0x00, 0x0c,
|
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x94, 0x21, 0xff, 0x58, 0x90, 0x01, 0x00, 0x08,
|
||||||
0x7c, 0x09, 0x02, 0xa6, 0x90, 0x01, 0x00, 0x10, 0x7c, 0x01, 0x02, 0xa6, 0x90, 0x01, 0x00, 0x14,
|
// 0x7c, 0x08, 0x02, 0xa6, 0x90, 0x01, 0x00, 0xac, 0x7c, 0x00, 0x00, 0x26, 0x90, 0x01, 0x00, 0x0c,
|
||||||
0xbc, 0x61, 0x00, 0x18, 0x7f, 0x20, 0x00, 0xa6, 0x63, 0x3a, 0x20, 0x00, 0x73, 0x5a, 0xf9, 0xff,
|
// 0x7c, 0x09, 0x02, 0xa6, 0x90, 0x01, 0x00, 0x10, 0x7c, 0x01, 0x02, 0xa6, 0x90, 0x01, 0x00, 0x14,
|
||||||
0x7f, 0x40, 0x01, 0x24, 0xd8, 0x41, 0x00, 0x98, 0xd8, 0x61, 0x00, 0xa0, 0x3f, 0xe0, 0x80, 0x00,
|
// 0xbc, 0x61, 0x00, 0x18, 0x7f, 0x20, 0x00, 0xa6, 0x63, 0x3a, 0x20, 0x00, 0x73, 0x5a, 0xf9, 0xff,
|
||||||
0x3e, 0x80, 0xcc, 0x00, 0xa3, 0x94, 0x40, 0x10, 0x63, 0x95, 0x00, 0xff, 0xb2, 0xb4, 0x40, 0x10,
|
// 0x7f, 0x40, 0x01, 0x24, 0xd8, 0x41, 0x00, 0x98, 0xd8, 0x61, 0x00, 0xa0, 0x3f, 0xe0, 0x80, 0x00,
|
||||||
0x7f, 0xa8, 0x02, 0xa6, 0x3d, 0xe0, 0x80, 0x00, 0x61, 0xef, 0x22, 0xa8, 0x63, 0xe7, 0x18, 0x08,
|
// 0x3e, 0x80, 0xcc, 0x00, 0xa3, 0x94, 0x40, 0x10, 0x63, 0x95, 0x00, 0xff, 0xb2, 0xb4, 0x40, 0x10,
|
||||||
0x3c, 0xc0, 0x80, 0x00, 0x7c, 0xd0, 0x33, 0x78, 0x39, 0x00, 0x00, 0x00, 0x3c, 0x60, 0x00, 0xd0,
|
// 0x7f, 0xa8, 0x02, 0xa6, 0x3d, 0xe0, 0x80, 0x00, 0x61, 0xef, 0x22, 0xa8, 0x63, 0xe7, 0x18, 0x08,
|
||||||
0x60, 0x63, 0xc0, 0xde, 0x80, 0x8f, 0x00, 0x00, 0x7c, 0x03, 0x20, 0x00, 0x40, 0x82, 0x00, 0x18,
|
// 0x3c, 0xc0, 0x80, 0x00, 0x7c, 0xd0, 0x33, 0x78, 0x39, 0x00, 0x00, 0x00, 0x3c, 0x60, 0x00, 0xd0,
|
||||||
0x80, 0x8f, 0x00, 0x04, 0x7c, 0x03, 0x20, 0x00, 0x40, 0x82, 0x00, 0x0c, 0x39, 0xef, 0x00, 0x08,
|
// 0x60, 0x63, 0xc0, 0xde, 0x80, 0x8f, 0x00, 0x00, 0x7c, 0x03, 0x20, 0x00, 0x40, 0x82, 0x00, 0x18,
|
||||||
0x48, 0x00, 0x00, 0x4c, 0x7f, 0xa8, 0x03, 0xa6, 0xb3, 0x94, 0x40, 0x10, 0xc8, 0x41, 0x00, 0x98,
|
// 0x80, 0x8f, 0x00, 0x04, 0x7c, 0x03, 0x20, 0x00, 0x40, 0x82, 0x00, 0x0c, 0x39, 0xef, 0x00, 0x08,
|
||||||
0xc8, 0x61, 0x00, 0xa0, 0x7f, 0x20, 0x00, 0xa6, 0x80, 0x01, 0x00, 0xac, 0x7c, 0x08, 0x03, 0xa6,
|
// 0x48, 0x00, 0x00, 0x4c, 0x7f, 0xa8, 0x03, 0xa6, 0xb3, 0x94, 0x40, 0x10, 0xc8, 0x41, 0x00, 0x98,
|
||||||
0x80, 0x01, 0x00, 0x0c, 0x7c, 0x0f, 0xf1, 0x20, 0x80, 0x01, 0x00, 0x10, 0x7c, 0x09, 0x03, 0xa6,
|
// 0xc8, 0x61, 0x00, 0xa0, 0x7f, 0x20, 0x00, 0xa6, 0x80, 0x01, 0x00, 0xac, 0x7c, 0x08, 0x03, 0xa6,
|
||||||
0x80, 0x01, 0x00, 0x14, 0x7c, 0x01, 0x03, 0xa6, 0xb8, 0x61, 0x00, 0x18, 0x80, 0x01, 0x00, 0x08,
|
// 0x80, 0x01, 0x00, 0x0c, 0x7c, 0x0f, 0xf1, 0x20, 0x80, 0x01, 0x00, 0x10, 0x7c, 0x09, 0x03, 0xa6,
|
||||||
0x38, 0x21, 0x00, 0xa8, 0x4c, 0x00, 0x01, 0x2c, 0x4e, 0x80, 0x00, 0x20, 0x80, 0x6f, 0x00, 0x00,
|
// 0x80, 0x01, 0x00, 0x14, 0x7c, 0x01, 0x03, 0xa6, 0xb8, 0x61, 0x00, 0x18, 0x80, 0x01, 0x00, 0x08,
|
||||||
0x80, 0x8f, 0x00, 0x04, 0x39, 0xef, 0x00, 0x08, 0x71, 0x09, 0x00, 0x01, 0x2f, 0x89, 0x00, 0x00,
|
// 0x38, 0x21, 0x00, 0xa8, 0x4c, 0x00, 0x01, 0x2c, 0x4e, 0x80, 0x00, 0x20, 0x80, 0x6f, 0x00, 0x00,
|
||||||
0x39, 0x20, 0x00, 0x00, 0x54, 0x6a, 0x1f, 0x7e, 0x54, 0x65, 0x3f, 0x7e, 0x74, 0x6b, 0x10, 0x00,
|
// 0x80, 0x8f, 0x00, 0x04, 0x39, 0xef, 0x00, 0x08, 0x71, 0x09, 0x00, 0x01, 0x2f, 0x89, 0x00, 0x00,
|
||||||
0x54, 0x63, 0x01, 0xfe, 0x40, 0x82, 0x00, 0x0c, 0x54, 0xcc, 0x00, 0x0c, 0x48, 0x00, 0x00, 0x08,
|
// 0x39, 0x20, 0x00, 0x00, 0x54, 0x6a, 0x1f, 0x7e, 0x54, 0x65, 0x3f, 0x7e, 0x74, 0x6b, 0x10, 0x00,
|
||||||
0x7e, 0x0c, 0x83, 0x78, 0x2e, 0x05, 0x00, 0x00, 0x2c, 0x0a, 0x00, 0x01, 0x41, 0xa0, 0x00, 0x2c,
|
// 0x54, 0x63, 0x01, 0xfe, 0x40, 0x82, 0x00, 0x0c, 0x54, 0xcc, 0x00, 0x0c, 0x48, 0x00, 0x00, 0x08,
|
||||||
0x41, 0xa2, 0x00, 0xe4, 0x2c, 0x0a, 0x00, 0x03, 0x41, 0xa0, 0x01, 0xac, 0x41, 0x82, 0x02, 0x50,
|
// 0x7e, 0x0c, 0x83, 0x78, 0x2e, 0x05, 0x00, 0x00, 0x2c, 0x0a, 0x00, 0x01, 0x41, 0xa0, 0x00, 0x2c,
|
||||||
0x2c, 0x0a, 0x00, 0x05, 0x41, 0x80, 0x02, 0xd4, 0x41, 0xa2, 0x04, 0xe0, 0x2c, 0x0a, 0x00, 0x07,
|
// 0x41, 0xa2, 0x00, 0xe4, 0x2c, 0x0a, 0x00, 0x03, 0x41, 0xa0, 0x01, 0xac, 0x41, 0x82, 0x02, 0x50,
|
||||||
0x41, 0xa0, 0x05, 0x0c, 0x48, 0x00, 0x05, 0xf0, 0x7d, 0x8c, 0x1a, 0x14, 0x2c, 0x05, 0x00, 0x03,
|
// 0x2c, 0x0a, 0x00, 0x05, 0x41, 0x80, 0x02, 0xd4, 0x41, 0xa2, 0x04, 0xe0, 0x2c, 0x0a, 0x00, 0x07,
|
||||||
0x41, 0x82, 0x00, 0x48, 0x41, 0x81, 0x00, 0x60, 0x40, 0xbe, 0xff, 0x84, 0x2e, 0x05, 0x00, 0x01,
|
// 0x41, 0xa0, 0x05, 0x0c, 0x48, 0x00, 0x05, 0xf0, 0x7d, 0x8c, 0x1a, 0x14, 0x2c, 0x05, 0x00, 0x03,
|
||||||
0x41, 0x91, 0x00, 0x2c, 0x54, 0x8a, 0x84, 0x3e, 0x41, 0x92, 0x00, 0x10, 0x7c, 0x89, 0x61, 0xae,
|
// 0x41, 0x82, 0x00, 0x48, 0x41, 0x81, 0x00, 0x60, 0x40, 0xbe, 0xff, 0x84, 0x2e, 0x05, 0x00, 0x01,
|
||||||
0x39, 0x29, 0x00, 0x01, 0x48, 0x00, 0x00, 0x0c, 0x7c, 0x89, 0x63, 0x2e, 0x39, 0x29, 0x00, 0x02,
|
// 0x41, 0x91, 0x00, 0x2c, 0x54, 0x8a, 0x84, 0x3e, 0x41, 0x92, 0x00, 0x10, 0x7c, 0x89, 0x61, 0xae,
|
||||||
0x35, 0x4a, 0xff, 0xff, 0x40, 0xa0, 0xff, 0xe4, 0x4b, 0xff, 0xff, 0x54, 0x55, 0x8c, 0x00, 0x3a,
|
// 0x39, 0x29, 0x00, 0x01, 0x48, 0x00, 0x00, 0x0c, 0x7c, 0x89, 0x63, 0x2e, 0x39, 0x29, 0x00, 0x02,
|
||||||
0x90, 0x8c, 0x00, 0x00, 0x4b, 0xff, 0xff, 0x48, 0x7c, 0x89, 0x23, 0x78, 0x40, 0x9e, 0x04, 0xc8,
|
// 0x35, 0x4a, 0xff, 0xff, 0x40, 0xa0, 0xff, 0xe4, 0x4b, 0xff, 0xff, 0x54, 0x55, 0x8c, 0x00, 0x3a,
|
||||||
0x35, 0x29, 0xff, 0xff, 0x41, 0x80, 0x04, 0xc0, 0x7c, 0xa9, 0x78, 0xae, 0x7c, 0xa9, 0x61, 0xae,
|
// 0x90, 0x8c, 0x00, 0x00, 0x4b, 0xff, 0xff, 0x48, 0x7c, 0x89, 0x23, 0x78, 0x40, 0x9e, 0x04, 0xc8,
|
||||||
0x4b, 0xff, 0xff, 0xf0, 0x39, 0xef, 0x00, 0x08, 0x40, 0xbe, 0xff, 0x24, 0x80, 0xaf, 0xff, 0xf8,
|
// 0x35, 0x29, 0xff, 0xff, 0x41, 0x80, 0x04, 0xc0, 0x7c, 0xa9, 0x78, 0xae, 0x7c, 0xa9, 0x61, 0xae,
|
||||||
0x81, 0x6f, 0xff, 0xfc, 0x54, 0xb1, 0x04, 0x3e, 0x54, 0xaa, 0x85, 0x3e, 0x54, 0xa5, 0x27, 0x3e,
|
// 0x4b, 0xff, 0xff, 0xf0, 0x39, 0xef, 0x00, 0x08, 0x40, 0xbe, 0xff, 0x24, 0x80, 0xaf, 0xff, 0xf8,
|
||||||
0x2e, 0x85, 0x00, 0x01, 0x41, 0x96, 0x00, 0x10, 0x41, 0xb5, 0x00, 0x14, 0x7c, 0x89, 0x61, 0xae,
|
// 0x81, 0x6f, 0xff, 0xfc, 0x54, 0xb1, 0x04, 0x3e, 0x54, 0xaa, 0x85, 0x3e, 0x54, 0xa5, 0x27, 0x3e,
|
||||||
0x48, 0x00, 0x00, 0x10, 0x7c, 0x89, 0x63, 0x2e, 0x48, 0x00, 0x00, 0x08, 0x7c, 0x89, 0x61, 0x2e,
|
// 0x2e, 0x85, 0x00, 0x01, 0x41, 0x96, 0x00, 0x10, 0x41, 0xb5, 0x00, 0x14, 0x7c, 0x89, 0x61, 0xae,
|
||||||
0x7c, 0x84, 0x5a, 0x14, 0x7d, 0x29, 0x8a, 0x14, 0x35, 0x4a, 0xff, 0xff, 0x40, 0x80, 0xff, 0xd4,
|
// 0x48, 0x00, 0x00, 0x10, 0x7c, 0x89, 0x63, 0x2e, 0x48, 0x00, 0x00, 0x08, 0x7c, 0x89, 0x61, 0x2e,
|
||||||
0x4b, 0xff, 0xfe, 0xdc, 0x54, 0x69, 0x07, 0xff, 0x41, 0x82, 0x00, 0x10, 0x55, 0x08, 0xf8, 0x7e,
|
// 0x7c, 0x84, 0x5a, 0x14, 0x7d, 0x29, 0x8a, 0x14, 0x35, 0x4a, 0xff, 0xff, 0x40, 0x80, 0xff, 0xd4,
|
||||||
0x71, 0x09, 0x00, 0x01, 0x2f, 0x89, 0x00, 0x00, 0x2e, 0x85, 0x00, 0x04, 0x2d, 0x8a, 0x00, 0x05,
|
// 0x4b, 0xff, 0xfe, 0xdc, 0x54, 0x69, 0x07, 0xff, 0x41, 0x82, 0x00, 0x10, 0x55, 0x08, 0xf8, 0x7e,
|
||||||
0x51, 0x08, 0x08, 0x3c, 0x40, 0x9e, 0x00, 0x78, 0x41, 0x8d, 0x04, 0xb8, 0x7d, 0x8c, 0x1a, 0x14,
|
// 0x71, 0x09, 0x00, 0x01, 0x2f, 0x89, 0x00, 0x00, 0x2e, 0x85, 0x00, 0x04, 0x2d, 0x8a, 0x00, 0x05,
|
||||||
0x41, 0x8c, 0x00, 0x0c, 0x41, 0x94, 0x00, 0x30, 0x48, 0x00, 0x00, 0x1c, 0x40, 0x94, 0x00, 0x10,
|
// 0x51, 0x08, 0x08, 0x3c, 0x40, 0x9e, 0x00, 0x78, 0x41, 0x8d, 0x04, 0xb8, 0x7d, 0x8c, 0x1a, 0x14,
|
||||||
0x55, 0x8c, 0x00, 0x3a, 0x81, 0x6c, 0x00, 0x00, 0x48, 0x00, 0x00, 0x1c, 0x55, 0x8c, 0x00, 0x3c,
|
// 0x41, 0x8c, 0x00, 0x0c, 0x41, 0x94, 0x00, 0x30, 0x48, 0x00, 0x00, 0x1c, 0x40, 0x94, 0x00, 0x10,
|
||||||
0xa1, 0x6c, 0x00, 0x00, 0x7c, 0x89, 0x20, 0xf8, 0x55, 0x29, 0x84, 0x3e, 0x7d, 0x6b, 0x48, 0x38,
|
// 0x55, 0x8c, 0x00, 0x3a, 0x81, 0x6c, 0x00, 0x00, 0x48, 0x00, 0x00, 0x1c, 0x55, 0x8c, 0x00, 0x3c,
|
||||||
0x54, 0x84, 0x04, 0x3e, 0x7f, 0x0b, 0x20, 0x40, 0x70, 0xa9, 0x00, 0x03, 0x41, 0x82, 0x00, 0x18,
|
// 0xa1, 0x6c, 0x00, 0x00, 0x7c, 0x89, 0x20, 0xf8, 0x55, 0x29, 0x84, 0x3e, 0x7d, 0x6b, 0x48, 0x38,
|
||||||
0x2c, 0x09, 0x00, 0x02, 0x41, 0x82, 0x00, 0x18, 0x41, 0x81, 0x00, 0x1c, 0x40, 0x9a, 0x00, 0x20,
|
// 0x54, 0x84, 0x04, 0x3e, 0x7f, 0x0b, 0x20, 0x40, 0x70, 0xa9, 0x00, 0x03, 0x41, 0x82, 0x00, 0x18,
|
||||||
0x48, 0x00, 0x00, 0x18, 0x41, 0x9a, 0x00, 0x18, 0x48, 0x00, 0x00, 0x10, 0x41, 0x99, 0x00, 0x10,
|
// 0x2c, 0x09, 0x00, 0x02, 0x41, 0x82, 0x00, 0x18, 0x41, 0x81, 0x00, 0x1c, 0x40, 0x9a, 0x00, 0x20,
|
||||||
0x48, 0x00, 0x00, 0x08, 0x41, 0x98, 0x00, 0x08, 0x61, 0x08, 0x00, 0x01, 0x40, 0x8e, 0xfe, 0x40,
|
// 0x48, 0x00, 0x00, 0x18, 0x41, 0x9a, 0x00, 0x18, 0x48, 0x00, 0x00, 0x10, 0x41, 0x99, 0x00, 0x10,
|
||||||
0x41, 0x94, 0xfe, 0x3c, 0x81, 0x6f, 0xff, 0xf8, 0x40, 0x9e, 0x00, 0x20, 0x70, 0x6c, 0x00, 0x08,
|
// 0x48, 0x00, 0x00, 0x08, 0x41, 0x98, 0x00, 0x08, 0x61, 0x08, 0x00, 0x01, 0x40, 0x8e, 0xfe, 0x40,
|
||||||
0x41, 0x82, 0x00, 0x0c, 0x71, 0x0c, 0x00, 0x01, 0x41, 0x82, 0x00, 0x10, 0x39, 0x8b, 0x00, 0x10,
|
// 0x41, 0x94, 0xfe, 0x3c, 0x81, 0x6f, 0xff, 0xf8, 0x40, 0x9e, 0x00, 0x20, 0x70, 0x6c, 0x00, 0x08,
|
||||||
0x51, 0x8b, 0x03, 0x36, 0x48, 0x00, 0x00, 0x08, 0x55, 0x6b, 0x07, 0x16, 0x91, 0x6f, 0xff, 0xf8,
|
// 0x41, 0x82, 0x00, 0x0c, 0x71, 0x0c, 0x00, 0x01, 0x41, 0x82, 0x00, 0x10, 0x39, 0x8b, 0x00, 0x10,
|
||||||
0x4b, 0xff, 0xfe, 0x0c, 0x40, 0xbe, 0xfe, 0x08, 0x54, 0x69, 0x16, 0xba, 0x54, 0x6e, 0x87, 0xfe,
|
// 0x51, 0x8b, 0x03, 0x36, 0x48, 0x00, 0x00, 0x08, 0x55, 0x6b, 0x07, 0x16, 0x91, 0x6f, 0xff, 0xf8,
|
||||||
0x2d, 0x8e, 0x00, 0x00, 0x2e, 0x05, 0x00, 0x04, 0x70, 0xae, 0x00, 0x03, 0x2e, 0x8e, 0x00, 0x02,
|
// 0x4b, 0xff, 0xfe, 0x0c, 0x40, 0xbe, 0xfe, 0x08, 0x54, 0x69, 0x16, 0xba, 0x54, 0x6e, 0x87, 0xfe,
|
||||||
0x41, 0x94, 0x00, 0x14, 0x41, 0x96, 0x00, 0x50, 0x7c, 0x64, 0x07, 0x34, 0x7c, 0x84, 0x7a, 0x14,
|
// 0x2d, 0x8e, 0x00, 0x00, 0x2e, 0x05, 0x00, 0x04, 0x70, 0xae, 0x00, 0x03, 0x2e, 0x8e, 0x00, 0x02,
|
||||||
0x48, 0x00, 0x00, 0x68, 0x54, 0x65, 0xa7, 0xff, 0x41, 0x82, 0x00, 0x0c, 0x7d, 0x27, 0x48, 0x2e,
|
// 0x41, 0x94, 0x00, 0x14, 0x41, 0x96, 0x00, 0x50, 0x7c, 0x64, 0x07, 0x34, 0x7c, 0x84, 0x7a, 0x14,
|
||||||
0x7c, 0x84, 0x4a, 0x14, 0x41, 0x8e, 0x00, 0x08, 0x7c, 0x8c, 0x22, 0x14, 0x2e, 0x8e, 0x00, 0x01,
|
// 0x48, 0x00, 0x00, 0x68, 0x54, 0x65, 0xa7, 0xff, 0x41, 0x82, 0x00, 0x0c, 0x7d, 0x27, 0x48, 0x2e,
|
||||||
0x41, 0x96, 0x00, 0x08, 0x80, 0x84, 0x00, 0x00, 0x54, 0x63, 0x67, 0xff, 0x41, 0x82, 0x00, 0x3c,
|
// 0x7c, 0x84, 0x4a, 0x14, 0x41, 0x8e, 0x00, 0x08, 0x7c, 0x8c, 0x22, 0x14, 0x2e, 0x8e, 0x00, 0x01,
|
||||||
0x40, 0x90, 0x00, 0x0c, 0x7c, 0x84, 0x32, 0x14, 0x48, 0x00, 0x00, 0x30, 0x7c, 0x84, 0x82, 0x14,
|
// 0x41, 0x96, 0x00, 0x08, 0x80, 0x84, 0x00, 0x00, 0x54, 0x63, 0x67, 0xff, 0x41, 0x82, 0x00, 0x3c,
|
||||||
0x48, 0x00, 0x00, 0x28, 0x54, 0x65, 0xa7, 0xff, 0x41, 0x82, 0x00, 0x0c, 0x7d, 0x27, 0x48, 0x2e,
|
// 0x40, 0x90, 0x00, 0x0c, 0x7c, 0x84, 0x32, 0x14, 0x48, 0x00, 0x00, 0x30, 0x7c, 0x84, 0x82, 0x14,
|
||||||
0x7c, 0x84, 0x4a, 0x14, 0x40, 0x90, 0x00, 0x0c, 0x7c, 0xcc, 0x21, 0x2e, 0x4b, 0xff, 0xfd, 0x80,
|
// 0x48, 0x00, 0x00, 0x28, 0x54, 0x65, 0xa7, 0xff, 0x41, 0x82, 0x00, 0x0c, 0x7d, 0x27, 0x48, 0x2e,
|
||||||
0x7e, 0x0c, 0x21, 0x2e, 0x4b, 0xff, 0xfd, 0x78, 0x40, 0x90, 0x00, 0x0c, 0x7c, 0x86, 0x23, 0x78,
|
// 0x7c, 0x84, 0x4a, 0x14, 0x40, 0x90, 0x00, 0x0c, 0x7c, 0xcc, 0x21, 0x2e, 0x4b, 0xff, 0xfd, 0x80,
|
||||||
0x4b, 0xff, 0xfd, 0x6c, 0x7c, 0x90, 0x23, 0x78, 0x4b, 0xff, 0xfd, 0x64, 0x54, 0x89, 0x1e, 0x78,
|
// 0x7e, 0x0c, 0x21, 0x2e, 0x4b, 0xff, 0xfd, 0x78, 0x40, 0x90, 0x00, 0x0c, 0x7c, 0x86, 0x23, 0x78,
|
||||||
0x39, 0x29, 0x00, 0x40, 0x2c, 0x05, 0x00, 0x02, 0x41, 0x80, 0x00, 0x48, 0x54, 0x6b, 0x50, 0x03,
|
// 0x4b, 0xff, 0xfd, 0x6c, 0x7c, 0x90, 0x23, 0x78, 0x4b, 0xff, 0xfd, 0x64, 0x54, 0x89, 0x1e, 0x78,
|
||||||
0x41, 0x82, 0x00, 0x14, 0x41, 0x81, 0x00, 0x08, 0x48, 0x00, 0x00, 0x10, 0x41, 0xbe, 0xfd, 0x40,
|
// 0x39, 0x29, 0x00, 0x40, 0x2c, 0x05, 0x00, 0x02, 0x41, 0x80, 0x00, 0x48, 0x54, 0x6b, 0x50, 0x03,
|
||||||
0x48, 0x00, 0x00, 0x08, 0x40, 0xbe, 0xfd, 0x38, 0x2c, 0x05, 0x00, 0x03, 0x41, 0x81, 0x00, 0x10,
|
// 0x41, 0x82, 0x00, 0x14, 0x41, 0x81, 0x00, 0x08, 0x48, 0x00, 0x00, 0x10, 0x41, 0xbe, 0xfd, 0x40,
|
||||||
0x41, 0xa2, 0x00, 0x10, 0x7d, 0xe7, 0x48, 0x2e, 0x4b, 0xff, 0xfd, 0x24, 0x7d, 0xe7, 0x49, 0x2e,
|
// 0x48, 0x00, 0x00, 0x08, 0x40, 0xbe, 0xfd, 0x38, 0x2c, 0x05, 0x00, 0x03, 0x41, 0x81, 0x00, 0x10,
|
||||||
0x7c, 0x64, 0x07, 0x34, 0x54, 0x84, 0x1a, 0x78, 0x7d, 0xef, 0x22, 0x14, 0x4b, 0xff, 0xfd, 0x10,
|
// 0x41, 0xa2, 0x00, 0x10, 0x7d, 0xe7, 0x48, 0x2e, 0x4b, 0xff, 0xfd, 0x24, 0x7d, 0xe7, 0x49, 0x2e,
|
||||||
0x40, 0xbe, 0xfd, 0x0c, 0x7c, 0xa7, 0x4a, 0x14, 0x40, 0x92, 0x00, 0x14, 0x54, 0x64, 0x04, 0x3e,
|
// 0x7c, 0x64, 0x07, 0x34, 0x54, 0x84, 0x1a, 0x78, 0x7d, 0xef, 0x22, 0x14, 0x4b, 0xff, 0xfd, 0x10,
|
||||||
0x91, 0xe5, 0x00, 0x00, 0x90, 0x85, 0x00, 0x04, 0x4b, 0xff, 0xfc, 0xf4, 0x81, 0x25, 0x00, 0x04,
|
// 0x40, 0xbe, 0xfd, 0x0c, 0x7c, 0xa7, 0x4a, 0x14, 0x40, 0x92, 0x00, 0x14, 0x54, 0x64, 0x04, 0x3e,
|
||||||
0x2c, 0x09, 0x00, 0x00, 0x41, 0xa2, 0xfc, 0xe8, 0x39, 0x29, 0xff, 0xff, 0x91, 0x25, 0x00, 0x04,
|
// 0x91, 0xe5, 0x00, 0x00, 0x90, 0x85, 0x00, 0x04, 0x4b, 0xff, 0xfc, 0xf4, 0x81, 0x25, 0x00, 0x04,
|
||||||
0x81, 0xe5, 0x00, 0x00, 0x4b, 0xff, 0xfc, 0xd8, 0x40, 0xbe, 0xfc, 0xd4, 0x54, 0x6b, 0x16, 0xba,
|
// 0x2c, 0x09, 0x00, 0x00, 0x41, 0xa2, 0xfc, 0xe8, 0x39, 0x29, 0xff, 0xff, 0x91, 0x25, 0x00, 0x04,
|
||||||
0x7f, 0x47, 0x5a, 0x14, 0x81, 0x3a, 0x00, 0x00, 0x54, 0x6e, 0x67, 0xbe, 0x41, 0x92, 0x00, 0x84,
|
// 0x81, 0xe5, 0x00, 0x00, 0x4b, 0xff, 0xfc, 0xd8, 0x40, 0xbe, 0xfc, 0xd4, 0x54, 0x6b, 0x16, 0xba,
|
||||||
0x2e, 0x05, 0x00, 0x05, 0x40, 0x90, 0x01, 0x74, 0x2e, 0x05, 0x00, 0x03, 0x40, 0x90, 0x00, 0x90,
|
// 0x7f, 0x47, 0x5a, 0x14, 0x81, 0x3a, 0x00, 0x00, 0x54, 0x6e, 0x67, 0xbe, 0x41, 0x92, 0x00, 0x84,
|
||||||
0x2e, 0x05, 0x00, 0x01, 0x54, 0x65, 0x87, 0xff, 0x41, 0x82, 0x00, 0x08, 0x7c, 0x8c, 0x22, 0x14,
|
// 0x2e, 0x05, 0x00, 0x05, 0x40, 0x90, 0x01, 0x74, 0x2e, 0x05, 0x00, 0x03, 0x40, 0x90, 0x00, 0x90,
|
||||||
0x2f, 0x0e, 0x00, 0x01, 0x40, 0x92, 0x00, 0x24, 0x41, 0xb9, 0x00, 0x18, 0x41, 0x9a, 0x00, 0x0c,
|
// 0x2e, 0x05, 0x00, 0x01, 0x54, 0x65, 0x87, 0xff, 0x41, 0x82, 0x00, 0x08, 0x7c, 0x8c, 0x22, 0x14,
|
||||||
0x88, 0x84, 0x00, 0x00, 0x48, 0x00, 0x00, 0xf8, 0xa0, 0x84, 0x00, 0x00, 0x48, 0x00, 0x00, 0xf0,
|
// 0x2f, 0x0e, 0x00, 0x01, 0x40, 0x92, 0x00, 0x24, 0x41, 0xb9, 0x00, 0x18, 0x41, 0x9a, 0x00, 0x0c,
|
||||||
0x80, 0x84, 0x00, 0x00, 0x48, 0x00, 0x00, 0xe8, 0x54, 0x73, 0xe5, 0x3e, 0x41, 0xb9, 0x00, 0x20,
|
// 0x88, 0x84, 0x00, 0x00, 0x48, 0x00, 0x00, 0xf8, 0xa0, 0x84, 0x00, 0x00, 0x48, 0x00, 0x00, 0xf0,
|
||||||
0x41, 0x9a, 0x00, 0x10, 0x99, 0x24, 0x00, 0x00, 0x38, 0x84, 0x00, 0x01, 0x48, 0x00, 0x00, 0x18,
|
// 0x80, 0x84, 0x00, 0x00, 0x48, 0x00, 0x00, 0xe8, 0x54, 0x73, 0xe5, 0x3e, 0x41, 0xb9, 0x00, 0x20,
|
||||||
0xb1, 0x24, 0x00, 0x00, 0x38, 0x84, 0x00, 0x02, 0x48, 0x00, 0x00, 0x0c, 0x91, 0x24, 0x00, 0x00,
|
// 0x41, 0x9a, 0x00, 0x10, 0x99, 0x24, 0x00, 0x00, 0x38, 0x84, 0x00, 0x01, 0x48, 0x00, 0x00, 0x18,
|
||||||
0x38, 0x84, 0x00, 0x04, 0x36, 0x73, 0xff, 0xff, 0x40, 0x80, 0xff, 0xd4, 0x4b, 0xff, 0xfc, 0x40,
|
// 0xb1, 0x24, 0x00, 0x00, 0x38, 0x84, 0x00, 0x02, 0x48, 0x00, 0x00, 0x0c, 0x91, 0x24, 0x00, 0x00,
|
||||||
0x54, 0x65, 0x87, 0xff, 0x41, 0x82, 0x00, 0x08, 0x7c, 0x84, 0x62, 0x14, 0x71, 0xc5, 0x00, 0x01,
|
// 0x38, 0x84, 0x00, 0x04, 0x36, 0x73, 0xff, 0xff, 0x40, 0x80, 0xff, 0xd4, 0x4b, 0xff, 0xfc, 0x40,
|
||||||
0x41, 0x82, 0x00, 0x9c, 0x7c, 0x84, 0x4a, 0x14, 0x48, 0x00, 0x00, 0x94, 0x54, 0x6a, 0x87, 0xbe,
|
// 0x54, 0x65, 0x87, 0xff, 0x41, 0x82, 0x00, 0x08, 0x7c, 0x84, 0x62, 0x14, 0x71, 0xc5, 0x00, 0x01,
|
||||||
0x54, 0x8e, 0x16, 0xba, 0x7e, 0x67, 0x72, 0x14, 0x40, 0x92, 0x00, 0x08, 0x3a, 0x6f, 0xff, 0xfc,
|
// 0x41, 0x82, 0x00, 0x9c, 0x7c, 0x84, 0x4a, 0x14, 0x48, 0x00, 0x00, 0x94, 0x54, 0x6a, 0x87, 0xbe,
|
||||||
0x80, 0x9a, 0x00, 0x00, 0x81, 0x33, 0x00, 0x00, 0x71, 0x4b, 0x00, 0x01, 0x41, 0x82, 0x00, 0x08,
|
// 0x54, 0x8e, 0x16, 0xba, 0x7e, 0x67, 0x72, 0x14, 0x40, 0x92, 0x00, 0x08, 0x3a, 0x6f, 0xff, 0xfc,
|
||||||
0x7c, 0x9a, 0x23, 0x78, 0x71, 0x4b, 0x00, 0x02, 0x41, 0x82, 0x00, 0x10, 0x7d, 0x33, 0x4b, 0x78,
|
// 0x80, 0x9a, 0x00, 0x00, 0x81, 0x33, 0x00, 0x00, 0x71, 0x4b, 0x00, 0x01, 0x41, 0x82, 0x00, 0x08,
|
||||||
0x40, 0xb2, 0x00, 0x08, 0x7e, 0x6c, 0x9a, 0x14, 0x54, 0x65, 0x67, 0x3f, 0x2c, 0x05, 0x00, 0x09,
|
// 0x7c, 0x9a, 0x23, 0x78, 0x71, 0x4b, 0x00, 0x02, 0x41, 0x82, 0x00, 0x10, 0x7d, 0x33, 0x4b, 0x78,
|
||||||
0x40, 0x80, 0x00, 0x54, 0x48, 0x00, 0x00, 0x79, 0x7c, 0x89, 0x22, 0x14, 0x48, 0x00, 0x00, 0x40,
|
// 0x40, 0xb2, 0x00, 0x08, 0x7e, 0x6c, 0x9a, 0x14, 0x54, 0x65, 0x67, 0x3f, 0x2c, 0x05, 0x00, 0x09,
|
||||||
0x7c, 0x89, 0x21, 0xd6, 0x48, 0x00, 0x00, 0x38, 0x7d, 0x24, 0x23, 0x78, 0x48, 0x00, 0x00, 0x30,
|
// 0x40, 0x80, 0x00, 0x54, 0x48, 0x00, 0x00, 0x79, 0x7c, 0x89, 0x22, 0x14, 0x48, 0x00, 0x00, 0x40,
|
||||||
0x7d, 0x24, 0x20, 0x38, 0x48, 0x00, 0x00, 0x28, 0x7d, 0x24, 0x22, 0x78, 0x48, 0x00, 0x00, 0x20,
|
// 0x7c, 0x89, 0x21, 0xd6, 0x48, 0x00, 0x00, 0x38, 0x7d, 0x24, 0x23, 0x78, 0x48, 0x00, 0x00, 0x30,
|
||||||
0x7d, 0x24, 0x20, 0x30, 0x48, 0x00, 0x00, 0x18, 0x7d, 0x24, 0x24, 0x30, 0x48, 0x00, 0x00, 0x10,
|
// 0x7d, 0x24, 0x20, 0x38, 0x48, 0x00, 0x00, 0x28, 0x7d, 0x24, 0x22, 0x78, 0x48, 0x00, 0x00, 0x20,
|
||||||
0x5d, 0x24, 0x20, 0x3e, 0x48, 0x00, 0x00, 0x08, 0x7d, 0x24, 0x26, 0x30, 0x90, 0x9a, 0x00, 0x00,
|
// 0x7d, 0x24, 0x20, 0x30, 0x48, 0x00, 0x00, 0x18, 0x7d, 0x24, 0x24, 0x30, 0x48, 0x00, 0x00, 0x10,
|
||||||
0x4b, 0xff, 0xfb, 0x8c, 0x2c, 0x05, 0x00, 0x0a, 0x41, 0x81, 0xfb, 0x84, 0xc0, 0x5a, 0x00, 0x00,
|
// 0x5d, 0x24, 0x20, 0x3e, 0x48, 0x00, 0x00, 0x08, 0x7d, 0x24, 0x26, 0x30, 0x90, 0x9a, 0x00, 0x00,
|
||||||
0xc0, 0x73, 0x00, 0x00, 0x41, 0x82, 0x00, 0x0c, 0xec, 0x43, 0x10, 0x2a, 0x48, 0x00, 0x00, 0x08,
|
// 0x4b, 0xff, 0xfb, 0x8c, 0x2c, 0x05, 0x00, 0x0a, 0x41, 0x81, 0xfb, 0x84, 0xc0, 0x5a, 0x00, 0x00,
|
||||||
0xec, 0x43, 0x00, 0xb2, 0xd0, 0x5a, 0x00, 0x00, 0x4b, 0xff, 0xfb, 0x64, 0x7d, 0x48, 0x02, 0xa6,
|
// 0xc0, 0x73, 0x00, 0x00, 0x41, 0x82, 0x00, 0x0c, 0xec, 0x43, 0x10, 0x2a, 0x48, 0x00, 0x00, 0x08,
|
||||||
0x54, 0xa5, 0x1e, 0x78, 0x7d, 0x4a, 0x2a, 0x14, 0x80, 0x9a, 0x00, 0x00, 0x81, 0x33, 0x00, 0x00,
|
// 0xec, 0x43, 0x00, 0xb2, 0xd0, 0x5a, 0x00, 0x00, 0x4b, 0xff, 0xfb, 0x64, 0x7d, 0x48, 0x02, 0xa6,
|
||||||
0x7d, 0x48, 0x03, 0xa6, 0x4e, 0x80, 0x00, 0x20, 0x40, 0xbe, 0xfb, 0x44, 0x54, 0x69, 0xc0, 0x3e,
|
// 0x54, 0xa5, 0x1e, 0x78, 0x7d, 0x4a, 0x2a, 0x14, 0x80, 0x9a, 0x00, 0x00, 0x81, 0x33, 0x00, 0x00,
|
||||||
0x7d, 0x8e, 0x63, 0x78, 0x48, 0x00, 0x00, 0x35, 0x41, 0x92, 0x00, 0x0c, 0x7e, 0x31, 0x22, 0x14,
|
// 0x7d, 0x48, 0x03, 0xa6, 0x4e, 0x80, 0x00, 0x20, 0x40, 0xbe, 0xfb, 0x44, 0x54, 0x69, 0xc0, 0x3e,
|
||||||
0x48, 0x00, 0x00, 0x08, 0x7d, 0x29, 0x22, 0x14, 0x54, 0x64, 0xc4, 0x3f, 0x38, 0xa0, 0x00, 0x00,
|
// 0x7d, 0x8e, 0x63, 0x78, 0x48, 0x00, 0x00, 0x35, 0x41, 0x92, 0x00, 0x0c, 0x7e, 0x31, 0x22, 0x14,
|
||||||
0x41, 0x82, 0xfb, 0x1c, 0x7d, 0x45, 0x88, 0xae, 0x7d, 0x45, 0x49, 0xae, 0x38, 0xa5, 0x00, 0x01,
|
// 0x48, 0x00, 0x00, 0x08, 0x7d, 0x29, 0x22, 0x14, 0x54, 0x64, 0xc4, 0x3f, 0x38, 0xa0, 0x00, 0x00,
|
||||||
0x7c, 0x05, 0x20, 0x00, 0x4b, 0xff, 0xff, 0xec, 0x2e, 0x8a, 0x00, 0x04, 0x55, 0x31, 0x36, 0xba,
|
// 0x41, 0x82, 0xfb, 0x1c, 0x7d, 0x45, 0x88, 0xae, 0x7d, 0x45, 0x49, 0xae, 0x38, 0xa5, 0x00, 0x01,
|
||||||
0x2c, 0x11, 0x00, 0x3c, 0x7e, 0x27, 0x88, 0x2e, 0x40, 0x82, 0x00, 0x08, 0x7d, 0xd1, 0x73, 0x78,
|
// 0x7c, 0x05, 0x20, 0x00, 0x4b, 0xff, 0xff, 0xec, 0x2e, 0x8a, 0x00, 0x04, 0x55, 0x31, 0x36, 0xba,
|
||||||
0x41, 0x96, 0x00, 0x08, 0xa2, 0x31, 0x00, 0x00, 0x55, 0x29, 0x56, 0xba, 0x2c, 0x09, 0x00, 0x3c,
|
// 0x2c, 0x11, 0x00, 0x3c, 0x7e, 0x27, 0x88, 0x2e, 0x40, 0x82, 0x00, 0x08, 0x7d, 0xd1, 0x73, 0x78,
|
||||||
0x7d, 0x27, 0x48, 0x2e, 0x40, 0x82, 0x00, 0x08, 0x7d, 0xc9, 0x73, 0x78, 0x41, 0x96, 0x00, 0x08,
|
// 0x41, 0x96, 0x00, 0x08, 0xa2, 0x31, 0x00, 0x00, 0x55, 0x29, 0x56, 0xba, 0x2c, 0x09, 0x00, 0x3c,
|
||||||
0xa1, 0x29, 0x00, 0x00, 0x4e, 0x80, 0x00, 0x20, 0x2c, 0x05, 0x00, 0x04, 0x40, 0x80, 0x00, 0x28,
|
// 0x7d, 0x27, 0x48, 0x2e, 0x40, 0x82, 0x00, 0x08, 0x7d, 0xc9, 0x73, 0x78, 0x41, 0x96, 0x00, 0x08,
|
||||||
0x7c, 0x89, 0x23, 0x78, 0x7d, 0xc3, 0x62, 0x14, 0x55, 0xce, 0x00, 0x3c, 0x4b, 0xff, 0xff, 0xad,
|
// 0xa1, 0x29, 0x00, 0x00, 0x4e, 0x80, 0x00, 0x20, 0x2c, 0x05, 0x00, 0x04, 0x40, 0x80, 0x00, 0x28,
|
||||||
0x7c, 0x84, 0x20, 0xf8, 0x54, 0x84, 0x04, 0x3e, 0x7d, 0x2b, 0x20, 0x38, 0x7e, 0x24, 0x20, 0x38,
|
// 0x7c, 0x89, 0x23, 0x78, 0x7d, 0xc3, 0x62, 0x14, 0x55, 0xce, 0x00, 0x3c, 0x4b, 0xff, 0xff, 0xad,
|
||||||
0x4b, 0xff, 0xfb, 0xc4, 0x54, 0x6b, 0xe4, 0x3e, 0x4b, 0xff, 0xfb, 0xbc, 0x7c, 0x9a, 0x23, 0x78,
|
// 0x7c, 0x84, 0x20, 0xf8, 0x54, 0x84, 0x04, 0x3e, 0x7d, 0x2b, 0x20, 0x38, 0x7e, 0x24, 0x20, 0x38,
|
||||||
0x54, 0x84, 0x18, 0x38, 0x40, 0x92, 0x00, 0x20, 0x40, 0x9e, 0x00, 0x0c, 0x7d, 0xe8, 0x03, 0xa6,
|
// 0x4b, 0xff, 0xfb, 0xc4, 0x54, 0x6b, 0xe4, 0x3e, 0x4b, 0xff, 0xfb, 0xbc, 0x7c, 0x9a, 0x23, 0x78,
|
||||||
0x4e, 0x80, 0x00, 0x21, 0x7d, 0xe4, 0x7a, 0x14, 0x39, 0xef, 0x00, 0x07, 0x55, 0xef, 0x00, 0x38,
|
// 0x54, 0x84, 0x18, 0x38, 0x40, 0x92, 0x00, 0x20, 0x40, 0x9e, 0x00, 0x0c, 0x7d, 0xe8, 0x03, 0xa6,
|
||||||
0x4b, 0xff, 0xfa, 0x6c, 0x2e, 0x05, 0x00, 0x03, 0x41, 0x91, 0x00, 0x5c, 0x3c, 0xa0, 0x48, 0x00,
|
// 0x4e, 0x80, 0x00, 0x21, 0x7d, 0xe4, 0x7a, 0x14, 0x39, 0xef, 0x00, 0x07, 0x55, 0xef, 0x00, 0x38,
|
||||||
0x7d, 0x83, 0x62, 0x14, 0x55, 0x8c, 0x00, 0x3a, 0x40, 0x92, 0x00, 0x20, 0x40, 0xbe, 0xfa, 0x50,
|
// 0x4b, 0xff, 0xfa, 0x6c, 0x2e, 0x05, 0x00, 0x03, 0x41, 0x91, 0x00, 0x5c, 0x3c, 0xa0, 0x48, 0x00,
|
||||||
0x57, 0x44, 0x00, 0x3a, 0x7c, 0x8c, 0x20, 0x50, 0x50, 0x85, 0x01, 0xba, 0x50, 0x65, 0x07, 0xfe,
|
// 0x7d, 0x83, 0x62, 0x14, 0x55, 0x8c, 0x00, 0x3a, 0x40, 0x92, 0x00, 0x20, 0x40, 0xbe, 0xfa, 0x50,
|
||||||
0x90, 0xac, 0x00, 0x00, 0x4b, 0xff, 0xfa, 0x38, 0x40, 0xbe, 0xff, 0xbc, 0x7d, 0x2c, 0x78, 0x50,
|
// 0x57, 0x44, 0x00, 0x3a, 0x7c, 0x8c, 0x20, 0x50, 0x50, 0x85, 0x01, 0xba, 0x50, 0x65, 0x07, 0xfe,
|
||||||
0x51, 0x25, 0x01, 0xba, 0x90, 0xac, 0x00, 0x00, 0x39, 0x8c, 0x00, 0x04, 0x7d, 0x6f, 0x22, 0x14,
|
// 0x90, 0xac, 0x00, 0x00, 0x4b, 0xff, 0xfa, 0x38, 0x40, 0xbe, 0xff, 0xbc, 0x7d, 0x2c, 0x78, 0x50,
|
||||||
0x39, 0x6b, 0xff, 0xfc, 0x7d, 0x2b, 0x60, 0x50, 0x51, 0x25, 0x01, 0xba, 0x90, 0xab, 0x00, 0x00,
|
// 0x51, 0x25, 0x01, 0xba, 0x90, 0xac, 0x00, 0x00, 0x39, 0x8c, 0x00, 0x04, 0x7d, 0x6f, 0x22, 0x14,
|
||||||
0x4b, 0xff, 0xff, 0x94, 0x2e, 0x05, 0x00, 0x06, 0x41, 0x92, 0x00, 0x28, 0x4b, 0xff, 0xfb, 0x28,
|
// 0x39, 0x6b, 0xff, 0xfc, 0x7d, 0x2b, 0x60, 0x50, 0x51, 0x25, 0x01, 0xba, 0x90, 0xab, 0x00, 0x00,
|
||||||
0x55, 0x8c, 0x84, 0x3e, 0x57, 0x44, 0x84, 0x3e, 0x57, 0x5a, 0x04, 0x3e, 0x7c, 0x0c, 0x20, 0x00,
|
// 0x4b, 0xff, 0xff, 0x94, 0x2e, 0x05, 0x00, 0x06, 0x41, 0x92, 0x00, 0x28, 0x4b, 0xff, 0xfb, 0x28,
|
||||||
0x41, 0x80, 0xfb, 0xa8, 0x7c, 0x0c, 0xd0, 0x00, 0x40, 0x80, 0xfb, 0xa0, 0x4b, 0xff, 0xf9, 0xe0,
|
// 0x55, 0x8c, 0x84, 0x3e, 0x57, 0x44, 0x84, 0x3e, 0x57, 0x5a, 0x04, 0x3e, 0x7c, 0x0c, 0x20, 0x00,
|
||||||
0x57, 0x45, 0xff, 0xfe, 0x68, 0xa5, 0x00, 0x01, 0x71, 0x03, 0x00, 0x01, 0x7c, 0x05, 0x18, 0x00,
|
// 0x41, 0x80, 0xfb, 0xa8, 0x7c, 0x0c, 0xd0, 0x00, 0x40, 0x80, 0xfb, 0xa0, 0x4b, 0xff, 0xf9, 0xe0,
|
||||||
0x41, 0x82, 0x00, 0x1c, 0x51, 0x1a, 0x0f, 0xbc, 0x6b, 0x5a, 0x00, 0x02, 0x57, 0x45, 0xff, 0xff,
|
// 0x57, 0x45, 0xff, 0xfe, 0x68, 0xa5, 0x00, 0x01, 0x71, 0x03, 0x00, 0x01, 0x7c, 0x05, 0x18, 0x00,
|
||||||
0x41, 0x82, 0x00, 0x08, 0x6b, 0x5a, 0x00, 0x01, 0x93, 0x4f, 0xff, 0xfc, 0x53, 0x48, 0x07, 0xfe,
|
// 0x41, 0x82, 0x00, 0x1c, 0x51, 0x1a, 0x0f, 0xbc, 0x6b, 0x5a, 0x00, 0x02, 0x57, 0x45, 0xff, 0xff,
|
||||||
0x4b, 0xff, 0xf9, 0xac, 0x2c, 0x0b, 0x00, 0x00, 0x41, 0x82, 0x01, 0x38, 0x2c, 0x05, 0x00, 0x01,
|
// 0x41, 0x82, 0x00, 0x08, 0x6b, 0x5a, 0x00, 0x01, 0x93, 0x4f, 0xff, 0xfc, 0x53, 0x48, 0x07, 0xfe,
|
||||||
0x41, 0x82, 0x00, 0x18, 0x2c, 0x05, 0x00, 0x02, 0x41, 0x82, 0x00, 0x14, 0x2c, 0x05, 0x00, 0x03,
|
// 0x4b, 0xff, 0xf9, 0xac, 0x2c, 0x0b, 0x00, 0x00, 0x41, 0x82, 0x01, 0x38, 0x2c, 0x05, 0x00, 0x01,
|
||||||
0x41, 0x82, 0x00, 0x70, 0x4b, 0xff, 0xf9, 0x40, 0x54, 0xcc, 0x00, 0x0c, 0x54, 0x97, 0x46, 0x3e,
|
// 0x41, 0x82, 0x00, 0x18, 0x2c, 0x05, 0x00, 0x02, 0x41, 0x82, 0x00, 0x14, 0x2c, 0x05, 0x00, 0x03,
|
||||||
0x54, 0x98, 0xc4, 0x3e, 0x54, 0x84, 0x06, 0x3e, 0x40, 0x9e, 0x00, 0xfc, 0x56, 0xf9, 0x06, 0x31,
|
// 0x41, 0x82, 0x00, 0x70, 0x4b, 0xff, 0xf9, 0x40, 0x54, 0xcc, 0x00, 0x0c, 0x54, 0x97, 0x46, 0x3e,
|
||||||
0x7d, 0x9a, 0x63, 0x78, 0x7f, 0x43, 0xd2, 0x14, 0x57, 0x5a, 0x00, 0x3a, 0x41, 0x82, 0x00, 0x18,
|
// 0x54, 0x98, 0xc4, 0x3e, 0x54, 0x84, 0x06, 0x3e, 0x40, 0x9e, 0x00, 0xfc, 0x56, 0xf9, 0x06, 0x31,
|
||||||
0x7e, 0xf7, 0x07, 0x74, 0x7e, 0xf7, 0x00, 0xd0, 0x1f, 0x37, 0x00, 0x02, 0x3b, 0x39, 0x00, 0x04,
|
// 0x7d, 0x9a, 0x63, 0x78, 0x7f, 0x43, 0xd2, 0x14, 0x57, 0x5a, 0x00, 0x3a, 0x41, 0x82, 0x00, 0x18,
|
||||||
0x7f, 0x59, 0xd0, 0x50, 0x2c, 0x17, 0x00, 0x00, 0x41, 0x82, 0x00, 0x1c, 0x3b, 0x20, 0x00, 0x00,
|
// 0x7e, 0xf7, 0x07, 0x74, 0x7e, 0xf7, 0x00, 0xd0, 0x1f, 0x37, 0x00, 0x02, 0x3b, 0x39, 0x00, 0x04,
|
||||||
0x7e, 0xe9, 0x03, 0xa6, 0xa3, 0x7a, 0x00, 0x04, 0x7f, 0x79, 0xca, 0x78, 0x3b, 0x5a, 0x00, 0x02,
|
// 0x7f, 0x59, 0xd0, 0x50, 0x2c, 0x17, 0x00, 0x00, 0x41, 0x82, 0x00, 0x1c, 0x3b, 0x20, 0x00, 0x00,
|
||||||
0x42, 0x00, 0xff, 0xf4, 0x7c, 0x18, 0xc8, 0x00, 0x40, 0x82, 0x00, 0xac, 0x4b, 0xff, 0xfe, 0x90,
|
// 0x7e, 0xe9, 0x03, 0xa6, 0xa3, 0x7a, 0x00, 0x04, 0x7f, 0x79, 0xca, 0x78, 0x3b, 0x5a, 0x00, 0x02,
|
||||||
0x51, 0x08, 0x08, 0x3c, 0x40, 0x9e, 0x00, 0x9c, 0x54, 0x77, 0xb0, 0x03, 0x41, 0x81, 0x00, 0x88,
|
// 0x42, 0x00, 0xff, 0xf4, 0x7c, 0x18, 0xc8, 0x00, 0x40, 0x82, 0x00, 0xac, 0x4b, 0xff, 0xfe, 0x90,
|
||||||
0x41, 0x80, 0x00, 0x8c, 0x54, 0x7e, 0x06, 0x3e, 0x1f, 0xde, 0x00, 0x02, 0x54, 0x97, 0x00, 0x1e,
|
// 0x51, 0x08, 0x08, 0x3c, 0x40, 0x9e, 0x00, 0x9c, 0x54, 0x77, 0xb0, 0x03, 0x41, 0x81, 0x00, 0x88,
|
||||||
0x6e, 0xf8, 0x80, 0x00, 0x2c, 0x18, 0x00, 0x00, 0x40, 0x82, 0x00, 0x08, 0x62, 0xf7, 0x30, 0x00,
|
// 0x41, 0x80, 0x00, 0x8c, 0x54, 0x7e, 0x06, 0x3e, 0x1f, 0xde, 0x00, 0x02, 0x54, 0x97, 0x00, 0x1e,
|
||||||
0x54, 0x98, 0x80, 0x1e, 0x1f, 0x3e, 0x00, 0x04, 0x7f, 0x19, 0xc0, 0x50, 0x3b, 0x20, 0x00, 0x00,
|
// 0x6e, 0xf8, 0x80, 0x00, 0x2c, 0x18, 0x00, 0x00, 0x40, 0x82, 0x00, 0x08, 0x62, 0xf7, 0x30, 0x00,
|
||||||
0x1f, 0x59, 0x00, 0x04, 0x7f, 0x6f, 0xd0, 0x2e, 0x7f, 0x57, 0xd0, 0x2e, 0x3b, 0x39, 0x00, 0x01,
|
// 0x54, 0x98, 0x80, 0x1e, 0x1f, 0x3e, 0x00, 0x04, 0x7f, 0x19, 0xc0, 0x50, 0x3b, 0x20, 0x00, 0x00,
|
||||||
0x7c, 0x17, 0xc0, 0x40, 0x41, 0x81, 0x00, 0x34, 0x7c, 0x19, 0xf0, 0x00, 0x41, 0x81, 0x00, 0x14,
|
// 0x1f, 0x59, 0x00, 0x04, 0x7f, 0x6f, 0xd0, 0x2e, 0x7f, 0x57, 0xd0, 0x2e, 0x3b, 0x39, 0x00, 0x01,
|
||||||
0x7c, 0x1a, 0xd8, 0x00, 0x41, 0x82, 0xff, 0xdc, 0x3a, 0xf7, 0x00, 0x04, 0x4b, 0xff, 0xff, 0xd0,
|
// 0x7c, 0x17, 0xc0, 0x40, 0x41, 0x81, 0x00, 0x34, 0x7c, 0x19, 0xf0, 0x00, 0x41, 0x81, 0x00, 0x14,
|
||||||
0x80, 0x6f, 0xff, 0xf8, 0x60, 0x63, 0x03, 0x00, 0x90, 0x6f, 0xff, 0xf8, 0x92, 0xef, 0xff, 0xfc,
|
// 0x7c, 0x1a, 0xd8, 0x00, 0x41, 0x82, 0xff, 0xdc, 0x3a, 0xf7, 0x00, 0x04, 0x4b, 0xff, 0xff, 0xd0,
|
||||||
0x7e, 0xf0, 0xbb, 0x78, 0x48, 0x00, 0x00, 0x1c, 0x80, 0x6f, 0xff, 0xf8, 0x60, 0x63, 0x01, 0x00,
|
// 0x80, 0x6f, 0xff, 0xf8, 0x60, 0x63, 0x03, 0x00, 0x90, 0x6f, 0xff, 0xf8, 0x92, 0xef, 0xff, 0xfc,
|
||||||
0x90, 0x6f, 0xff, 0xf8, 0x61, 0x08, 0x00, 0x01, 0x48, 0x00, 0x00, 0x08, 0x7c, 0x90, 0x23, 0x78,
|
// 0x7e, 0xf0, 0xbb, 0x78, 0x48, 0x00, 0x00, 0x1c, 0x80, 0x6f, 0xff, 0xf8, 0x60, 0x63, 0x01, 0x00,
|
||||||
0x54, 0x64, 0x06, 0x3e, 0x1c, 0x84, 0x00, 0x08, 0x7d, 0xe4, 0x7a, 0x14, 0x4b, 0xff, 0xf8, 0x70,
|
// 0x90, 0x6f, 0xff, 0xf8, 0x61, 0x08, 0x00, 0x01, 0x48, 0x00, 0x00, 0x08, 0x7c, 0x90, 0x23, 0x78,
|
||||||
0x40, 0x92, 0x00, 0x0c, 0x39, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x14, 0x54, 0x69, 0x06, 0xff,
|
// 0x54, 0x64, 0x06, 0x3e, 0x1c, 0x84, 0x00, 0x08, 0x7d, 0xe4, 0x7a, 0x14, 0x4b, 0xff, 0xf8, 0x70,
|
||||||
0x54, 0x65, 0x67, 0xfe, 0x7d, 0x08, 0x4c, 0x30, 0x55, 0x17, 0xff, 0xff, 0x40, 0x82, 0x00, 0x08,
|
// 0x40, 0x92, 0x00, 0x0c, 0x39, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x14, 0x54, 0x69, 0x06, 0xff,
|
||||||
0x7d, 0x08, 0x2a, 0x78, 0x54, 0x85, 0x00, 0x1f, 0x41, 0x82, 0x00, 0x08, 0x7c, 0xa6, 0x2b, 0x78,
|
// 0x54, 0x65, 0x67, 0xfe, 0x7d, 0x08, 0x4c, 0x30, 0x55, 0x17, 0xff, 0xff, 0x40, 0x82, 0x00, 0x08,
|
||||||
0x54, 0x85, 0x80, 0x1f, 0x41, 0x82, 0x00, 0x08, 0x7c, 0xb0, 0x2b, 0x78, 0x4b, 0xff, 0xf8, 0x30,
|
// 0x7d, 0x08, 0x2a, 0x78, 0x54, 0x85, 0x00, 0x1f, 0x41, 0x82, 0x00, 0x08, 0x7c, 0xa6, 0x2b, 0x78,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
// 0x54, 0x85, 0x80, 0x1f, 0x41, 0x82, 0x00, 0x08, 0x7c, 0xb0, 0x2b, 0x78, 0x4b, 0xff, 0xf8, 0x30,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
};
|
// 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||||
|
//};
|
||||||
|
2
Config.c
2
Config.c
@ -4,7 +4,7 @@ DML_CFG *DMLCfg;
|
|||||||
|
|
||||||
void ConfigInit( DML_CFG *Cfg )
|
void ConfigInit( DML_CFG *Cfg )
|
||||||
{
|
{
|
||||||
DMLCfg = (DML_CFG*)malloc( sizeof( DML_CFG ) );
|
DMLCfg = (DML_CFG*)0xFFFE4200;
|
||||||
|
|
||||||
memset32( DMLCfg, 0, sizeof(DML_CFG) );
|
memset32( DMLCfg, 0, sizeof(DML_CFG) );
|
||||||
|
|
||||||
|
63
DVD.c
63
DVD.c
@ -6,6 +6,11 @@ static char GamePath[256];
|
|||||||
|
|
||||||
extern FIL GameFile;
|
extern FIL GameFile;
|
||||||
extern u32 FSTMode;
|
extern u32 FSTMode;
|
||||||
|
extern u32 DOLMaxOff;
|
||||||
|
extern u32 DOLOffset;
|
||||||
|
|
||||||
|
u8 HardDriveConnected;
|
||||||
|
FATFS fatfs;
|
||||||
|
|
||||||
static u8 *FSTable ALIGNED(32);
|
static u8 *FSTable ALIGNED(32);
|
||||||
|
|
||||||
@ -17,7 +22,7 @@ u32 FSTableOffset = 0;
|
|||||||
u32 FCEntry=0;
|
u32 FCEntry=0;
|
||||||
FileCache FC[FILECACHE_MAX];
|
FileCache FC[FILECACHE_MAX];
|
||||||
u32 FCState[FILECACHE_MAX];
|
u32 FCState[FILECACHE_MAX];
|
||||||
DWORD LTable[1024];
|
DWORD LTable[0x1D0];
|
||||||
|
|
||||||
static void DVDCreateLinkMap( FIL *File )
|
static void DVDCreateLinkMap( FIL *File )
|
||||||
{
|
{
|
||||||
@ -30,6 +35,62 @@ static void DVDCreateLinkMap( FIL *File )
|
|||||||
GameFile.cltbl = NULL;
|
GameFile.cltbl = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
void DVDInit( void )
|
||||||
|
{
|
||||||
|
int i=0;
|
||||||
|
s32 fres = FR_DISK_ERR;
|
||||||
|
int MountFail=0;
|
||||||
|
HardDriveConnected = 0;
|
||||||
|
|
||||||
|
while(!HardDriveConnected)
|
||||||
|
{
|
||||||
|
while(1)
|
||||||
|
{
|
||||||
|
fres = f_mount(0, &fatfs );
|
||||||
|
dbgprintf( "DIP:f_mount():%d\n", fres );
|
||||||
|
if( fres == FR_OK )
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
MountFail++;
|
||||||
|
|
||||||
|
if( MountFail == 10 )
|
||||||
|
{
|
||||||
|
dbgprintf( "DIP:too much fail! looping now!\n");
|
||||||
|
while(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
udelay(500000);
|
||||||
|
}
|
||||||
|
|
||||||
|
//try to open a file, it doesn't have to exist, just testing if FS works
|
||||||
|
FIL f;
|
||||||
|
fres = f_open( &f, "/randmb.in", FA_READ|FA_OPEN_EXISTING );
|
||||||
|
switch(fres)
|
||||||
|
{
|
||||||
|
case FR_OK:
|
||||||
|
f_close( &f );
|
||||||
|
case FR_NO_PATH:
|
||||||
|
case FR_NO_FILE:
|
||||||
|
{
|
||||||
|
HardDriveConnected = 1;
|
||||||
|
fres = FR_OK;
|
||||||
|
} break;
|
||||||
|
default:
|
||||||
|
case FR_DISK_ERR:
|
||||||
|
{
|
||||||
|
dbgprintf( "DIP:Disk error\n", fres );
|
||||||
|
while(1);
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( fres != FR_OK )
|
||||||
|
{
|
||||||
|
dbgprintf( "DIP:Could not find any USB device!");
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
s32 DVDSelectGame( void )
|
s32 DVDSelectGame( void )
|
||||||
{
|
{
|
||||||
char *str = (char*)malloca( 256, 32 );
|
char *str = (char*)malloca( 256, 32 );
|
||||||
|
4
DVD.h
4
DVD.h
@ -6,6 +6,7 @@
|
|||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
#include "ff.h"
|
#include "ff.h"
|
||||||
#include "dol.h"
|
#include "dol.h"
|
||||||
|
#include "Drive.h"
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
@ -16,8 +17,11 @@ typedef struct
|
|||||||
u8 GameInfo[][0x80];
|
u8 GameInfo[][0x80];
|
||||||
} DVDConfig;
|
} DVDConfig;
|
||||||
|
|
||||||
|
void DVDInit( void );
|
||||||
void DVDReadConfig( void );
|
void DVDReadConfig( void );
|
||||||
s32 DVDSelectGame( void );
|
s32 DVDSelectGame( void );
|
||||||
|
void DVDUpdateFSTRAM( void );
|
||||||
|
void DiscBackup( u32 FrameBuffer );
|
||||||
|
|
||||||
u32 FSTInit( void );
|
u32 FSTInit( void );
|
||||||
void FSTRead( char *Buffer, u32 Length, u32 Offset );
|
void FSTRead( char *Buffer, u32 Length, u32 Offset );
|
||||||
|
29
Drive.c
29
Drive.c
@ -73,6 +73,35 @@ u32 LowReadDiscID( void *data )
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
u32 LowRead( void *data, u32 Offset, u32 Length )
|
||||||
|
{
|
||||||
|
write32( 0x0D806008, 0xA8000000 );
|
||||||
|
write32( 0x0D80600C, Offset>>2 );
|
||||||
|
write32( 0x0D806010, Length );
|
||||||
|
write32( 0x0D806018, Length );
|
||||||
|
|
||||||
|
write32( 0x0D806014, (u32)data );
|
||||||
|
|
||||||
|
write32( 0x0D806000, 0x3A );
|
||||||
|
|
||||||
|
write32( 0x0D80601C, 3 );
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
if( read32( 0x0D806000 ) & (1<<2) )
|
||||||
|
{
|
||||||
|
set32( 0x0D806000, (1<<2) );
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if( read32( 0x0D806000 ) & (1<<4) )
|
||||||
|
{
|
||||||
|
set32( 0x0D806000, (1<<4) );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
u32 DVDEnableAudioStreaming( u32 Enable )
|
u32 DVDEnableAudioStreaming( u32 Enable )
|
||||||
{
|
{
|
||||||
write32( 0x0D806004, read32( 0x0D806004 ) );
|
write32( 0x0D806004, read32( 0x0D806004 ) );
|
||||||
|
413
HW.c
413
HW.c
@ -51,88 +51,87 @@ void HWRegWriteBatch( u32 A, u32 B, u32 C, u32 D, u32 delay )
|
|||||||
// DRAMRead( 0x0163 );
|
// DRAMRead( 0x0163 );
|
||||||
// return DRAMRead( 0x0162 );
|
// return DRAMRead( 0x0162 );
|
||||||
//}
|
//}
|
||||||
//void SomeFuncA( void )
|
void SomeFuncA( void )
|
||||||
//{
|
{
|
||||||
// set32( 0xD80018C, 0x400 );
|
set32( 0xD80018C, 0x400 );
|
||||||
// set32( 0xD80018C, 0x800 );
|
set32( 0xD80018C, 0x800 );
|
||||||
//}
|
}
|
||||||
//void SomeFuncD( void )
|
void SomeFuncD( void )
|
||||||
//{
|
{
|
||||||
// u32 cookie = *(vu32*)(0xD8001D8) & 0x7FFFFFFF;
|
u32 cookie = *(vu32*)(0xD8001D8) & 0x7FFFFFFF;
|
||||||
// write32( 0xD8001D8, cookie );
|
write32( 0xD8001D8, cookie );
|
||||||
// udelay(2);
|
udelay(2);
|
||||||
//
|
|
||||||
// write32( 0xD8001D8, cookie & 0xBFFFFFFF );
|
write32( 0xD8001D8, cookie & 0xBFFFFFFF );
|
||||||
// udelay(10);
|
udelay(10);
|
||||||
//
|
|
||||||
// write32( 0xD8001D8, (read32(0xD8001D8) & 0xBFFFFFFF) | 0x40000000 );
|
write32( 0xD8001D8, (read32(0xD8001D8) & 0xBFFFFFFF) | 0x40000000 );
|
||||||
// udelay(50);
|
udelay(50);
|
||||||
//
|
|
||||||
// write32( 0xD8001D8, (read32(0xD8001D8) & 0x7FFFFFFF) | 0x80000000 );
|
write32( 0xD8001D8, (read32(0xD8001D8) & 0x7FFFFFFF) | 0x80000000 );
|
||||||
// udelay(2);
|
udelay(2);
|
||||||
//
|
|
||||||
//}
|
}
|
||||||
//void EHCIInit( void )
|
void EHCIInit( void )
|
||||||
//{
|
{
|
||||||
// //SomeFuncA();
|
SomeFuncA();
|
||||||
//
|
|
||||||
//
|
u32 HWVerFlag = ((*(vu32*)0xD800214) << 0x18) >> 0x1C;
|
||||||
// u32 HWVerFlag = ((*(vu32*)0xD800214) << 0x18) >> 0x1C;
|
|
||||||
//
|
write32( 0xD800088, 0xFE );
|
||||||
// write32( 0xD800088, 0xFE );
|
udelay(2);
|
||||||
// udelay(2);
|
|
||||||
//
|
SomeFuncD();
|
||||||
// SomeFuncD();
|
|
||||||
//
|
write32( 0xD800088, 0xF6 );
|
||||||
// write32( 0xD800088, 0xF6 );
|
udelay(50);
|
||||||
// udelay(50);
|
|
||||||
//
|
write32( 0xD800088, 0xF4 );
|
||||||
// write32( 0xD800088, 0xF4 );
|
udelay(1);
|
||||||
// udelay(1);
|
|
||||||
//
|
write32( 0xD800088, 0xF0 );
|
||||||
// write32( 0xD800088, 0xF0 );
|
udelay(1);
|
||||||
// udelay(1);
|
|
||||||
//
|
write32( 0xD800088, 0x70 );
|
||||||
// write32( 0xD800088, 0x70 );
|
udelay(1);
|
||||||
// udelay(1);
|
|
||||||
//
|
write32( 0xD800088, 0x60 );
|
||||||
// write32( 0xD800088, 0x60 );
|
udelay(1);
|
||||||
// udelay(1);
|
|
||||||
//
|
write32( 0xD800088, 0x40 );
|
||||||
// write32( 0xD800088, 0x40 );
|
udelay(1);
|
||||||
// udelay(1);
|
|
||||||
//
|
write32( 0xD800088, 0x00 );
|
||||||
// write32( 0xD800088, 0x00 );
|
udelay(1);
|
||||||
// udelay(1);
|
|
||||||
//
|
write32( 0xD0400B4, 0x2214 );
|
||||||
// write32( 0xD0400B4, 0x2214 );
|
|
||||||
//
|
if( HWVerFlag == 0 )
|
||||||
// if( HWVerFlag == 0 )
|
{
|
||||||
// {
|
write32( 0xD0400B0, 0x20400 );
|
||||||
// write32( 0xD0400B0, 0x20400 );
|
} else {
|
||||||
// } else {
|
write32( 0xD0400B0, 0x20600 );
|
||||||
// write32( 0xD0400B0, 0x20600 );
|
}
|
||||||
// }
|
|
||||||
//
|
write32( 0xD0400A4, 0x26 );
|
||||||
// write32( 0xD0400A4, 0x26 );
|
udelay(1);
|
||||||
// udelay(1);
|
|
||||||
//
|
write32( 0xD0400A4, 0x2026 );
|
||||||
// write32( 0xD0400A4, 0x2026 );
|
udelay(1);
|
||||||
// udelay(1);
|
|
||||||
//
|
write32( 0xD0400A4, 0x4026 );
|
||||||
// write32( 0xD0400A4, 0x4026 );
|
udelay(20);
|
||||||
// udelay(20);
|
|
||||||
//
|
write32( 0xD0400CC, 0x111 );
|
||||||
// write32( 0xD0400CC, 0x111 );
|
udelay(1);
|
||||||
// udelay(1);
|
|
||||||
//
|
//set32( 0xD800194, 0x7FDFBCF );
|
||||||
// //set32( 0xD800194, 0x7FDFBCF );
|
|
||||||
//
|
write32( 0xD8001E0, 0x65244A );
|
||||||
// write32( 0xD8001E0, 0x65244A );
|
write32( 0xD8001E4, 0x46A024 );
|
||||||
// write32( 0xD8001E4, 0x46A024 );
|
|
||||||
//
|
return;
|
||||||
// return;
|
}
|
||||||
//}
|
|
||||||
void Shutdown( void )
|
void Shutdown( void )
|
||||||
{
|
{
|
||||||
udelay(200);
|
udelay(200);
|
||||||
@ -196,13 +195,13 @@ void DRAMInit( u32 A, u32 B )
|
|||||||
}
|
}
|
||||||
void HWMAgic( u32 R0, u32 R1, u32 R2, u32 R3 )
|
void HWMAgic( u32 R0, u32 R1, u32 R2, u32 R3 )
|
||||||
{
|
{
|
||||||
u32 /*R10,R11,R7,R8,R9,*/value;
|
u32 R10,R11,R7,R8,R9,value;
|
||||||
|
|
||||||
R3 = R3 << 24;
|
R3 = R3 << 24;
|
||||||
SP[1] = R3 >> 24;
|
SP[1] = R3 >> 24;
|
||||||
SP[2] = R0;
|
SP[2] = R0;
|
||||||
|
|
||||||
// R10 = (R1<<16)>>16;
|
R10 = (R1<<16)>>16;
|
||||||
|
|
||||||
//if( read32( HW_RESETS ) & 0x800 )
|
//if( read32( HW_RESETS ) & 0x800 )
|
||||||
//{
|
//{
|
||||||
@ -596,121 +595,121 @@ void MIOSUnkInit( void )
|
|||||||
udelay(2);
|
udelay(2);
|
||||||
|
|
||||||
}
|
}
|
||||||
//void MIOSEHCISub( void )
|
void MIOSEHCISub( void )
|
||||||
//{
|
{
|
||||||
// u32 v = read32( 0xD8001D8 ) & 0x7FFFFFFF;
|
u32 v = read32( 0xD8001D8 ) & 0x7FFFFFFF;
|
||||||
//
|
|
||||||
// write32( 0xD8001D8, v );
|
write32( 0xD8001D8, v );
|
||||||
// udelay(2);
|
udelay(2);
|
||||||
//
|
|
||||||
// write32( 0xD8001D8, v & 0xBFFFFFFF );
|
write32( 0xD8001D8, v & 0xBFFFFFFF );
|
||||||
// udelay(10);
|
udelay(10);
|
||||||
//
|
|
||||||
// write32( 0xD8001D8, ( read32( 0xD8001D8 ) & 0xBFFFFFFF ) | 0x40000000 );
|
write32( 0xD8001D8, ( read32( 0xD8001D8 ) & 0xBFFFFFFF ) | 0x40000000 );
|
||||||
// udelay(50);
|
udelay(50);
|
||||||
//
|
|
||||||
// write32( 0xD8001D8, ( read32( 0xD8001D8 ) & 0x7FFFFFFF ) | 0x80000000 );
|
write32( 0xD8001D8, ( read32( 0xD8001D8 ) & 0x7FFFFFFF ) | 0x80000000 );
|
||||||
// udelay(2);
|
udelay(2);
|
||||||
//}
|
}
|
||||||
//char EHCIData[] = {
|
char EHCIData[] = {
|
||||||
// 0x02, 0x00, 0x00, 0x00,
|
0x02, 0x00, 0x00, 0x00,
|
||||||
// 0x04, 0x00, 0x00, 0x00,
|
0x04, 0x00, 0x00, 0x00,
|
||||||
// 0x05, 0x0F, 0x00, 0x00,
|
0x05, 0x0F, 0x00, 0x00,
|
||||||
//};
|
};
|
||||||
//void MIOSEHCISub2( u32 A )
|
void MIOSEHCISub2( u32 A )
|
||||||
//{
|
{
|
||||||
// if( A > 2 )
|
if( A > 2 )
|
||||||
// A = 2;
|
A = 2;
|
||||||
//
|
|
||||||
// A <<= 2;
|
A <<= 2;
|
||||||
//
|
|
||||||
// u32 R1 = *(u8*)(EHCIData+A);
|
u32 R1 = *(u8*)(EHCIData+A);
|
||||||
// u32 R3 = *(u8*)(EHCIData+A+1);
|
u32 R3 = *(u8*)(EHCIData+A+1);
|
||||||
//
|
|
||||||
// R1 &= 0xF;
|
R1 &= 0xF;
|
||||||
// R3 &= 0xF;
|
R3 &= 0xF;
|
||||||
//
|
|
||||||
//u32 R4 = R1 << 8;
|
u32 R4 = R1 << 8;
|
||||||
// R3 = R3 << 0x17;
|
R3 = R3 << 0x17;
|
||||||
//
|
|
||||||
// R4 = R4 | R3;
|
R4 = R4 | R3;
|
||||||
//u32 R2 = R1 << 2;
|
u32 R2 = R1 << 2;
|
||||||
// R2 = R2 + R1;
|
R2 = R2 + R1;
|
||||||
// R4 = R4 | 0x2014;
|
R4 = R4 | 0x2014;
|
||||||
//
|
|
||||||
// R2 = R2 - 4;
|
R2 = R2 - 4;
|
||||||
// R2 = R2 & 0xFF;
|
R2 = R2 & 0xFF;
|
||||||
//
|
|
||||||
// R2 = R2 << 8;
|
R2 = R2 << 8;
|
||||||
// R2 = R2 | 0x20000;
|
R2 = R2 | 0x20000;
|
||||||
//
|
|
||||||
// write32( 0xD0400B4, R4 );
|
write32( 0xD0400B4, R4 );
|
||||||
// write32( 0xD0400B0, R2 );
|
write32( 0xD0400B0, R2 );
|
||||||
//}
|
}
|
||||||
//void MIOSEHCIInit( u32 A )
|
void MIOSEHCIInit( u32 A )
|
||||||
//{
|
{
|
||||||
// write32( 0xD800088, 0xFE );
|
write32( 0xD800088, 0xFE );
|
||||||
// udelay(2);
|
udelay(2);
|
||||||
//
|
|
||||||
// MIOSEHCISub();
|
MIOSEHCISub();
|
||||||
//
|
|
||||||
// write32( 0xD800088, 0xF6 );
|
write32( 0xD800088, 0xF6 );
|
||||||
// udelay(50);
|
udelay(50);
|
||||||
//
|
|
||||||
// write32( 0xD800088, 0xF4 );
|
write32( 0xD800088, 0xF4 );
|
||||||
// udelay(1);
|
udelay(1);
|
||||||
//
|
|
||||||
// write32( 0xD800088, 0xF0 );
|
write32( 0xD800088, 0xF0 );
|
||||||
// udelay(1);
|
udelay(1);
|
||||||
//
|
|
||||||
// write32( 0xD800088, 0x70 );
|
write32( 0xD800088, 0x70 );
|
||||||
// udelay(1);
|
udelay(1);
|
||||||
//
|
|
||||||
// write32( 0xD800088, 0x60 );
|
write32( 0xD800088, 0x60 );
|
||||||
// udelay(1);
|
udelay(1);
|
||||||
//
|
|
||||||
// write32( 0xD800088, 0x40 );
|
write32( 0xD800088, 0x40 );
|
||||||
// udelay(1);
|
udelay(1);
|
||||||
//
|
|
||||||
// write32( 0xD800088, 0x00 );
|
write32( 0xD800088, 0x00 );
|
||||||
// udelay(1);
|
udelay(1);
|
||||||
//
|
|
||||||
// MIOSEHCISub2( A );
|
MIOSEHCISub2( A );
|
||||||
//
|
|
||||||
// if( A > 1 )
|
if( A > 1 )
|
||||||
// {
|
{
|
||||||
// write32( 0xD0400A4, 0x23 );
|
write32( 0xD0400A4, 0x23 );
|
||||||
// udelay(1);
|
udelay(1);
|
||||||
// write32( 0xD0400A4, 0x2023 );
|
write32( 0xD0400A4, 0x2023 );
|
||||||
// udelay(1);
|
udelay(1);
|
||||||
// write32( 0xD0400A4, 0x4023 );
|
write32( 0xD0400A4, 0x4023 );
|
||||||
// udelay(20);
|
udelay(20);
|
||||||
// } else {
|
} else {
|
||||||
// write32( 0xD0400A4, 0x26 );
|
write32( 0xD0400A4, 0x26 );
|
||||||
// udelay(1);
|
udelay(1);
|
||||||
// write32( 0xD0400A4, 0x2026 );
|
write32( 0xD0400A4, 0x2026 );
|
||||||
// udelay(1);
|
udelay(1);
|
||||||
// write32( 0xD0400A4, 0x4026 );
|
write32( 0xD0400A4, 0x4026 );
|
||||||
// udelay(20);
|
udelay(20);
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// write32( 0xD0400CC, 0x111 );
|
write32( 0xD0400CC, 0x111 );
|
||||||
//
|
|
||||||
//}
|
}
|
||||||
//void MIOSEHCIInit2( void )
|
void MIOSEHCIInit2( void )
|
||||||
//{
|
{
|
||||||
// GetRevision( SP+1, SP );
|
GetRevision( SP+1, SP );
|
||||||
//
|
|
||||||
// if( SP[1] <= 1 )
|
if( SP[1] <= 1 )
|
||||||
// {
|
{
|
||||||
// write32( 0xD8001E0, 0x65244A );
|
write32( 0xD8001E0, 0x65244A );
|
||||||
// write32( 0xD8001E4, 0x46A024 );
|
write32( 0xD8001E4, 0x46A024 );
|
||||||
// return;
|
return;
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
//// dbgprintf("Unsupported CPU version!\n");
|
// dbgprintf("Unsupported CPU version!\n");
|
||||||
//
|
|
||||||
//}
|
}
|
||||||
void MIOSHWInit( u32 A, u32 B )
|
void MIOSHWInit( u32 A, u32 B )
|
||||||
{
|
{
|
||||||
GetRevision( SP+1, SP );
|
GetRevision( SP+1, SP );
|
||||||
@ -721,11 +720,11 @@ void MIOSHWInit( u32 A, u32 B )
|
|||||||
|
|
||||||
MIOSUnkInit();
|
MIOSUnkInit();
|
||||||
|
|
||||||
//MIOSEHCIInit( SP[1] );
|
MIOSEHCIInit( SP[1] );
|
||||||
|
|
||||||
set32( HW_RESETS, 0x7FDFBCF );
|
set32( HW_RESETS, 0x7FDFBCF );
|
||||||
|
|
||||||
//MIOSEHCIInit2();
|
MIOSEHCIInit2();
|
||||||
}
|
}
|
||||||
void UNKInit( u32 A, u32 B )
|
void UNKInit( u32 A, u32 B )
|
||||||
{
|
{
|
||||||
@ -927,7 +926,7 @@ void MEMInitLow( void )
|
|||||||
write32( 0x00F0, 0x01800000 );
|
write32( 0x00F0, 0x01800000 );
|
||||||
|
|
||||||
write32( 0x0030, 0x00000000 );
|
write32( 0x0030, 0x00000000 );
|
||||||
write32( 0x0034, 0x01800000 );
|
write32( 0x0034, 0x81800000 );
|
||||||
|
|
||||||
write32( 0x00D0, 16*1024*1024 ); //Set ARAM size
|
write32( 0x00D0, 16*1024*1024 ); //Set ARAM size
|
||||||
|
|
||||||
@ -946,11 +945,11 @@ void MEMInitLow( void )
|
|||||||
DRAMCTRLWrite( 0x4A, 0x0E );
|
DRAMCTRLWrite( 0x4A, 0x0E );
|
||||||
DRAMCTRLWrite( 0x0F, 0x08 );
|
DRAMCTRLWrite( 0x0F, 0x08 );
|
||||||
DRAMCTRLWrite( 0x03, 0x0E );
|
DRAMCTRLWrite( 0x03, 0x0E );
|
||||||
DRAMCTRLWrite( 0x49, 0x0E );
|
//DRAMCTRLWrite( 0x49, 0x0E );
|
||||||
udelay(2);
|
//udelay(2);
|
||||||
|
|
||||||
DRAMCTRLWrite( 0x49, 0x0F );
|
//DRAMCTRLWrite( 0x49, 0x0F );
|
||||||
udelay(2);
|
//udelay(2);
|
||||||
|
|
||||||
DRAMWrite( 0x113, 631 );
|
DRAMWrite( 0x113, 631 );
|
||||||
|
|
||||||
@ -1031,7 +1030,7 @@ void MEMInitLow( void )
|
|||||||
|
|
||||||
val |= 0x00000040;
|
val |= 0x00000040;
|
||||||
val &= ~0x00200000;
|
val &= ~0x00200000;
|
||||||
//val |= 0x00200000; // Enable DVD-R access by NOT setting this bit
|
val |= 0x00200000;
|
||||||
val &= ~0x00400000;
|
val &= ~0x00400000;
|
||||||
val |= 0x00400000;
|
val |= 0x00400000;
|
||||||
val &= ~0x00001000;
|
val &= ~0x00001000;
|
||||||
|
13
Makefile
13
Makefile
@ -9,20 +9,21 @@ CFLAGS += -fno-builtin-memcpy -fno-builtin-memset -fno-builtin-toupper -fno-buil
|
|||||||
|
|
||||||
ASFLAGS = -mbig-endian -mcpu=arm926ej-s
|
ASFLAGS = -mbig-endian -mcpu=arm926ej-s
|
||||||
|
|
||||||
LDFLAGS = -nostartfiles -nodefaultlibs -mbig-endian -Wl,-T,diosmioslite.ld,-Map,diosmioslite.map -n
|
LDFLAGS = -nostartfiles -nodefaultlibs -mbig-endian -Wl,-T,iosmodule.ld,-Map,iosmodule.map -n
|
||||||
|
|
||||||
LIBS = -lgcc
|
LIBS = -lgcc
|
||||||
|
|
||||||
TARGET = diosmioslite.elf
|
TARGET = iosmodule.elf
|
||||||
OBJECTS = start.o utils_asm.o HW.o Card.o memory.o memory_asm.o Config.o common.o sdhc.o ff.o sdmmc.o diskio.o alloc.o Drive.o DVD.o dip.o Patches.o main.o vsprintf.o string.o
|
OBJECTS = start.o utils_asm.o HW.o Card.o memory.o memory_asm.o Config.o common.o ff.o diskio.o alloc.o Drive.o DVD.o dip.o Patches.o main.o vsprintf.o string.o tiny_ehci_glue.o usb_os.o
|
||||||
.PHONY: FORCE
|
.PHONY: FORCE
|
||||||
|
|
||||||
all: $(TARGET)
|
all: $(TARGET)
|
||||||
|
|
||||||
$(TARGET) : diosmioslite.ld $(OBJECTS)
|
$(TARGET) : iosmodule.ld $(OBJECTS)
|
||||||
@echo "LD $@"
|
@echo "LD $@"
|
||||||
@$(LD) $(LDFLAGS) $(OBJECTS) $(LIBS) -o $@
|
@$(LD) $(LDFLAGS) $(OBJECTS) $(LIBS) -o $@
|
||||||
@$(SSTRIP) -s $@
|
@echo $(SSTRIP) -s $@
|
||||||
|
|
||||||
|
|
||||||
%.o : %.s
|
%.o : %.s
|
||||||
@echo "AS $@"
|
@echo "AS $@"
|
||||||
@ -46,9 +47,7 @@ $(TARGET) : diosmioslite.ld $(OBJECTS)
|
|||||||
@echo "DEP $@"
|
@echo "DEP $@"
|
||||||
@touch $@
|
@touch $@
|
||||||
|
|
||||||
ifneq ($(MAKECMDGOALS),clean)
|
|
||||||
-include $(OBJECTS:.o=.d)
|
-include $(OBJECTS:.o=.d)
|
||||||
endif
|
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
-rm -f *.elf *.o *.bin *.d *.map
|
-rm -f *.elf *.o *.bin *.d *.map
|
||||||
|
12
Patches.c
12
Patches.c
@ -763,14 +763,14 @@ void DoPatches( char *ptr, u32 size, u32 SectionOffset )
|
|||||||
|
|
||||||
u32 DBGSize;
|
u32 DBGSize;
|
||||||
|
|
||||||
if( ConfigGetConfig( DML_CFG_DEBUGGER ) )
|
//if( ConfigGetConfig( DML_CFG_DEBUGGER ) )
|
||||||
{
|
//{
|
||||||
memcpy( (void*)0x1800, kenobigcDBG, sizeof(kenobigcDBG) );
|
memcpy( (void*)0x1800, kenobigcDBG, sizeof(kenobigcDBG) );
|
||||||
DBGSize = sizeof(kenobigcDBG);
|
DBGSize = sizeof(kenobigcDBG);
|
||||||
} else {
|
//} else {
|
||||||
memcpy( (void*)0x1800, kenobigc, sizeof(kenobigc) );
|
// memcpy( (void*)0x1800, kenobigc, sizeof(kenobigc) );
|
||||||
DBGSize = sizeof(kenobigc);
|
// DBGSize = sizeof(kenobigc);
|
||||||
}
|
//}
|
||||||
|
|
||||||
if( ConfigGetConfig(DML_CFG_DEBUGWAIT) )
|
if( ConfigGetConfig(DML_CFG_DEBUGWAIT) )
|
||||||
write32( P2C(read32(0x1808)), 1 );
|
write32( P2C(read32(0x1808)), 1 );
|
||||||
|
35
alloc.c
35
alloc.c
@ -1,36 +1,43 @@
|
|||||||
#include "alloc.h"
|
#include "alloc.h"
|
||||||
#include "vsprintf.h"
|
#include "vsprintf.h"
|
||||||
|
|
||||||
u8 *RAM;
|
u8 *RAM;//[_AHEAP_SIZE_TOTAL];
|
||||||
HeapInfoEntry *HeapInfoEntries=NULL;
|
HeapInfoEntry *HeapInfoEntries=(HeapInfoEntry *)NULL;
|
||||||
|
|
||||||
extern u32 DRAMRead( u32 a );
|
extern u32 DRAMRead( u32 a );
|
||||||
extern void DRAMWrite( u32 a, u32 b );
|
extern void DRAMWrite( u32 a, u32 b );
|
||||||
|
|
||||||
void HeapInit( void )
|
void HeapInit( u8 *Offset )
|
||||||
{
|
{
|
||||||
RAM = (u8*)0xFFFE4000;
|
//RAM = (u8*)0xFFFE4000;
|
||||||
|
//RAM = (u8*)0x13600000;
|
||||||
|
//RAM = (u8*)0x00600000;
|
||||||
|
|
||||||
|
RAM = Offset;
|
||||||
|
|
||||||
HeapInfoEntries = (HeapInfoEntry*)(RAM+_AHEAP_SIZE);
|
HeapInfoEntries = (HeapInfoEntry*)(RAM+_AHEAP_SIZE);
|
||||||
memset32( HeapInfoEntries, 0, _AHEAP_INFO_SIZE );
|
memset32( HeapInfoEntries, 0, _AHEAP_INFO_SIZE );
|
||||||
|
|
||||||
while( HeapInfoEntries[0].Offset != 0 )
|
while( HeapInfoEntries[0].Offset != 0 )
|
||||||
{
|
{
|
||||||
dbgprintf("Failed to clear memory!");
|
EXIControl(1);
|
||||||
|
dbgprintf("Alloc:Failed to clear memory!:%08X", HeapInfoEntries[0].Offset );
|
||||||
Shutdown();
|
Shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
// dbgprintf("Cleared 0x%04X bytes Space for %d allocs\n", _AHEAP_INFO_SIZE, _AHEAP_INFO_SIZE / 8 );
|
// dbgprintf("Cleared 0x%04X bytes Space for %d allocs\n", _AHEAP_INFO_SIZE, _AHEAP_INFO_SIZE / 8 );
|
||||||
|
|
||||||
}
|
}
|
||||||
void *malloc( u32 size )
|
void *malloc( u32 _size )
|
||||||
{
|
{
|
||||||
if( size == 0 )
|
if( _size == 0 )
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if( size > _AHEAP_SIZE )
|
if( _size > _AHEAP_SIZE )
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
//align size to 32, easy cheat toallow all allocs to be aligned easily
|
//align size to 32, easy cheat toallow all allocs to be aligned easily
|
||||||
size = (size+0x1F) & (~0x1F);
|
u32 size = (_size+0x1F) & (~0x1F);
|
||||||
|
|
||||||
//find a free entry to be used
|
//find a free entry to be used
|
||||||
u32 entry = 0xdeadbeef;
|
u32 entry = 0xdeadbeef;
|
||||||
@ -44,13 +51,15 @@ void *malloc( u32 size )
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( entry == 0xdeadbeef )
|
if( entry == 0xdeadbeef )
|
||||||
{
|
{
|
||||||
dbgprintf("run out of entries!\n");
|
EXIControl(1);
|
||||||
return NULL;
|
dbgprintf("Alloc: run out of entries!\n");
|
||||||
|
while(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
//dbgprintf("Using entry:%d to alloc %d bytes...\n", entry, size );
|
//dbgprintf("Alloc:Using entry:%d to alloc %u(%u) bytes...\n", entry, size, _size );
|
||||||
|
|
||||||
//Now we search a used entry
|
//Now we search a used entry
|
||||||
u32 used_entry = 0xdeadbeef;
|
u32 used_entry = 0xdeadbeef;
|
||||||
@ -168,7 +177,7 @@ find_space:
|
|||||||
if( used_entry != 0xdeadbeef )
|
if( used_entry != 0xdeadbeef )
|
||||||
goto find_space;
|
goto find_space;
|
||||||
|
|
||||||
dbgprintf("failed to alloc %d bytes\n", size );
|
dbgprintf("Alloc:failed to alloc %d bytes\n", size );
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
4
alloc.h
4
alloc.h
@ -5,7 +5,7 @@
|
|||||||
#ifndef _ALLOC_
|
#ifndef _ALLOC_
|
||||||
#define _ALLOC_
|
#define _ALLOC_
|
||||||
|
|
||||||
#define _AHEAP_SIZE_TOTAL 0x4000
|
#define _AHEAP_SIZE_TOTAL 0x3000
|
||||||
#define _AHEAP_INFO_SIZE 0x0100
|
#define _AHEAP_INFO_SIZE 0x0100
|
||||||
#define _AHEAP_SIZE _AHEAP_SIZE_TOTAL-_AHEAP_INFO_SIZE
|
#define _AHEAP_SIZE _AHEAP_SIZE_TOTAL-_AHEAP_INFO_SIZE
|
||||||
|
|
||||||
@ -15,7 +15,7 @@ typedef struct
|
|||||||
u32 Size;
|
u32 Size;
|
||||||
} HeapInfoEntry;
|
} HeapInfoEntry;
|
||||||
|
|
||||||
void HeapInit( void );
|
void HeapInit( u8 *Offset );
|
||||||
void *malloc( u32 size );
|
void *malloc( u32 size );
|
||||||
void *malloca( u32 size, u32 align );
|
void *malloca( u32 size, u32 align );
|
||||||
void free( void *ptr );
|
void free( void *ptr );
|
||||||
|
@ -2,11 +2,7 @@
|
|||||||
#define __BSDTYPES_H__
|
#define __BSDTYPES_H__
|
||||||
|
|
||||||
#include "global.h"
|
#include "global.h"
|
||||||
|
#include "errno.h"
|
||||||
#define ENXIO 6
|
|
||||||
#define EINVAL 22
|
|
||||||
#define WSAETIMEDOUT 10060L
|
|
||||||
#define ETIMEDOUT WSAETIMEDOUT
|
|
||||||
|
|
||||||
typedef u32 u_int;
|
typedef u32 u_int;
|
||||||
//typedef u32 u_int32_t;
|
//typedef u32 u_int32_t;
|
||||||
|
9
dip.c
9
dip.c
@ -46,6 +46,8 @@ void DIInit( void )
|
|||||||
|
|
||||||
write32( DI_SCONFIG, 0xFF );
|
write32( DI_SCONFIG, 0xFF );
|
||||||
write32( DI_SCOVER, 0 );
|
write32( DI_SCOVER, 0 );
|
||||||
|
|
||||||
|
write32( HW_TIMER, 0 );
|
||||||
}
|
}
|
||||||
u32 DIUpdateRegisters( void )
|
u32 DIUpdateRegisters( void )
|
||||||
{
|
{
|
||||||
@ -365,5 +367,12 @@ u32 DIUpdateRegisters( void )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( (u64)read32(HW_TIMER) >= 25 * 243000000LL / 128 )
|
||||||
|
{
|
||||||
|
USBStorage_Read_Sectors( (read32(HW_TIMER) << 3) & 0x000FFFFF, 1, (void*)0x1000 );
|
||||||
|
|
||||||
|
write32( HW_TIMER, 0 );
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
1
dip.h
1
dip.h
@ -13,6 +13,7 @@
|
|||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
#include "DVD.h"
|
#include "DVD.h"
|
||||||
#include "elf.h"
|
#include "elf.h"
|
||||||
|
#include "usbstorage.h"
|
||||||
|
|
||||||
enum opcodes
|
enum opcodes
|
||||||
{
|
{
|
||||||
|
51
diskio.c
51
diskio.c
@ -1,30 +1,55 @@
|
|||||||
#include "diskio.h"
|
#include "diskio.h"
|
||||||
#include "string.h"
|
#include "string.h"
|
||||||
#include "sdmmc.h"
|
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
|
|
||||||
|
extern u32 IsInit;
|
||||||
|
|
||||||
DSTATUS disk_initialize( BYTE drv )
|
DSTATUS disk_initialize( BYTE drv )
|
||||||
{
|
{
|
||||||
if (sdmmc_check_card() == SDMMC_NO_CARD)
|
s32 r, s_cnt;
|
||||||
return STA_NOINIT;
|
u32 s_size;
|
||||||
|
|
||||||
|
while( 1 )
|
||||||
|
{
|
||||||
|
udelay( 50000 );
|
||||||
|
|
||||||
|
tiny_ehci_init();
|
||||||
|
|
||||||
|
int ret = -ENODEV;
|
||||||
|
|
||||||
|
do {
|
||||||
|
|
||||||
|
udelay( 4000 );
|
||||||
|
ret = ehci_discover();
|
||||||
|
|
||||||
|
} while( ret == -ENODEV );
|
||||||
|
|
||||||
|
dbgprintf("ehci_discover():%d\n", ret );
|
||||||
|
|
||||||
|
r = USBStorage_Init();
|
||||||
|
|
||||||
|
if( r == 0 )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
s_cnt = USBStorage_Get_Capacity( &s_size );
|
||||||
|
|
||||||
|
dbgprintf( "DIP: Drive size: %dMB SectorSize:%d\n", s_cnt / 1024 * s_size / 1024, s_size);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
|
||||||
sdmmc_ack_card();
|
|
||||||
return disk_status(drv);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DSTATUS disk_status( BYTE drv )
|
DSTATUS disk_status( BYTE drv )
|
||||||
{
|
{
|
||||||
(void)drv;
|
(void)drv;
|
||||||
if (sdmmc_check_card() == SDMMC_INSERTED)
|
|
||||||
return 0;
|
return 0;
|
||||||
else
|
|
||||||
return STA_NODISK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DRESULT disk_read( BYTE drv, BYTE *buff, DWORD sector, BYTE count )
|
DRESULT disk_read( BYTE drv, BYTE *buff, DWORD sector, BYTE count )
|
||||||
{
|
{
|
||||||
u8 *buffer = (u8*)buff;
|
u8 *buffer = (u8*)buff;
|
||||||
//dbgprintf("sdmmc_read( %d, %d, %p, %p)\n", sector, count, buff, buffer );
|
//dbgprintf("disk_read( %d, %d, %p, %p)\n", sector, count, buff, buffer );
|
||||||
|
|
||||||
if( (u32)buff & 0xF0000000 )
|
if( (u32)buff & 0xF0000000 )
|
||||||
{
|
{
|
||||||
@ -36,7 +61,7 @@ DRESULT disk_read( BYTE drv, BYTE *buff, DWORD sector, BYTE count )
|
|||||||
if( (count-i) < Blocks )
|
if( (count-i) < Blocks )
|
||||||
Blocks = (count-i);
|
Blocks = (count-i);
|
||||||
|
|
||||||
sdmmc_read( sector + i, Blocks, buffer );
|
USBStorage_Read_Sectors( sector + i, Blocks, buffer );
|
||||||
memcpy( buff + i * 512, buffer, Blocks * 512 );
|
memcpy( buff + i * 512, buffer, Blocks * 512 );
|
||||||
|
|
||||||
i+=Blocks;
|
i+=Blocks;
|
||||||
@ -45,7 +70,7 @@ DRESULT disk_read( BYTE drv, BYTE *buff, DWORD sector, BYTE count )
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
sdmmc_read( sector, count, buffer );
|
USBStorage_Read_Sectors( sector, count, buffer );
|
||||||
dc_flushrange( buffer, count*512 );
|
dc_flushrange( buffer, count*512 );
|
||||||
ahb_flush_from( AHB_SDHC );
|
ahb_flush_from( AHB_SDHC );
|
||||||
}
|
}
|
||||||
@ -64,12 +89,12 @@ DRESULT disk_write( BYTE drv, const BYTE *buff, DWORD sector, BYTE count )
|
|||||||
for( i=0; i < count; ++i )
|
for( i=0; i < count; ++i )
|
||||||
{
|
{
|
||||||
memcpy( buffer, (void*)buff + i * 512, 512 );
|
memcpy( buffer, (void*)buff + i * 512, 512 );
|
||||||
sdmmc_write( sector + i, 1, buffer );
|
USBStorage_Write_Sectors( sector + i, 1, buffer );
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
ahb_flush_to( AHB_SDHC );
|
ahb_flush_to( AHB_SDHC );
|
||||||
sdmmc_write( sector, count, buffer );
|
USBStorage_Write_Sectors( sector, count, buffer );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
64
diskio.h
64
diskio.h
@ -1,14 +1,31 @@
|
|||||||
/*-----------------------------------------------------------------------
|
/*-----------------------------------------------------------------------
|
||||||
/ Low level disk interface modlue include file
|
/ Low level disk interface modlue include file R0.07 (C)ChaN, 2009
|
||||||
/-----------------------------------------------------------------------*/
|
/-----------------------------------------------------------------------
|
||||||
|
/ FatFs module is an open source project to implement FAT file system to small
|
||||||
|
/ embedded systems. It is opened for education, research and development under
|
||||||
|
/ license policy of following trems.
|
||||||
|
/
|
||||||
|
/ Copyright (C) 2009, ChaN, all right reserved.
|
||||||
|
/
|
||||||
|
/ * The FatFs module is a free software and there is no warranty.
|
||||||
|
/ * You can use, modify and/or redistribute it for personal, non-profit or
|
||||||
|
/ commercial use without any restriction under your responsibility.
|
||||||
|
/ * Redistributions of source code must retain the above copyright notice.
|
||||||
|
/
|
||||||
|
/----------------------------------------------------------------------------*/
|
||||||
|
// original source: http://elm-chan.org/fsw/ff/00index_e.html
|
||||||
|
|
||||||
#ifndef _DISKIO
|
#ifndef _DISKIO
|
||||||
|
|
||||||
#define _READONLY 0 /* 1: Remove write functions */
|
#define _READONLY 0 /* 1: Read-only mode */
|
||||||
#define _USE_IOCTL 1 /* 1: Use disk_ioctl fucntion */
|
#define _USE_IOCTL 1
|
||||||
|
|
||||||
#include "integer.h"
|
#include "integer.h"
|
||||||
|
#include "string.h"
|
||||||
|
#include "ehci.h"
|
||||||
|
#include "alloc.h"
|
||||||
|
#include "tiny_ehci_glue.h"
|
||||||
|
#include "dip.h"
|
||||||
|
|
||||||
/* Status of Disk Functions */
|
/* Status of Disk Functions */
|
||||||
typedef BYTE DSTATUS;
|
typedef BYTE DSTATUS;
|
||||||
@ -26,15 +43,15 @@ typedef enum {
|
|||||||
/*---------------------------------------*/
|
/*---------------------------------------*/
|
||||||
/* Prototypes for disk control functions */
|
/* Prototypes for disk control functions */
|
||||||
|
|
||||||
int assign_drives (int, int);
|
|
||||||
DSTATUS disk_initialize (BYTE);
|
DSTATUS disk_initialize (BYTE);
|
||||||
DSTATUS disk_status (BYTE);
|
DSTATUS disk_status (BYTE);
|
||||||
DRESULT disk_read (BYTE, BYTE*, DWORD, BYTE);
|
DRESULT disk_read (BYTE, BYTE*, DWORD, BYTE);
|
||||||
#if _READONLY == 0
|
#if _READONLY == 0
|
||||||
DRESULT disk_write (BYTE, const BYTE*, DWORD, BYTE);
|
DRESULT disk_write (BYTE, const BYTE*, DWORD, BYTE);
|
||||||
#endif
|
#endif
|
||||||
|
#if _USE_IOCTL == 1
|
||||||
DRESULT disk_ioctl (BYTE, BYTE, void*);
|
DRESULT disk_ioctl (BYTE, BYTE, void*);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* Disk Status Bits (DSTATUS) */
|
/* Disk Status Bits (DSTATUS) */
|
||||||
@ -44,35 +61,10 @@ DRESULT disk_ioctl (BYTE, BYTE, void*);
|
|||||||
#define STA_PROTECT 0x04 /* Write protected */
|
#define STA_PROTECT 0x04 /* Write protected */
|
||||||
|
|
||||||
|
|
||||||
/* Command code for disk_ioctrl fucntion */
|
#if _USE_IOCTL == 1
|
||||||
|
/* Command code for disk_ioctl() */
|
||||||
/* Generic command (defined for FatFs) */
|
#define CTRL_SYNC 0 /* Mandatory for write functions */
|
||||||
#define CTRL_SYNC 0 /* Flush disk cache (for write functions) */
|
#endif
|
||||||
#define GET_SECTOR_COUNT 1 /* Get media size (for only f_mkfs()) */
|
|
||||||
#define GET_SECTOR_SIZE 2 /* Get sector size (for multiple sector size (_MAX_SS >= 1024)) */
|
|
||||||
#define GET_BLOCK_SIZE 3 /* Get erase block size (for only f_mkfs()) */
|
|
||||||
#define CTRL_ERASE_SECTOR 4 /* Force erased a block of sectors (for only _USE_ERASE) */
|
|
||||||
|
|
||||||
/* Generic command */
|
|
||||||
#define CTRL_POWER 5 /* Get/Set power status */
|
|
||||||
#define CTRL_LOCK 6 /* Lock/Unlock media removal */
|
|
||||||
#define CTRL_EJECT 7 /* Eject media */
|
|
||||||
|
|
||||||
/* MMC/SDC specific ioctl command */
|
|
||||||
#define MMC_GET_TYPE 10 /* Get card type */
|
|
||||||
#define MMC_GET_CSD 11 /* Get CSD */
|
|
||||||
#define MMC_GET_CID 12 /* Get CID */
|
|
||||||
#define MMC_GET_OCR 13 /* Get OCR */
|
|
||||||
#define MMC_GET_SDSTAT 14 /* Get SD status */
|
|
||||||
|
|
||||||
/* ATA/CF specific ioctl command */
|
|
||||||
#define ATA_GET_REV 20 /* Get F/W revision */
|
|
||||||
#define ATA_GET_MODEL 21 /* Get model name */
|
|
||||||
#define ATA_GET_SN 22 /* Get serial number */
|
|
||||||
|
|
||||||
/* NAND specific ioctl command */
|
|
||||||
#define NAND_FORMAT 30 /* Create physical format */
|
|
||||||
|
|
||||||
|
|
||||||
#define _DISKIO
|
#define _DISKIO
|
||||||
#endif
|
#endif
|
||||||
|
78
ehci-mem.c
Normal file
78
ehci-mem.c
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
* Original Copyright (c) 2001 by David Brownell
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 2 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* this file is part of ehci.c */
|
||||||
|
|
||||||
|
|
||||||
|
static inline void ehci_qtd_init(struct ehci_qtd *qtd
|
||||||
|
)
|
||||||
|
{
|
||||||
|
dma_addr_t dma = ehci_virt_to_dma(qtd);
|
||||||
|
memset (qtd, 0, sizeof *qtd);
|
||||||
|
qtd->qtd_dma = dma;
|
||||||
|
qtd->hw_token = (QTD_STS_HALT);
|
||||||
|
qtd->hw_next = EHCI_LIST_END();
|
||||||
|
qtd->hw_alt_next = EHCI_LIST_END();
|
||||||
|
}
|
||||||
|
static inline struct ehci_qtd * ehci_qtd_alloc(void)
|
||||||
|
{
|
||||||
|
struct ehci_qtd *qtd ;
|
||||||
|
//debug_printf("ehci_qtd used=%x\n",ehci->qtd_used);
|
||||||
|
BUG_ON(ehci->qtd_used>=EHCI_MAX_QTD);
|
||||||
|
qtd = ehci->qtds[ehci->qtd_used++];
|
||||||
|
ehci_qtd_init(qtd);
|
||||||
|
return qtd;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ehci_mem_init (void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
u32 ptr = 0x1800000 - DEFAULT_I_TDPS * sizeof(__le32);
|
||||||
|
|
||||||
|
ehci->periodic = (u32*)ptr;
|
||||||
|
ehci->periodic_dma = ehci_virt_to_dma(ehci->periodic);
|
||||||
|
|
||||||
|
for (i = 0; i < DEFAULT_I_TDPS; i++)
|
||||||
|
ehci->periodic[i] = EHCI_LIST_END();
|
||||||
|
|
||||||
|
ehci_writel( ehci->periodic_dma, &ehci->regs->frame_list );
|
||||||
|
|
||||||
|
for(i=0;i<EHCI_MAX_QTD;i++)
|
||||||
|
{
|
||||||
|
ptr -= sizeof(struct ehci_qtd);
|
||||||
|
ehci->qtds[i] = (struct ehci_qtd*)(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
ehci->qtd_used = 0;
|
||||||
|
|
||||||
|
ptr -= sizeof(struct ehci_qh);
|
||||||
|
ehci->asyncqh = (struct ehci_qh*)ptr;
|
||||||
|
|
||||||
|
ehci->asyncqh->ehci = ehci;
|
||||||
|
ehci->asyncqh->qh_dma = ehci_virt_to_dma(ehci->asyncqh);
|
||||||
|
ehci->asyncqh->qtd_head = NULL;
|
||||||
|
|
||||||
|
ptr -= sizeof(struct ehci_qh);
|
||||||
|
ehci->async = (struct ehci_qh*)ptr;
|
||||||
|
|
||||||
|
ehci->async->ehci = ehci;
|
||||||
|
ehci->async->qh_dma = ehci_virt_to_dma(ehci->async);
|
||||||
|
ehci->async->qtd_head = NULL;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
832
ehci.c
Normal file
832
ehci.c
Normal file
@ -0,0 +1,832 @@
|
|||||||
|
/* simplest usb-ehci driver which features:
|
||||||
|
|
||||||
|
control and bulk transfers only
|
||||||
|
only one transfer pending
|
||||||
|
driver is synchronous (waiting for the end of the transfer)
|
||||||
|
endianess independant
|
||||||
|
no uncached memory allocation needed
|
||||||
|
|
||||||
|
this driver is originally based on the GPL linux ehci-hcd driver
|
||||||
|
|
||||||
|
* Original Copyright (c) 2001 by David Brownell
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 2 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* magic numbers that can affect system performance */
|
||||||
|
|
||||||
|
u32 IsInit = 0;
|
||||||
|
|
||||||
|
#undef DEBUG
|
||||||
|
|
||||||
|
#define EHCI_TUNE_CERR 3 /* 0-3 qtd retries; 0 == don't stop */
|
||||||
|
#define EHCI_TUNE_RL_HS 4 /* nak throttle; see 4.9 */
|
||||||
|
#define EHCI_TUNE_RL_TT 0
|
||||||
|
#define EHCI_TUNE_MULT_HS 1 /* 1-3 transactions/uframe; 4.10.3 */
|
||||||
|
#define EHCI_TUNE_MULT_TT 1
|
||||||
|
#define EHCI_TUNE_FLS 2 /* (small) 256 frame schedule */
|
||||||
|
extern int verbose;
|
||||||
|
static void
|
||||||
|
dbg_qtd (const char *label, struct ehci_qtd *qtd)
|
||||||
|
{
|
||||||
|
//ehci_dbg( "%s td %p n%08x %08x t%08x p0=%08x\n", label, qtd,
|
||||||
|
// hc32_to_cpup( &qtd->hw_next),
|
||||||
|
// hc32_to_cpup( &qtd->hw_alt_next),
|
||||||
|
// hc32_to_cpup( &qtd->hw_token),
|
||||||
|
// hc32_to_cpup( &qtd->hw_buf [0]));
|
||||||
|
//if (qtd->hw_buf [1])
|
||||||
|
// ehci_dbg( " p1=%08x p2=%08x p3=%08x p4=%08x\n",
|
||||||
|
// hc32_to_cpup( &qtd->hw_buf[1]),
|
||||||
|
// hc32_to_cpup( &qtd->hw_buf[2]),
|
||||||
|
// hc32_to_cpup( &qtd->hw_buf[3]),
|
||||||
|
// hc32_to_cpup( &qtd->hw_buf[4]));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
dbg_qh (const char *label, struct ehci_qh *qh)
|
||||||
|
{
|
||||||
|
//ehci_dbg ( "%s qh %p n%08x info %x %x qtd %x\n", label,
|
||||||
|
// qh,
|
||||||
|
// hc32_to_cpu(qh->hw_next),
|
||||||
|
// hc32_to_cpu(qh->hw_info1),
|
||||||
|
// hc32_to_cpu(qh->hw_info2),
|
||||||
|
// hc32_to_cpu(qh->hw_current));
|
||||||
|
//dbg_qtd ("overlay", (struct ehci_qtd *) &qh->hw_qtd_next);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
dbg_command (void)
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
u32 command=ehci_readl( &ehci->regs->command);
|
||||||
|
u32 async=ehci_readl( &ehci->regs->async_next);
|
||||||
|
|
||||||
|
ehci_dbg ("async_next: %08x\n",async);
|
||||||
|
ehci_dbg (
|
||||||
|
"command %06x %s=%d ithresh=%d%s%s%s%s %s %s\n",
|
||||||
|
command,
|
||||||
|
(command & CMD_PARK) ? "park" : "(park)",
|
||||||
|
CMD_PARK_CNT (command),
|
||||||
|
(command >> 16) & 0x3f,
|
||||||
|
(command & CMD_LRESET) ? " LReset" : "",
|
||||||
|
(command & CMD_IAAD) ? " IAAD" : "",
|
||||||
|
(command & CMD_ASE) ? " Async" : "",
|
||||||
|
(command & CMD_PSE) ? " Periodic" : "",
|
||||||
|
(command & CMD_RESET) ? " Reset" : "",
|
||||||
|
(command & CMD_RUN) ? "RUN" : "HALT"
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
dbg_status (void)
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
u32 status=ehci_readl( &ehci->regs->status);
|
||||||
|
ehci_dbg (
|
||||||
|
"status %04x%s%s%s%s%s%s%s%s%s%s\n",
|
||||||
|
status,
|
||||||
|
(status & STS_ASS) ? " Async" : "",
|
||||||
|
(status & STS_PSS) ? " Periodic" : "",
|
||||||
|
(status & STS_RECL) ? " Recl" : "",
|
||||||
|
(status & STS_HALT) ? " Halt" : "",
|
||||||
|
(status & STS_IAA) ? " IAA" : "",
|
||||||
|
(status & STS_FATAL) ? " FATAL" : "",
|
||||||
|
(status & STS_FLR) ? " FLR" : "",
|
||||||
|
(status & STS_PCD) ? " PCD" : "",
|
||||||
|
(status & STS_ERR) ? " ERR" : "",
|
||||||
|
(status & STS_INT) ? " INT" : ""
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void debug_qtds(void)
|
||||||
|
{
|
||||||
|
//struct ehci_qh *qh = ehci->async;
|
||||||
|
//struct ehci_qtd *qtd;
|
||||||
|
//dbg_qh ("qh",qh);
|
||||||
|
//dbg_command ();
|
||||||
|
//dbg_status ();
|
||||||
|
//for(qtd = qh->qtd_head; qtd; qtd = qtd->next)
|
||||||
|
//{
|
||||||
|
// ehci_dma_unmap_bidir(qtd->qtd_dma,sizeof(struct ehci_qtd));
|
||||||
|
// dbg_qtd("qtd",qtd);
|
||||||
|
// ehci_dma_map_bidir(qtd,sizeof(struct ehci_qtd));
|
||||||
|
//}
|
||||||
|
|
||||||
|
}
|
||||||
|
void dump_qh(struct ehci_qh *qh)
|
||||||
|
{
|
||||||
|
//struct ehci_qtd *qtd;
|
||||||
|
//dbg_command ();
|
||||||
|
//dbg_status ();
|
||||||
|
//ehci_dma_unmap_bidir(qh->qh_dma,sizeof(struct ehci_qh));
|
||||||
|
//dbg_qh("qh",qh);
|
||||||
|
//print_hex_dump_bytes("qh:",DUMP_PREFIX_OFFSET,(void*)qh,12*4);
|
||||||
|
//for(qtd = qh->qtd_head; qtd; qtd = qtd->next){
|
||||||
|
// u32 *buf;
|
||||||
|
// ehci_dma_unmap_bidir(qtd->qtd_dma,sizeof(struct ehci_qtd));
|
||||||
|
// dbg_qtd("qtd",qtd);
|
||||||
|
// print_hex_dump_bytes("qtd:",DUMP_PREFIX_OFFSET,(void*)qtd,8*4);
|
||||||
|
// buf = (u32*)hc32_to_cpu(qtd->hw_buf[0]);
|
||||||
|
// if(buf)
|
||||||
|
// print_hex_dump_bytes("qtd buf:",DUMP_PREFIX_OFFSET,(void*)(buf),8*4);
|
||||||
|
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* handshake - spin reading hc until handshake completes or fails
|
||||||
|
* @ptr: address of hc register to be read
|
||||||
|
* @mask: bits to look at in result of read
|
||||||
|
* @done: value of those bits when handshake succeeds
|
||||||
|
* @usec: timeout in microseconds
|
||||||
|
*
|
||||||
|
* Returns negative errno, or zero on success
|
||||||
|
*
|
||||||
|
* Success happens when the "mask" bits have the specified value (hardware
|
||||||
|
* handshake done). There are two failure modes: "usec" have passed (major
|
||||||
|
* hardware flakeout), or the register reads as all-ones (hardware removed).
|
||||||
|
*
|
||||||
|
* That last failure should_only happen in cases like physical cardbus eject
|
||||||
|
* before driver shutdown. But it also seems to be caused by bugs in cardbus
|
||||||
|
* bridge shutdown: shutting down the bridge before the devices using it.
|
||||||
|
*/
|
||||||
|
static int handshake (void __iomem *ptr,
|
||||||
|
u32 mask, u32 done, int usec)
|
||||||
|
{
|
||||||
|
u32 result;
|
||||||
|
do {
|
||||||
|
result = ehci_readl( ptr);
|
||||||
|
if (result == ~(u32)0) /* card removed */
|
||||||
|
return -ENODEV;
|
||||||
|
result &= mask;
|
||||||
|
if (result == done)
|
||||||
|
return 0;
|
||||||
|
udelay(1);
|
||||||
|
usec--;
|
||||||
|
} while (usec > 0);
|
||||||
|
|
||||||
|
ehci_dbg("EHCI:handshake timeout!!\n");
|
||||||
|
dump_qh(ehci->async);
|
||||||
|
dump_qh(ehci->asyncqh);
|
||||||
|
//BUG();
|
||||||
|
return -ETIMEDOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "ehci-mem.c"
|
||||||
|
/* one-time init, only for memory state */
|
||||||
|
static int ehci_init(void)
|
||||||
|
{
|
||||||
|
int retval;
|
||||||
|
if( (retval = ehci_mem_init()) < 0 )
|
||||||
|
return retval;
|
||||||
|
/*
|
||||||
|
* dedicate a qh for the async ring head, since we couldn't unlink
|
||||||
|
* a 'real' qh without stopping the async schedule [4.8]. use it
|
||||||
|
* as the 'reclamation list head' too.
|
||||||
|
* its dummy is used in hw_alt_next of many tds, to prevent the qh
|
||||||
|
* from automatically advancing to the next td after short reads.
|
||||||
|
*/
|
||||||
|
ehci->async->hw_next = QH_NEXT( ehci->async->qh_dma);
|
||||||
|
ehci->async->hw_info1 = cpu_to_hc32( QH_HEAD);
|
||||||
|
ehci->async->hw_token = cpu_to_hc32( QTD_STS_HALT);
|
||||||
|
ehci->async->hw_qtd_next = EHCI_LIST_END();
|
||||||
|
ehci->async->hw_alt_next = EHCI_LIST_END();//QTD_NEXT( ehci->async->dummy->qtd_dma);
|
||||||
|
|
||||||
|
if( ehci->ctrl_buffer != NULL )
|
||||||
|
USB_Free( ehci->ctrl_buffer );
|
||||||
|
|
||||||
|
ehci->ctrl_buffer = USB_Alloc(sizeof(usbctrlrequest));
|
||||||
|
|
||||||
|
ehci->command = 0;
|
||||||
|
ehci_writel( 0x00800002, &ehci->regs->command);
|
||||||
|
ehci_writel( ehci->periodic_dma, &ehci->regs->frame_list);
|
||||||
|
ehci_writel( ehci->async->qh_dma, &ehci->regs->async_next);
|
||||||
|
ehci_writel( 0x00010009, &ehci->regs->command);
|
||||||
|
ehci_writel( 1, &ehci->regs->configured_flag);
|
||||||
|
ehci_writel( 0x00010029, &ehci->regs->command);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fill a qtd, returning how much of the buffer we were able to queue up */
|
||||||
|
static int qtd_fill( struct ehci_qtd *qtd, dma_addr_t buf, size_t len, int token, int maxpacket)
|
||||||
|
{
|
||||||
|
int i, count;
|
||||||
|
u64 addr = buf;
|
||||||
|
//ehci_dbg("fill qtd with dma %X len %X\n",buf,len);
|
||||||
|
/* one buffer entry per 4K ... first might be short or unaligned */
|
||||||
|
qtd->hw_buf[0] = cpu_to_hc32( (u32)addr);
|
||||||
|
qtd->hw_buf_hi[0] = 0;
|
||||||
|
count = 0x1000 - (buf & 0x0fff); /* rest of that page */
|
||||||
|
if (likely (len < count)) /* ... iff needed */
|
||||||
|
count = len;
|
||||||
|
else {
|
||||||
|
buf += 0x1000;
|
||||||
|
buf &= ~0x0fff;
|
||||||
|
|
||||||
|
/* per-qtd limit: from 16K to 20K (best alignment) */
|
||||||
|
for (i = 1; count < len && i < 5; i++) {
|
||||||
|
addr = buf;
|
||||||
|
qtd->hw_buf[i] = cpu_to_hc32( (u32)addr);
|
||||||
|
qtd->hw_buf_hi[i] = cpu_to_hc32(
|
||||||
|
(u32)(addr >> 32));
|
||||||
|
buf += 0x1000;
|
||||||
|
if ((count + 0x1000) < len)
|
||||||
|
count += 0x1000;
|
||||||
|
else
|
||||||
|
count = len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* short packets may only terminate transfers */
|
||||||
|
if (count != len)
|
||||||
|
count -= (count % maxpacket);
|
||||||
|
}
|
||||||
|
qtd->hw_token = cpu_to_hc32( (count << 16) | token);
|
||||||
|
qtd->length = count;
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
// high bandwidth multiplier, as encoded in highspeed endpoint descriptors
|
||||||
|
#define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03))
|
||||||
|
// ... and packet size, for any kind of endpoint descriptor
|
||||||
|
#define max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x07ff)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* reverse of qh_urb_transaction: free a list of TDs.
|
||||||
|
* also count the actual transfer length.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static void qh_end_transfer (void)
|
||||||
|
{
|
||||||
|
struct ehci_qtd *qtd;
|
||||||
|
struct ehci_qh *qh = ehci->asyncqh;
|
||||||
|
u32 token;
|
||||||
|
int error = 0;
|
||||||
|
for(qtd = qh->qtd_head; qtd; qtd = qtd->next)
|
||||||
|
{
|
||||||
|
token = hc32_to_cpu( qtd->hw_token);
|
||||||
|
if (likely (QTD_PID (token) != 2))
|
||||||
|
qtd->urb->actual_length += qtd->length - QTD_LENGTH (token);
|
||||||
|
|
||||||
|
if (!(qtd->length ==0 && ((token & 0xff)==QTD_STS_HALT)) && (token & QTD_STS_HALT))
|
||||||
|
{
|
||||||
|
ehci_dbg("EHCI:qtd error!:");
|
||||||
|
if (token & QTD_STS_BABBLE)
|
||||||
|
{
|
||||||
|
/* FIXME "must" disable babbling device's port too */
|
||||||
|
ehci_dbg(" BABBLE");
|
||||||
|
}
|
||||||
|
if (token & QTD_STS_MMF)
|
||||||
|
{
|
||||||
|
/* fs/ls interrupt xfer missed the complete-split */
|
||||||
|
ehci_dbg(" missed micro frame");
|
||||||
|
}
|
||||||
|
if (token & QTD_STS_DBE)
|
||||||
|
{
|
||||||
|
ehci_dbg(" databuffer error");
|
||||||
|
}
|
||||||
|
if (token & QTD_STS_XACT)
|
||||||
|
{
|
||||||
|
ehci_dbg(" wrong ack");
|
||||||
|
}
|
||||||
|
if (QTD_CERR (token)==0)
|
||||||
|
ehci_dbg(" toomany errors");
|
||||||
|
|
||||||
|
ehci_dbg("\n");
|
||||||
|
error = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(error)
|
||||||
|
{
|
||||||
|
dump_qh(ehci->asyncqh);
|
||||||
|
qtd->urb->actual_length = error;
|
||||||
|
}
|
||||||
|
ehci->qtd_used = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* create a list of filled qtds for this URB; won't link into qh.
|
||||||
|
*/
|
||||||
|
struct ehci_qtd *qh_urb_transaction (
|
||||||
|
struct ehci_urb *urb
|
||||||
|
) {
|
||||||
|
struct ehci_qtd *qtd, *qtd_prev;
|
||||||
|
struct ehci_qtd *head;
|
||||||
|
dma_addr_t buf;
|
||||||
|
int len, maxpacket;
|
||||||
|
int is_input;
|
||||||
|
u32 token;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* URBs map to sequences of QTDs: one logical transaction
|
||||||
|
*/
|
||||||
|
head = qtd = ehci_qtd_alloc ();
|
||||||
|
qtd->urb = urb;
|
||||||
|
|
||||||
|
urb->actual_length = 0;
|
||||||
|
token = QTD_STS_ACTIVE;
|
||||||
|
token |= (EHCI_TUNE_CERR << 10);
|
||||||
|
/* for split transactions, SplitXState initialized to zero */
|
||||||
|
|
||||||
|
len = urb->transfer_buffer_length;
|
||||||
|
is_input = urb->input;
|
||||||
|
if (urb->ep==0) {/* is control */
|
||||||
|
/* SETUP pid */
|
||||||
|
qtd_fill( qtd, urb->setup_dma, sizeof (usbctrlrequest), token | (2 /* "setup" */ << 8), 8);
|
||||||
|
|
||||||
|
/* ... and always at least one more pid */
|
||||||
|
token ^= QTD_TOGGLE;
|
||||||
|
qtd_prev = qtd;
|
||||||
|
qtd = ehci_qtd_alloc ();
|
||||||
|
qtd->urb = urb;
|
||||||
|
qtd_prev->hw_next = QTD_NEXT( qtd->qtd_dma);
|
||||||
|
qtd_prev->next = qtd;
|
||||||
|
|
||||||
|
/* for zero length DATA stages, STATUS is always IN */
|
||||||
|
if (len == 0)
|
||||||
|
token |= (1 /* "in" */ << 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* data transfer stage: buffer setup
|
||||||
|
*/
|
||||||
|
buf = urb->transfer_dma;
|
||||||
|
|
||||||
|
if (is_input)
|
||||||
|
token |= (1 /* "in" */ << 8);
|
||||||
|
/* else it's already initted to "out" pid (0 << 8) */
|
||||||
|
|
||||||
|
maxpacket = max_packet(urb->maxpacket);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* buffer gets wrapped in one or more qtds;
|
||||||
|
* last one may be "short" (including zero len)
|
||||||
|
* and may serve as a control status ack
|
||||||
|
*/
|
||||||
|
for (;;) {
|
||||||
|
int this_qtd_len;
|
||||||
|
|
||||||
|
this_qtd_len = qtd_fill( qtd, buf, len, token, maxpacket);
|
||||||
|
len -= this_qtd_len;
|
||||||
|
buf += this_qtd_len;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* short reads advance to a "magic" dummy instead of the next
|
||||||
|
* qtd ... that forces the queue to stop, for manual cleanup.
|
||||||
|
* (this will usually be overridden later.)
|
||||||
|
*/
|
||||||
|
if (is_input)
|
||||||
|
qtd->hw_alt_next = ehci->asyncqh->hw_alt_next;
|
||||||
|
|
||||||
|
/* qh makes control packets use qtd toggle; maybe switch it */
|
||||||
|
if ((maxpacket & (this_qtd_len + (maxpacket - 1))) == 0)
|
||||||
|
token ^= QTD_TOGGLE;
|
||||||
|
|
||||||
|
if (likely (len <= 0))
|
||||||
|
break;
|
||||||
|
|
||||||
|
qtd_prev = qtd;
|
||||||
|
qtd = ehci_qtd_alloc ();
|
||||||
|
qtd->urb = urb;
|
||||||
|
qtd_prev->hw_next = QTD_NEXT( qtd->qtd_dma);
|
||||||
|
qtd_prev->next = qtd;
|
||||||
|
}
|
||||||
|
|
||||||
|
qtd->hw_alt_next = EHCI_LIST_END();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* control requests may need a terminating data "status" ack;
|
||||||
|
* bulk ones may need a terminating short packet (zero length).
|
||||||
|
*/
|
||||||
|
if (likely (urb->transfer_buffer_length != 0)) {
|
||||||
|
int one_more = 0;
|
||||||
|
|
||||||
|
if (urb->ep==0) {
|
||||||
|
one_more = 1;
|
||||||
|
token ^= 0x0100; /* "in" <--> "out" */
|
||||||
|
token |= QTD_TOGGLE; /* force DATA1 */
|
||||||
|
} else if(!(urb->transfer_buffer_length % maxpacket)) {
|
||||||
|
//one_more = 1;
|
||||||
|
}
|
||||||
|
if (one_more) {
|
||||||
|
qtd_prev = qtd;
|
||||||
|
qtd = ehci_qtd_alloc ();
|
||||||
|
qtd->urb = urb;
|
||||||
|
qtd_prev->hw_next = QTD_NEXT( qtd->qtd_dma);
|
||||||
|
qtd_prev->next = qtd;
|
||||||
|
|
||||||
|
/* never any data in such packets */
|
||||||
|
qtd_fill( qtd, 0, 0, token, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* by default, enable interrupt on urb completion */
|
||||||
|
qtd->hw_token |= cpu_to_hc32( QTD_IOC);
|
||||||
|
return head;
|
||||||
|
}
|
||||||
|
int ehci_do_urb ( struct ehci_device *dev, struct ehci_urb *urb)
|
||||||
|
{
|
||||||
|
struct ehci_qh *qh;
|
||||||
|
struct ehci_qtd *qtd;
|
||||||
|
u32 info1 = 0, info2 = 0;
|
||||||
|
int is_input;
|
||||||
|
int maxp = 0;
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
//ehci_dbg ("do urb %X %X ep %X\n",urb->setup_buffer,urb->transfer_buffer,urb->ep);
|
||||||
|
if(urb->ep==0) //control message
|
||||||
|
urb->setup_dma = ehci_dma_map_to(urb->setup_buffer,sizeof (usbctrlrequest));
|
||||||
|
|
||||||
|
if( urb->transfer_buffer_length )
|
||||||
|
{
|
||||||
|
if(urb->input)
|
||||||
|
urb->transfer_dma = ehci_dma_map_to( urb->transfer_buffer, urb->transfer_buffer_length );
|
||||||
|
else
|
||||||
|
urb->transfer_dma = ehci_dma_map_from( urb->transfer_buffer, urb->transfer_buffer_length );
|
||||||
|
}
|
||||||
|
|
||||||
|
qh = ehci->asyncqh;
|
||||||
|
memset(qh,0,12*4);
|
||||||
|
qtd = qh_urb_transaction( urb );
|
||||||
|
qh->qtd_head = qtd;
|
||||||
|
|
||||||
|
info1 |= ((urb->ep)&0xf)<<8;
|
||||||
|
info1 |= dev->id;
|
||||||
|
is_input = urb->input;
|
||||||
|
maxp = urb->maxpacket;
|
||||||
|
|
||||||
|
info1 |= (2 << 12); /* EPS "high" */
|
||||||
|
if(urb->ep==0)// control
|
||||||
|
{
|
||||||
|
info1 |= (EHCI_TUNE_RL_HS << 28);
|
||||||
|
info1 |= 64 << 16; /* usb2 fixed maxpacket */
|
||||||
|
info1 |= 1 << 14; /* toggle from qtd */
|
||||||
|
info2 |= (EHCI_TUNE_MULT_HS << 30);
|
||||||
|
} else {//bulk
|
||||||
|
|
||||||
|
info1 |= (EHCI_TUNE_RL_HS << 28);
|
||||||
|
/* The USB spec says that high speed bulk endpoints
|
||||||
|
* always use 512 byte maxpacket. But some device
|
||||||
|
* vendors decided to ignore that, and MSFT is happy
|
||||||
|
* to help them do so. So now people expect to use
|
||||||
|
* such nonconformant devices with Linux too; sigh.
|
||||||
|
*/
|
||||||
|
info1 |= max_packet(maxp) << 16;
|
||||||
|
info2 |= (EHCI_TUNE_MULT_HS << 30);
|
||||||
|
}
|
||||||
|
|
||||||
|
//ehci_dbg("HW info: %08X\n",info1);
|
||||||
|
qh->hw_info1 = cpu_to_hc32( info1);
|
||||||
|
qh->hw_info2 = cpu_to_hc32( info2);
|
||||||
|
|
||||||
|
qh->hw_next = QH_NEXT( qh->qh_dma );
|
||||||
|
qh->hw_qtd_next = QTD_NEXT( qtd->qtd_dma );
|
||||||
|
qh->hw_alt_next = EHCI_LIST_END();
|
||||||
|
|
||||||
|
if( urb->ep != 0 )
|
||||||
|
{
|
||||||
|
if( get_toggle( dev, urb->ep ) )
|
||||||
|
qh->hw_token |= cpu_to_hc32(QTD_TOGGLE);
|
||||||
|
else
|
||||||
|
qh->hw_token &= ~cpu_to_hc32(QTD_TOGGLE);
|
||||||
|
|
||||||
|
//ehci_dbg("toggle for ep %x: %d %x\n", urb->ep, get_toggle(dev,urb->ep), qh->hw_token );
|
||||||
|
}
|
||||||
|
|
||||||
|
qh->hw_token &= cpu_to_hc32( QTD_TOGGLE | QTD_STS_PING);
|
||||||
|
|
||||||
|
qh->hw_next = QH_NEXT(ehci->async->qh_dma);
|
||||||
|
|
||||||
|
|
||||||
|
ehci_dma_map_bidir(qh,sizeof(struct ehci_qh));
|
||||||
|
for(qtd = qh->qtd_head; qtd; qtd = qtd->next)
|
||||||
|
ehci_dma_map_bidir(qtd,sizeof(struct ehci_qtd));
|
||||||
|
|
||||||
|
// start (link qh)
|
||||||
|
ehci->async->hw_next = QH_NEXT(qh->qh_dma);
|
||||||
|
ehci_dma_map_bidir(ehci->async,sizeof(struct ehci_qh));
|
||||||
|
|
||||||
|
retval = handshake(&ehci->regs->status,STS_INT,STS_INT,1000*1000);
|
||||||
|
|
||||||
|
//print_hex_dump_bytes ("qh mem",0,(void*)qh,17*4);
|
||||||
|
//retval = poll_transfer_end(1000*1000);
|
||||||
|
ehci_dma_unmap_bidir(ehci->async->qh_dma,sizeof(struct ehci_qh));
|
||||||
|
ehci_dma_unmap_bidir(qh->qh_dma,sizeof(struct ehci_qh));
|
||||||
|
|
||||||
|
for(qtd = qh->qtd_head; qtd; qtd = qtd->next)
|
||||||
|
ehci_dma_unmap_bidir(qtd->qtd_dma,sizeof(struct ehci_qtd));
|
||||||
|
|
||||||
|
// stop (unlink qh)
|
||||||
|
ehci->async->hw_next = QH_NEXT(ehci->async->qh_dma);
|
||||||
|
ehci_dma_map_bidir(ehci->async,sizeof(struct ehci_qh));
|
||||||
|
ehci_dma_unmap_bidir(ehci->async->qh_dma,sizeof(struct ehci_qh));
|
||||||
|
|
||||||
|
// ack
|
||||||
|
ehci_writel( STS_RECL|STS_IAA|STS_INT, &ehci->regs->status);
|
||||||
|
|
||||||
|
if(urb->ep!=0)
|
||||||
|
{
|
||||||
|
set_toggle(dev,urb->ep,(qh->hw_token & cpu_to_hc32(QTD_TOGGLE))?1:0);
|
||||||
|
//ehci_dbg("toggle for ep %x: %d %d %x %X\n",urb->ep,get_toggle(dev,urb->ep),(qh->hw_token & cpu_to_hc32(QTD_TOGGLE)),qh->hw_token,dev->toggles);
|
||||||
|
}
|
||||||
|
|
||||||
|
if( retval >= 0 )
|
||||||
|
// wait hc really stopped
|
||||||
|
retval = handshake(&ehci->regs->async_next,~0,ehci->async->qh_dma,1*1000);
|
||||||
|
//release memory, and actualise urb->actual_length
|
||||||
|
qh_end_transfer();
|
||||||
|
|
||||||
|
if(urb->transfer_buffer_length)
|
||||||
|
{
|
||||||
|
if(urb->input)
|
||||||
|
ehci_dma_unmap_to(urb->transfer_dma,urb->transfer_buffer_length);
|
||||||
|
else
|
||||||
|
ehci_dma_unmap_from(urb->transfer_dma,urb->transfer_buffer_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
if( urb->ep == 0 ) //control message
|
||||||
|
ehci_dma_unmap_to(urb->setup_dma,sizeof (usbctrlrequest));
|
||||||
|
|
||||||
|
if(retval==0)
|
||||||
|
{
|
||||||
|
return urb->actual_length;
|
||||||
|
}
|
||||||
|
ehci_dbg ( "EHCI:unsuccessfull urb %d!!\n", retval);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 ehci_control_message(struct ehci_device *dev,u8 bmRequestType,u8 bmRequest,u16 wValue,u16 wIndex,u16 wLength,void *buf)
|
||||||
|
{
|
||||||
|
struct ehci_urb urb;
|
||||||
|
int ret;
|
||||||
|
usbctrlrequest *req = (void*)0x17C0;
|
||||||
|
|
||||||
|
if( verbose )
|
||||||
|
ehci_dbg("control msg: rt%02X r%02X v%04X i%04X s%04x %p\n", bmRequestType, bmRequest, wValue, wIndex, wLength, buf );
|
||||||
|
|
||||||
|
u32 *_req = (u32*)req;
|
||||||
|
|
||||||
|
_req[0] = (bmRequestType<<24) | (bmRequest<<16) | swab16(wValue);
|
||||||
|
_req[1] = (swab16(wIndex) << 16) | swab16(wLength);
|
||||||
|
|
||||||
|
urb.setup_buffer = req;
|
||||||
|
urb.ep = 0;
|
||||||
|
urb.input = (bmRequestType&USB_CTRLTYPE_DIR_DEVICE2HOST)!=0;
|
||||||
|
urb.maxpacket = 64;
|
||||||
|
urb.transfer_buffer_length = wLength;
|
||||||
|
|
||||||
|
if( urb.transfer_buffer_length )
|
||||||
|
{
|
||||||
|
if( ((u32)buf >> 28 ) == 0xF )
|
||||||
|
{
|
||||||
|
urb.transfer_buffer = USB_Alloc( wLength );
|
||||||
|
|
||||||
|
//dbgprintf("memcpy(%p,%p,%u)\n", urb.transfer_buffer, buf, wLength );
|
||||||
|
memcpy( urb.transfer_buffer, buf, wLength );
|
||||||
|
|
||||||
|
ret = ehci_do_urb( dev, &urb );
|
||||||
|
|
||||||
|
memcpy( buf, urb.transfer_buffer, wLength );
|
||||||
|
USB_Free( urb.transfer_buffer );
|
||||||
|
|
||||||
|
} else {
|
||||||
|
urb.transfer_buffer = buf;
|
||||||
|
ret = ehci_do_urb( dev, &urb );
|
||||||
|
}
|
||||||
|
|
||||||
|
//hexdump( buf, wLength > 0x20 ? 0x20 : wLength );
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
urb.transfer_buffer = NULL;
|
||||||
|
ret = ehci_do_urb( dev, &urb );
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
s32 ehci_bulk_message(struct ehci_device *dev,u8 bEndpoint,u16 wLength,void *rpData)
|
||||||
|
{
|
||||||
|
struct ehci_urb urb;
|
||||||
|
s32 ret;
|
||||||
|
urb.setup_buffer = NULL;
|
||||||
|
urb.ep = bEndpoint;
|
||||||
|
urb.input = (bEndpoint&0x80)!=0;
|
||||||
|
urb.maxpacket = 512;
|
||||||
|
urb.transfer_buffer_length = wLength;
|
||||||
|
urb.transfer_buffer = rpData;
|
||||||
|
|
||||||
|
if (verbose)
|
||||||
|
ehci_dbg ( "bulk msg: ep:%02X size:%02X addr:%04X\n", bEndpoint, wLength, urb.transfer_buffer );
|
||||||
|
|
||||||
|
// hexdump( urb.transfer_buffer, urb.transfer_buffer_length );
|
||||||
|
if( ((u32)rpData >> 28) == 0xF )
|
||||||
|
{
|
||||||
|
memcpy( (void*)0xFE0, rpData, wLength );
|
||||||
|
|
||||||
|
urb.transfer_buffer = (u8*)0xFE0;
|
||||||
|
|
||||||
|
ret = ehci_do_urb( dev, &urb );
|
||||||
|
|
||||||
|
memcpy( rpData, (void*)0xFE0, wLength );
|
||||||
|
|
||||||
|
} else {
|
||||||
|
ret = ehci_do_urb( dev, &urb );
|
||||||
|
}
|
||||||
|
|
||||||
|
// hexdump( urb.transfer_buffer, urb.transfer_buffer_length );
|
||||||
|
|
||||||
|
if (verbose)
|
||||||
|
ehci_dbg ( "==>%d\n", ret);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
int ehci_reset_port(int port)
|
||||||
|
{
|
||||||
|
u32 __iomem *status_reg = &ehci->regs->port_status[port];
|
||||||
|
struct ehci_device *dev = &ehci->devices[port];
|
||||||
|
|
||||||
|
u32 status = ehci_readl(status_reg);
|
||||||
|
int retval = 0;
|
||||||
|
|
||||||
|
dev->id = 0;
|
||||||
|
|
||||||
|
if( (PORT_OWNER&status) || !(PORT_CONNECT&status) )
|
||||||
|
{
|
||||||
|
int retries = 10;
|
||||||
|
while( !(PORT_CONNECT&status) && retries > 0 )
|
||||||
|
{
|
||||||
|
msleep(1000); // sleep 1 second
|
||||||
|
status = ehci_readl(status_reg);
|
||||||
|
ehci_dbg ( "EHCI:port %d status at retry %d %X \n", port,retries,status);
|
||||||
|
retries--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( retries <= 0 )
|
||||||
|
{
|
||||||
|
ehci_writel( PORT_OWNER, status_reg );
|
||||||
|
ehci_dbg ( "EHCI:port %d had no usb2 device connected at startup %X \n", port,ehci_readl(status_reg) );
|
||||||
|
return -ENODEV;// no USB2 device connected
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ehci_dbg ( "EHCI:port %d has usb2 device connected! reset it...\n", port);
|
||||||
|
|
||||||
|
if( PORT_USB11(ehci_readl(status_reg)) )
|
||||||
|
{
|
||||||
|
ehci_dbg("EHCI:Device is USB1.1\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
status = ehci_readl(status_reg);
|
||||||
|
status|= PORT_RESET;
|
||||||
|
ehci_writel( status, status_reg );
|
||||||
|
|
||||||
|
msleep(50); // wait 50ms for the reset sequence
|
||||||
|
|
||||||
|
status = ehci_readl(status_reg);
|
||||||
|
status ^= PORT_RESET;
|
||||||
|
ehci_writel( status, status_reg );
|
||||||
|
|
||||||
|
retval = handshake( status_reg, PORT_RESET, 0, 2000 );
|
||||||
|
if(retval != 0)
|
||||||
|
{
|
||||||
|
ehci_dbg ( "EHCI:port %d reset error %d\n", port, retval);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
ehci_dbg ( "EHCI:port %d reseted status:%04x...\n", port,ehci_readl(status_reg));
|
||||||
|
msleep(100);
|
||||||
|
|
||||||
|
// now the device has the default device id
|
||||||
|
retval = ehci_control_message( dev, USB_CTRLTYPE_DIR_DEVICE2HOST, USB_REQ_GETDESCRIPTOR, USB_DT_DEVICE<<8, 0, sizeof(dev->desc), &dev->desc );
|
||||||
|
if (retval < 0)
|
||||||
|
{
|
||||||
|
ehci_dbg("EHCI:unable to get device desc...\n");
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
retval = ehci_control_message( dev, USB_CTRLTYPE_DIR_HOST2DEVICE, USB_REQ_SETADDRESS,port+1,0,0,0);
|
||||||
|
if (retval < 0)
|
||||||
|
{
|
||||||
|
ehci_dbg("EHCI:unable to set device addr...\n");
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
dev->toggles = 0;
|
||||||
|
|
||||||
|
dev->id = port+1;
|
||||||
|
ehci_dbg ( "EHCI:device %d: %X %X...\n", dev->id,le16_to_cpu(dev->desc.idVendor),le16_to_cpu(dev->desc.idProduct));
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
int ehci_reset_device(struct ehci_device *dev)
|
||||||
|
{
|
||||||
|
return ehci_reset_port(dev->port);
|
||||||
|
}
|
||||||
|
#include "usbstorage.h"
|
||||||
|
int ehci_discover(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int ret = 0 ;
|
||||||
|
// precondition: the ehci should be halted
|
||||||
|
for(i = 0;i<ehci->num_port; i++)
|
||||||
|
{
|
||||||
|
struct ehci_device *dev = &ehci->devices[i];
|
||||||
|
dev->port = i;
|
||||||
|
ret = ehci_reset_port(i);
|
||||||
|
|
||||||
|
if( ret != -ENODEV )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
/* wii: quickly release non ehci or not connected ports,
|
||||||
|
as we can't kick OHCI drivers laters if we discover a device for them.
|
||||||
|
*/
|
||||||
|
int ehci_release_ports(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
u32 __iomem *status_reg = &ehci->regs->port_status[2];
|
||||||
|
while(ehci_readl(&ehci->regs->port_status[2]) == 0x1000);// wait port 2 to init
|
||||||
|
msleep(1);// wait another msec..
|
||||||
|
for(i = 0;i<ehci->num_port; i++){
|
||||||
|
status_reg = &ehci->regs->port_status[i];
|
||||||
|
u32 status = ehci_readl(status_reg);
|
||||||
|
if (i==2 || !(PORT_CONNECT&status) || PORT_USB11(status))
|
||||||
|
ehci_writel( PORT_OWNER,status_reg); // release port.
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ehci_open_device(int vid,int pid,int fd)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for(i=0;i<ehci->num_port;i++)
|
||||||
|
{
|
||||||
|
ehci_dbg("try device: %d\n",i);
|
||||||
|
if(ehci->devices[i].fd == 0 &&
|
||||||
|
le16_to_cpu(ehci->devices[i].desc.idVendor) == vid &&
|
||||||
|
le16_to_cpu(ehci->devices[i].desc.idProduct) == pid)
|
||||||
|
{
|
||||||
|
ehci_dbg("found device: %x %x\n",vid,pid);
|
||||||
|
ehci->devices[i].fd = fd;
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -6;
|
||||||
|
}
|
||||||
|
int ehci_close_device(struct ehci_device *dev)
|
||||||
|
{
|
||||||
|
if (dev)
|
||||||
|
dev->fd = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
void * ehci_fd_to_dev(int fd)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for(i=0;i<ehci->num_port;i++)
|
||||||
|
{
|
||||||
|
struct ehci_device *dev = &ehci->devices[i];
|
||||||
|
ehci_dbg ( "EHCI:device %d:fd:%d %X %X...\n", dev->id,dev->fd,le16_to_cpu(dev->desc.idVendor),le16_to_cpu(dev->desc.idProduct));
|
||||||
|
if(dev->fd == fd){
|
||||||
|
return dev;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ehci_dbg("unkown fd! %d\n",fd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#define g_ehci #error
|
||||||
|
int ehci_get_device_list(u8 maxdev,u8 b0,u8*num,u16*buf)
|
||||||
|
{
|
||||||
|
int i,j = 0;
|
||||||
|
for(i=0;i<ehci->num_port && j<maxdev ;i++)
|
||||||
|
{
|
||||||
|
struct ehci_device *dev = &ehci->devices[i];
|
||||||
|
if(dev->id != 0){
|
||||||
|
ehci_dbg ( "EHCI:device %d: %X %X...\n", dev->id,le16_to_cpu(dev->desc.idVendor),le16_to_cpu(dev->desc.idProduct));
|
||||||
|
buf[j*4] = 0;
|
||||||
|
buf[j*4+1] = 0;
|
||||||
|
buf[j*4+2] = le16_to_cpu(dev->desc.idVendor);
|
||||||
|
buf[j*4+3] = le16_to_cpu(dev->desc.idProduct);
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ehci_dbg("EHCI:found %d devices\n",j);
|
||||||
|
*num = j;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#include "usb.c"
|
||||||
|
#include "usbstorage.c"
|
282
ehci.h
Normal file
282
ehci.h
Normal file
@ -0,0 +1,282 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009 Kwiirk
|
||||||
|
* Original Copyright (c) 2001-2002 by David Brownell
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 2 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ehci_types.h"
|
||||||
|
|
||||||
|
#ifndef __LINUX_EHCI_HCD_H
|
||||||
|
#define __LINUX_EHCI_HCD_H
|
||||||
|
/* definitions used for the EHCI driver */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* __hc32 and __hc16 are "Host Controller" types, they may be equivalent to
|
||||||
|
* __leXX (normally) or __beXX (given EHCI_BIG_ENDIAN_DESC), depending on
|
||||||
|
* the host controller implementation.
|
||||||
|
*
|
||||||
|
* To facilitate the strongest possible byte-order checking from "sparse"
|
||||||
|
* and so on, we use __leXX unless that's not practical.
|
||||||
|
*/
|
||||||
|
#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_DESC
|
||||||
|
typedef __u32 __bitwise __hc32;
|
||||||
|
typedef __u16 __bitwise __hc16;
|
||||||
|
#else
|
||||||
|
#define __hc32 __le32
|
||||||
|
#define __hc16 __le16
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#define EHCI_MAX_ROOT_PORTS 4 /* see HCS_N_PORTS */
|
||||||
|
#define EHCI_MAX_QTD 8
|
||||||
|
#include "usb.h"
|
||||||
|
|
||||||
|
struct ehci_device{
|
||||||
|
usb_devdesc desc;
|
||||||
|
int id;
|
||||||
|
int port;
|
||||||
|
int fd;
|
||||||
|
u32 toggles;
|
||||||
|
};
|
||||||
|
#define ep_bit(ep) (((ep)&0xf)+(((ep)>>7)?16:0))
|
||||||
|
#define get_toggle(dev,ep) (((dev)->toggles>>ep_bit(ep))&1)
|
||||||
|
#define set_toggle(dev,ep,v) (dev)->toggles = ((dev)->toggles &(~(1<<ep_bit(ep)))) | ((v)<<ep_bit(ep))
|
||||||
|
|
||||||
|
struct ehci_urb{
|
||||||
|
void* setup_buffer;
|
||||||
|
dma_addr_t setup_dma;
|
||||||
|
|
||||||
|
void* transfer_buffer;
|
||||||
|
dma_addr_t transfer_dma;
|
||||||
|
u32 transfer_buffer_length;
|
||||||
|
u32 actual_length;
|
||||||
|
|
||||||
|
u8 ep;
|
||||||
|
u8 input;
|
||||||
|
u32 maxpacket;
|
||||||
|
};
|
||||||
|
struct ehci_hcd { /* one per controller */
|
||||||
|
/* glue to PCI and HCD framework */
|
||||||
|
void __iomem *_regs;
|
||||||
|
struct ehci_caps __iomem *caps;
|
||||||
|
struct ehci_regs __iomem *regs;
|
||||||
|
struct ehci_dbg_port __iomem *debug;
|
||||||
|
void *device;
|
||||||
|
__u32 hcs_params; /* cached register copy */
|
||||||
|
|
||||||
|
/* async schedule support */
|
||||||
|
struct ehci_qh *async; // the head never gets a qtd inside.
|
||||||
|
struct ehci_qh *asyncqh;
|
||||||
|
|
||||||
|
struct ehci_qtd *qtds[EHCI_MAX_QTD];
|
||||||
|
int qtd_used;
|
||||||
|
unsigned long next_statechange;
|
||||||
|
u32 command;
|
||||||
|
|
||||||
|
/* HW need periodic table initialised even if we dont use it @todo:is it really true? */
|
||||||
|
#define DEFAULT_I_TDPS 1024 /* some HCs can do less */
|
||||||
|
__hc32 *periodic; /* hw periodic table */
|
||||||
|
dma_addr_t periodic_dma;
|
||||||
|
|
||||||
|
u8 num_port;
|
||||||
|
struct ehci_device devices[EHCI_MAX_ROOT_PORTS]; /* the attached device list per port */
|
||||||
|
void *ctrl_buffer; /* pre allocated buffer for control messages */
|
||||||
|
};
|
||||||
|
/*-------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include "ehci_defs.h"
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------*/
|
||||||
|
#define QTD_NEXT( dma) cpu_to_hc32( (u32)dma)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* EHCI Specification 0.95 Section 3.5
|
||||||
|
* QTD: describe data transfer components (buffer, direction, ...)
|
||||||
|
* See Fig 3-6 "Queue Element Transfer Descriptor Block Diagram".
|
||||||
|
*
|
||||||
|
* These are associated only with "QH" (Queue Head) structures,
|
||||||
|
* used with control, bulk, and interrupt transfers.
|
||||||
|
*/
|
||||||
|
struct ehci_qtd {
|
||||||
|
/* first part defined by EHCI spec */
|
||||||
|
__hc32 hw_next; /* see EHCI 3.5.1 */
|
||||||
|
__hc32 hw_alt_next; /* see EHCI 3.5.2 */
|
||||||
|
__hc32 hw_token; /* see EHCI 3.5.3 */
|
||||||
|
#define QTD_TOGGLE (1 << 31) /* data toggle */
|
||||||
|
#define QTD_LENGTH(tok) (((tok)>>16) & 0x7fff)
|
||||||
|
#define QTD_IOC (1 << 15) /* interrupt on complete */
|
||||||
|
#define QTD_CERR(tok) (((tok)>>10) & 0x3)
|
||||||
|
#define QTD_PID(tok) (((tok)>>8) & 0x3)
|
||||||
|
#define QTD_STS_ACTIVE (1 << 7) /* HC may execute this */
|
||||||
|
#define QTD_STS_HALT (1 << 6) /* halted on error */
|
||||||
|
#define QTD_STS_DBE (1 << 5) /* data buffer error (in HC) */
|
||||||
|
#define QTD_STS_BABBLE (1 << 4) /* device was babbling (qtd halted) */
|
||||||
|
#define QTD_STS_XACT (1 << 3) /* device gave illegal response */
|
||||||
|
#define QTD_STS_MMF (1 << 2) /* incomplete split transaction */
|
||||||
|
#define QTD_STS_STS (1 << 1) /* split transaction state */
|
||||||
|
#define QTD_STS_PING (1 << 0) /* issue PING? */
|
||||||
|
|
||||||
|
#define ACTIVE_BIT(ehci) cpu_to_hc32( QTD_STS_ACTIVE)
|
||||||
|
#define HALT_BIT(ehci) cpu_to_hc32( QTD_STS_HALT)
|
||||||
|
#define STATUS_BIT(ehci) cpu_to_hc32( QTD_STS_STS)
|
||||||
|
|
||||||
|
__hc32 hw_buf [5]; /* see EHCI 3.5.4 */
|
||||||
|
__hc32 hw_buf_hi [5]; /* Appendix B */
|
||||||
|
|
||||||
|
/* the rest is HCD-private */
|
||||||
|
dma_addr_t qtd_dma; /* qtd address */
|
||||||
|
struct ehci_qtd *next; /* sw qtd list */
|
||||||
|
struct ehci_urb *urb; /* qtd's urb */
|
||||||
|
size_t length; /* length of buffer */
|
||||||
|
} __attribute__ ((aligned (32)));
|
||||||
|
|
||||||
|
/* mask NakCnt+T in qh->hw_alt_next */
|
||||||
|
#define QTD_MASK(ehci) cpu_to_hc32 ( ~0x1f)
|
||||||
|
|
||||||
|
#define IS_SHORT_READ(token) (QTD_LENGTH (token) != 0 && QTD_PID (token) == 1)
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* type tag from {qh,itd,sitd,fstn}->hw_next */
|
||||||
|
#define Q_NEXT_TYPE(dma) ((dma) & cpu_to_hc32( 3 << 1))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now the following defines are not converted using the
|
||||||
|
* __constant_cpu_to_le32() macro anymore, since we have to support
|
||||||
|
* "dynamic" switching between be and le support, so that the driver
|
||||||
|
* can be used on one system with SoC EHCI controller using big-endian
|
||||||
|
* descriptors as well as a normal little-endian PCI EHCI controller.
|
||||||
|
*/
|
||||||
|
/* values for that type tag */
|
||||||
|
#define Q_TYPE_ITD (0 << 1)
|
||||||
|
#define Q_TYPE_QH (1 << 1)
|
||||||
|
#define Q_TYPE_SITD (2 << 1)
|
||||||
|
#define Q_TYPE_FSTN (3 << 1)
|
||||||
|
|
||||||
|
/* next async queue entry, or pointer to interrupt/periodic QH */
|
||||||
|
#define QH_NEXT(dma) (cpu_to_hc32( (((u32)dma)&~0x01f)|Q_TYPE_QH))
|
||||||
|
|
||||||
|
/* for periodic/async schedules and qtd lists, mark end of list */
|
||||||
|
#define EHCI_LIST_END() cpu_to_hc32( 1) /* "null pointer" to hw */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Entries in periodic shadow table are pointers to one of four kinds
|
||||||
|
* of data structure. That's dictated by the hardware; a type tag is
|
||||||
|
* encoded in the low bits of the hardware's periodic schedule. Use
|
||||||
|
* Q_NEXT_TYPE to get the tag.
|
||||||
|
*
|
||||||
|
* For entries in the async schedule, the type tag always says "qh".
|
||||||
|
*/
|
||||||
|
union ehci_shadow {
|
||||||
|
struct ehci_qh *qh; /* Q_TYPE_QH */
|
||||||
|
struct ehci_itd *itd; /* Q_TYPE_ITD */
|
||||||
|
struct ehci_sitd *sitd; /* Q_TYPE_SITD */
|
||||||
|
struct ehci_fstn *fstn; /* Q_TYPE_FSTN */
|
||||||
|
__hc32 *hw_next; /* (all types) */
|
||||||
|
void *ptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* EHCI Specification 0.95 Section 3.6
|
||||||
|
* QH: describes control/bulk/interrupt endpoints
|
||||||
|
* See Fig 3-7 "Queue Head Structure Layout".
|
||||||
|
*
|
||||||
|
* These appear in both the async and (for interrupt) periodic schedules.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct ehci_qh {
|
||||||
|
/* first part defined by EHCI spec */
|
||||||
|
__hc32 hw_next; /* see EHCI 3.6.1 */
|
||||||
|
__hc32 hw_info1; /* see EHCI 3.6.2 */
|
||||||
|
#define QH_HEAD 0x00008000
|
||||||
|
__hc32 hw_info2; /* see EHCI 3.6.2 */
|
||||||
|
#define QH_SMASK 0x000000ff
|
||||||
|
#define QH_CMASK 0x0000ff00
|
||||||
|
#define QH_HUBADDR 0x007f0000
|
||||||
|
#define QH_HUBPORT 0x3f800000
|
||||||
|
#define QH_MULT 0xc0000000
|
||||||
|
__hc32 hw_current; /* qtd list - see EHCI 3.6.4 */
|
||||||
|
|
||||||
|
/* qtd overlay (hardware parts of a struct ehci_qtd) */
|
||||||
|
__hc32 hw_qtd_next;
|
||||||
|
__hc32 hw_alt_next;
|
||||||
|
__hc32 hw_token;
|
||||||
|
__hc32 hw_buf [5];
|
||||||
|
__hc32 hw_buf_hi [5];
|
||||||
|
|
||||||
|
/* the rest is HCD-private */
|
||||||
|
dma_addr_t qh_dma; /* address of qh */
|
||||||
|
struct ehci_qtd *qtd_head; /* sw qtd list */
|
||||||
|
|
||||||
|
struct ehci_hcd *ehci;
|
||||||
|
|
||||||
|
#define NO_FRAME ((unsigned short)~0) /* pick new start */
|
||||||
|
} __attribute__ ((aligned (32)));
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* cpu to ehci */
|
||||||
|
#define cpu_to_hc32(b) cpu_to_le32(b)
|
||||||
|
#define hc32_to_cpu(b) le32_to_cpu(b)
|
||||||
|
#define hc32_to_cpup(b) le32_to_cpu(*(b))
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* os specific functions */
|
||||||
|
void*ehci_maligned(int size,int alignement,int crossing);
|
||||||
|
dma_addr_t ehci_virt_to_dma(void *);
|
||||||
|
dma_addr_t ehci_dma_map_to(void *buf,size_t len);
|
||||||
|
dma_addr_t ehci_dma_map_from(void *buf,size_t len);
|
||||||
|
dma_addr_t ehci_dma_map_bidir(void *buf,size_t len);
|
||||||
|
void ehci_dma_unmap_to(dma_addr_t buf,size_t len);
|
||||||
|
void ehci_dma_unmap_from(dma_addr_t buf,size_t len);
|
||||||
|
void ehci_dma_unmap_bidir(dma_addr_t buf,size_t len);
|
||||||
|
|
||||||
|
|
||||||
|
/* extern API */
|
||||||
|
|
||||||
|
s32 ehci_control_message(struct ehci_device *dev,u8 bmRequestType,u8 bmRequest,u16 wValue,u16 wIndex,u16 wLength,void *buf);
|
||||||
|
s32 ehci_bulk_message(struct ehci_device *dev,u8 bEndpoint,u16 wLength,void *rpData);
|
||||||
|
int ehci_discover(void);
|
||||||
|
int ehci_get_device_list(u8 maxdev,u8 b0,u8*num,u16*buf);
|
||||||
|
|
||||||
|
extern struct ehci_hcd *ehci; /* @todo put ehci as a static global and remove ehci from APIs.. */
|
||||||
|
extern int ehci_open_device(int vid,int pid,int fd);
|
||||||
|
extern int ehci_close_device(struct ehci_device *dev);
|
||||||
|
extern void * ehci_fd_to_dev(int fd);
|
||||||
|
extern int ehci_release_ports(void);
|
||||||
|
|
||||||
|
/* UMS API */
|
||||||
|
|
||||||
|
s32 USBStorage_Init(void);
|
||||||
|
s32 USBStorage_Get_Capacity(u32*sector_size);
|
||||||
|
s32 USBStorage_Read_Sectors(u32 sector, u32 numSectors, void *buffer);
|
||||||
|
s32 USBStorage_Read_Stress(u32 sector, u32 numSectors, void *buffer);
|
||||||
|
s32 USBStorage_Write_Sectors(u32 sector, u32 numSectors, const void *buffer);
|
||||||
|
|
||||||
|
#ifndef DEBUG
|
||||||
|
#define STUB_DEBUG_FILES
|
||||||
|
#endif /* DEBUG */
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#endif /* __LINUX_EHCI_HCD_H */
|
160
ehci_defs.h
Normal file
160
ehci_defs.h
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2001-2002 by David Brownell
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 2 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LINUX_USB_EHCI_DEF_H
|
||||||
|
#define __LINUX_USB_EHCI_DEF_H
|
||||||
|
|
||||||
|
/* EHCI register interface, corresponds to EHCI Revision 0.95 specification */
|
||||||
|
|
||||||
|
/* Section 2.2 Host Controller Capability Registers */
|
||||||
|
struct ehci_caps {
|
||||||
|
/* these fields are specified as 8 and 16 bit registers,
|
||||||
|
* but some hosts can't perform 8 or 16 bit PCI accesses.
|
||||||
|
*/
|
||||||
|
u32 hc_capbase;
|
||||||
|
#define HC_LENGTH(p) (((p)>>00)&0x00ff) /* bits 7:0 */
|
||||||
|
#define HC_VERSION(p) (((p)>>16)&0xffff) /* bits 31:16 */
|
||||||
|
u32 hcs_params; /* HCSPARAMS - offset 0x4 */
|
||||||
|
#define HCS_DEBUG_PORT(p) (((p)>>20)&0xf) /* bits 23:20, debug port? */
|
||||||
|
#define HCS_INDICATOR(p) ((p)&(1 << 16)) /* true: has port indicators */
|
||||||
|
#define HCS_N_CC(p) (((p)>>12)&0xf) /* bits 15:12, #companion HCs */
|
||||||
|
#define HCS_N_PCC(p) (((p)>>8)&0xf) /* bits 11:8, ports per CC */
|
||||||
|
#define HCS_PORTROUTED(p) ((p)&(1 << 7)) /* true: port routing */
|
||||||
|
#define HCS_PPC(p) ((p)&(1 << 4)) /* true: port power control */
|
||||||
|
#define HCS_N_PORTS(p) (((p)>>0)&0xf) /* bits 3:0, ports on HC */
|
||||||
|
|
||||||
|
u32 hcc_params; /* HCCPARAMS - offset 0x8 */
|
||||||
|
#define HCC_EXT_CAPS(p) (((p)>>8)&0xff) /* for pci extended caps */
|
||||||
|
#define HCC_ISOC_CACHE(p) ((p)&(1 << 7)) /* true: can cache isoc frame */
|
||||||
|
#define HCC_ISOC_THRES(p) (((p)>>4)&0x7) /* bits 6:4, uframes cached */
|
||||||
|
#define HCC_CANPARK(p) ((p)&(1 << 2)) /* true: can park on async qh */
|
||||||
|
#define HCC_PGM_FRAMELISTLEN(p) ((p)&(1 << 1)) /* true: periodic_size changes*/
|
||||||
|
#define HCC_64BIT_ADDR(p) ((p)&(1)) /* true: can use 64-bit addr */
|
||||||
|
u8 portroute [8]; /* nibbles for routing - offset 0xC */
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
|
||||||
|
/* Section 2.3 Host Controller Operational Registers */
|
||||||
|
struct ehci_regs {
|
||||||
|
|
||||||
|
/* USBCMD: offset 0x00 */
|
||||||
|
u32 command;
|
||||||
|
/* 23:16 is r/w intr rate, in microframes; default "8" == 1/msec */
|
||||||
|
#define CMD_PARK (1<<11) /* enable "park" on async qh */
|
||||||
|
#define CMD_PARK_CNT(c) (((c)>>8)&3) /* how many transfers to park for */
|
||||||
|
#define CMD_LRESET (1<<7) /* partial reset (no ports, etc) */
|
||||||
|
#define CMD_IAAD (1<<6) /* "doorbell" interrupt async advance */
|
||||||
|
#define CMD_ASE (1<<5) /* async schedule enable */
|
||||||
|
#define CMD_PSE (1<<4) /* periodic schedule enable */
|
||||||
|
/* 3:2 is periodic frame list size */
|
||||||
|
#define CMD_RESET (1<<1) /* reset HC not bus */
|
||||||
|
#define CMD_RUN (1<<0) /* start/stop HC */
|
||||||
|
|
||||||
|
/* USBSTS: offset 0x04 */
|
||||||
|
u32 status;
|
||||||
|
#define STS_ASS (1<<15) /* Async Schedule Status */
|
||||||
|
#define STS_PSS (1<<14) /* Periodic Schedule Status */
|
||||||
|
#define STS_RECL (1<<13) /* Reclamation */
|
||||||
|
#define STS_HALT (1<<12) /* Not running (any reason) */
|
||||||
|
/* some bits reserved */
|
||||||
|
/* these STS_* flags are also intr_enable bits (USBINTR) */
|
||||||
|
#define STS_IAA (1<<5) /* Interrupted on async advance */
|
||||||
|
#define STS_FATAL (1<<4) /* such as some PCI access errors */
|
||||||
|
#define STS_FLR (1<<3) /* frame list rolled over */
|
||||||
|
#define STS_PCD (1<<2) /* port change detect */
|
||||||
|
#define STS_ERR (1<<1) /* "error" completion (overflow, ...) */
|
||||||
|
#define STS_INT (1<<0) /* "normal" completion (short, ...) */
|
||||||
|
|
||||||
|
/* USBINTR: offset 0x08 */
|
||||||
|
u32 intr_enable;
|
||||||
|
|
||||||
|
/* FRINDEX: offset 0x0C */
|
||||||
|
u32 frame_index; /* current microframe number */
|
||||||
|
/* CTRLDSSEGMENT: offset 0x10 */
|
||||||
|
u32 segment; /* address bits 63:32 if needed */
|
||||||
|
/* PERIODICLISTBASE: offset 0x14 */
|
||||||
|
u32 frame_list; /* points to periodic list */
|
||||||
|
/* ASYNCLISTADDR: offset 0x18 */
|
||||||
|
u32 async_next; /* address of next async queue head */
|
||||||
|
|
||||||
|
u32 reserved [9];
|
||||||
|
|
||||||
|
/* CONFIGFLAG: offset 0x40 */
|
||||||
|
u32 configured_flag;
|
||||||
|
#define FLAG_CF (1<<0) /* true: we'll support "high speed" */
|
||||||
|
|
||||||
|
/* PORTSC: offset 0x44 */
|
||||||
|
u32 port_status [0]; /* up to N_PORTS */
|
||||||
|
/* 31:23 reserved */
|
||||||
|
#define PORT_WKOC_E (1<<22) /* wake on overcurrent (enable) */
|
||||||
|
#define PORT_WKDISC_E (1<<21) /* wake on disconnect (enable) */
|
||||||
|
#define PORT_WKCONN_E (1<<20) /* wake on connect (enable) */
|
||||||
|
/* 19:16 for port testing */
|
||||||
|
#define PORT_LED_OFF (0<<14)
|
||||||
|
#define PORT_LED_AMBER (1<<14)
|
||||||
|
#define PORT_LED_GREEN (2<<14)
|
||||||
|
#define PORT_LED_MASK (3<<14)
|
||||||
|
#define PORT_OWNER (1<<13) /* true: companion hc owns this port */
|
||||||
|
#define PORT_POWER (1<<12) /* true: has power (see PPC) */
|
||||||
|
#define PORT_USB11(x) (((x)&(3<<10)) == (1<<10)) /* USB 1.1 device */
|
||||||
|
/* 11:10 for detecting lowspeed devices (reset vs release ownership) */
|
||||||
|
/* 9 reserved */
|
||||||
|
#define PORT_RESET (1<<8) /* reset port */
|
||||||
|
#define PORT_SUSPEND (1<<7) /* suspend port */
|
||||||
|
#define PORT_RESUME (1<<6) /* resume it */
|
||||||
|
#define PORT_OCC (1<<5) /* over current change */
|
||||||
|
#define PORT_OC (1<<4) /* over current active */
|
||||||
|
#define PORT_PEC (1<<3) /* port enable change */
|
||||||
|
#define PORT_PE (1<<2) /* port enable */
|
||||||
|
#define PORT_CSC (1<<1) /* connect status change */
|
||||||
|
#define PORT_CONNECT (1<<0) /* device connected */
|
||||||
|
#define PORT_RWC_BITS (PORT_CSC | PORT_PEC | PORT_OCC)
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
#define USBMODE 0x68 /* USB Device mode */
|
||||||
|
#define USBMODE_SDIS (1<<3) /* Stream disable */
|
||||||
|
#define USBMODE_BE (1<<2) /* BE/LE endianness select */
|
||||||
|
#define USBMODE_CM_HC (3<<0) /* host controller mode */
|
||||||
|
#define USBMODE_CM_IDLE (0<<0) /* idle state */
|
||||||
|
|
||||||
|
/* Appendix C, Debug port ... intended for use with special "debug devices"
|
||||||
|
* that can help if there's no serial console. (nonstandard enumeration.)
|
||||||
|
*/
|
||||||
|
struct ehci_dbg_port {
|
||||||
|
u32 control;
|
||||||
|
#define DBGP_OWNER (1<<30)
|
||||||
|
#define DBGP_ENABLED (1<<28)
|
||||||
|
#define DBGP_DONE (1<<16)
|
||||||
|
#define DBGP_INUSE (1<<10)
|
||||||
|
#define DBGP_ERRCODE(x) (((x)>>7)&0x07)
|
||||||
|
# define DBGP_ERR_BAD 1
|
||||||
|
# define DBGP_ERR_SIGNAL 2
|
||||||
|
#define DBGP_ERROR (1<<6)
|
||||||
|
#define DBGP_GO (1<<5)
|
||||||
|
#define DBGP_OUT (1<<4)
|
||||||
|
#define DBGP_LEN(x) (((x)>>0)&0x0f)
|
||||||
|
u32 pids;
|
||||||
|
#define DBGP_PID_GET(x) (((x)>>16)&0xff)
|
||||||
|
#define DBGP_PID_SET(data, tok) (((data)<<8)|(tok))
|
||||||
|
u32 data03;
|
||||||
|
u32 data47;
|
||||||
|
u32 address;
|
||||||
|
#define DBGP_EPADDR(dev, ep) (((dev)<<8)|(ep))
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
#endif /* __LINUX_USB_EHCI_DEF_H */
|
55
ehci_types.h
Normal file
55
ehci_types.h
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
#ifndef __EHCI_TYPES_H__
|
||||||
|
#define __EHCI_TYPES_H__
|
||||||
|
|
||||||
|
#include "global.h"
|
||||||
|
|
||||||
|
/* linux kernel types needed by our code */
|
||||||
|
#define __iomem
|
||||||
|
|
||||||
|
typedef unsigned long uint32_t;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
typedef unsigned long u32;
|
||||||
|
typedef signed long s32;
|
||||||
|
typedef unsigned short u16;
|
||||||
|
typedef unsigned char u8;
|
||||||
|
typedef char s8;
|
||||||
|
typedef unsigned long long u64;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define __u32 u32
|
||||||
|
#define __le32 u32
|
||||||
|
#define dma_addr_t u32
|
||||||
|
#define __GNUG__
|
||||||
|
typedef u32 spinlock_t;
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
GFP_KERNEL=1
|
||||||
|
}gfp_t;
|
||||||
|
struct timer_list
|
||||||
|
{
|
||||||
|
int time;
|
||||||
|
};
|
||||||
|
enum{
|
||||||
|
ENODEV =1,
|
||||||
|
ETIMEDOUT,
|
||||||
|
EINVAL,
|
||||||
|
ENOMEM,
|
||||||
|
|
||||||
|
};
|
||||||
|
#define jiffies 0
|
||||||
|
#define likely(x) (x)
|
||||||
|
#define unlikely(x) (x)
|
||||||
|
#define container_of(ptr, type, member) ({ \
|
||||||
|
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
|
||||||
|
(type *)( (char *)__mptr - offsetof(type,member) );})
|
||||||
|
|
||||||
|
#undef offsetof
|
||||||
|
#ifdef __compiler_offsetof
|
||||||
|
#define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER)
|
||||||
|
#else
|
||||||
|
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
@ -1,6 +1,6 @@
|
|||||||
include ../starlet.mk
|
include starlet.mk
|
||||||
|
|
||||||
CFLAGS += -fpic
|
CFLAGS += -fpic -fno-builtin-memcpy
|
||||||
LDSCRIPT = stub.ld
|
LDSCRIPT = stub.ld
|
||||||
LIBS = -lgcc
|
LIBS = -lgcc
|
||||||
|
|
||||||
@ -8,7 +8,7 @@ TARGET = elfloader.elf
|
|||||||
TARGET_BIN = elfloader.bin
|
TARGET_BIN = elfloader.bin
|
||||||
OBJS = start.o stub.o string.o utils.o
|
OBJS = start.o stub.o string.o utils.o
|
||||||
|
|
||||||
include ../common.mk
|
include common.mk
|
||||||
|
|
||||||
all: $(TARGET_BIN)
|
all: $(TARGET_BIN)
|
||||||
|
|
||||||
|
2
global.h
2
global.h
@ -15,7 +15,7 @@
|
|||||||
#define PADHOOK 1
|
#define PADHOOK 1
|
||||||
|
|
||||||
#define CONFIG_VERSION 0x00000002
|
#define CONFIG_VERSION 0x00000002
|
||||||
#define DML_VERSION 0x0002000B
|
#define DM_VERSION 0x0002000B
|
||||||
|
|
||||||
#define DI_SUCCESS 1
|
#define DI_SUCCESS 1
|
||||||
#define DI_ERROR 2
|
#define DI_ERROR 2
|
||||||
|
70
main.c
70
main.c
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
|
|
||||||
DIOS MIOS Lite - Gamecube SD loader for Nintendo Wii
|
DIOS MIOS - Gamecube USB loader for Nintendo Wii
|
||||||
|
|
||||||
Copyright (C) 2010-2012 crediar
|
Copyright (C) 2010-2012 crediar
|
||||||
|
|
||||||
@ -16,7 +16,6 @@ Copyright (C) 2010-2012 crediar
|
|||||||
#include "Patches.h"
|
#include "Patches.h"
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
#include "Card.h"
|
#include "Card.h"
|
||||||
#include "sdhc.h"
|
|
||||||
#include "DVD.h"
|
#include "DVD.h"
|
||||||
#include "Drive.h"
|
#include "Drive.h"
|
||||||
#include "dip.h"
|
#include "dip.h"
|
||||||
@ -118,9 +117,6 @@ u32 fail;
|
|||||||
|
|
||||||
int main( int argc, char *argv[] )
|
int main( int argc, char *argv[] )
|
||||||
{
|
{
|
||||||
FATFS fatfs;
|
|
||||||
s32 fres = 0;
|
|
||||||
|
|
||||||
udelay(800);
|
udelay(800);
|
||||||
|
|
||||||
#ifndef REALNAND
|
#ifndef REALNAND
|
||||||
@ -154,44 +150,56 @@ int main( int argc, char *argv[] )
|
|||||||
MIOSInit();
|
MIOSInit();
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
dbgprintf("DIOS-MIOS Lite [DEBUG] v%d.%d\n", DML_VERSION>>16, DML_VERSION & 0xFFFF );
|
dbgprintf("DIOS-MIOS [DEBUG] v%d.%d\n", DM_VERSION>>16, DM_VERSION & 0xFFFF );
|
||||||
#else
|
#else
|
||||||
#ifdef REALNAND
|
#ifdef REALNAND
|
||||||
dbgprintf("DIOS-MIOS Lite v%d.%db\n", DML_VERSION>>16, DML_VERSION & 0xFFFF );
|
dbgprintf("DIOS-MIOS v%d.%db\n", DM_VERSION>>16, DM_VERSION & 0xFFFF );
|
||||||
#else
|
#else
|
||||||
dbgprintf("DIOS-MIOS Lite v%d.%da\n", DML_VERSION>>16, DML_VERSION & 0xFFFF );
|
dbgprintf("DIOS-MIOS v%d.%da\n", DM_VERSION>>16, DM_VERSION & 0xFFFF );
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
dbgprintf("Built: " __DATE__ " " __TIME__ "\n");
|
dbgprintf("Built: " __DATE__ " " __TIME__ "\n");
|
||||||
dbgprintf("This software is licensed under GPLv3, for more details visit:\nhttp://code.google.com/p/diosmioslite\n");
|
dbgprintf("This software is licensed under GPLv3, for more details visit:\nhttp://code.google.com/p/diosmios\n");
|
||||||
|
|
||||||
//dbgprintf("MEMInitLow()...\n");
|
//dbgprintf("MEMInitLow()...\n");
|
||||||
MEMInitLow();
|
MEMInitLow();
|
||||||
|
|
||||||
//EHCIInit();
|
// EHCI
|
||||||
//dbgprintf("EHCIInit()\n");
|
|
||||||
|
*(vu32*)0x0D0400A4 = 0x00004026;
|
||||||
|
*(vu32*)0x0D0400B0 = 0x0002422E;
|
||||||
|
*(vu32*)0x0D0400B4 = 0x03802E14;
|
||||||
|
|
||||||
|
// DDR control
|
||||||
|
|
||||||
|
*(vu16*)0x0D8B4034 = 0x0000;
|
||||||
|
*(vu16*)0x0D8B403C = 0x0000;
|
||||||
|
*(vu16*)0x0D8B4034 = 0x0000;
|
||||||
|
*(vu16*)0x0D8B403C = 0x0000;
|
||||||
|
*(vu16*)0x0D8B4040 = 0x0000;
|
||||||
|
*(vu16*)0x0D8B4044 = 0x0000;
|
||||||
|
*(vu16*)0x0D8B4048 = 0x0000;
|
||||||
|
*(vu16*)0x0D8B404C = 0x0000;
|
||||||
|
*(vu16*)0x0D8B4050 = 0x0000;
|
||||||
|
*(vu16*)0x0D8B4054 = 0x13EB;
|
||||||
|
*(vu16*)0x0D8B4058 = 0x09B5;
|
||||||
|
*(vu16*)0x0D8B4060 = 0x0000;
|
||||||
|
*(vu16*)0x0D8B4064 = 0x0000;
|
||||||
|
*(vu16*)0x0D8B420C = 0x3620;
|
||||||
|
*(vu16*)0x0D8B4220 = 0xF000;
|
||||||
|
|
||||||
udelay(8000);
|
udelay(8000);
|
||||||
|
|
||||||
HeapInit();
|
HeapInit( (u8*)0x13600000 );
|
||||||
//dbgprintf("HeapInit()\n");
|
|
||||||
|
|
||||||
sdhc_init();
|
|
||||||
|
|
||||||
//dbgprintf("f_mount()");
|
|
||||||
fres = f_mount(0, &fatfs );
|
|
||||||
//dbgprintf(":%d\n", fres );
|
|
||||||
|
|
||||||
if( fres != FR_OK )
|
|
||||||
{
|
|
||||||
dbgprintf("Error: Could not mount fatfs, ret: %d\n", fres);
|
|
||||||
Shutdown();
|
|
||||||
}
|
|
||||||
|
|
||||||
set32( HW_EXICTRL, 1 );
|
set32( HW_EXICTRL, 1 );
|
||||||
|
|
||||||
|
DVDInit();
|
||||||
|
|
||||||
ConfigInit( (DML_CFG*)0x01200000 );
|
ConfigInit( (DML_CFG*)0x01200000 );
|
||||||
|
|
||||||
|
ConfigSetConfig( DML_CFG_BOOT_DISC2 );
|
||||||
|
|
||||||
if( !ConfigGetConfig(DML_CFG_BOOT_DISC) )
|
if( !ConfigGetConfig(DML_CFG_BOOT_DISC) )
|
||||||
{
|
{
|
||||||
if( DVDSelectGame() == DI_SUCCESS )
|
if( DVDSelectGame() == DI_SUCCESS )
|
||||||
@ -210,12 +218,23 @@ int main( int argc, char *argv[] )
|
|||||||
|
|
||||||
DIInit();
|
DIInit();
|
||||||
|
|
||||||
|
//Switch mem2 to ARAM
|
||||||
|
DRAMCTRLWrite( 0x49, 0x0E );
|
||||||
|
udelay(2);
|
||||||
|
|
||||||
|
DRAMCTRLWrite( 0x49, 0x0F );
|
||||||
|
udelay(2);
|
||||||
|
|
||||||
|
HeapInit( (u8*)0xFFFE5000 );
|
||||||
|
|
||||||
write32( HW_PPCIRQFLAG, read32(HW_PPCIRQFLAG) );
|
write32( HW_PPCIRQFLAG, read32(HW_PPCIRQFLAG) );
|
||||||
write32( HW_ARMIRQFLAG, read32(HW_ARMIRQFLAG) );
|
write32( HW_ARMIRQFLAG, read32(HW_ARMIRQFLAG) );
|
||||||
|
|
||||||
set32( HW_PPCIRQMASK, (1<<31) );
|
set32( HW_PPCIRQMASK, (1<<31) );
|
||||||
set32( HW_IPC_PPCCTRL, 0x30 );
|
set32( HW_IPC_PPCCTRL, 0x30 );
|
||||||
|
|
||||||
|
write32( 0x0D806008, 0 );
|
||||||
|
|
||||||
EXIControl(0);
|
EXIControl(0);
|
||||||
|
|
||||||
write32( 0x1860, 0xdeadbeef ); // Clear OSReport area
|
write32( 0x1860, 0xdeadbeef ); // Clear OSReport area
|
||||||
@ -265,7 +284,6 @@ int main( int argc, char *argv[] )
|
|||||||
{
|
{
|
||||||
SysReset();
|
SysReset();
|
||||||
}
|
}
|
||||||
|
|
||||||
if( (((read32(0x12FC) >> 16) & 0x234) == 0x234 ) )
|
if( (((read32(0x12FC) >> 16) & 0x234) == 0x234 ) )
|
||||||
{
|
{
|
||||||
SysShutdown();
|
SysShutdown();
|
||||||
|
854
sdhc.c
854
sdhc.c
@ -1,854 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
|
|
||||||
* Copyright (c) 2009 Sven Peter <svenpeter@gmail.com>
|
|
||||||
*
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
|
||||||
* copyright notice and this permission notice appear in all copies.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
||||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
||||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
||||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
||||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* SD Host Controller driver based on the SD Host Controller Standard
|
|
||||||
* Simplified Specification Version 1.00 (www.sdcard.com).
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "bsdtypes.h"
|
|
||||||
#include "sdmmc.h"
|
|
||||||
#include "sdhc.h"
|
|
||||||
#include "string.h"
|
|
||||||
#include "utils.h"
|
|
||||||
#include "memory.h"
|
|
||||||
|
|
||||||
struct sdhc_host sc_host;
|
|
||||||
|
|
||||||
//#define SDHC_DEBUG
|
|
||||||
|
|
||||||
#define SDHC_COMMAND_TIMEOUT 500
|
|
||||||
#define SDHC_TRANSFER_TIMEOUT 5000
|
|
||||||
|
|
||||||
#define sdhc_wait_intr(a,b,c) sdhc_wait_intr_debug(__func__, __LINE__, a, b, c)
|
|
||||||
|
|
||||||
static inline u32 bus_space_read_4(bus_space_handle_t ioh, u32 reg)
|
|
||||||
{
|
|
||||||
return read32(ioh + reg);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline u16 bus_space_read_2(bus_space_handle_t ioh, u32 reg)
|
|
||||||
{
|
|
||||||
u32 val;
|
|
||||||
if(reg & 3)
|
|
||||||
val = (read32((ioh + reg) & ~3) & 0xffff0000) >> 16;
|
|
||||||
else
|
|
||||||
val = (read32(ioh + reg) & 0xffff);
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline u8 bus_space_read_1(bus_space_handle_t ioh, u32 reg)
|
|
||||||
{
|
|
||||||
u32 mask;
|
|
||||||
u32 addr;
|
|
||||||
u8 shift;
|
|
||||||
|
|
||||||
shift = (reg & 3) * 8;
|
|
||||||
mask = (0xFF << shift);
|
|
||||||
addr = ioh + reg;
|
|
||||||
|
|
||||||
return (read32(addr & ~3) & mask) >> shift;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void bus_space_write_4(bus_space_handle_t ioh, u32 r, u32 v)
|
|
||||||
{
|
|
||||||
write32(ioh + r, v);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void bus_space_write_2(bus_space_handle_t ioh, u32 r, u16 v)
|
|
||||||
{
|
|
||||||
if(r & 3)
|
|
||||||
mask32((ioh + r) & ~3, 0xffff0000, v << 16);
|
|
||||||
else
|
|
||||||
mask32((ioh + r), 0xffff, ((u32)v));
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void bus_space_write_1(bus_space_handle_t ioh, u32 r, u8 v)
|
|
||||||
{
|
|
||||||
u32 mask;
|
|
||||||
u32 addr;
|
|
||||||
u8 shift;
|
|
||||||
|
|
||||||
shift = (r & 3) * 8;
|
|
||||||
mask = (0xFF << shift);
|
|
||||||
addr = ioh + r;
|
|
||||||
|
|
||||||
mask32(addr & ~3, mask, v << shift);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/* flag values */
|
|
||||||
#define SHF_USE_DMA 0x0001
|
|
||||||
|
|
||||||
#define HREAD1(hp, reg) \
|
|
||||||
(bus_space_read_1((hp)->ioh, (reg)))
|
|
||||||
#define HREAD2(hp, reg) \
|
|
||||||
(bus_space_read_2((hp)->ioh, (reg)))
|
|
||||||
#define HREAD4(hp, reg) \
|
|
||||||
(bus_space_read_4((hp)->ioh, (reg)))
|
|
||||||
#define HWRITE1(hp, reg, val) \
|
|
||||||
bus_space_write_1((hp)->ioh, (reg), (val))
|
|
||||||
#define HWRITE2(hp, reg, val) \
|
|
||||||
bus_space_write_2((hp)->ioh, (reg), (val))
|
|
||||||
#define HWRITE4(hp, reg, val) \
|
|
||||||
bus_space_write_4((hp)->ioh, (reg), (val))
|
|
||||||
#define HCLR1(hp, reg, bits) \
|
|
||||||
HWRITE1((hp), (reg), HREAD1((hp), (reg)) & ~(bits))
|
|
||||||
#define HCLR2(hp, reg, bits) \
|
|
||||||
HWRITE2((hp), (reg), HREAD2((hp), (reg)) & ~(bits))
|
|
||||||
#define HSET1(hp, reg, bits) \
|
|
||||||
HWRITE1((hp), (reg), HREAD1((hp), (reg)) | (bits))
|
|
||||||
#define HSET2(hp, reg, bits) \
|
|
||||||
HWRITE2((hp), (reg), HREAD2((hp), (reg)) | (bits))
|
|
||||||
|
|
||||||
int sdhc_start_command(struct sdhc_host *, struct sdmmc_command *);
|
|
||||||
int sdhc_wait_state(struct sdhc_host *, u_int32_t, u_int32_t);
|
|
||||||
int sdhc_soft_reset(struct sdhc_host *, int);
|
|
||||||
void sdhc_reset_intr_status(struct sdhc_host *hp);
|
|
||||||
int sdhc_wait_intr_debug(const char *func, int line, struct sdhc_host *, int, int);
|
|
||||||
void sdhc_transfer_data(struct sdhc_host *, struct sdmmc_command *);
|
|
||||||
void sdhc_read_data(struct sdhc_host *, u_char *, int);
|
|
||||||
void sdhc_write_data(struct sdhc_host *, u_char *, int);
|
|
||||||
//#define SDHC_DEBUG 1
|
|
||||||
#ifdef SDHC_DEBUG
|
|
||||||
int sdhcdebug = 0;
|
|
||||||
#define DPRINTF(n,s) do { if ((n) <= sdhcdebug) dbgprintf s; } while (0)
|
|
||||||
void sdhc_dump_regs(struct sdhc_host *);
|
|
||||||
#else
|
|
||||||
#define DPRINTF(n,s) do {} while(0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Called by attachment driver. For each SD card slot there is one SD
|
|
||||||
* host controller standard register set. (1.3)
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
sdhc_host_found(bus_space_tag_t iot, bus_space_handle_t ioh, int usedma)
|
|
||||||
{
|
|
||||||
u_int32_t caps;
|
|
||||||
int error = 1;
|
|
||||||
|
|
||||||
#ifdef SDHC_DEBUG
|
|
||||||
u_int16_t version;
|
|
||||||
|
|
||||||
version = bus_space_read_2(ioh, SDHC_HOST_CTL_VERSION);
|
|
||||||
dbgprintf("sdhc: SD Host Specification/Vendor Version ");
|
|
||||||
|
|
||||||
switch(SDHC_SPEC_VERSION(version)) {
|
|
||||||
case 0x00:
|
|
||||||
dbgprintf("1.0/%u\n", SDHC_VENDOR_VERSION(version));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
dbgprintf(">1.0/%u\n", SDHC_VENDOR_VERSION(version));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
memset8(&sc_host, 0, sizeof(sc_host));
|
|
||||||
|
|
||||||
/* Fill in the new host structure. */
|
|
||||||
sc_host.iot = iot;
|
|
||||||
sc_host.ioh = ioh;
|
|
||||||
sc_host.data_command = 0;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Reset the host controller and enable interrupts.
|
|
||||||
*/
|
|
||||||
error = sdhc_host_reset(&sc_host);
|
|
||||||
|
|
||||||
/* Determine host capabilities. */
|
|
||||||
caps = HREAD4(&sc_host, SDHC_CAPABILITIES);
|
|
||||||
|
|
||||||
/* Use DMA if the host system and the controller support it. */
|
|
||||||
if (usedma && ISSET(caps, SDHC_DMA_SUPPORT))
|
|
||||||
SET(sc_host.flags, SHF_USE_DMA);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Determine the base clock frequency. (2.2.24)
|
|
||||||
*/
|
|
||||||
if (SDHC_BASE_FREQ_KHZ(caps) != 0)
|
|
||||||
sc_host.clkbase = SDHC_BASE_FREQ_KHZ(caps);
|
|
||||||
if (sc_host.clkbase == 0) {
|
|
||||||
/* The attachment driver must tell us. */
|
|
||||||
//dbgprintf("sdhc: base clock frequency unknown\n");
|
|
||||||
goto err;
|
|
||||||
} else if (sc_host.clkbase < 10000 || sc_host.clkbase > 63000) {
|
|
||||||
/* SDHC 1.0 supports only 10-63 MHz. */
|
|
||||||
//dbgprintf("sdhc: base clock frequency out of range: %u MHz\n", sc_host.clkbase / 1000);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* XXX Set the data timeout counter value according to
|
|
||||||
* capabilities. (2.2.15)
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (ISSET(caps, SDHC_VOLTAGE_SUPP_1_8V))
|
|
||||||
SET(sc_host.ocr, MMC_OCR_1_7V_1_8V | MMC_OCR_1_8V_1_9V);
|
|
||||||
if (ISSET(caps, SDHC_VOLTAGE_SUPP_3_0V))
|
|
||||||
SET(sc_host.ocr, MMC_OCR_2_9V_3_0V | MMC_OCR_3_0V_3_1V);
|
|
||||||
if (ISSET(caps, SDHC_VOLTAGE_SUPP_3_3V))
|
|
||||||
SET(sc_host.ocr, MMC_OCR_3_2V_3_3V | MMC_OCR_3_3V_3_4V);
|
|
||||||
/*
|
|
||||||
* Determine the maximum block length supported by the host
|
|
||||||
* controller. (2.2.24)
|
|
||||||
*/
|
|
||||||
//switch((caps >> SDHC_MAX_BLK_LEN_SHIFT) & SDHC_MAX_BLK_LEN_MASK)
|
|
||||||
//{
|
|
||||||
// case SDHC_MAX_BLK_LEN_512:
|
|
||||||
// hp->maxblklen = 512;
|
|
||||||
// break;
|
|
||||||
// case SDHC_MAX_BLK_LEN_1024:
|
|
||||||
// hp->maxblklen = 1024;
|
|
||||||
// break;
|
|
||||||
// case SDHC_MAX_BLK_LEN_2048:
|
|
||||||
// hp->maxblklen = 2048;
|
|
||||||
// break;
|
|
||||||
// default:
|
|
||||||
// hp->maxblklen = 1;
|
|
||||||
// break;
|
|
||||||
//}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Attach the generic SD/MMC bus driver. (The bus driver must
|
|
||||||
* not invoke any chipset functions before it is attached.)
|
|
||||||
*/
|
|
||||||
sdmmc_attach(&sc_host);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
err:
|
|
||||||
return (error);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef LOADER
|
|
||||||
/*
|
|
||||||
* Shutdown hook established by or called from attachment driver.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
sdhc_shutdown(void)
|
|
||||||
{
|
|
||||||
/* XXX chip locks up if we don't disable it before reboot. */
|
|
||||||
(void)sdhc_host_reset(&sc_host);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Reset the host controller. Called during initialization, when
|
|
||||||
* cards are removed, upon resume, and during error recovery.
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
sdhc_host_reset(struct sdhc_host *hp)
|
|
||||||
{
|
|
||||||
u_int16_t imask;
|
|
||||||
int error;
|
|
||||||
|
|
||||||
/* Disable all interrupts. */
|
|
||||||
HWRITE2(hp, SDHC_NINTR_SIGNAL_EN, 0);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Reset the entire host controller and wait up to 100ms for
|
|
||||||
* the controller to clear the reset bit.
|
|
||||||
*/
|
|
||||||
if ((error = sdhc_soft_reset(hp, SDHC_RESET_ALL)) != 0)
|
|
||||||
{
|
|
||||||
return (error);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set data timeout counter value to max for now. */
|
|
||||||
HWRITE1(hp, SDHC_TIMEOUT_CTL, SDHC_TIMEOUT_MAX);
|
|
||||||
|
|
||||||
/* Enable interrupts. */
|
|
||||||
imask =
|
|
||||||
#ifndef LOADER
|
|
||||||
SDHC_CARD_REMOVAL | SDHC_CARD_INSERTION |
|
|
||||||
#endif
|
|
||||||
SDHC_BUFFER_READ_READY | SDHC_BUFFER_WRITE_READY |
|
|
||||||
SDHC_DMA_INTERRUPT | SDHC_BLOCK_GAP_EVENT |
|
|
||||||
SDHC_TRANSFER_COMPLETE | SDHC_COMMAND_COMPLETE;
|
|
||||||
|
|
||||||
HWRITE2(hp, SDHC_NINTR_STATUS_EN, imask);
|
|
||||||
HWRITE2(hp, SDHC_EINTR_STATUS_EN, SDHC_EINTR_STATUS_MASK);
|
|
||||||
HWRITE2(hp, SDHC_NINTR_SIGNAL_EN, imask);
|
|
||||||
HWRITE2(hp, SDHC_EINTR_SIGNAL_EN, SDHC_EINTR_SIGNAL_MASK);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Return non-zero if the card is currently inserted.
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
sdhc_card_detect(struct sdhc_host *hp)
|
|
||||||
{
|
|
||||||
return ISSET(HREAD4(hp, SDHC_PRESENT_STATE), SDHC_CARD_INSERTED) ?
|
|
||||||
1 : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Set or change SD bus voltage and enable or disable SD bus power.
|
|
||||||
* Return zero on success.
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
sdhc_bus_power(struct sdhc_host *hp, u_int32_t ocr)
|
|
||||||
{
|
|
||||||
//dbgprintf("sdhc_bus_power(%u)\n", ocr);
|
|
||||||
/* Disable bus power before voltage change. */
|
|
||||||
HWRITE1(hp, SDHC_POWER_CTL, 0);
|
|
||||||
|
|
||||||
/* If power is disabled, reset the host and return now. */
|
|
||||||
if (ocr == 0) {
|
|
||||||
(void)sdhc_host_reset(hp);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Enable bus power. Wait at least 1 ms (or 74 clocks) plus
|
|
||||||
* voltage ramp until power rises.
|
|
||||||
*/
|
|
||||||
HWRITE1(hp, SDHC_POWER_CTL, (SDHC_VOLTAGE_3_3V << SDHC_VOLTAGE_SHIFT) |
|
|
||||||
SDHC_BUS_POWER);
|
|
||||||
udelay(10000);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The host system may not power the bus due to battery low,
|
|
||||||
* etc. In that case, the host controller should clear the
|
|
||||||
* bus power bit.
|
|
||||||
*/
|
|
||||||
if (!ISSET(HREAD1(hp, SDHC_POWER_CTL), SDHC_BUS_POWER))
|
|
||||||
{
|
|
||||||
//dbgprintf("Host controller failed to enable bus power\n");
|
|
||||||
return ENXIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Return the smallest possible base clock frequency divisor value
|
|
||||||
* for the CLOCK_CTL register to produce `freq' (KHz).
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
sdhc_clock_divisor(struct sdhc_host *hp, u_int freq)
|
|
||||||
{
|
|
||||||
int div;
|
|
||||||
|
|
||||||
for (div = 1; div <= 256; div *= 2)
|
|
||||||
if ((hp->clkbase / div) <= freq)
|
|
||||||
return (div / 2);
|
|
||||||
/* No divisor found. */
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Set or change SDCLK frequency or disable the SD clock.
|
|
||||||
* Return zero on success.
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
sdhc_bus_clock(struct sdhc_host *hp, int freq)
|
|
||||||
{
|
|
||||||
int div;
|
|
||||||
int timo;
|
|
||||||
|
|
||||||
//dbgprintf("%s(%d)\n", __FUNCTION__, freq);
|
|
||||||
#ifdef DIAGNOSTIC
|
|
||||||
/* Must not stop the clock if commands are in progress. */
|
|
||||||
if (ISSET(HREAD4(hp, SDHC_PRESENT_STATE), SDHC_CMD_INHIBIT_MASK) &&
|
|
||||||
sdhc_card_detect(hp))
|
|
||||||
dbgprintf("sdhc_sdclk_frequency_select: command in progress\n");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Stop SD clock before changing the frequency. */
|
|
||||||
HWRITE2(hp, SDHC_CLOCK_CTL, 0);
|
|
||||||
if (freq == SDMMC_SDCLK_OFF)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* Set the minimum base clock frequency divisor. */
|
|
||||||
if ((div = sdhc_clock_divisor(hp, freq)) < 0) {
|
|
||||||
/* Invalid base clock frequency or `freq' value. */
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
HWRITE2(hp, SDHC_CLOCK_CTL, div << SDHC_SDCLK_DIV_SHIFT);
|
|
||||||
|
|
||||||
/* Start internal clock. Wait 10ms for stabilization. */
|
|
||||||
HSET2(hp, SDHC_CLOCK_CTL, SDHC_INTCLK_ENABLE);
|
|
||||||
for (timo = 1000; timo > 0; timo--) {
|
|
||||||
if (ISSET(HREAD2(hp, SDHC_CLOCK_CTL), SDHC_INTCLK_STABLE))
|
|
||||||
break;
|
|
||||||
udelay(10);
|
|
||||||
}
|
|
||||||
if (timo == 0) {
|
|
||||||
//dbgprintf("sdhc: internal clock never stabilized\n");
|
|
||||||
return ETIMEDOUT;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Enable SD clock. */
|
|
||||||
HSET2(hp, SDHC_CLOCK_CTL, SDHC_SDCLK_ENABLE);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
sdhc_card_intr_mask(struct sdhc_host *hp, int enable)
|
|
||||||
{
|
|
||||||
if (enable) {
|
|
||||||
HSET2(hp, SDHC_NINTR_STATUS_EN, SDHC_CARD_INTERRUPT);
|
|
||||||
HSET2(hp, SDHC_NINTR_SIGNAL_EN, SDHC_CARD_INTERRUPT);
|
|
||||||
} else {
|
|
||||||
HCLR2(hp, SDHC_NINTR_SIGNAL_EN, SDHC_CARD_INTERRUPT);
|
|
||||||
HCLR2(hp, SDHC_NINTR_STATUS_EN, SDHC_CARD_INTERRUPT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
sdhc_card_intr_ack(struct sdhc_host *hp)
|
|
||||||
{
|
|
||||||
HSET2(hp, SDHC_NINTR_STATUS_EN, SDHC_CARD_INTERRUPT);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
sdhc_wait_state(struct sdhc_host *hp, u_int32_t mask, u_int32_t value)
|
|
||||||
{
|
|
||||||
u_int32_t state;
|
|
||||||
int timeout;
|
|
||||||
|
|
||||||
for (timeout = 500; timeout > 0; timeout--) {
|
|
||||||
if (((state = HREAD4(hp, SDHC_PRESENT_STATE)) & mask) == value)
|
|
||||||
return 0;
|
|
||||||
udelay(10000);
|
|
||||||
}
|
|
||||||
return ETIMEDOUT;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
sdhc_exec_command(struct sdhc_host *hp, struct sdmmc_command *cmd)
|
|
||||||
{
|
|
||||||
int error;
|
|
||||||
|
|
||||||
if (cmd->c_datalen > 0)
|
|
||||||
hp->data_command = 1;
|
|
||||||
|
|
||||||
if (cmd->c_timeout == 0) {
|
|
||||||
if (cmd->c_datalen > 0)
|
|
||||||
cmd->c_timeout = SDHC_TRANSFER_TIMEOUT;
|
|
||||||
else
|
|
||||||
cmd->c_timeout = SDHC_COMMAND_TIMEOUT;
|
|
||||||
}
|
|
||||||
|
|
||||||
hp->intr_status = 0;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Start the MMC command, or mark `cmd' as failed and return.
|
|
||||||
*/
|
|
||||||
error = sdhc_start_command(hp, cmd);
|
|
||||||
if (error != 0) {
|
|
||||||
cmd->c_error = error;
|
|
||||||
SET(cmd->c_flags, SCF_ITSDONE);
|
|
||||||
hp->data_command = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Wait until the command phase is done, or until the command
|
|
||||||
* is marked done for any other reason.
|
|
||||||
*/
|
|
||||||
|
|
||||||
int status = sdhc_wait_intr(hp, SDHC_COMMAND_COMPLETE, cmd->c_timeout);
|
|
||||||
if (!ISSET(status, SDHC_COMMAND_COMPLETE)) {
|
|
||||||
cmd->c_error = ETIMEDOUT;
|
|
||||||
//dbgprintf("timeout dump: error_intr: 0x%x intr: 0x%x\n", hp->intr_error_status, hp->intr_status);
|
|
||||||
//sdhc_dump_regs(hp);
|
|
||||||
SET(cmd->c_flags, SCF_ITSDONE);
|
|
||||||
hp->data_command = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//dbgprintf("command_complete, continuing...\n");
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The host controller removes bits [0:7] from the response
|
|
||||||
* data (CRC) and we pass the data up unchanged to the bus
|
|
||||||
* driver (without padding).
|
|
||||||
*/
|
|
||||||
if (cmd->c_error == 0 && ISSET(cmd->c_flags, SCF_RSP_PRESENT)) {
|
|
||||||
if (ISSET(cmd->c_flags, SCF_RSP_136)) {
|
|
||||||
u_char *p = (u_char *)cmd->c_resp;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < 15; i++)
|
|
||||||
*p++ = HREAD1(hp, SDHC_RESPONSE + i);
|
|
||||||
} else
|
|
||||||
cmd->c_resp[0] = HREAD4(hp, SDHC_RESPONSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If the command has data to transfer in any direction,
|
|
||||||
* execute the transfer now.
|
|
||||||
*/
|
|
||||||
if (cmd->c_error == 0 && cmd->c_datalen > 0)
|
|
||||||
sdhc_transfer_data(hp, cmd);
|
|
||||||
|
|
||||||
SET(cmd->c_flags, SCF_ITSDONE);
|
|
||||||
hp->data_command = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
sdhc_start_command(struct sdhc_host *hp, struct sdmmc_command *cmd)
|
|
||||||
{
|
|
||||||
u_int16_t blksize = 0;
|
|
||||||
u_int16_t blkcount = 0;
|
|
||||||
u_int16_t mode;
|
|
||||||
u_int16_t command;
|
|
||||||
int error;
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The maximum block length for commands should be the minimum
|
|
||||||
* of the host buffer size and the card buffer size. (1.7.2)
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Fragment the data into proper blocks. */
|
|
||||||
if (cmd->c_datalen > 0) {
|
|
||||||
blksize = MIN(cmd->c_datalen, cmd->c_blklen);
|
|
||||||
blkcount = cmd->c_datalen / blksize;
|
|
||||||
if (cmd->c_datalen % blksize > 0) {
|
|
||||||
/* XXX: Split this command. (1.7.4) */
|
|
||||||
//dbgprintf("sdhc: data not a multiple of %d bytes\n", blksize);
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check limit imposed by 9-bit block count. (1.7.2) */
|
|
||||||
if (blkcount > SDHC_BLOCK_COUNT_MAX) {
|
|
||||||
//dbgprintf("sdhc: too much data\n");
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Prepare transfer mode register value. (2.2.5) */
|
|
||||||
mode = 0;
|
|
||||||
if (ISSET(cmd->c_flags, SCF_CMD_READ))
|
|
||||||
mode |= SDHC_READ_MODE;
|
|
||||||
if (blkcount > 0) {
|
|
||||||
mode |= SDHC_BLOCK_COUNT_ENABLE;
|
|
||||||
// if (blkcount > 1) {
|
|
||||||
mode |= SDHC_MULTI_BLOCK_MODE;
|
|
||||||
/* XXX only for memory commands? */
|
|
||||||
mode |= SDHC_AUTO_CMD12_ENABLE;
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
if (ISSET(hp->flags, SHF_USE_DMA))
|
|
||||||
mode |= SDHC_DMA_ENABLE;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Prepare command register value. (2.2.6)
|
|
||||||
*/
|
|
||||||
command = (cmd->c_opcode & SDHC_COMMAND_INDEX_MASK) <<
|
|
||||||
SDHC_COMMAND_INDEX_SHIFT;
|
|
||||||
|
|
||||||
if (ISSET(cmd->c_flags, SCF_RSP_CRC))
|
|
||||||
command |= SDHC_CRC_CHECK_ENABLE;
|
|
||||||
if (ISSET(cmd->c_flags, SCF_RSP_IDX))
|
|
||||||
command |= SDHC_INDEX_CHECK_ENABLE;
|
|
||||||
if (cmd->c_data != NULL)
|
|
||||||
command |= SDHC_DATA_PRESENT_SELECT;
|
|
||||||
|
|
||||||
if (!ISSET(cmd->c_flags, SCF_RSP_PRESENT))
|
|
||||||
command |= SDHC_NO_RESPONSE;
|
|
||||||
else if (ISSET(cmd->c_flags, SCF_RSP_136))
|
|
||||||
command |= SDHC_RESP_LEN_136;
|
|
||||||
else if (ISSET(cmd->c_flags, SCF_RSP_BSY))
|
|
||||||
command |= SDHC_RESP_LEN_48_CHK_BUSY;
|
|
||||||
else
|
|
||||||
command |= SDHC_RESP_LEN_48;
|
|
||||||
|
|
||||||
/* Wait until command and data inhibit bits are clear. (1.5) */
|
|
||||||
if ((error = sdhc_wait_state(hp, SDHC_CMD_INHIBIT_MASK, 0)) != 0)
|
|
||||||
return error;
|
|
||||||
|
|
||||||
if( ISSET( hp->flags, SHF_USE_DMA) && cmd->c_datalen > 0 )
|
|
||||||
{
|
|
||||||
cmd->c_resid = blkcount;
|
|
||||||
cmd->c_buf = cmd->c_data;
|
|
||||||
|
|
||||||
if( ISSET(cmd->c_flags, SCF_CMD_READ) )
|
|
||||||
{
|
|
||||||
dc_invalidaterange(cmd->c_data, cmd->c_datalen);
|
|
||||||
} else {
|
|
||||||
dc_flushrange(cmd->c_data, cmd->c_datalen);
|
|
||||||
ahb_flush_to(AHB_SDHC);
|
|
||||||
}
|
|
||||||
HWRITE4(hp, SDHC_DMA_ADDR, (u32)cmd->c_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Start a CPU data transfer. Writing to the high order byte
|
|
||||||
* of the SDHC_COMMAND register triggers the SD command. (1.5)
|
|
||||||
*/
|
|
||||||
HWRITE2(hp, SDHC_BLOCK_SIZE, blksize | 7<<12);
|
|
||||||
if (blkcount > 0)
|
|
||||||
HWRITE2(hp, SDHC_BLOCK_COUNT, blkcount);
|
|
||||||
HWRITE4(hp, SDHC_ARGUMENT, cmd->c_arg);
|
|
||||||
HWRITE4(hp, SDHC_TRANSFER_MODE, ((u32)command<<16)|mode);
|
|
||||||
// HWRITE2(hp, SDHC_COMMAND, command);
|
|
||||||
// HWRITE2(hp, SDHC_TRANSFER_MODE, mode);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
sdhc_transfer_data(struct sdhc_host *hp, struct sdmmc_command *cmd)
|
|
||||||
{
|
|
||||||
int error;
|
|
||||||
int status;
|
|
||||||
|
|
||||||
error = 0;
|
|
||||||
|
|
||||||
if (ISSET(hp->flags, SHF_USE_DMA)) {
|
|
||||||
for(;;) {
|
|
||||||
status = sdhc_wait_intr(hp, SDHC_TRANSFER_COMPLETE |
|
|
||||||
SDHC_DMA_INTERRUPT,
|
|
||||||
SDHC_TRANSFER_TIMEOUT);
|
|
||||||
if (!status) {
|
|
||||||
error = ETIMEDOUT;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ISSET(status, SDHC_TRANSFER_COMPLETE))
|
|
||||||
{
|
|
||||||
//dbgprintf("got a TRANSFER_COMPLETE: %08x\n", status);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (ISSET(status, SDHC_DMA_INTERRUPT)) {
|
|
||||||
// this works because our virtual memory
|
|
||||||
// addresses are equal to the physical memory
|
|
||||||
// addresses and because we require the target
|
|
||||||
// buffer to be contiguous
|
|
||||||
HWRITE4(hp, SDHC_DMA_ADDR,
|
|
||||||
HREAD4(hp, SDHC_DMA_ADDR));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef SDHC_DEBUG
|
|
||||||
/* XXX I forgot why I wanted to know when this happens :-( */
|
|
||||||
if ((cmd->c_opcode == 52 || cmd->c_opcode == 53) &&
|
|
||||||
ISSET(MMC_R1(cmd->c_resp), 0xcb00))
|
|
||||||
dbgprintf("sdhc: CMD52/53 error response flags %#x\n",
|
|
||||||
MMC_R1(cmd->c_resp) & 0xff00);
|
|
||||||
#endif
|
|
||||||
if (ISSET(cmd->c_flags, SCF_CMD_READ))
|
|
||||||
ahb_flush_from( AHB_SDHC );
|
|
||||||
|
|
||||||
if (error != 0)
|
|
||||||
cmd->c_error = error;
|
|
||||||
SET(cmd->c_flags, SCF_ITSDONE);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Prepare for another command. */
|
|
||||||
int
|
|
||||||
sdhc_soft_reset(struct sdhc_host *hp, int mask)
|
|
||||||
{
|
|
||||||
int timo;
|
|
||||||
|
|
||||||
|
|
||||||
HWRITE1(hp, SDHC_SOFTWARE_RESET, mask);
|
|
||||||
for (timo = 10; timo > 0; timo--) {
|
|
||||||
if (!ISSET(HREAD1(hp, SDHC_SOFTWARE_RESET), mask))
|
|
||||||
break;
|
|
||||||
udelay(10000);
|
|
||||||
HWRITE1(hp, SDHC_SOFTWARE_RESET, 0);
|
|
||||||
}
|
|
||||||
if (timo == 0) {
|
|
||||||
HWRITE1(hp, SDHC_SOFTWARE_RESET, 0);
|
|
||||||
return (ETIMEDOUT);
|
|
||||||
}
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
sdhc_wait_intr_debug(const char *funcname, int line, struct sdhc_host *hp, int mask, int timo)
|
|
||||||
{
|
|
||||||
int status;
|
|
||||||
|
|
||||||
mask |= SDHC_ERROR_INTERRUPT;
|
|
||||||
mask |= SDHC_ERROR_TIMEOUT;
|
|
||||||
|
|
||||||
status = hp->intr_status & mask;
|
|
||||||
|
|
||||||
for (; timo > 0; timo--)
|
|
||||||
{
|
|
||||||
sdhc_irq(); // seems backwards but ok
|
|
||||||
|
|
||||||
if (hp->intr_status != 0) {
|
|
||||||
status = hp->intr_status & mask;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
udelay(1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (timo == 0) {
|
|
||||||
status |= SDHC_ERROR_TIMEOUT;
|
|
||||||
}
|
|
||||||
hp->intr_status &= ~status;
|
|
||||||
|
|
||||||
//DPRINTF(2,("sdhc: funcname=%s, line=%d, timo=%d status=%#x intr status=%#x error %#x\n",
|
|
||||||
// funcname, line, timo, status, hp->intr_status, hp->intr_error_status));
|
|
||||||
|
|
||||||
/* Command timeout has higher priority than command complete. */
|
|
||||||
if (ISSET(status, SDHC_ERROR_INTERRUPT)) {
|
|
||||||
//dbgprintf("resetting due to error interrupt\n");
|
|
||||||
//sdhc_dump_regs(hp);
|
|
||||||
|
|
||||||
hp->intr_error_status = 0;
|
|
||||||
(void)sdhc_soft_reset(hp, SDHC_RESET_DAT|SDHC_RESET_CMD);
|
|
||||||
status = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Command timeout has higher priority than command complete. */
|
|
||||||
if (ISSET(status, SDHC_ERROR_TIMEOUT)) {
|
|
||||||
//dbgprintf("not resetting due to timeout\n");
|
|
||||||
//sdhc_dump_regs(hp);
|
|
||||||
|
|
||||||
hp->intr_error_status = 0;
|
|
||||||
// (void)sdhc_soft_reset(hp, SDHC_RESET_DAT|SDHC_RESET_CMD);
|
|
||||||
status = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Established by attachment driver at interrupt priority IPL_SDMMC.
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
sdhc_intr(void)
|
|
||||||
{
|
|
||||||
u_int16_t status;
|
|
||||||
|
|
||||||
//DPRINTF(1,("shdc_intr():\n"));
|
|
||||||
//sdhc_dump_regs(&sc_host);
|
|
||||||
|
|
||||||
/* Find out which interrupts are pending. */
|
|
||||||
status = HREAD2(&sc_host, SDHC_NINTR_STATUS);
|
|
||||||
if (!ISSET(status, SDHC_NINTR_STATUS_MASK)) {
|
|
||||||
//DPRINTF(1, ("unknown interrupt\n"));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Acknowledge the interrupts we are about to handle. */
|
|
||||||
HWRITE2(&sc_host, SDHC_NINTR_STATUS, status);
|
|
||||||
//DPRINTF(2,("sdhc: interrupt status=%d\n", status));
|
|
||||||
|
|
||||||
/* Service error interrupts. */
|
|
||||||
if (ISSET(status, SDHC_ERROR_INTERRUPT)) {
|
|
||||||
u_int16_t error;
|
|
||||||
u_int16_t signal;
|
|
||||||
|
|
||||||
/* Acknowledge error interrupts. */
|
|
||||||
error = HREAD2(&sc_host, SDHC_EINTR_STATUS);
|
|
||||||
signal = HREAD2(&sc_host, SDHC_EINTR_SIGNAL_EN);
|
|
||||||
HWRITE2(&sc_host, SDHC_EINTR_SIGNAL_EN, 0);
|
|
||||||
(void)sdhc_soft_reset(&sc_host, SDHC_RESET_DAT|SDHC_RESET_CMD);
|
|
||||||
if (sc_host.data_command == 1) {
|
|
||||||
sc_host.data_command = 0;
|
|
||||||
|
|
||||||
// TODO: add a way to send commands from irq
|
|
||||||
// context and uncomment this
|
|
||||||
// sdmmc_abort();
|
|
||||||
}
|
|
||||||
HWRITE2(&sc_host, SDHC_EINTR_STATUS, error);
|
|
||||||
HWRITE2(&sc_host, SDHC_EINTR_SIGNAL_EN, signal);
|
|
||||||
|
|
||||||
//DPRINTF(2,("sdhc: error interrupt, status=%d\n", error));
|
|
||||||
|
|
||||||
if (ISSET(error, SDHC_CMD_TIMEOUT_ERROR|
|
|
||||||
SDHC_DATA_TIMEOUT_ERROR)) {
|
|
||||||
sc_host.intr_error_status |= error;
|
|
||||||
sc_host.intr_status |= status;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Wake up the blocking process to service command
|
|
||||||
* related interrupt(s).
|
|
||||||
*/
|
|
||||||
if (ISSET(status, SDHC_BUFFER_READ_READY|
|
|
||||||
SDHC_BUFFER_WRITE_READY|SDHC_COMMAND_COMPLETE|
|
|
||||||
SDHC_TRANSFER_COMPLETE|SDHC_DMA_INTERRUPT)) {
|
|
||||||
sc_host.intr_status |= status;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Service SD card interrupts. */
|
|
||||||
if (ISSET(status, SDHC_CARD_INTERRUPT)) {
|
|
||||||
//DPRINTF(0,("sdhc: card interrupt\n"));
|
|
||||||
HCLR2(&sc_host, SDHC_NINTR_STATUS_EN, SDHC_CARD_INTERRUPT);
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef SDHC_DEBUG
|
|
||||||
void
|
|
||||||
sdhc_dump_regs(struct sdhc_host *hp)
|
|
||||||
{
|
|
||||||
dbgprintf("0x%02x PRESENT_STATE: %x\n", SDHC_PRESENT_STATE,
|
|
||||||
HREAD4(hp, SDHC_PRESENT_STATE));
|
|
||||||
dbgprintf("0x%02x POWER_CTL: %x\n", SDHC_POWER_CTL,
|
|
||||||
HREAD1(hp, SDHC_POWER_CTL));
|
|
||||||
dbgprintf("0x%02x NINTR_STATUS: %x\n", SDHC_NINTR_STATUS,
|
|
||||||
HREAD2(hp, SDHC_NINTR_STATUS));
|
|
||||||
dbgprintf("0x%02x EINTR_STATUS: %x\n", SDHC_EINTR_STATUS,
|
|
||||||
HREAD2(hp, SDHC_EINTR_STATUS));
|
|
||||||
dbgprintf("0x%02x NINTR_STATUS_EN: %x\n", SDHC_NINTR_STATUS_EN,
|
|
||||||
HREAD2(hp, SDHC_NINTR_STATUS_EN));
|
|
||||||
dbgprintf("0x%02x EINTR_STATUS_EN: %x\n", SDHC_EINTR_STATUS_EN,
|
|
||||||
HREAD2(hp, SDHC_EINTR_STATUS_EN));
|
|
||||||
dbgprintf("0x%02x NINTR_SIGNAL_EN: %x\n", SDHC_NINTR_SIGNAL_EN,
|
|
||||||
HREAD2(hp, SDHC_NINTR_SIGNAL_EN));
|
|
||||||
dbgprintf("0x%02x EINTR_SIGNAL_EN: %x\n", SDHC_EINTR_SIGNAL_EN,
|
|
||||||
HREAD2(hp, SDHC_EINTR_SIGNAL_EN));
|
|
||||||
dbgprintf("0x%02x CAPABILITIES: %x\n", SDHC_CAPABILITIES,
|
|
||||||
HREAD4(hp, SDHC_CAPABILITIES));
|
|
||||||
dbgprintf("0x%02x MAX_CAPABILITIES: %x\n", SDHC_MAX_CAPABILITIES,
|
|
||||||
HREAD4(hp, SDHC_MAX_CAPABILITIES));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "hollywood.h"
|
|
||||||
|
|
||||||
void sdhc_irq(void)
|
|
||||||
{
|
|
||||||
sdhc_intr();
|
|
||||||
}
|
|
||||||
|
|
||||||
void sdhc_init(void)
|
|
||||||
{
|
|
||||||
sdhc_host_found(0, SDHC_REG_BASE, 1);
|
|
||||||
//sdhc_host_found(0, SDHC_REG_BASE + 0x100, 1);
|
|
||||||
//sdhc_host_found(0, 0x0d080000, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void sdhc_exit(void)
|
|
||||||
{
|
|
||||||
sdhc_shutdown();
|
|
||||||
}
|
|
210
sdhc.h
210
sdhc.h
@ -1,210 +0,0 @@
|
|||||||
/* $OpenBSD: sdhcvar.h,v 1.3 2007/09/06 08:01:01 jsg Exp $ */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
|
|
||||||
* Copyright (c) 2009 Sven Peter <svenpeter@gmail.com>
|
|
||||||
*
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
|
||||||
* copyright notice and this permission notice appear in all copies.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
||||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
||||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
||||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
||||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _SDHCVAR_H_
|
|
||||||
#define _SDHCVAR_H_
|
|
||||||
|
|
||||||
#include "bsdtypes.h"
|
|
||||||
#ifdef CAN_HAZ_IPC
|
|
||||||
#include "ipc.h"
|
|
||||||
#endif
|
|
||||||
#include "sdmmc.h"
|
|
||||||
struct sdhc_host {
|
|
||||||
bus_space_tag_t iot; /* host register set tag */
|
|
||||||
bus_space_handle_t ioh; /* host register set handle */
|
|
||||||
u_int clkbase; /* base clock frequency in KHz */
|
|
||||||
int flags; /* flags for this host */
|
|
||||||
u_int32_t ocr; /* OCR value from capabilities */
|
|
||||||
u_int8_t regs[14]; /* host controller state */
|
|
||||||
u_int16_t intr_status; /* soft interrupt status */
|
|
||||||
u_int16_t intr_error_status; /* soft error status */
|
|
||||||
int data_command;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern struct sdhc_host sc_host;
|
|
||||||
|
|
||||||
/* Host controller functions called by the attachment driver. */
|
|
||||||
int sdhc_host_found(bus_space_tag_t, bus_space_handle_t, int);
|
|
||||||
void sdhc_power(int, void *);
|
|
||||||
void sdhc_shutdown(void);
|
|
||||||
int sdhc_intr(void);
|
|
||||||
void sdhc_init(void);
|
|
||||||
void sdhc_exit(void);
|
|
||||||
void sdhc_irq(void);
|
|
||||||
#ifdef CAN_HAZ_IPC
|
|
||||||
void sdhc_ipc(volatile ipc_request *req);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Host standard register set */
|
|
||||||
#define SDHC_DMA_ADDR 0x00
|
|
||||||
#define SDHC_BLOCK_SIZE 0x04
|
|
||||||
#define SDHC_BLOCK_COUNT 0x06
|
|
||||||
#define SDHC_BLOCK_COUNT_MAX 512
|
|
||||||
#define SDHC_ARGUMENT 0x08
|
|
||||||
#define SDHC_TRANSFER_MODE 0x0c
|
|
||||||
#define SDHC_MULTI_BLOCK_MODE (1<<5)
|
|
||||||
#define SDHC_READ_MODE (1<<4)
|
|
||||||
#define SDHC_AUTO_CMD12_ENABLE (1<<2)
|
|
||||||
#define SDHC_BLOCK_COUNT_ENABLE (1<<1)
|
|
||||||
#define SDHC_DMA_ENABLE (1<<0)
|
|
||||||
#define SDHC_COMMAND 0x0e
|
|
||||||
/* 14-15 reserved */
|
|
||||||
#define SDHC_COMMAND_INDEX_SHIFT 8
|
|
||||||
#define SDHC_COMMAND_INDEX_MASK 0x3f
|
|
||||||
#define SDHC_COMMAND_TYPE_ABORT (3<<6)
|
|
||||||
#define SDHC_COMMAND_TYPE_RESUME (2<<6)
|
|
||||||
#define SDHC_COMMAND_TYPE_SUSPEND (1<<6)
|
|
||||||
#define SDHC_COMMAND_TYPE_NORMAL (0<<6)
|
|
||||||
#define SDHC_DATA_PRESENT_SELECT (1<<5)
|
|
||||||
#define SDHC_INDEX_CHECK_ENABLE (1<<4)
|
|
||||||
#define SDHC_CRC_CHECK_ENABLE (1<<3)
|
|
||||||
/* 2 reserved */
|
|
||||||
#define SDHC_RESP_LEN_48_CHK_BUSY (3<<0)
|
|
||||||
#define SDHC_RESP_LEN_48 (2<<0)
|
|
||||||
#define SDHC_RESP_LEN_136 (1<<0)
|
|
||||||
#define SDHC_NO_RESPONSE (0<<0)
|
|
||||||
#define SDHC_RESPONSE 0x10 /* - 0x1f */
|
|
||||||
#define SDHC_DATA 0x20
|
|
||||||
#define SDHC_PRESENT_STATE 0x24
|
|
||||||
/* 25-31 reserved */
|
|
||||||
#define SDHC_CMD_LINE_SIGNAL_LEVEL (1<<24)
|
|
||||||
#define SDHC_DAT3_LINE_LEVEL (1<<23)
|
|
||||||
#define SDHC_DAT2_LINE_LEVEL (1<<22)
|
|
||||||
#define SDHC_DAT1_LINE_LEVEL (1<<21)
|
|
||||||
#define SDHC_DAT0_LINE_LEVEL (1<<20)
|
|
||||||
#define SDHC_WRITE_PROTECT_SWITCH (1<<19)
|
|
||||||
#define SDHC_CARD_DETECT_PIN_LEVEL (1<<18)
|
|
||||||
#define SDHC_CARD_STATE_STABLE (1<<17)
|
|
||||||
#define SDHC_CARD_INSERTED (1<<16)
|
|
||||||
/* 12-15 reserved */
|
|
||||||
#define SDHC_BUFFER_READ_ENABLE (1<<11)
|
|
||||||
#define SDHC_BUFFER_WRITE_ENABLE (1<<10)
|
|
||||||
#define SDHC_READ_TRANSFER_ACTIVE (1<<9)
|
|
||||||
#define SDHC_WRITE_TRANSFER_ACTIVE (1<<8)
|
|
||||||
/* 3-7 reserved */
|
|
||||||
#define SDHC_DAT_ACTIVE (1<<2)
|
|
||||||
#define SDHC_CMD_INHIBIT_DAT (1<<1)
|
|
||||||
#define SDHC_CMD_INHIBIT_CMD (1<<0)
|
|
||||||
#define SDHC_CMD_INHIBIT_MASK 0x0003
|
|
||||||
#define SDHC_HOST_CTL 0x28
|
|
||||||
#define SDHC_HIGH_SPEED (1<<2)
|
|
||||||
#define SDHC_4BIT_MODE (1<<1)
|
|
||||||
#define SDHC_LED_ON (1<<0)
|
|
||||||
#define SDHC_POWER_CTL 0x29
|
|
||||||
#define SDHC_VOLTAGE_SHIFT 1
|
|
||||||
#define SDHC_VOLTAGE_MASK 0x07
|
|
||||||
#define SDHC_VOLTAGE_3_3V 0x07
|
|
||||||
#define SDHC_VOLTAGE_3_0V 0x06
|
|
||||||
#define SDHC_VOLTAGE_1_8V 0x05
|
|
||||||
#define SDHC_BUS_POWER (1<<0)
|
|
||||||
#define SDHC_BLOCK_GAP_CTL 0x2a
|
|
||||||
#define SDHC_WAKEUP_CTL 0x2b
|
|
||||||
#define SDHC_CLOCK_CTL 0x2c
|
|
||||||
#define SDHC_SDCLK_DIV_SHIFT 8
|
|
||||||
#define SDHC_SDCLK_DIV_MASK 0xff
|
|
||||||
#define SDHC_SDCLK_ENABLE (1<<2)
|
|
||||||
#define SDHC_INTCLK_STABLE (1<<1)
|
|
||||||
#define SDHC_INTCLK_ENABLE (1<<0)
|
|
||||||
#define SDHC_TIMEOUT_CTL 0x2e
|
|
||||||
#define SDHC_TIMEOUT_MAX 0x0e
|
|
||||||
#define SDHC_SOFTWARE_RESET 0x2f
|
|
||||||
#define SDHC_RESET_MASK 0x5
|
|
||||||
#define SDHC_RESET_DAT (1<<2)
|
|
||||||
#define SDHC_RESET_CMD (1<<1)
|
|
||||||
#define SDHC_RESET_ALL (1<<0)
|
|
||||||
#define SDHC_NINTR_STATUS 0x30
|
|
||||||
#define SDHC_ERROR_INTERRUPT (1<<15)
|
|
||||||
#define SDHC_ERROR_TIMEOUT (1<<14)
|
|
||||||
#define SDHC_CARD_INTERRUPT (1<<8)
|
|
||||||
#define SDHC_CARD_REMOVAL (1<<7)
|
|
||||||
#define SDHC_CARD_INSERTION (1<<6)
|
|
||||||
#define SDHC_BUFFER_READ_READY (1<<5)
|
|
||||||
#define SDHC_BUFFER_WRITE_READY (1<<4)
|
|
||||||
#define SDHC_DMA_INTERRUPT (1<<3)
|
|
||||||
#define SDHC_BLOCK_GAP_EVENT (1<<2)
|
|
||||||
#define SDHC_TRANSFER_COMPLETE (1<<1)
|
|
||||||
#define SDHC_COMMAND_COMPLETE (1<<0)
|
|
||||||
#define SDHC_NINTR_STATUS_MASK 0x81ff
|
|
||||||
#define SDHC_EINTR_STATUS 0x32
|
|
||||||
#define SDHC_ADMA_ERROR (1<<9)
|
|
||||||
#define SDHC_AUTO_CMD12_ERROR (1<<8)
|
|
||||||
#define SDHC_CURRENT_LIMIT_ERROR (1<<7)
|
|
||||||
#define SDHC_DATA_END_BIT_ERROR (1<<6)
|
|
||||||
#define SDHC_DATA_CRC_ERROR (1<<5)
|
|
||||||
#define SDHC_DATA_TIMEOUT_ERROR (1<<4)
|
|
||||||
#define SDHC_DATA_ERROR 0x70
|
|
||||||
#define SDHC_CMD_INDEX_ERROR (1<<3)
|
|
||||||
#define SDHC_CMD_END_BIT_ERROR (1<<2)
|
|
||||||
#define SDHC_CMD_CRC_ERROR (1<<1)
|
|
||||||
#define SDHC_CMD_TIMEOUT_ERROR (1<<0)
|
|
||||||
#define SDHC_CMD_ERROR 0x0f
|
|
||||||
#define SDHC_EINTR_STATUS_MASK 0x03ff /* excluding vendor signals */
|
|
||||||
#define SDHC_NINTR_STATUS_EN 0x34
|
|
||||||
#define SDHC_EINTR_STATUS_EN 0x36
|
|
||||||
#define SDHC_NINTR_SIGNAL_EN 0x38
|
|
||||||
#define SDHC_NINTR_SIGNAL_MASK 0x01ff
|
|
||||||
#define SDHC_EINTR_SIGNAL_EN 0x3a
|
|
||||||
#define SDHC_EINTR_SIGNAL_MASK 0x03ff /* excluding vendor signals */
|
|
||||||
#define SDHC_CMD12_ERROR_STATUS 0x3c
|
|
||||||
#define SDHC_CAPABILITIES 0x40
|
|
||||||
#define SDHC_VOLTAGE_SUPP_1_8V (1<<26)
|
|
||||||
#define SDHC_VOLTAGE_SUPP_3_0V (1<<25)
|
|
||||||
#define SDHC_VOLTAGE_SUPP_3_3V (1<<24)
|
|
||||||
#define SDHC_DMA_SUPPORT (1<<22)
|
|
||||||
#define SDHC_HIGH_SPEED_SUPP (1<<21)
|
|
||||||
#define SDHC_BASE_FREQ_SHIFT 8
|
|
||||||
#define SDHC_BASE_FREQ_MASK 0x3f
|
|
||||||
#define SDHC_TIMEOUT_FREQ_UNIT (1<<7) /* 0=KHz, 1=MHz */
|
|
||||||
#define SDHC_TIMEOUT_FREQ_SHIFT 0
|
|
||||||
#define SDHC_TIMEOUT_FREQ_MASK 0x1f
|
|
||||||
#define SDHC_MAX_CAPABILITIES 0x48
|
|
||||||
#define SDHC_SLOT_INTR_STATUS 0xfc
|
|
||||||
#define SDHC_HOST_CTL_VERSION 0xfe
|
|
||||||
#define SDHC_SPEC_VERS_SHIFT 0
|
|
||||||
#define SDHC_SPEC_VERS_MASK 0xff
|
|
||||||
#define SDHC_VENDOR_VERS_SHIFT 8
|
|
||||||
#define SDHC_VENDOR_VERS_MASK 0xff
|
|
||||||
|
|
||||||
/* SDHC_CAPABILITIES decoding */
|
|
||||||
#define SDHC_BASE_FREQ_KHZ(cap) \
|
|
||||||
((((cap) >> SDHC_BASE_FREQ_SHIFT) & SDHC_BASE_FREQ_MASK) * 1000)
|
|
||||||
#define SDHC_TIMEOUT_FREQ(cap) \
|
|
||||||
(((cap) >> SDHC_TIMEOUT_FREQ_SHIFT) & SDHC_TIMEOUT_FREQ_MASK)
|
|
||||||
#define SDHC_TIMEOUT_FREQ_KHZ(cap) \
|
|
||||||
(((cap) & SDHC_TIMEOUT_FREQ_UNIT) ? \
|
|
||||||
SDHC_TIMEOUT_FREQ(cap) * 1000: \
|
|
||||||
SDHC_TIMEOUT_FREQ(cap))
|
|
||||||
|
|
||||||
/* SDHC_HOST_CTL_VERSION decoding */
|
|
||||||
#define SDHC_SPEC_VERSION(hcv) \
|
|
||||||
(((hcv) >> SDHC_SPEC_VERS_SHIFT) & SDHC_SPEC_VERS_MASK)
|
|
||||||
#define SDHC_VENDOR_VERSION(hcv) \
|
|
||||||
(((hcv) >> SDHC_VENDOR_VERS_SHIFT) & SDHC_VENDOR_VERS_MASK)
|
|
||||||
|
|
||||||
struct sdmmc_command;
|
|
||||||
|
|
||||||
int sdhc_host_reset(struct sdhc_host *hp);
|
|
||||||
int sdhc_card_detect(struct sdhc_host *hp);
|
|
||||||
int sdhc_bus_power(struct sdhc_host *hp, u_int32_t);
|
|
||||||
int sdhc_bus_clock(struct sdhc_host *hp, int);
|
|
||||||
void sdhc_card_intr_mask(struct sdhc_host *hp, int);
|
|
||||||
void sdhc_card_intr_ack(struct sdhc_host *hp);
|
|
||||||
void sdhc_exec_command(struct sdhc_host *hp, struct sdmmc_command *);
|
|
||||||
|
|
||||||
#endif
|
|
172
sdhcreg.h
172
sdhcreg.h
@ -1,172 +0,0 @@
|
|||||||
/* $OpenBSD: sdhcreg.h,v 1.4 2006/07/30 17:20:40 fgsch Exp $ */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
|
|
||||||
*
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
|
||||||
* copyright notice and this permission notice appear in all copies.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
||||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
||||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
||||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
||||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _SDHCREG_H_
|
|
||||||
#define _SDHCREG_H_
|
|
||||||
|
|
||||||
/* Host standard register set */
|
|
||||||
#define SDHC_DMA_ADDR 0x00
|
|
||||||
#define SDHC_BLOCK_SIZE 0x04
|
|
||||||
#define SDHC_BLOCK_COUNT 0x06
|
|
||||||
#define SDHC_BLOCK_COUNT_MAX 512
|
|
||||||
#define SDHC_ARGUMENT 0x08
|
|
||||||
#define SDHC_TRANSFER_MODE 0x0c
|
|
||||||
#define SDHC_MULTI_BLOCK_MODE (1<<5)
|
|
||||||
#define SDHC_READ_MODE (1<<4)
|
|
||||||
#define SDHC_AUTO_CMD12_ENABLE (1<<2)
|
|
||||||
#define SDHC_BLOCK_COUNT_ENABLE (1<<1)
|
|
||||||
#define SDHC_DMA_ENABLE (1<<0)
|
|
||||||
#define SDHC_COMMAND 0x0e
|
|
||||||
/* 14-15 reserved */
|
|
||||||
#define SDHC_COMMAND_INDEX_SHIFT 8
|
|
||||||
#define SDHC_COMMAND_INDEX_MASK 0x3f
|
|
||||||
#define SDHC_COMMAND_TYPE_ABORT (3<<6)
|
|
||||||
#define SDHC_COMMAND_TYPE_RESUME (2<<6)
|
|
||||||
#define SDHC_COMMAND_TYPE_SUSPEND (1<<6)
|
|
||||||
#define SDHC_COMMAND_TYPE_NORMAL (0<<6)
|
|
||||||
#define SDHC_DATA_PRESENT_SELECT (1<<5)
|
|
||||||
#define SDHC_INDEX_CHECK_ENABLE (1<<4)
|
|
||||||
#define SDHC_CRC_CHECK_ENABLE (1<<3)
|
|
||||||
/* 2 reserved */
|
|
||||||
#define SDHC_RESP_LEN_48_CHK_BUSY (3<<0)
|
|
||||||
#define SDHC_RESP_LEN_48 (2<<0)
|
|
||||||
#define SDHC_RESP_LEN_136 (1<<0)
|
|
||||||
#define SDHC_NO_RESPONSE (0<<0)
|
|
||||||
#define SDHC_RESPONSE 0x10 /* - 0x1f */
|
|
||||||
#define SDHC_DATA 0x20
|
|
||||||
#define SDHC_PRESENT_STATE 0x24
|
|
||||||
/* 25-31 reserved */
|
|
||||||
#define SDHC_CMD_LINE_SIGNAL_LEVEL (1<<24)
|
|
||||||
#define SDHC_DAT3_LINE_LEVEL (1<<23)
|
|
||||||
#define SDHC_DAT2_LINE_LEVEL (1<<22)
|
|
||||||
#define SDHC_DAT1_LINE_LEVEL (1<<21)
|
|
||||||
#define SDHC_DAT0_LINE_LEVEL (1<<20)
|
|
||||||
#define SDHC_WRITE_PROTECT_SWITCH (1<<19)
|
|
||||||
#define SDHC_CARD_DETECT_PIN_LEVEL (1<<18)
|
|
||||||
#define SDHC_CARD_STATE_STABLE (1<<17)
|
|
||||||
#define SDHC_CARD_INSERTED (1<<16)
|
|
||||||
/* 12-15 reserved */
|
|
||||||
#define SDHC_BUFFER_READ_ENABLE (1<<11)
|
|
||||||
#define SDHC_BUFFER_WRITE_ENABLE (1<<10)
|
|
||||||
#define SDHC_READ_TRANSFER_ACTIVE (1<<9)
|
|
||||||
#define SDHC_WRITE_TRANSFER_ACTIVE (1<<8)
|
|
||||||
/* 3-7 reserved */
|
|
||||||
#define SDHC_DAT_ACTIVE (1<<2)
|
|
||||||
#define SDHC_CMD_INHIBIT_DAT (1<<1)
|
|
||||||
#define SDHC_CMD_INHIBIT_CMD (1<<0)
|
|
||||||
#define SDHC_CMD_INHIBIT_MASK 0x0003
|
|
||||||
#define SDHC_HOST_CTL 0x28
|
|
||||||
#define SDHC_HIGH_SPEED (1<<2)
|
|
||||||
#define SDHC_4BIT_MODE (1<<1)
|
|
||||||
#define SDHC_LED_ON (1<<0)
|
|
||||||
#define SDHC_POWER_CTL 0x29
|
|
||||||
#define SDHC_VOLTAGE_SHIFT 1
|
|
||||||
#define SDHC_VOLTAGE_MASK 0x07
|
|
||||||
#define SDHC_VOLTAGE_3_3V 0x07
|
|
||||||
#define SDHC_VOLTAGE_3_0V 0x06
|
|
||||||
#define SDHC_VOLTAGE_1_8V 0x05
|
|
||||||
#define SDHC_BUS_POWER (1<<0)
|
|
||||||
#define SDHC_BLOCK_GAP_CTL 0x2a
|
|
||||||
#define SDHC_WAKEUP_CTL 0x2b
|
|
||||||
#define SDHC_CLOCK_CTL 0x2c
|
|
||||||
#define SDHC_SDCLK_DIV_SHIFT 8
|
|
||||||
#define SDHC_SDCLK_DIV_MASK 0xff
|
|
||||||
#define SDHC_SDCLK_ENABLE (1<<2)
|
|
||||||
#define SDHC_INTCLK_STABLE (1<<1)
|
|
||||||
#define SDHC_INTCLK_ENABLE (1<<0)
|
|
||||||
#define SDHC_TIMEOUT_CTL 0x2e
|
|
||||||
#define SDHC_TIMEOUT_MAX 0x0e
|
|
||||||
#define SDHC_SOFTWARE_RESET 0x2f
|
|
||||||
#define SDHC_RESET_MASK 0x5
|
|
||||||
#define SDHC_RESET_DAT (1<<2)
|
|
||||||
#define SDHC_RESET_CMD (1<<1)
|
|
||||||
#define SDHC_RESET_ALL (1<<0)
|
|
||||||
#define SDHC_NINTR_STATUS 0x30
|
|
||||||
#define SDHC_ERROR_INTERRUPT (1<<15)
|
|
||||||
#define SDHC_CARD_INTERRUPT (1<<8)
|
|
||||||
#define SDHC_CARD_REMOVAL (1<<7)
|
|
||||||
#define SDHC_CARD_INSERTION (1<<6)
|
|
||||||
#define SDHC_BUFFER_READ_READY (1<<5)
|
|
||||||
#define SDHC_BUFFER_WRITE_READY (1<<4)
|
|
||||||
#define SDHC_DMA_INTERRUPT (1<<3)
|
|
||||||
#define SDHC_BLOCK_GAP_EVENT (1<<2)
|
|
||||||
#define SDHC_TRANSFER_COMPLETE (1<<1)
|
|
||||||
#define SDHC_COMMAND_COMPLETE (1<<0)
|
|
||||||
#define SDHC_NINTR_STATUS_MASK 0x81ff
|
|
||||||
#define SDHC_EINTR_STATUS 0x32
|
|
||||||
#define SDHC_ADMA_ERROR (1<<9)
|
|
||||||
#define SDHC_AUTO_CMD12_ERROR (1<<8)
|
|
||||||
#define SDHC_CURRENT_LIMIT_ERROR (1<<7)
|
|
||||||
#define SDHC_DATA_END_BIT_ERROR (1<<6)
|
|
||||||
#define SDHC_DATA_CRC_ERROR (1<<5)
|
|
||||||
#define SDHC_DATA_TIMEOUT_ERROR (1<<4)
|
|
||||||
#define SDHC_DATA_ERROR 0x70
|
|
||||||
#define SDHC_CMD_INDEX_ERROR (1<<3)
|
|
||||||
#define SDHC_CMD_END_BIT_ERROR (1<<2)
|
|
||||||
#define SDHC_CMD_CRC_ERROR (1<<1)
|
|
||||||
#define SDHC_CMD_TIMEOUT_ERROR (1<<0)
|
|
||||||
#define SDHC_CMD_ERROR 0x0f
|
|
||||||
#define SDHC_EINTR_STATUS_MASK 0x03ff /* excluding vendor signals */
|
|
||||||
#define SDHC_NINTR_STATUS_EN 0x34
|
|
||||||
#define SDHC_EINTR_STATUS_EN 0x36
|
|
||||||
#define SDHC_NINTR_SIGNAL_EN 0x38
|
|
||||||
#define SDHC_NINTR_SIGNAL_MASK 0x01ff
|
|
||||||
#define SDHC_EINTR_SIGNAL_EN 0x3a
|
|
||||||
#define SDHC_EINTR_SIGNAL_MASK 0x03ff /* excluding vendor signals */
|
|
||||||
#define SDHC_CMD12_ERROR_STATUS 0x3c
|
|
||||||
#define SDHC_CAPABILITIES 0x40
|
|
||||||
#define SDHC_VOLTAGE_SUPP_1_8V (1<<26)
|
|
||||||
#define SDHC_VOLTAGE_SUPP_3_0V (1<<25)
|
|
||||||
#define SDHC_VOLTAGE_SUPP_3_3V (1<<24)
|
|
||||||
#define SDHC_DMA_SUPPORT (1<<22)
|
|
||||||
#define SDHC_HIGH_SPEED_SUPP (1<<21)
|
|
||||||
#define SDHC_MAX_BLK_LEN_512 0
|
|
||||||
#define SDHC_MAX_BLK_LEN_1024 1
|
|
||||||
#define SDHC_MAX_BLK_LEN_2048 2
|
|
||||||
#define SDHC_MAX_BLK_LEN_SHIFT 16
|
|
||||||
#define SDHC_MAX_BLK_LEN_MASK 0x3
|
|
||||||
#define SDHC_BASE_FREQ_SHIFT 8
|
|
||||||
#define SDHC_BASE_FREQ_MASK 0x3f
|
|
||||||
#define SDHC_TIMEOUT_FREQ_UNIT (1<<7) /* 0=KHz, 1=MHz */
|
|
||||||
#define SDHC_TIMEOUT_FREQ_SHIFT 0
|
|
||||||
#define SDHC_TIMEOUT_FREQ_MASK 0x1f
|
|
||||||
#define SDHC_MAX_CAPABILITIES 0x48
|
|
||||||
#define SDHC_SLOT_INTR_STATUS 0xfc
|
|
||||||
#define SDHC_HOST_CTL_VERSION 0xfe
|
|
||||||
#define SDHC_SPEC_VERS_SHIFT 0
|
|
||||||
#define SDHC_SPEC_VERS_MASK 0xff
|
|
||||||
#define SDHC_VENDOR_VERS_SHIFT 8
|
|
||||||
#define SDHC_VENDOR_VERS_MASK 0xff
|
|
||||||
|
|
||||||
/* SDHC_CAPABILITIES decoding */
|
|
||||||
#define SDHC_BASE_FREQ_KHZ(cap) \
|
|
||||||
((((cap) >> SDHC_BASE_FREQ_SHIFT) & SDHC_BASE_FREQ_MASK) * 1000)
|
|
||||||
#define SDHC_TIMEOUT_FREQ(cap) \
|
|
||||||
(((cap) >> SDHC_TIMEOUT_FREQ_SHIFT) & SDHC_TIMEOUT_FREQ_MASK)
|
|
||||||
#define SDHC_TIMEOUT_FREQ_KHZ(cap) \
|
|
||||||
(((cap) & SDHC_TIMEOUT_FREQ_UNIT) ? \
|
|
||||||
SDHC_TIMEOUT_FREQ(cap) * 1000: \
|
|
||||||
SDHC_TIMEOUT_FREQ(cap))
|
|
||||||
|
|
||||||
/* SDHC_HOST_CTL_VERSION decoding */
|
|
||||||
#define SDHC_SPEC_VERSION(hcv) \
|
|
||||||
(((hcv) >> SDHC_SPEC_VERS_SHIFT) & SDHC_SPEC_VERS_MASK)
|
|
||||||
#define SDHC_VENDOR_VERSION(hcv) \
|
|
||||||
(((hcv) >> SDHC_VENDOR_VERS_SHIFT) & SDHC_VENDOR_VERS_MASK)
|
|
||||||
|
|
||||||
#endif
|
|
62
sdhcvar.h
62
sdhcvar.h
@ -1,62 +0,0 @@
|
|||||||
/* $OpenBSD: sdhcvar.h,v 1.3 2007/09/06 08:01:01 jsg Exp $ */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
|
|
||||||
* Copyright (c) 2009 Sven Peter <svenpeter@gmail.com>
|
|
||||||
*
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
|
||||||
* copyright notice and this permission notice appear in all copies.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
||||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
||||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
||||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
||||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _SDHCVAR_H_
|
|
||||||
#define _SDHCVAR_H_
|
|
||||||
|
|
||||||
#include "bsdtypes.h"
|
|
||||||
|
|
||||||
#define SDHC_MAX_HOSTS 4
|
|
||||||
|
|
||||||
struct sdhc_host {
|
|
||||||
struct sdhc_softc *sc; /* host controller device */
|
|
||||||
struct device *sdmmc; /* generic SD/MMC device */
|
|
||||||
bus_space_tag_t iot; /* host register set tag */
|
|
||||||
bus_space_handle_t ioh; /* host register set handle */
|
|
||||||
u_int clkbase; /* base clock frequency in KHz */
|
|
||||||
int maxblklen; /* maximum block length */
|
|
||||||
int flags; /* flags for this host */
|
|
||||||
u_int32_t ocr; /* OCR value from capabilities */
|
|
||||||
u_int8_t regs[14]; /* host controller state */
|
|
||||||
u_int16_t intr_status; /* soft interrupt status */
|
|
||||||
u_int16_t intr_error_status; /* soft error status */
|
|
||||||
int data_command;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct sdhc_softc {
|
|
||||||
struct device sc_dev;
|
|
||||||
struct sdhc_host sc_host[SDHC_MAX_HOSTS];
|
|
||||||
int sc_nhosts;
|
|
||||||
u_int sc_flags;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/* Host controller functions called by the attachment driver. */
|
|
||||||
int sdhc_host_found(struct sdhc_softc *, bus_space_tag_t,
|
|
||||||
bus_space_handle_t, int);
|
|
||||||
void sdhc_power(int, void *);
|
|
||||||
void sdhc_shutdown(void *);
|
|
||||||
int sdhc_intr(void *);
|
|
||||||
void SDHCInit(void);
|
|
||||||
void sdhc_irq(void);
|
|
||||||
|
|
||||||
/* flag values */
|
|
||||||
#define SDHC_F_NOPWR0 (1 << 0)
|
|
||||||
|
|
||||||
#endif
|
|
373
sdmmc.c
373
sdmmc.c
@ -1,373 +0,0 @@
|
|||||||
/*
|
|
||||||
mini - a Free Software replacement for the Nintendo/BroadOn IOS.
|
|
||||||
SD/MMC interface
|
|
||||||
|
|
||||||
Copyright (C) 2008, 2009 Sven Peter <svenpeter@gmail.com>
|
|
||||||
|
|
||||||
# This code is licensed to you under the terms of the GNU GPL, version 2;
|
|
||||||
# see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "bsdtypes.h"
|
|
||||||
#include "sdhc.h"
|
|
||||||
#include "string.h"
|
|
||||||
#include "utils.h"
|
|
||||||
|
|
||||||
//#define SDMMC_DEBUG
|
|
||||||
|
|
||||||
#ifdef SDMMC_DEBUG
|
|
||||||
static int sdmmcdebug = 0;
|
|
||||||
#define DPRINTF(n,s) do { if ((n) <= sdmmcdebug) dbgprintf s; } while (0)
|
|
||||||
#else
|
|
||||||
#define DPRINTF(n,s) do {} while(0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct sdmmc_card {
|
|
||||||
sdmmc_chipset_handle_t handle;
|
|
||||||
int inserted;
|
|
||||||
int sdhc_blockmode;
|
|
||||||
int selected;
|
|
||||||
int new_card; // set to 1 everytime a new card is inserted
|
|
||||||
|
|
||||||
u32 timeout;
|
|
||||||
u32 num_sectors;
|
|
||||||
u32 cid;
|
|
||||||
u16 rca;
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef LOADER
|
|
||||||
static struct sdmmc_card card;
|
|
||||||
#else
|
|
||||||
static struct sdmmc_card card;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void sdmmc_attach(sdmmc_chipset_handle_t handle)
|
|
||||||
{
|
|
||||||
memset8(&card, 0, sizeof(card));
|
|
||||||
|
|
||||||
card.handle = handle;
|
|
||||||
|
|
||||||
//DPRINTF(0, ("sdmmc: attached new SD/MMC card\n"));
|
|
||||||
|
|
||||||
sdhc_host_reset(card.handle);
|
|
||||||
|
|
||||||
if (sdhc_card_detect(card.handle)) {
|
|
||||||
//DPRINTF(1, ("card is inserted. starting init sequence.\n"));
|
|
||||||
sdmmc_needs_discover();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void sdmmc_abort(void) {
|
|
||||||
struct sdmmc_command cmd;
|
|
||||||
//dbgprintf("abortion kthx\n");
|
|
||||||
|
|
||||||
memset8(&cmd, 0, sizeof(cmd));
|
|
||||||
cmd.c_opcode = MMC_STOP_TRANSMISSION;
|
|
||||||
cmd.c_arg = 0;
|
|
||||||
cmd.c_flags = SCF_RSP_R1B;
|
|
||||||
sdhc_exec_command(card.handle, &cmd);
|
|
||||||
}
|
|
||||||
|
|
||||||
void sdmmc_needs_discover(void)
|
|
||||||
{
|
|
||||||
struct sdmmc_command cmd;
|
|
||||||
u32 ocr;
|
|
||||||
|
|
||||||
//DPRINTF(0, ("sdmmc: card needs discovery.\n"));
|
|
||||||
sdhc_host_reset(card.handle);
|
|
||||||
card.new_card = 1;
|
|
||||||
|
|
||||||
if (!sdhc_card_detect(card.handle)) {
|
|
||||||
//DPRINTF(1, ("sdmmc: card (no longer?) inserted.\n"));
|
|
||||||
card.inserted = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sdhc_bus_power(card.handle, 1) != 0) {
|
|
||||||
//dbgprintf("sdmmc: powerup failed for card\n");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sdhc_bus_clock(card.handle, SDMMC_DEFAULT_CLOCK) != 0) {
|
|
||||||
//dbgprintf("sdmmc: could not enable clock for card\n");
|
|
||||||
goto out_power;
|
|
||||||
}
|
|
||||||
|
|
||||||
memset8(&cmd, 0, sizeof(cmd));
|
|
||||||
cmd.c_opcode = MMC_GO_IDLE_STATE;
|
|
||||||
cmd.c_flags = SCF_RSP_R0;
|
|
||||||
sdhc_exec_command(card.handle, &cmd);
|
|
||||||
|
|
||||||
if (cmd.c_error) {
|
|
||||||
//dbgprintf("sdmmc: GO_IDLE_STATE failed with %d\n", cmd.c_error);
|
|
||||||
goto out_clock;
|
|
||||||
}
|
|
||||||
|
|
||||||
memset8(&cmd, 0, sizeof(cmd));
|
|
||||||
cmd.c_opcode = SD_SEND_IF_COND;
|
|
||||||
cmd.c_arg = 0x1aa;
|
|
||||||
cmd.c_flags = SCF_RSP_R7;
|
|
||||||
cmd.c_timeout = 100;
|
|
||||||
sdhc_exec_command(card.handle, &cmd);
|
|
||||||
|
|
||||||
ocr = card.handle->ocr;
|
|
||||||
if (cmd.c_error || (cmd.c_resp[0] & 0xff) != 0xaa)
|
|
||||||
ocr &= ~SD_OCR_SDHC_CAP;
|
|
||||||
else
|
|
||||||
ocr |= SD_OCR_SDHC_CAP;
|
|
||||||
|
|
||||||
int tries;
|
|
||||||
for (tries = 100; tries > 0; tries--) {
|
|
||||||
udelay(100000);
|
|
||||||
|
|
||||||
memset8(&cmd, 0, sizeof(cmd));
|
|
||||||
cmd.c_opcode = MMC_APP_CMD;
|
|
||||||
cmd.c_arg = 0;
|
|
||||||
cmd.c_flags = SCF_RSP_R1;
|
|
||||||
sdhc_exec_command(card.handle, &cmd);
|
|
||||||
|
|
||||||
if (cmd.c_error)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
memset8(&cmd, 0, sizeof(cmd));
|
|
||||||
cmd.c_opcode = SD_APP_OP_COND;
|
|
||||||
cmd.c_arg = ocr;
|
|
||||||
cmd.c_flags = SCF_RSP_R3;
|
|
||||||
sdhc_exec_command(card.handle, &cmd);
|
|
||||||
if (cmd.c_error)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (ISSET(MMC_R1(cmd.c_resp), MMC_OCR_MEM_READY))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!ISSET(cmd.c_resp[0], MMC_OCR_MEM_READY)) {
|
|
||||||
//dbgprintf("sdmmc: card failed to powerup.\n");
|
|
||||||
goto out_power;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ISSET(MMC_R1(cmd.c_resp), SD_OCR_SDHC_CAP))
|
|
||||||
card.sdhc_blockmode = 1;
|
|
||||||
else
|
|
||||||
card.sdhc_blockmode = 0;
|
|
||||||
|
|
||||||
u8 *resp;
|
|
||||||
memset8(&cmd, 0, sizeof(cmd));
|
|
||||||
cmd.c_opcode = MMC_ALL_SEND_CID;
|
|
||||||
cmd.c_arg = 0;
|
|
||||||
cmd.c_flags = SCF_RSP_R2;
|
|
||||||
sdhc_exec_command(card.handle, &cmd);
|
|
||||||
if (cmd.c_error) {
|
|
||||||
goto out_clock;
|
|
||||||
}
|
|
||||||
|
|
||||||
card.cid = MMC_R1(cmd.c_resp);
|
|
||||||
resp = (u8 *)cmd.c_resp;
|
|
||||||
|
|
||||||
memset8(&cmd, 0, sizeof(cmd));
|
|
||||||
cmd.c_opcode = SD_SEND_RELATIVE_ADDR;
|
|
||||||
cmd.c_arg = 0;
|
|
||||||
cmd.c_flags = SCF_RSP_R6;
|
|
||||||
sdhc_exec_command(card.handle, &cmd);
|
|
||||||
if (cmd.c_error) {
|
|
||||||
//dbgprintf("sdmmc: SD_SEND_RCA failed with %d\n", cmd.c_error);
|
|
||||||
goto out_clock;
|
|
||||||
}
|
|
||||||
|
|
||||||
card.rca = MMC_R1(cmd.c_resp)>>16;
|
|
||||||
|
|
||||||
card.selected = 0;
|
|
||||||
card.inserted = 1;
|
|
||||||
|
|
||||||
memset8(&cmd, 0, sizeof(cmd));
|
|
||||||
cmd.c_opcode = MMC_SEND_CSD;
|
|
||||||
cmd.c_arg = ((u32)card.rca)<<16;
|
|
||||||
cmd.c_flags = SCF_RSP_R2;
|
|
||||||
sdhc_exec_command(card.handle, &cmd);
|
|
||||||
if (cmd.c_error) {
|
|
||||||
//dbgprintf("sdmmc: MMC_SEND_CSD failed with %d\n", cmd.c_error);
|
|
||||||
goto out_power;
|
|
||||||
}
|
|
||||||
|
|
||||||
resp = (u8 *)cmd.c_resp;
|
|
||||||
|
|
||||||
|
|
||||||
if (resp[13] == 0xe) { // sdhc
|
|
||||||
unsigned int c_size = resp[7] << 16 | resp[6] << 8 | resp[5];
|
|
||||||
//dbgprintf("sdmmc: sdhc mode, c_size=%u, card size = %uk\n", c_size, (c_size + 1)* 512);
|
|
||||||
card.timeout = 250 * 1000000; // spec says read timeout is 100ms and write/erase timeout is 250ms
|
|
||||||
card.num_sectors = (c_size + 1) * 1024; // number of 512-byte sectors
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
unsigned int taac, nsac, read_bl_len, c_size, c_size_mult;
|
|
||||||
taac = resp[13];
|
|
||||||
nsac = resp[12];
|
|
||||||
read_bl_len = resp[9] & 0xF;
|
|
||||||
|
|
||||||
c_size = (resp[8] & 3) << 10;
|
|
||||||
c_size |= (resp[7] << 2);
|
|
||||||
c_size |= (resp[6] >> 6);
|
|
||||||
c_size_mult = (resp[5] & 3) << 1;
|
|
||||||
c_size_mult |= resp[4] >> 7;
|
|
||||||
//dbgprintf("taac=%u nsac=%u read_bl_len=%u c_size=%u c_size_mult=%u card size=%u bytes\n",
|
|
||||||
// taac, nsac, read_bl_len, c_size, c_size_mult, (c_size + 1) * (4 << c_size_mult) * (1 << read_bl_len));
|
|
||||||
static const unsigned int time_unit[] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000};
|
|
||||||
static const unsigned int time_value[] = {1, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80}; // must div by 10
|
|
||||||
card.timeout = time_unit[taac & 7] * time_value[(taac >> 3) & 0xf] / 10;
|
|
||||||
//dbgprintf("calculated timeout = %uns\n", card.timeout);
|
|
||||||
card.num_sectors = (c_size + 1) * (4 << c_size_mult) * (1 << read_bl_len) / 512;
|
|
||||||
}
|
|
||||||
|
|
||||||
sdmmc_select();
|
|
||||||
memset8(&cmd, 0, sizeof(cmd));
|
|
||||||
cmd.c_opcode = MMC_SET_BLOCKLEN;
|
|
||||||
cmd.c_arg = SDMMC_DEFAULT_BLOCKLEN;
|
|
||||||
cmd.c_flags = SCF_RSP_R1;
|
|
||||||
sdhc_exec_command(card.handle, &cmd);
|
|
||||||
if (cmd.c_error) {
|
|
||||||
//dbgprintf("sdmmc: MMC_SET_BLOCKLEN failed with %d\n", cmd.c_error);
|
|
||||||
card.inserted = card.selected = 0;
|
|
||||||
goto out_clock;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
|
|
||||||
out_clock:
|
|
||||||
sdhc_bus_clock(card.handle, SDMMC_SDCLK_OFF);
|
|
||||||
|
|
||||||
out_power:
|
|
||||||
sdhc_bus_power(card.handle, 0);
|
|
||||||
out:
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int sdmmc_select(void)
|
|
||||||
{
|
|
||||||
struct sdmmc_command cmd;
|
|
||||||
|
|
||||||
memset8(&cmd, 0, sizeof(cmd));
|
|
||||||
cmd.c_opcode = MMC_SELECT_CARD;
|
|
||||||
cmd.c_arg = ((u32)card.rca)<<16;
|
|
||||||
cmd.c_flags = SCF_RSP_R1B;
|
|
||||||
sdhc_exec_command(card.handle, &cmd);
|
|
||||||
|
|
||||||
|
|
||||||
if (cmd.c_error)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
card.selected = 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int sdmmc_check_card(void)
|
|
||||||
{
|
|
||||||
if (card.inserted == 0)
|
|
||||||
return SDMMC_NO_CARD;
|
|
||||||
|
|
||||||
if (card.new_card == 1)
|
|
||||||
return SDMMC_NEW_CARD;
|
|
||||||
|
|
||||||
return SDMMC_INSERTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
int sdmmc_ack_card(void)
|
|
||||||
{
|
|
||||||
if (card.new_card == 1) {
|
|
||||||
card.new_card = 0;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int sdmmc_read(u32 blk_start, u32 blk_count, void *data)
|
|
||||||
{
|
|
||||||
struct sdmmc_command cmd;
|
|
||||||
|
|
||||||
if (card.inserted == 0)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (card.selected == 0) {
|
|
||||||
if (sdmmc_select() < 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (card.new_card == 1) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
memset8(&cmd, 0, sizeof(cmd));
|
|
||||||
cmd.c_opcode = MMC_READ_BLOCK_MULTIPLE;
|
|
||||||
if (card.sdhc_blockmode)
|
|
||||||
cmd.c_arg = blk_start;
|
|
||||||
else
|
|
||||||
cmd.c_arg = blk_start * SDMMC_DEFAULT_BLOCKLEN;
|
|
||||||
cmd.c_data = data;
|
|
||||||
cmd.c_datalen = blk_count * SDMMC_DEFAULT_BLOCKLEN;
|
|
||||||
cmd.c_blklen = SDMMC_DEFAULT_BLOCKLEN;
|
|
||||||
cmd.c_flags = SCF_RSP_R1 | SCF_CMD_READ;
|
|
||||||
sdhc_exec_command(card.handle, &cmd);
|
|
||||||
|
|
||||||
if (cmd.c_error)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
int sdmmc_write(u32 blk_start, u32 blk_count, void *data)
|
|
||||||
{
|
|
||||||
struct sdmmc_command cmd;
|
|
||||||
|
|
||||||
if (card.inserted == 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (card.selected == 0) {
|
|
||||||
if (sdmmc_select() < 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (card.new_card == 1) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
memset8(&cmd, 0, sizeof(cmd));
|
|
||||||
cmd.c_opcode = MMC_WRITE_BLOCK_MULTIPLE;
|
|
||||||
if (card.sdhc_blockmode)
|
|
||||||
cmd.c_arg = blk_start;
|
|
||||||
else
|
|
||||||
cmd.c_arg = blk_start * SDMMC_DEFAULT_BLOCKLEN;
|
|
||||||
cmd.c_data = data;
|
|
||||||
cmd.c_datalen = blk_count * SDMMC_DEFAULT_BLOCKLEN;
|
|
||||||
cmd.c_blklen = SDMMC_DEFAULT_BLOCKLEN;
|
|
||||||
cmd.c_flags = SCF_RSP_R1;
|
|
||||||
sdhc_exec_command(card.handle, &cmd);
|
|
||||||
|
|
||||||
if (cmd.c_error)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int sdmmc_get_sectors(void)
|
|
||||||
{
|
|
||||||
if (card.inserted == 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (card.new_card == 1) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// sdhc_error(sdhci->reg_base, "num sectors = %u", sdhci->num_sectors);
|
|
||||||
|
|
||||||
return card.num_sectors;
|
|
||||||
}
|
|
||||||
|
|
370
sdmmc.h
370
sdmmc.h
@ -1,370 +0,0 @@
|
|||||||
#ifndef __SDMMC_H__
|
|
||||||
#define __SDMMC_H__
|
|
||||||
|
|
||||||
#include "bsdtypes.h"
|
|
||||||
|
|
||||||
struct sdmmc_command;
|
|
||||||
|
|
||||||
typedef struct sdhc_host * sdmmc_chipset_handle_t;
|
|
||||||
|
|
||||||
/* clock frequencies for sdmmc_chip_bus_clock() */
|
|
||||||
#define SDMMC_SDCLK_OFF 0
|
|
||||||
#define SDMMC_SDCLK_400KHZ 400
|
|
||||||
#define SDMMC_SDCLK_25MHZ 25000
|
|
||||||
|
|
||||||
|
|
||||||
struct sdmmc_csd {
|
|
||||||
int csdver; /* CSD structure format */
|
|
||||||
int mmcver; /* MMC version (for CID format) */
|
|
||||||
int capacity; /* total number of sectors */
|
|
||||||
int sector_size; /* sector size in bytes */
|
|
||||||
int read_bl_len; /* block length for reads */
|
|
||||||
/* ... */
|
|
||||||
};
|
|
||||||
|
|
||||||
struct sdmmc_cid {
|
|
||||||
int mid; /* manufacturer identification number */
|
|
||||||
int oid; /* OEM/product identification number */
|
|
||||||
char pnm[8]; /* product name (MMC v1 has the longest) */
|
|
||||||
int rev; /* product revision */
|
|
||||||
int psn; /* product serial number */
|
|
||||||
int mdt; /* manufacturing date */
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef u_int32_t sdmmc_response[4];
|
|
||||||
|
|
||||||
struct sdmmc_softc;
|
|
||||||
|
|
||||||
struct sdmmc_task {
|
|
||||||
void (*func)(void *arg);
|
|
||||||
void *arg;
|
|
||||||
int onqueue;
|
|
||||||
struct sdmmc_softc *sc;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define sdmmc_init_task(xtask, xfunc, xarg) do { \
|
|
||||||
(xtask)->func = (xfunc); \
|
|
||||||
(xtask)->arg = (xarg); \
|
|
||||||
(xtask)->onqueue = 0; \
|
|
||||||
(xtask)->sc = NULL; \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define sdmmc_task_pending(xtask) ((xtask)->onqueue)
|
|
||||||
|
|
||||||
struct sdmmc_command {
|
|
||||||
// struct sdmmc_task c_task; /* task queue entry */
|
|
||||||
u_int16_t c_opcode; /* SD or MMC command index */
|
|
||||||
u_int32_t c_arg; /* SD/MMC command argument */
|
|
||||||
sdmmc_response c_resp; /* response buffer */
|
|
||||||
void *c_data; /* buffer to send or read into */
|
|
||||||
int c_datalen; /* length of data buffer */
|
|
||||||
int c_blklen; /* block length */
|
|
||||||
int c_flags; /* see below */
|
|
||||||
#define SCF_ITSDONE 0x0001 /* command is complete */
|
|
||||||
#define SCF_CMD(flags) ((flags) & 0x00f0)
|
|
||||||
#define SCF_CMD_AC 0x0000
|
|
||||||
#define SCF_CMD_ADTC 0x0010
|
|
||||||
#define SCF_CMD_BC 0x0020
|
|
||||||
#define SCF_CMD_BCR 0x0030
|
|
||||||
#define SCF_CMD_READ 0x0040 /* read command (data expected) */
|
|
||||||
#define SCF_RSP_BSY 0x0100
|
|
||||||
#define SCF_RSP_136 0x0200
|
|
||||||
#define SCF_RSP_CRC 0x0400
|
|
||||||
#define SCF_RSP_IDX 0x0800
|
|
||||||
#define SCF_RSP_PRESENT 0x1000
|
|
||||||
/* response types */
|
|
||||||
#define SCF_RSP_R0 0 /* none */
|
|
||||||
#define SCF_RSP_R1 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX)
|
|
||||||
#define SCF_RSP_R1B (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX|SCF_RSP_BSY)
|
|
||||||
#define SCF_RSP_R2 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_136)
|
|
||||||
#define SCF_RSP_R3 (SCF_RSP_PRESENT)
|
|
||||||
#define SCF_RSP_R4 (SCF_RSP_PRESENT)
|
|
||||||
#define SCF_RSP_R5 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX)
|
|
||||||
#define SCF_RSP_R5B (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX|SCF_RSP_BSY)
|
|
||||||
#define SCF_RSP_R6 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX)
|
|
||||||
#define SCF_RSP_R7 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX)
|
|
||||||
int c_error; /* errno value on completion */
|
|
||||||
|
|
||||||
int c_timeout;
|
|
||||||
|
|
||||||
/* Host controller owned fields for data xfer in progress */
|
|
||||||
int c_resid; /* remaining I/O */
|
|
||||||
u_char *c_buf; /* remaining data */
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Decoded PC Card 16 based Card Information Structure (CIS),
|
|
||||||
* per card (function 0) and per function (1 and greater).
|
|
||||||
*/
|
|
||||||
struct sdmmc_cis {
|
|
||||||
u_int16_t manufacturer;
|
|
||||||
#define SDMMC_VENDOR_INVALID 0xffff
|
|
||||||
u_int16_t product;
|
|
||||||
#define SDMMC_PRODUCT_INVALID 0xffff
|
|
||||||
u_int8_t function;
|
|
||||||
#define SDMMC_FUNCTION_INVALID 0xff
|
|
||||||
u_char cis1_major;
|
|
||||||
u_char cis1_minor;
|
|
||||||
char cis1_info_buf[256];
|
|
||||||
char *cis1_info[4];
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Structure describing either an SD card I/O function or a SD/MMC
|
|
||||||
* memory card from a "stack of cards" that responded to CMD2. For a
|
|
||||||
* combo card with one I/O function and one memory card, there will be
|
|
||||||
* two of these structures allocated. Each card slot has such a list
|
|
||||||
* of sdmmc_function structures.
|
|
||||||
*/
|
|
||||||
struct sdmmc_function {
|
|
||||||
/* common members */
|
|
||||||
u_int16_t rca; /* relative card address */
|
|
||||||
int flags;
|
|
||||||
#define SFF_ERROR 0x0001 /* function is poo; ignore it */
|
|
||||||
#define SFF_SDHC 0x0002 /* SD High Capacity card */
|
|
||||||
/* SD card I/O function members */
|
|
||||||
int number; /* I/O function number or -1 */
|
|
||||||
struct sdmmc_cis cis; /* decoded CIS */
|
|
||||||
/* SD/MMC memory card members */
|
|
||||||
struct sdmmc_csd csd; /* decoded CSD value */
|
|
||||||
struct sdmmc_cid cid; /* decoded CID value */
|
|
||||||
sdmmc_response raw_cid; /* temp. storage for decoding */
|
|
||||||
};
|
|
||||||
|
|
||||||
#define SDMMC_LOCK(sc) lockmgr(&(sc)->sc_lock, LK_EXCLUSIVE, NULL)
|
|
||||||
#define SDMMC_UNLOCK(sc) lockmgr(&(sc)->sc_lock, LK_RELEASE, NULL)
|
|
||||||
#define SDMMC_ASSERT_LOCKED(sc) \
|
|
||||||
KASSERT(lockstatus(&((sc))->sc_lock) == LK_EXCLUSIVE)
|
|
||||||
|
|
||||||
#ifdef CAN_HAZ_IPC
|
|
||||||
#include "ipc.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define SDMMC_DEFAULT_CLOCK 25000
|
|
||||||
#define SDMMC_DEFAULT_BLOCKLEN 512
|
|
||||||
|
|
||||||
#define SDMMC_NO_CARD 1
|
|
||||||
#define SDMMC_NEW_CARD 2
|
|
||||||
#define SDMMC_INSERTED 3
|
|
||||||
|
|
||||||
int sdmmc_write(u32 blk_start, u32 blk_count, void *data);
|
|
||||||
void sdmmc_attach(sdmmc_chipset_handle_t handle);
|
|
||||||
void sdmmc_needs_discover(void);
|
|
||||||
int sdmmc_select(void);
|
|
||||||
int sdmmc_check_card(void);
|
|
||||||
int sdmmc_ack_card(void);
|
|
||||||
int sdmmc_read(u32 blk_start, u32 blk_count, void *data);
|
|
||||||
#ifdef CAN_HAZ_IPC
|
|
||||||
void sdmmc_ipc(volatile ipc_request *req);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* MMC commands */ /* response type */
|
|
||||||
#define MMC_GO_IDLE_STATE 0 /* R0 */
|
|
||||||
#define MMC_SEND_OP_COND 1 /* R3 */
|
|
||||||
#define MMC_ALL_SEND_CID 2 /* R2 */
|
|
||||||
#define MMC_SET_RELATIVE_ADDR 3 /* R1 */
|
|
||||||
#define MMC_SELECT_CARD 7 /* R1 */
|
|
||||||
#define MMC_SEND_CSD 9 /* R2 */
|
|
||||||
#define MMC_STOP_TRANSMISSION 12 /* R1B */
|
|
||||||
#define MMC_SEND_STATUS 13 /* R1 */
|
|
||||||
#define MMC_SET_BLOCKLEN 16 /* R1 */
|
|
||||||
#define MMC_READ_BLOCK_SINGLE 17 /* R1 */
|
|
||||||
#define MMC_READ_BLOCK_MULTIPLE 18 /* R1 */
|
|
||||||
#define MMC_SET_BLOCK_COUNT 23 /* R1 */
|
|
||||||
#define MMC_WRITE_BLOCK_SINGLE 24 /* R1 */
|
|
||||||
#define MMC_WRITE_BLOCK_MULTIPLE 25 /* R1 */
|
|
||||||
#define MMC_APP_CMD 55 /* R1 */
|
|
||||||
|
|
||||||
/* SD commands */ /* response type */
|
|
||||||
#define SD_SEND_RELATIVE_ADDR 3 /* R6 */
|
|
||||||
#define SD_SEND_IF_COND 8 /* R7 */
|
|
||||||
|
|
||||||
/* SD application commands */ /* response type */
|
|
||||||
#define SD_APP_SET_BUS_WIDTH 6 /* R1 */
|
|
||||||
#define SD_APP_OP_COND 41 /* R3 */
|
|
||||||
|
|
||||||
/* OCR bits */
|
|
||||||
#define MMC_OCR_MEM_READY (1<<31) /* memory power-up status bit */
|
|
||||||
#define MMC_OCR_3_5V_3_6V (1<<23)
|
|
||||||
#define MMC_OCR_3_4V_3_5V (1<<22)
|
|
||||||
#define MMC_OCR_3_3V_3_4V (1<<21)
|
|
||||||
#define MMC_OCR_3_2V_3_3V (1<<20)
|
|
||||||
#define MMC_OCR_3_1V_3_2V (1<<19)
|
|
||||||
#define MMC_OCR_3_0V_3_1V (1<<18)
|
|
||||||
#define MMC_OCR_2_9V_3_0V (1<<17)
|
|
||||||
#define MMC_OCR_2_8V_2_9V (1<<16)
|
|
||||||
#define MMC_OCR_2_7V_2_8V (1<<15)
|
|
||||||
#define MMC_OCR_2_6V_2_7V (1<<14)
|
|
||||||
#define MMC_OCR_2_5V_2_6V (1<<13)
|
|
||||||
#define MMC_OCR_2_4V_2_5V (1<<12)
|
|
||||||
#define MMC_OCR_2_3V_2_4V (1<<11)
|
|
||||||
#define MMC_OCR_2_2V_2_3V (1<<10)
|
|
||||||
#define MMC_OCR_2_1V_2_2V (1<<9)
|
|
||||||
#define MMC_OCR_2_0V_2_1V (1<<8)
|
|
||||||
#define MMC_OCR_1_9V_2_0V (1<<7)
|
|
||||||
#define MMC_OCR_1_8V_1_9V (1<<6)
|
|
||||||
#define MMC_OCR_1_7V_1_8V (1<<5)
|
|
||||||
#define MMC_OCR_1_6V_1_7V (1<<4)
|
|
||||||
|
|
||||||
#define SD_OCR_SDHC_CAP (1<<30)
|
|
||||||
#define SD_OCR_VOL_MASK 0xFF8000 /* bits 23:15 */
|
|
||||||
|
|
||||||
/* R1 response type bits */
|
|
||||||
#define MMC_R1_READY_FOR_DATA (1<<8) /* ready for next transfer */
|
|
||||||
#define MMC_R1_APP_CMD (1<<5) /* app. commands supported */
|
|
||||||
|
|
||||||
/* 48-bit response decoding (32 bits w/o CRC) */
|
|
||||||
#define MMC_R1(resp) ((resp)[0])
|
|
||||||
#define MMC_R3(resp) ((resp)[0])
|
|
||||||
#define SD_R6(resp) ((resp)[0])
|
|
||||||
|
|
||||||
/* RCA argument and response */
|
|
||||||
#define MMC_ARG_RCA(rca) ((rca) << 16)
|
|
||||||
#define SD_R6_RCA(resp) (SD_R6((resp)) >> 16)
|
|
||||||
|
|
||||||
/* bus width argument */
|
|
||||||
#define SD_ARG_BUS_WIDTH_1 0
|
|
||||||
#define SD_ARG_BUS_WIDTH_4 2
|
|
||||||
|
|
||||||
/* MMC R2 response (CSD) */
|
|
||||||
#define MMC_CSD_CSDVER(resp) MMC_RSP_BITS((resp), 126, 2)
|
|
||||||
#define MMC_CSD_CSDVER_1_0 1
|
|
||||||
#define MMC_CSD_CSDVER_2_0 2
|
|
||||||
#define MMC_CSD_MMCVER(resp) MMC_RSP_BITS((resp), 122, 4)
|
|
||||||
#define MMC_CSD_MMCVER_1_0 0 /* MMC 1.0 - 1.2 */
|
|
||||||
#define MMC_CSD_MMCVER_1_4 1 /* MMC 1.4 */
|
|
||||||
#define MMC_CSD_MMCVER_2_0 2 /* MMC 2.0 - 2.2 */
|
|
||||||
#define MMC_CSD_MMCVER_3_1 3 /* MMC 3.1 - 3.3 */
|
|
||||||
#define MMC_CSD_MMCVER_4_0 4 /* MMC 4 */
|
|
||||||
#define MMC_CSD_READ_BL_LEN(resp) MMC_RSP_BITS((resp), 80, 4)
|
|
||||||
#define MMC_CSD_C_SIZE(resp) MMC_RSP_BITS((resp), 62, 12)
|
|
||||||
#define MMC_CSD_CAPACITY(resp) ((MMC_CSD_C_SIZE((resp))+1) << \
|
|
||||||
(MMC_CSD_C_SIZE_MULT((resp))+2))
|
|
||||||
#define MMC_CSD_C_SIZE_MULT(resp) MMC_RSP_BITS((resp), 47, 3)
|
|
||||||
|
|
||||||
/* MMC v1 R2 response (CID) */
|
|
||||||
#define MMC_CID_MID_V1(resp) MMC_RSP_BITS((resp), 104, 24)
|
|
||||||
#define MMC_CID_PNM_V1_CPY(resp, pnm) \
|
|
||||||
do { \
|
|
||||||
(pnm)[0] = MMC_RSP_BITS((resp), 96, 8); \
|
|
||||||
(pnm)[1] = MMC_RSP_BITS((resp), 88, 8); \
|
|
||||||
(pnm)[2] = MMC_RSP_BITS((resp), 80, 8); \
|
|
||||||
(pnm)[3] = MMC_RSP_BITS((resp), 72, 8); \
|
|
||||||
(pnm)[4] = MMC_RSP_BITS((resp), 64, 8); \
|
|
||||||
(pnm)[5] = MMC_RSP_BITS((resp), 56, 8); \
|
|
||||||
(pnm)[6] = MMC_RSP_BITS((resp), 48, 8); \
|
|
||||||
(pnm)[7] = '\0'; \
|
|
||||||
} while (0)
|
|
||||||
#define MMC_CID_REV_V1(resp) MMC_RSP_BITS((resp), 40, 8)
|
|
||||||
#define MMC_CID_PSN_V1(resp) MMC_RSP_BITS((resp), 16, 24)
|
|
||||||
#define MMC_CID_MDT_V1(resp) MMC_RSP_BITS((resp), 8, 8)
|
|
||||||
|
|
||||||
/* MMC v2 R2 response (CID) */
|
|
||||||
#define MMC_CID_MID_V2(resp) MMC_RSP_BITS((resp), 120, 8)
|
|
||||||
#define MMC_CID_OID_V2(resp) MMC_RSP_BITS((resp), 104, 16)
|
|
||||||
#define MMC_CID_PNM_V2_CPY(resp, pnm) \
|
|
||||||
do { \
|
|
||||||
(pnm)[0] = MMC_RSP_BITS((resp), 96, 8); \
|
|
||||||
(pnm)[1] = MMC_RSP_BITS((resp), 88, 8); \
|
|
||||||
(pnm)[2] = MMC_RSP_BITS((resp), 80, 8); \
|
|
||||||
(pnm)[3] = MMC_RSP_BITS((resp), 72, 8); \
|
|
||||||
(pnm)[4] = MMC_RSP_BITS((resp), 64, 8); \
|
|
||||||
(pnm)[5] = MMC_RSP_BITS((resp), 56, 8); \
|
|
||||||
(pnm)[6] = '\0'; \
|
|
||||||
} while (0)
|
|
||||||
#define MMC_CID_PSN_V2(resp) MMC_RSP_BITS((resp), 16, 32)
|
|
||||||
|
|
||||||
/* SD R2 response (CSD) */
|
|
||||||
#define SD_CSD_CSDVER(resp) MMC_RSP_BITS((resp), 126, 2)
|
|
||||||
#define SD_CSD_CSDVER_1_0 0
|
|
||||||
#define SD_CSD_CSDVER_2_0 1
|
|
||||||
#define SD_CSD_TAAC(resp) MMC_RSP_BITS((resp), 112, 8)
|
|
||||||
#define SD_CSD_TAAC_1_5_MSEC 0x26
|
|
||||||
#define SD_CSD_NSAC(resp) MMC_RSP_BITS((resp), 104, 8)
|
|
||||||
#define SD_CSD_SPEED(resp) MMC_RSP_BITS((resp), 96, 8)
|
|
||||||
#define SD_CSD_SPEED_25_MHZ 0x32
|
|
||||||
#define SD_CSD_SPEED_50_MHZ 0x5a
|
|
||||||
#define SD_CSD_CCC(resp) MMC_RSP_BITS((resp), 84, 12)
|
|
||||||
#define SD_CSD_CCC_ALL 0x5f5
|
|
||||||
#define SD_CSD_READ_BL_LEN(resp) MMC_RSP_BITS((resp), 80, 4)
|
|
||||||
#define SD_CSD_READ_BL_PARTIAL(resp) MMC_RSP_BITS((resp), 79, 1)
|
|
||||||
#define SD_CSD_WRITE_BLK_MISALIGN(resp) MMC_RSP_BITS((resp), 78, 1)
|
|
||||||
#define SD_CSD_READ_BLK_MISALIGN(resp) MMC_RSP_BITS((resp), 77, 1)
|
|
||||||
#define SD_CSD_DSR_IMP(resp) MMC_RSP_BITS((resp), 76, 1)
|
|
||||||
#define SD_CSD_C_SIZE(resp) MMC_RSP_BITS((resp), 62, 12)
|
|
||||||
#define SD_CSD_CAPACITY(resp) ((SD_CSD_C_SIZE((resp))+1) << \
|
|
||||||
(SD_CSD_C_SIZE_MULT((resp))+2))
|
|
||||||
#define SD_CSD_V2_C_SIZE(resp) MMC_RSP_BITS((resp), 48, 22)
|
|
||||||
#define SD_CSD_V2_CAPACITY(resp) ((SD_CSD_V2_C_SIZE((resp))+1) << 10)
|
|
||||||
#define SD_CSD_V2_BL_LEN 0x9 /* 512 */
|
|
||||||
#define SD_CSD_VDD_R_CURR_MIN(resp) MMC_RSP_BITS((resp), 59, 3)
|
|
||||||
#define SD_CSD_VDD_R_CURR_MAX(resp) MMC_RSP_BITS((resp), 56, 3)
|
|
||||||
#define SD_CSD_VDD_W_CURR_MIN(resp) MMC_RSP_BITS((resp), 53, 3)
|
|
||||||
#define SD_CSD_VDD_W_CURR_MAX(resp) MMC_RSP_BITS((resp), 50, 3)
|
|
||||||
#define SD_CSD_VDD_RW_CURR_100mA 0x7
|
|
||||||
#define SD_CSD_VDD_RW_CURR_80mA 0x6
|
|
||||||
#define SD_CSD_C_SIZE_MULT(resp) MMC_RSP_BITS((resp), 47, 3)
|
|
||||||
#define SD_CSD_ERASE_BLK_EN(resp) MMC_RSP_BITS((resp), 46, 1)
|
|
||||||
#define SD_CSD_SECTOR_SIZE(resp) MMC_RSP_BITS((resp), 39, 7) /* +1 */
|
|
||||||
#define SD_CSD_WP_GRP_SIZE(resp) MMC_RSP_BITS((resp), 32, 7) /* +1 */
|
|
||||||
#define SD_CSD_WP_GRP_ENABLE(resp) MMC_RSP_BITS((resp), 31, 1)
|
|
||||||
#define SD_CSD_R2W_FACTOR(resp) MMC_RSP_BITS((resp), 26, 3)
|
|
||||||
#define SD_CSD_WRITE_BL_LEN(resp) MMC_RSP_BITS((resp), 22, 4)
|
|
||||||
#define SD_CSD_RW_BL_LEN_2G 0xa
|
|
||||||
#define SD_CSD_RW_BL_LEN_1G 0x9
|
|
||||||
#define SD_CSD_WRITE_BL_PARTIAL(resp) MMC_RSP_BITS((resp), 21, 1)
|
|
||||||
#define SD_CSD_FILE_FORMAT_GRP(resp) MMC_RSP_BITS((resp), 15, 1)
|
|
||||||
#define SD_CSD_COPY(resp) MMC_RSP_BITS((resp), 14, 1)
|
|
||||||
#define SD_CSD_PERM_WRITE_PROTECT(resp) MMC_RSP_BITS((resp), 13, 1)
|
|
||||||
#define SD_CSD_TMP_WRITE_PROTECT(resp) MMC_RSP_BITS((resp), 12, 1)
|
|
||||||
#define SD_CSD_FILE_FORMAT(resp) MMC_RSP_BITS((resp), 10, 2)
|
|
||||||
|
|
||||||
/* SD R2 response (CID) */
|
|
||||||
#define SD_CID_MID(resp) MMC_RSP_BITS((resp), 120, 8)
|
|
||||||
#define SD_CID_OID(resp) MMC_RSP_BITS((resp), 104, 16)
|
|
||||||
#define SD_CID_PNM_CPY(resp, pnm) \
|
|
||||||
do { \
|
|
||||||
(pnm)[0] = MMC_RSP_BITS((resp), 96, 8); \
|
|
||||||
(pnm)[1] = MMC_RSP_BITS((resp), 88, 8); \
|
|
||||||
(pnm)[2] = MMC_RSP_BITS((resp), 80, 8); \
|
|
||||||
(pnm)[3] = MMC_RSP_BITS((resp), 72, 8); \
|
|
||||||
(pnm)[4] = MMC_RSP_BITS((resp), 64, 8); \
|
|
||||||
(pnm)[5] = '\0'; \
|
|
||||||
} while (0)
|
|
||||||
#define SD_CID_REV(resp) MMC_RSP_BITS((resp), 56, 8)
|
|
||||||
#define SD_CID_PSN(resp) MMC_RSP_BITS((resp), 24, 32)
|
|
||||||
#define SD_CID_MDT(resp) MMC_RSP_BITS((resp), 8, 12)
|
|
||||||
|
|
||||||
/* Might be slow, but it should work on big and little endian systems. */
|
|
||||||
#define MMC_RSP_BITS(resp, start, len) __bitfield((resp), (start)-8, (len))
|
|
||||||
static __inline int
|
|
||||||
__bitfield(u_int32_t *src, int start, int len)
|
|
||||||
{
|
|
||||||
u_int8_t *sp;
|
|
||||||
u_int32_t dst, mask;
|
|
||||||
int shift, bs, bc;
|
|
||||||
|
|
||||||
if (start < 0 || len < 0 || len > 32)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
dst = 0;
|
|
||||||
mask = len % 32 ? UINT_MAX >> (32 - (len % 32)) : UINT_MAX;
|
|
||||||
shift = 0;
|
|
||||||
|
|
||||||
while (len > 0) {
|
|
||||||
sp = (u_int8_t *)src + start / 8;
|
|
||||||
bs = start % 8;
|
|
||||||
bc = 8 - bs;
|
|
||||||
if (bc > len)
|
|
||||||
bc = len;
|
|
||||||
dst |= (*sp++ >> bs) << shift;
|
|
||||||
shift += bc;
|
|
||||||
start += bc;
|
|
||||||
len -= bc;
|
|
||||||
}
|
|
||||||
|
|
||||||
dst &= mask;
|
|
||||||
return (int)dst;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
83
sdmmcchip.h
83
sdmmcchip.h
@ -1,83 +0,0 @@
|
|||||||
/* $OpenBSD: sdmmcchip.h,v 1.4 2009/02/20 19:16:35 miod Exp $ */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
|
|
||||||
*
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
|
||||||
* copyright notice and this permission notice appear in all copies.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
||||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
||||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
||||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
||||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _SDMMC_CHIP_H_
|
|
||||||
#define _SDMMC_CHIP_H_
|
|
||||||
|
|
||||||
struct sdmmc_command;
|
|
||||||
|
|
||||||
typedef struct sdmmc_chip_functions *sdmmc_chipset_tag_t;
|
|
||||||
typedef void *sdmmc_chipset_handle_t;
|
|
||||||
|
|
||||||
struct sdmmc_chip_functions {
|
|
||||||
/* host controller reset */
|
|
||||||
int (*host_reset)(sdmmc_chipset_handle_t);
|
|
||||||
/* host capabilities */
|
|
||||||
u_int32_t (*host_ocr)(sdmmc_chipset_handle_t);
|
|
||||||
int (*host_maxblklen)(sdmmc_chipset_handle_t);
|
|
||||||
/* card detection */
|
|
||||||
int (*card_detect)(sdmmc_chipset_handle_t);
|
|
||||||
/* bus power and clock frequency */
|
|
||||||
int (*bus_power)(sdmmc_chipset_handle_t, u_int32_t);
|
|
||||||
int (*bus_clock)(sdmmc_chipset_handle_t, int);
|
|
||||||
/* command execution */
|
|
||||||
void (*exec_command)(sdmmc_chipset_handle_t,
|
|
||||||
struct sdmmc_command *);
|
|
||||||
/* bus width */
|
|
||||||
void (*set_bus_width)(sdmmc_chipset_handle_t, int);
|
|
||||||
};
|
|
||||||
|
|
||||||
/* host controller reset */
|
|
||||||
#define sdmmc_chip_host_reset(tag, handle) \
|
|
||||||
((tag)->host_reset((handle)))
|
|
||||||
/* host capabilities */
|
|
||||||
#define sdmmc_chip_host_ocr(tag, handle) \
|
|
||||||
((tag)->host_ocr((handle)))
|
|
||||||
#define sdmmc_chip_host_maxblklen(tag, handle) \
|
|
||||||
((tag)->host_maxblklen((handle)))
|
|
||||||
/* card detection */
|
|
||||||
#define sdmmc_chip_card_detect(tag, handle) \
|
|
||||||
((tag)->card_detect((handle)))
|
|
||||||
/* bus power and clock frequency */
|
|
||||||
#define sdmmc_chip_bus_power(tag, handle, ocr) \
|
|
||||||
((tag)->bus_power((handle), (ocr)))
|
|
||||||
#define sdmmc_chip_bus_clock(tag, handle, freq) \
|
|
||||||
((tag)->bus_clock((handle), (freq)))
|
|
||||||
/* command execution */
|
|
||||||
#define sdmmc_chip_exec_command(tag, handle, cmdp) \
|
|
||||||
((tag)->exec_command((handle), (cmdp)))
|
|
||||||
/* bus widht */
|
|
||||||
#define sdmmc_chip_set_bus_width(tag, handle, enable) \
|
|
||||||
((tag)->set_bus_width((handle), (enable)))
|
|
||||||
|
|
||||||
/* clock frequencies for sdmmc_chip_bus_clock() */
|
|
||||||
#define SDMMC_SDCLK_OFF 0
|
|
||||||
#define SDMMC_SDCLK_400KHZ 400
|
|
||||||
#define SDMMC_SDCLK_25MHZ 25000
|
|
||||||
|
|
||||||
struct sdmmcbus_attach_args {
|
|
||||||
const char *saa_busname;
|
|
||||||
sdmmc_chipset_tag_t sct;
|
|
||||||
sdmmc_chipset_handle_t sch;
|
|
||||||
int flags;
|
|
||||||
long max_xfer;
|
|
||||||
};
|
|
||||||
|
|
||||||
void sdmmc_delay(u_int);
|
|
||||||
|
|
||||||
#endif
|
|
232
sdmmcreg.h
232
sdmmcreg.h
@ -1,232 +0,0 @@
|
|||||||
/* $OpenBSD: sdmmcreg.h,v 1.4 2009/01/09 10:55:22 jsg Exp $ */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
|
|
||||||
*
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
|
||||||
* copyright notice and this permission notice appear in all copies.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
||||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
||||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
||||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
||||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _SDMMCREG_H_
|
|
||||||
#define _SDMMCREG_H_
|
|
||||||
|
|
||||||
/* MMC commands */ /* response type */
|
|
||||||
#define MMC_GO_IDLE_STATE 0 /* R0 */
|
|
||||||
#define MMC_SEND_OP_COND 1 /* R3 */
|
|
||||||
#define MMC_ALL_SEND_CID 2 /* R2 */
|
|
||||||
#define MMC_SET_RELATIVE_ADDR 3 /* R1 */
|
|
||||||
#define MMC_SELECT_CARD 7 /* R1 */
|
|
||||||
#define MMC_SEND_CSD 9 /* R2 */
|
|
||||||
#define MMC_STOP_TRANSMISSION 12 /* R1B */
|
|
||||||
#define MMC_SEND_STATUS 13 /* R1 */
|
|
||||||
#define MMC_SET_BLOCKLEN 16 /* R1 */
|
|
||||||
#define MMC_READ_BLOCK_SINGLE 17 /* R1 */
|
|
||||||
#define MMC_READ_BLOCK_MULTIPLE 18 /* R1 */
|
|
||||||
#define MMC_SET_BLOCK_COUNT 23 /* R1 */
|
|
||||||
#define MMC_WRITE_BLOCK_SINGLE 24 /* R1 */
|
|
||||||
#define MMC_WRITE_BLOCK_MULTIPLE 25 /* R1 */
|
|
||||||
#define MMC_APP_CMD 55 /* R1 */
|
|
||||||
|
|
||||||
/* SD commands */ /* response type */
|
|
||||||
#define SD_SEND_RELATIVE_ADDR 3 /* R6 */
|
|
||||||
#define SD_SEND_IF_COND 8 /* R7 */
|
|
||||||
|
|
||||||
/* SD application commands */ /* response type */
|
|
||||||
#define SD_APP_SET_BUS_WIDTH 6 /* R1 */
|
|
||||||
#define SD_APP_OP_COND 41 /* R3 */
|
|
||||||
|
|
||||||
/* OCR bits */
|
|
||||||
#define MMC_OCR_MEM_READY (1<<31) /* memory power-up status bit */
|
|
||||||
#define MMC_OCR_3_5V_3_6V (1<<23)
|
|
||||||
#define MMC_OCR_3_4V_3_5V (1<<22)
|
|
||||||
#define MMC_OCR_3_3V_3_4V (1<<21)
|
|
||||||
#define MMC_OCR_3_2V_3_3V (1<<20)
|
|
||||||
#define MMC_OCR_3_1V_3_2V (1<<19)
|
|
||||||
#define MMC_OCR_3_0V_3_1V (1<<18)
|
|
||||||
#define MMC_OCR_2_9V_3_0V (1<<17)
|
|
||||||
#define MMC_OCR_2_8V_2_9V (1<<16)
|
|
||||||
#define MMC_OCR_2_7V_2_8V (1<<15)
|
|
||||||
#define MMC_OCR_2_6V_2_7V (1<<14)
|
|
||||||
#define MMC_OCR_2_5V_2_6V (1<<13)
|
|
||||||
#define MMC_OCR_2_4V_2_5V (1<<12)
|
|
||||||
#define MMC_OCR_2_3V_2_4V (1<<11)
|
|
||||||
#define MMC_OCR_2_2V_2_3V (1<<10)
|
|
||||||
#define MMC_OCR_2_1V_2_2V (1<<9)
|
|
||||||
#define MMC_OCR_2_0V_2_1V (1<<8)
|
|
||||||
#define MMC_OCR_1_9V_2_0V (1<<7)
|
|
||||||
#define MMC_OCR_1_8V_1_9V (1<<6)
|
|
||||||
#define MMC_OCR_1_7V_1_8V (1<<5)
|
|
||||||
#define MMC_OCR_1_6V_1_7V (1<<4)
|
|
||||||
|
|
||||||
#define SD_OCR_SDHC_CAP (1<<30)
|
|
||||||
#define SD_OCR_VOL_MASK 0xFF8000 /* bits 23:15 */
|
|
||||||
|
|
||||||
/* R1 response type bits */
|
|
||||||
#define MMC_R1_READY_FOR_DATA (1<<8) /* ready for next transfer */
|
|
||||||
#define MMC_R1_APP_CMD (1<<5) /* app. commands supported */
|
|
||||||
|
|
||||||
/* 48-bit response decoding (32 bits w/o CRC) */
|
|
||||||
#define MMC_R1(resp) ((resp)[0])
|
|
||||||
#define MMC_R3(resp) ((resp)[0])
|
|
||||||
#define SD_R6(resp) ((resp)[0])
|
|
||||||
|
|
||||||
/* RCA argument and response */
|
|
||||||
#define MMC_ARG_RCA(rca) ((rca) << 16)
|
|
||||||
#define SD_R6_RCA(resp) (SD_R6((resp)) >> 16)
|
|
||||||
|
|
||||||
/* bus width argument */
|
|
||||||
#define SD_ARG_BUS_WIDTH_1 0
|
|
||||||
#define SD_ARG_BUS_WIDTH_4 2
|
|
||||||
|
|
||||||
/* MMC R2 response (CSD) */
|
|
||||||
#define MMC_CSD_CSDVER(resp) MMC_RSP_BITS((resp), 126, 2)
|
|
||||||
#define MMC_CSD_CSDVER_1_0 1
|
|
||||||
#define MMC_CSD_CSDVER_2_0 2
|
|
||||||
#define MMC_CSD_MMCVER(resp) MMC_RSP_BITS((resp), 122, 4)
|
|
||||||
#define MMC_CSD_MMCVER_1_0 0 /* MMC 1.0 - 1.2 */
|
|
||||||
#define MMC_CSD_MMCVER_1_4 1 /* MMC 1.4 */
|
|
||||||
#define MMC_CSD_MMCVER_2_0 2 /* MMC 2.0 - 2.2 */
|
|
||||||
#define MMC_CSD_MMCVER_3_1 3 /* MMC 3.1 - 3.3 */
|
|
||||||
#define MMC_CSD_MMCVER_4_0 4 /* MMC 4 */
|
|
||||||
#define MMC_CSD_READ_BL_LEN(resp) MMC_RSP_BITS((resp), 80, 4)
|
|
||||||
#define MMC_CSD_C_SIZE(resp) MMC_RSP_BITS((resp), 62, 12)
|
|
||||||
#define MMC_CSD_CAPACITY(resp) ((MMC_CSD_C_SIZE((resp))+1) << \
|
|
||||||
(MMC_CSD_C_SIZE_MULT((resp))+2))
|
|
||||||
#define MMC_CSD_C_SIZE_MULT(resp) MMC_RSP_BITS((resp), 47, 3)
|
|
||||||
|
|
||||||
/* MMC v1 R2 response (CID) */
|
|
||||||
#define MMC_CID_MID_V1(resp) MMC_RSP_BITS((resp), 104, 24)
|
|
||||||
#define MMC_CID_PNM_V1_CPY(resp, pnm) \
|
|
||||||
do { \
|
|
||||||
(pnm)[0] = MMC_RSP_BITS((resp), 96, 8); \
|
|
||||||
(pnm)[1] = MMC_RSP_BITS((resp), 88, 8); \
|
|
||||||
(pnm)[2] = MMC_RSP_BITS((resp), 80, 8); \
|
|
||||||
(pnm)[3] = MMC_RSP_BITS((resp), 72, 8); \
|
|
||||||
(pnm)[4] = MMC_RSP_BITS((resp), 64, 8); \
|
|
||||||
(pnm)[5] = MMC_RSP_BITS((resp), 56, 8); \
|
|
||||||
(pnm)[6] = MMC_RSP_BITS((resp), 48, 8); \
|
|
||||||
(pnm)[7] = '\0'; \
|
|
||||||
} while (0)
|
|
||||||
#define MMC_CID_REV_V1(resp) MMC_RSP_BITS((resp), 40, 8)
|
|
||||||
#define MMC_CID_PSN_V1(resp) MMC_RSP_BITS((resp), 16, 24)
|
|
||||||
#define MMC_CID_MDT_V1(resp) MMC_RSP_BITS((resp), 8, 8)
|
|
||||||
|
|
||||||
/* MMC v2 R2 response (CID) */
|
|
||||||
#define MMC_CID_MID_V2(resp) MMC_RSP_BITS((resp), 120, 8)
|
|
||||||
#define MMC_CID_OID_V2(resp) MMC_RSP_BITS((resp), 104, 16)
|
|
||||||
#define MMC_CID_PNM_V2_CPY(resp, pnm) \
|
|
||||||
do { \
|
|
||||||
(pnm)[0] = MMC_RSP_BITS((resp), 96, 8); \
|
|
||||||
(pnm)[1] = MMC_RSP_BITS((resp), 88, 8); \
|
|
||||||
(pnm)[2] = MMC_RSP_BITS((resp), 80, 8); \
|
|
||||||
(pnm)[3] = MMC_RSP_BITS((resp), 72, 8); \
|
|
||||||
(pnm)[4] = MMC_RSP_BITS((resp), 64, 8); \
|
|
||||||
(pnm)[5] = MMC_RSP_BITS((resp), 56, 8); \
|
|
||||||
(pnm)[6] = '\0'; \
|
|
||||||
} while (0)
|
|
||||||
#define MMC_CID_PSN_V2(resp) MMC_RSP_BITS((resp), 16, 32)
|
|
||||||
|
|
||||||
/* SD R2 response (CSD) */
|
|
||||||
#define SD_CSD_CSDVER(resp) MMC_RSP_BITS((resp), 126, 2)
|
|
||||||
#define SD_CSD_CSDVER_1_0 0
|
|
||||||
#define SD_CSD_CSDVER_2_0 1
|
|
||||||
#define SD_CSD_TAAC(resp) MMC_RSP_BITS((resp), 112, 8)
|
|
||||||
#define SD_CSD_TAAC_1_5_MSEC 0x26
|
|
||||||
#define SD_CSD_NSAC(resp) MMC_RSP_BITS((resp), 104, 8)
|
|
||||||
#define SD_CSD_SPEED(resp) MMC_RSP_BITS((resp), 96, 8)
|
|
||||||
#define SD_CSD_SPEED_25_MHZ 0x32
|
|
||||||
#define SD_CSD_SPEED_50_MHZ 0x5a
|
|
||||||
#define SD_CSD_CCC(resp) MMC_RSP_BITS((resp), 84, 12)
|
|
||||||
#define SD_CSD_CCC_ALL 0x5f5
|
|
||||||
#define SD_CSD_READ_BL_LEN(resp) MMC_RSP_BITS((resp), 80, 4)
|
|
||||||
#define SD_CSD_READ_BL_PARTIAL(resp) MMC_RSP_BITS((resp), 79, 1)
|
|
||||||
#define SD_CSD_WRITE_BLK_MISALIGN(resp) MMC_RSP_BITS((resp), 78, 1)
|
|
||||||
#define SD_CSD_READ_BLK_MISALIGN(resp) MMC_RSP_BITS((resp), 77, 1)
|
|
||||||
#define SD_CSD_DSR_IMP(resp) MMC_RSP_BITS((resp), 76, 1)
|
|
||||||
#define SD_CSD_C_SIZE(resp) MMC_RSP_BITS((resp), 62, 12)
|
|
||||||
#define SD_CSD_CAPACITY(resp) ((SD_CSD_C_SIZE((resp))+1) << \
|
|
||||||
(SD_CSD_C_SIZE_MULT((resp))+2))
|
|
||||||
#define SD_CSD_V2_C_SIZE(resp) MMC_RSP_BITS((resp), 48, 22)
|
|
||||||
#define SD_CSD_V2_CAPACITY(resp) ((SD_CSD_V2_C_SIZE((resp))+1) << 10)
|
|
||||||
#define SD_CSD_V2_BL_LEN 0x9 /* 512 */
|
|
||||||
#define SD_CSD_VDD_R_CURR_MIN(resp) MMC_RSP_BITS((resp), 59, 3)
|
|
||||||
#define SD_CSD_VDD_R_CURR_MAX(resp) MMC_RSP_BITS((resp), 56, 3)
|
|
||||||
#define SD_CSD_VDD_W_CURR_MIN(resp) MMC_RSP_BITS((resp), 53, 3)
|
|
||||||
#define SD_CSD_VDD_W_CURR_MAX(resp) MMC_RSP_BITS((resp), 50, 3)
|
|
||||||
#define SD_CSD_VDD_RW_CURR_100mA 0x7
|
|
||||||
#define SD_CSD_VDD_RW_CURR_80mA 0x6
|
|
||||||
#define SD_CSD_C_SIZE_MULT(resp) MMC_RSP_BITS((resp), 47, 3)
|
|
||||||
#define SD_CSD_ERASE_BLK_EN(resp) MMC_RSP_BITS((resp), 46, 1)
|
|
||||||
#define SD_CSD_SECTOR_SIZE(resp) MMC_RSP_BITS((resp), 39, 7) /* +1 */
|
|
||||||
#define SD_CSD_WP_GRP_SIZE(resp) MMC_RSP_BITS((resp), 32, 7) /* +1 */
|
|
||||||
#define SD_CSD_WP_GRP_ENABLE(resp) MMC_RSP_BITS((resp), 31, 1)
|
|
||||||
#define SD_CSD_R2W_FACTOR(resp) MMC_RSP_BITS((resp), 26, 3)
|
|
||||||
#define SD_CSD_WRITE_BL_LEN(resp) MMC_RSP_BITS((resp), 22, 4)
|
|
||||||
#define SD_CSD_RW_BL_LEN_2G 0xa
|
|
||||||
#define SD_CSD_RW_BL_LEN_1G 0x9
|
|
||||||
#define SD_CSD_WRITE_BL_PARTIAL(resp) MMC_RSP_BITS((resp), 21, 1)
|
|
||||||
#define SD_CSD_FILE_FORMAT_GRP(resp) MMC_RSP_BITS((resp), 15, 1)
|
|
||||||
#define SD_CSD_COPY(resp) MMC_RSP_BITS((resp), 14, 1)
|
|
||||||
#define SD_CSD_PERM_WRITE_PROTECT(resp) MMC_RSP_BITS((resp), 13, 1)
|
|
||||||
#define SD_CSD_TMP_WRITE_PROTECT(resp) MMC_RSP_BITS((resp), 12, 1)
|
|
||||||
#define SD_CSD_FILE_FORMAT(resp) MMC_RSP_BITS((resp), 10, 2)
|
|
||||||
|
|
||||||
/* SD R2 response (CID) */
|
|
||||||
#define SD_CID_MID(resp) MMC_RSP_BITS((resp), 120, 8)
|
|
||||||
#define SD_CID_OID(resp) MMC_RSP_BITS((resp), 104, 16)
|
|
||||||
#define SD_CID_PNM_CPY(resp, pnm) \
|
|
||||||
do { \
|
|
||||||
(pnm)[0] = MMC_RSP_BITS((resp), 96, 8); \
|
|
||||||
(pnm)[1] = MMC_RSP_BITS((resp), 88, 8); \
|
|
||||||
(pnm)[2] = MMC_RSP_BITS((resp), 80, 8); \
|
|
||||||
(pnm)[3] = MMC_RSP_BITS((resp), 72, 8); \
|
|
||||||
(pnm)[4] = MMC_RSP_BITS((resp), 64, 8); \
|
|
||||||
(pnm)[5] = '\0'; \
|
|
||||||
} while (0)
|
|
||||||
#define SD_CID_REV(resp) MMC_RSP_BITS((resp), 56, 8)
|
|
||||||
#define SD_CID_PSN(resp) MMC_RSP_BITS((resp), 24, 32)
|
|
||||||
#define SD_CID_MDT(resp) MMC_RSP_BITS((resp), 8, 12)
|
|
||||||
|
|
||||||
/* Might be slow, but it should work on big and little endian systems. */
|
|
||||||
#define MMC_RSP_BITS(resp, start, len) __bitfield((resp), (start)-8, (len))
|
|
||||||
static __inline int
|
|
||||||
__bitfield(u_int32_t *src, int start, int len)
|
|
||||||
{
|
|
||||||
u_int8_t *sp;
|
|
||||||
u_int32_t dst, mask;
|
|
||||||
int shift, bs, bc;
|
|
||||||
|
|
||||||
if (start < 0 || len < 0 || len > 32)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
dst = 0;
|
|
||||||
mask = len % 32 ? UINT_MAX >> (32 - (len % 32)) : UINT_MAX;
|
|
||||||
shift = 0;
|
|
||||||
|
|
||||||
while (len > 0) {
|
|
||||||
sp = (u_int8_t *)src + start / 8;
|
|
||||||
bs = start % 8;
|
|
||||||
bc = 8 - bs;
|
|
||||||
if (bc > len)
|
|
||||||
bc = len;
|
|
||||||
dst |= (*sp++ >> bs) << shift;
|
|
||||||
shift += bc;
|
|
||||||
start += bc;
|
|
||||||
len -= bc;
|
|
||||||
}
|
|
||||||
|
|
||||||
dst &= mask;
|
|
||||||
return (int)dst;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
182
sdmmcvar.h
182
sdmmcvar.h
@ -1,182 +0,0 @@
|
|||||||
/* $OpenBSD: sdmmcvar.h,v 1.16 2009/04/07 16:35:52 blambert Exp $ */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
|
|
||||||
* Copyright (c) 2009 Sven Peter <svenpeter@gmail.com>
|
|
||||||
*
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
|
||||||
* copyright notice and this permission notice appear in all copies.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
||||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
||||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
||||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
||||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _SDMMCVAR_H_
|
|
||||||
#define _SDMMCVAR_H_
|
|
||||||
|
|
||||||
struct sdmmc_csd {
|
|
||||||
int csdver; /* CSD structure format */
|
|
||||||
int mmcver; /* MMC version (for CID format) */
|
|
||||||
int capacity; /* total number of sectors */
|
|
||||||
int sector_size; /* sector size in bytes */
|
|
||||||
int read_bl_len; /* block length for reads */
|
|
||||||
/* ... */
|
|
||||||
};
|
|
||||||
|
|
||||||
struct sdmmc_cid {
|
|
||||||
int mid; /* manufacturer identification number */
|
|
||||||
int oid; /* OEM/product identification number */
|
|
||||||
char pnm[8]; /* product name (MMC v1 has the longest) */
|
|
||||||
int rev; /* product revision */
|
|
||||||
int psn; /* product serial number */
|
|
||||||
int mdt; /* manufacturing date */
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef u_int32_t sdmmc_response[4];
|
|
||||||
|
|
||||||
struct sdmmc_softc;
|
|
||||||
|
|
||||||
struct sdmmc_task {
|
|
||||||
void (*func)(void *arg);
|
|
||||||
void *arg;
|
|
||||||
int onqueue;
|
|
||||||
struct sdmmc_softc *sc;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define sdmmc_init_task(xtask, xfunc, xarg) do { \
|
|
||||||
(xtask)->func = (xfunc); \
|
|
||||||
(xtask)->arg = (xarg); \
|
|
||||||
(xtask)->onqueue = 0; \
|
|
||||||
(xtask)->sc = NULL; \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define sdmmc_task_pending(xtask) ((xtask)->onqueue)
|
|
||||||
|
|
||||||
struct sdmmc_command {
|
|
||||||
// struct sdmmc_task c_task; /* task queue entry */
|
|
||||||
u_int16_t c_opcode; /* SD or MMC command index */
|
|
||||||
u_int32_t c_arg; /* SD/MMC command argument */
|
|
||||||
sdmmc_response c_resp; /* response buffer */
|
|
||||||
void *c_data; /* buffer to send or read into */
|
|
||||||
int c_datalen; /* length of data buffer */
|
|
||||||
int c_blklen; /* block length */
|
|
||||||
int c_flags; /* see below */
|
|
||||||
#define SCF_ITSDONE 0x0001 /* command is complete */
|
|
||||||
#define SCF_CMD(flags) ((flags) & 0x00f0)
|
|
||||||
#define SCF_CMD_AC 0x0000
|
|
||||||
#define SCF_CMD_ADTC 0x0010
|
|
||||||
#define SCF_CMD_BC 0x0020
|
|
||||||
#define SCF_CMD_BCR 0x0030
|
|
||||||
#define SCF_CMD_READ 0x0040 /* read command (data expected) */
|
|
||||||
#define SCF_RSP_BSY 0x0100
|
|
||||||
#define SCF_RSP_136 0x0200
|
|
||||||
#define SCF_RSP_CRC 0x0400
|
|
||||||
#define SCF_RSP_IDX 0x0800
|
|
||||||
#define SCF_RSP_PRESENT 0x1000
|
|
||||||
/* response types */
|
|
||||||
#define SCF_RSP_R0 0 /* none */
|
|
||||||
#define SCF_RSP_R1 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX)
|
|
||||||
#define SCF_RSP_R1B (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX|SCF_RSP_BSY)
|
|
||||||
#define SCF_RSP_R2 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_136)
|
|
||||||
#define SCF_RSP_R3 (SCF_RSP_PRESENT)
|
|
||||||
#define SCF_RSP_R4 (SCF_RSP_PRESENT)
|
|
||||||
#define SCF_RSP_R5 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX)
|
|
||||||
#define SCF_RSP_R5B (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX|SCF_RSP_BSY)
|
|
||||||
#define SCF_RSP_R6 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX)
|
|
||||||
#define SCF_RSP_R7 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX)
|
|
||||||
int c_error; /* errno value on completion */
|
|
||||||
|
|
||||||
/* Host controller owned fields for data xfer in progress */
|
|
||||||
int c_resid; /* remaining I/O */
|
|
||||||
u_char *c_buf; /* remaining data */
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Decoded PC Card 16 based Card Information Structure (CIS),
|
|
||||||
* per card (function 0) and per function (1 and greater).
|
|
||||||
*/
|
|
||||||
struct sdmmc_cis {
|
|
||||||
u_int16_t manufacturer;
|
|
||||||
#define SDMMC_VENDOR_INVALID 0xffff
|
|
||||||
u_int16_t product;
|
|
||||||
#define SDMMC_PRODUCT_INVALID 0xffff
|
|
||||||
u_int8_t function;
|
|
||||||
#define SDMMC_FUNCTION_INVALID 0xff
|
|
||||||
u_char cis1_major;
|
|
||||||
u_char cis1_minor;
|
|
||||||
char cis1_info_buf[256];
|
|
||||||
char *cis1_info[4];
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Structure describing either an SD card I/O function or a SD/MMC
|
|
||||||
* memory card from a "stack of cards" that responded to CMD2. For a
|
|
||||||
* combo card with one I/O function and one memory card, there will be
|
|
||||||
* two of these structures allocated. Each card slot has such a list
|
|
||||||
* of sdmmc_function structures.
|
|
||||||
*/
|
|
||||||
struct sdmmc_function {
|
|
||||||
/* common members */
|
|
||||||
struct sdmmc_softc *sc; /* card slot softc */
|
|
||||||
u_int16_t rca; /* relative card address */
|
|
||||||
int flags;
|
|
||||||
#define SFF_ERROR 0x0001 /* function is poo; ignore it */
|
|
||||||
#define SFF_SDHC 0x0002 /* SD High Capacity card */
|
|
||||||
/* SD card I/O function members */
|
|
||||||
int number; /* I/O function number or -1 */
|
|
||||||
struct device *child; /* function driver */
|
|
||||||
struct sdmmc_cis cis; /* decoded CIS */
|
|
||||||
/* SD/MMC memory card members */
|
|
||||||
struct sdmmc_csd csd; /* decoded CSD value */
|
|
||||||
struct sdmmc_cid cid; /* decoded CID value */
|
|
||||||
sdmmc_response raw_cid; /* temp. storage for decoding */
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Structure describing a single SD/MMC/SDIO card slot.
|
|
||||||
*/
|
|
||||||
struct sdmmc_softc {
|
|
||||||
struct device sc_dev; /* base device */
|
|
||||||
#define SDMMCDEVNAME(sc) ((sc)->sc_dev.dv_xname)
|
|
||||||
sdmmc_chipset_tag_t sct; /* host controller chipset tag */
|
|
||||||
sdmmc_chipset_handle_t sch; /* host controller chipset handle */
|
|
||||||
int sc_flags;
|
|
||||||
#define SMF_SD_MODE 0x0001 /* host in SD mode (MMC otherwise) */
|
|
||||||
#define SMF_IO_MODE 0x0002 /* host in I/O mode (SD mode only) */
|
|
||||||
#define SMF_MEM_MODE 0x0004 /* host in memory mode (SD or MMC) */
|
|
||||||
#define SMF_CARD_PRESENT 0x0010 /* card presence noticed */
|
|
||||||
#define SMF_CARD_ATTACHED 0x0020 /* card driver(s) attached */
|
|
||||||
#define SMF_STOP_AFTER_MULTIPLE 0x0040 /* send a stop after a multiple cmd */
|
|
||||||
int sc_function_count; /* number of I/O functions (SDIO) */
|
|
||||||
struct sdmmc_function *sc_card; /* selected card */
|
|
||||||
struct sdmmc_function *sc_fn0; /* function 0, the card itself */
|
|
||||||
int sc_dying; /* bus driver is shutting down */
|
|
||||||
struct proc *sc_task_thread; /* asynchronous tasks */
|
|
||||||
struct sdmmc_task sc_discover_task; /* card attach/detach task */
|
|
||||||
struct sdmmc_task sc_intr_task; /* card interrupt task */
|
|
||||||
void *sc_scsibus; /* SCSI bus emulation softc */
|
|
||||||
long sc_max_xfer; /* maximum transfer size */
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Attach devices at the sdmmc bus.
|
|
||||||
*/
|
|
||||||
struct sdmmc_attach_args {
|
|
||||||
struct scsi_link *scsi_link; /* XXX */
|
|
||||||
struct sdmmc_function *sf;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define IPL_SDMMC IPL_BIO
|
|
||||||
|
|
||||||
#define SDMMC_LOCK(sc) lockmgr(&(sc)->sc_lock, LK_EXCLUSIVE, NULL)
|
|
||||||
#define SDMMC_UNLOCK(sc) lockmgr(&(sc)->sc_lock, LK_RELEASE, NULL)
|
|
||||||
#define SDMMC_ASSERT_LOCKED(sc) \
|
|
||||||
KASSERT(lockstatus(&((sc))->sc_lock) == LK_EXCLUSIVE)
|
|
||||||
|
|
||||||
#endif
|
|
92
tiny_ehci_glue.c
Normal file
92
tiny_ehci_glue.c
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
/*
|
||||||
|
EHCI glue. A bit hacky for the moment. needs cleaning..
|
||||||
|
|
||||||
|
Copyright (C) 2008 kwiirk.
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "tiny_ehci_glue.h"
|
||||||
|
|
||||||
|
#define static
|
||||||
|
#define inline extern
|
||||||
|
|
||||||
|
int verbose=0;
|
||||||
|
|
||||||
|
void BUG(void)
|
||||||
|
{
|
||||||
|
dbgprintf("bug\n");
|
||||||
|
while(1);
|
||||||
|
}
|
||||||
|
#define BUG_ON(a) if(a)BUG()
|
||||||
|
|
||||||
|
void msleep(int msec)
|
||||||
|
{
|
||||||
|
udelay(msec*1000);
|
||||||
|
}
|
||||||
|
extern u32 __exe_start_virt__;
|
||||||
|
extern u32 __ram_start_virt__;
|
||||||
|
|
||||||
|
extern u32 ios_thread_stack;
|
||||||
|
|
||||||
|
void print_hex_dump_bytes(char *header,int prefix,u8 *buf,int len)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
if (len>0x100)len=0x100;
|
||||||
|
dbgprintf("%s %08X\n",header,(u32)buf);
|
||||||
|
for (i=0;i<len;i++){
|
||||||
|
dbgprintf("%02x ",buf[i]);
|
||||||
|
if((i&0xf) == 0xf)
|
||||||
|
dbgprintf("\n");
|
||||||
|
}
|
||||||
|
dbgprintf("\n");
|
||||||
|
}
|
||||||
|
#define DUMP_PREFIX_OFFSET 1
|
||||||
|
#include "ehci.h"
|
||||||
|
#define ehci_readl(a) ((*((volatile u32*)(a))))
|
||||||
|
//#define ehci_writel(e,v,a) do{msleep(40);dbgprintf("writel %08X %08X\n",a,v);*((volatile u32*)(a))=(v);}while(0)
|
||||||
|
#define ehci_writel(v,a) do{*((volatile u32*)(a))=(v);}while(0)
|
||||||
|
|
||||||
|
struct ehci_hcd _ehci;
|
||||||
|
struct ehci_hcd *ehci;
|
||||||
|
|
||||||
|
#include "ehci.c"
|
||||||
|
|
||||||
|
int usb_os_init(void);
|
||||||
|
int tiny_ehci_init(void)
|
||||||
|
{
|
||||||
|
int retval;
|
||||||
|
ehci = &_ehci;
|
||||||
|
|
||||||
|
//memset(ehci,0,sizeof(*ehci));
|
||||||
|
if(usb_os_init()<0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
ehci->caps = (void*)0x0D040000;
|
||||||
|
ehci->regs = (void*)(0x0D040000 + HC_LENGTH(ehci_readl(&ehci->caps->hc_capbase)));
|
||||||
|
|
||||||
|
ehci->num_port = 4;
|
||||||
|
/* cache this readonly data; minimize chip reads */
|
||||||
|
ehci->hcs_params = ehci_readl( &ehci->caps->hcs_params );
|
||||||
|
|
||||||
|
/* data structure init */
|
||||||
|
retval = ehci_init();
|
||||||
|
if (retval)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
ehci_release_ports(); //quickly release none usb2 port
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
25
tiny_ehci_glue.h
Normal file
25
tiny_ehci_glue.h
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#ifndef _TEGLUE_
|
||||||
|
#define _TEGLUE_
|
||||||
|
|
||||||
|
#include "string.h"
|
||||||
|
|
||||||
|
#include "ehci_types.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include "vsprintf.h"
|
||||||
|
|
||||||
|
int tiny_ehci_init(void);
|
||||||
|
|
||||||
|
#define readl(a) (*((volatile u32*)(a)))
|
||||||
|
#define writel(v,a) do{*((volatile u32*)(a))=(v);}while(0)
|
||||||
|
#define ehci_dbg(a...) dbgprintf(a)
|
||||||
|
#define printk(a...) dbgprintf(a)
|
||||||
|
#define get_timer() (*(((volatile u32*)0x0D800010)))
|
||||||
|
|
||||||
|
#define cpu_to_le32(a) swab32(a)
|
||||||
|
#define le32_to_cpu(a) swab32(a)
|
||||||
|
#define cpu_to_le16(a) swab16(a)
|
||||||
|
#define le16_to_cpu(a) swab16(a)
|
||||||
|
#define cpu_to_be32(a) (a)
|
||||||
|
#define be32_to_cpu(a) (a)
|
||||||
|
|
||||||
|
#endif
|
244
usb.c
Normal file
244
usb.c
Normal file
@ -0,0 +1,244 @@
|
|||||||
|
/*
|
||||||
|
This file implements libogc usb API, but with ehci direct call
|
||||||
|
|
||||||
|
most of the file credit goes to libogc devs
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define __usb_control_message(fd, b, c,d, e, f, g, h, i) ehci_control_message(fd,b,c,d,e,f,g)
|
||||||
|
|
||||||
|
static s32 __usb_getdesc(struct ehci_device * fd, u8 *buffer, u8 type, u8 index, u8 size)
|
||||||
|
{
|
||||||
|
//printk("usb_get desc %X %X %p\n",type,index,buffer);
|
||||||
|
return __usb_control_message(fd, USB_ENDPOINT_IN ,USB_REQ_GETDESCRIPTOR, (type << 8) | index, 0, size, buffer, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 USB_GetDescriptors(struct ehci_device * fd, usb_devdesc *udd)
|
||||||
|
{
|
||||||
|
u8 *buffer = NULL;
|
||||||
|
u8 *ptr = NULL;
|
||||||
|
usb_configurationdesc *ucd = NULL;
|
||||||
|
usb_interfacedesc *uid = NULL;
|
||||||
|
usb_endpointdesc *ued = NULL;
|
||||||
|
s32 retval = 0;
|
||||||
|
u32 iConf, iInterface, iEndpoint;
|
||||||
|
|
||||||
|
buffer = USB_Alloc(sizeof(*udd));
|
||||||
|
if(buffer == NULL)
|
||||||
|
{
|
||||||
|
retval = -ENOMEM;
|
||||||
|
goto free_and_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
retval = __usb_getdesc(fd, buffer, USB_DT_DEVICE, 0, USB_DT_DEVICE_SIZE);
|
||||||
|
if(retval < 0)
|
||||||
|
{
|
||||||
|
dbgprintf("USB:__usb_getdesc():%d failed\n", retval );
|
||||||
|
goto free_and_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy( udd, buffer, USB_DT_DEVICE_SIZE );
|
||||||
|
USB_Free(buffer);
|
||||||
|
|
||||||
|
u32 *_udd = (u32*)udd;
|
||||||
|
|
||||||
|
_udd[1] = ( udd->bLength << 24 ) | ( udd->bDescriptorType << 16 ) | cpu_to_le16(udd->bcdUSB);
|
||||||
|
_udd[2] = ( cpu_to_le16(udd->idVendor) << 16 ) | cpu_to_le16(udd->idProduct);
|
||||||
|
_udd[3] = ( cpu_to_le16(udd->bcdDevice) << 16 ) | (udd->iManufacturer<<8) | udd->iProduct;
|
||||||
|
|
||||||
|
u32 _ptr = (u32)USB_Alloc( udd->bNumConfigurations * sizeof(*udd->configurations) );
|
||||||
|
|
||||||
|
//udd->configurations = USB_Alloc(udd->bNumConfigurations* sizeof(*udd->configurations));
|
||||||
|
if( _ptr == 0)
|
||||||
|
{
|
||||||
|
dbgprintf("USB:USB_Alloc():failed:%u\n", __LINE__ );
|
||||||
|
retval = -ENOMEM;
|
||||||
|
goto free_and_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
_udd[4] = ( udd->iSerialNumber << 24 ) | ( udd->bNumConfigurations << 16 ) | (_ptr>>16);
|
||||||
|
_udd[5] = ((_ptr & 0xFFFF) << 16) | (_udd[5]&0xFFFF);
|
||||||
|
|
||||||
|
memset( udd->configurations, 0, udd->bNumConfigurations * sizeof(*udd->configurations) );
|
||||||
|
|
||||||
|
for( iConf = 0; iConf < udd->bNumConfigurations; iConf++)
|
||||||
|
{
|
||||||
|
buffer = USB_Alloc( USB_DT_CONFIG_SIZE );
|
||||||
|
if(buffer == NULL)
|
||||||
|
{
|
||||||
|
retval = -ENOMEM;
|
||||||
|
goto free_and_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
retval = __usb_getdesc(fd, buffer, USB_DT_CONFIG, iConf, USB_DT_CONFIG_SIZE);
|
||||||
|
ucd = &udd->configurations[iConf];
|
||||||
|
memcpy( ucd, buffer, USB_DT_CONFIG_SIZE );
|
||||||
|
USB_Free( buffer );
|
||||||
|
|
||||||
|
u32 *_ucd = (u32*)ucd;
|
||||||
|
|
||||||
|
_ucd[0] = ( ucd->bLength << 24 ) | ( ucd->bDescriptorType << 16 ) | cpu_to_le16(ucd->wTotalLength);
|
||||||
|
|
||||||
|
//ucd->wTotalLength = cpu_to_le16(ucd->wTotalLength);
|
||||||
|
|
||||||
|
buffer = USB_Alloc( ucd->wTotalLength);
|
||||||
|
if(buffer == NULL)
|
||||||
|
{
|
||||||
|
retval = -ENOMEM;
|
||||||
|
goto free_and_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
retval = __usb_getdesc(fd, buffer, USB_DT_CONFIG, iConf, ucd->wTotalLength);
|
||||||
|
if(retval < 0)
|
||||||
|
goto free_and_error;
|
||||||
|
|
||||||
|
ptr = buffer;
|
||||||
|
ptr += ucd->bLength;
|
||||||
|
|
||||||
|
retval = -ENOMEM;
|
||||||
|
//ucd->interfaces = USB_Alloc(ucd->bNumInterfaces* sizeof(*ucd->interfaces));
|
||||||
|
//if(ucd->interfaces == NULL)
|
||||||
|
// goto free_and_error;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
u32 _ptrB = (u32)USB_Alloc(ucd->bNumInterfaces* sizeof(*ucd->interfaces));
|
||||||
|
if( _ptrB == 0 )
|
||||||
|
goto free_and_error;
|
||||||
|
|
||||||
|
_ucd[2] = ( ucd->bMaxPower << 24 ) | (_ptrB>>8);
|
||||||
|
_ucd[3] = ((_ptrB & 0xFF) << 24) | (_ucd[3]&0xFFFFFF);
|
||||||
|
|
||||||
|
//dbgprintf("ucd->interfaces:%p\n", ucd->interfaces );
|
||||||
|
memset( ucd->interfaces, 0, ucd->bNumInterfaces * sizeof(*ucd->interfaces) );
|
||||||
|
|
||||||
|
for(iInterface = 0; iInterface < ucd->bNumInterfaces; iInterface++)
|
||||||
|
{
|
||||||
|
uid = &ucd->interfaces[iInterface];
|
||||||
|
memcpy(uid, ptr, USB_DT_INTERFACE_SIZE);
|
||||||
|
ptr += uid->bLength;
|
||||||
|
|
||||||
|
//uid->endpoints = USB_Alloc(uid->bNumEndpoints* sizeof(*uid->endpoints));
|
||||||
|
//if(uid->endpoints == NULL)
|
||||||
|
// goto free_and_error;
|
||||||
|
|
||||||
|
u32 *_uid = (u32*)uid;
|
||||||
|
u32 _ptrC = (u32)USB_Alloc(uid->bNumEndpoints* sizeof(*uid->endpoints));
|
||||||
|
|
||||||
|
_uid[2] = (uid->iInterface<<24) | (_ptrC >> 8);
|
||||||
|
_uid[3] = (_ptrC<<24) | (_uid[3]&0xFFFFFF);
|
||||||
|
|
||||||
|
memset( uid->endpoints, 0, uid->bNumEndpoints * sizeof(*uid->endpoints) );
|
||||||
|
|
||||||
|
for( iEndpoint = 0; iEndpoint < uid->bNumEndpoints; iEndpoint++)
|
||||||
|
{
|
||||||
|
ued = &uid->endpoints[iEndpoint];
|
||||||
|
memcpy( ued, ptr, USB_DT_ENDPOINT_SIZE );
|
||||||
|
ptr += ued->bLength;
|
||||||
|
|
||||||
|
//ued->wMaxPacketSize = cpu_to_le16(ued->wMaxPacketSize);
|
||||||
|
u32 *_ued = (u32*)ued;
|
||||||
|
_ued[1] = (cpu_to_le16(ued->wMaxPacketSize) << 16 ) | (_ued[1] & 0xFFFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
USB_Free((void*)_ptrC);
|
||||||
|
}
|
||||||
|
|
||||||
|
USB_Free((void*)_ptrB);
|
||||||
|
|
||||||
|
USB_Free( buffer);
|
||||||
|
buffer = (u8*)NULL;
|
||||||
|
}
|
||||||
|
retval = 0;
|
||||||
|
|
||||||
|
free_and_error:
|
||||||
|
if( _ptr != 0 )
|
||||||
|
USB_Free((void*)_ptr);
|
||||||
|
|
||||||
|
if(buffer != NULL)
|
||||||
|
USB_Free(buffer);
|
||||||
|
|
||||||
|
if(retval < 0)
|
||||||
|
USB_FreeDescriptors(udd);
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
void USB_FreeDescriptors(usb_devdesc *udd)
|
||||||
|
{
|
||||||
|
int iConf, iInterface;
|
||||||
|
usb_configurationdesc *ucd;
|
||||||
|
usb_interfacedesc *uid;
|
||||||
|
if(udd->configurations != NULL)
|
||||||
|
{
|
||||||
|
for(iConf = 0; iConf < udd->bNumConfigurations; iConf++)
|
||||||
|
{
|
||||||
|
ucd = &udd->configurations[iConf];
|
||||||
|
if(ucd->interfaces != NULL)
|
||||||
|
{
|
||||||
|
for(iInterface = 0; iInterface < ucd->bNumInterfaces; iInterface++)
|
||||||
|
{
|
||||||
|
uid = &ucd->interfaces[iInterface];
|
||||||
|
if(uid->endpoints != NULL)
|
||||||
|
USB_Free(uid->endpoints);
|
||||||
|
}
|
||||||
|
USB_Free(ucd->interfaces);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
USB_Free(udd->configurations);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void USB_SuspendDevice(struct ehci_device *fd)
|
||||||
|
{
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
void USB_ResumeDevice(struct ehci_device *fd)
|
||||||
|
{
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
s32 USB_WriteBlkMsg(struct ehci_device *fd,u8 bEndpoint,u16 wLength,void *rpData)
|
||||||
|
{
|
||||||
|
return ehci_bulk_message(fd,bEndpoint,wLength,rpData);
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 USB_WriteCtrlMsg(struct ehci_device *fd,u8 bmRequestType,u8 bmRequest,u16 wValue,u16 wIndex,u16 wLength,void *rpData)
|
||||||
|
{
|
||||||
|
return __usb_control_message(fd,bmRequestType,bmRequest,wValue,wIndex,wLength,rpData,NULL,NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 USB_GetConfiguration(struct ehci_device *fd, u8 *configuration)
|
||||||
|
{
|
||||||
|
u8 *_configuration;
|
||||||
|
s32 retval;
|
||||||
|
|
||||||
|
_configuration = USB_Alloc(1);
|
||||||
|
if(_configuration == NULL)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
retval = __usb_control_message(fd, (USB_CTRLTYPE_DIR_DEVICE2HOST | USB_CTRLTYPE_TYPE_STANDARD | USB_CTRLTYPE_REC_DEVICE), USB_REQ_GETCONFIG, 0, 0, 1, _configuration, NULL, NULL);
|
||||||
|
if(retval >= 0)
|
||||||
|
*configuration = *_configuration;
|
||||||
|
USB_Free( _configuration);
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
s32 USB_SetConfiguration(struct ehci_device *fd, u8 configuration)
|
||||||
|
{
|
||||||
|
return __usb_control_message(fd, (USB_CTRLTYPE_DIR_HOST2DEVICE | USB_CTRLTYPE_TYPE_STANDARD | USB_CTRLTYPE_REC_DEVICE), USB_REQ_SETCONFIG, configuration, 0, 0, NULL, NULL, NULL);
|
||||||
|
}
|
||||||
|
s32 USB_SetAlternativeInterface(struct ehci_device *fd, u8 interface, u8 alternateSetting)
|
||||||
|
{
|
||||||
|
if(alternateSetting == 0)
|
||||||
|
return -EINVAL;
|
||||||
|
return __usb_control_message(fd, (USB_CTRLTYPE_DIR_HOST2DEVICE | USB_CTRLTYPE_TYPE_STANDARD | USB_CTRLTYPE_REC_INTERFACE),
|
||||||
|
USB_REQ_SETINTERFACE, alternateSetting, interface, 0, NULL, NULL, NULL);
|
||||||
|
|
||||||
|
}
|
||||||
|
s32 USB_ClearHalt(struct ehci_device *fd, u8 endpoint)
|
||||||
|
{
|
||||||
|
return __usb_control_message(fd, (USB_CTRLTYPE_DIR_HOST2DEVICE | USB_CTRLTYPE_TYPE_STANDARD | USB_CTRLTYPE_REC_ENDPOINT),
|
||||||
|
USB_REQ_CLEARFEATURE, USB_FEATURE_ENDPOINT_HALT, endpoint, 0, NULL, NULL, NULL);
|
||||||
|
}
|
176
usb.h
Normal file
176
usb.h
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
#ifndef __USB_H__
|
||||||
|
#define __USB_H__
|
||||||
|
|
||||||
|
|
||||||
|
#define USB_MAXPATH IPC_MAXPATH_LEN
|
||||||
|
|
||||||
|
#define USB_OK 0
|
||||||
|
#define USB_FAILED 1
|
||||||
|
|
||||||
|
/* Descriptor types */
|
||||||
|
#define USB_DT_DEVICE 0x01
|
||||||
|
#define USB_DT_CONFIG 0x02
|
||||||
|
#define USB_DT_STRING 0x03
|
||||||
|
#define USB_DT_INTERFACE 0x04
|
||||||
|
#define USB_DT_ENDPOINT 0x05
|
||||||
|
|
||||||
|
/* Standard requests */
|
||||||
|
#define USB_REQ_GETSTATUS 0x00
|
||||||
|
#define USB_REQ_CLEARFEATURE 0x01
|
||||||
|
#define USB_REQ_SETFEATURE 0x03
|
||||||
|
#define USB_REQ_SETADDRESS 0x05
|
||||||
|
#define USB_REQ_GETDESCRIPTOR 0x06
|
||||||
|
#define USB_REQ_SETDESCRIPTOR 0x07
|
||||||
|
#define USB_REQ_GETCONFIG 0x08
|
||||||
|
#define USB_REQ_SETCONFIG 0x09
|
||||||
|
#define USB_REQ_GETINTERFACE 0x0a
|
||||||
|
#define USB_REQ_SETINTERFACE 0x0b
|
||||||
|
#define USB_REQ_SYNCFRAME 0x0c
|
||||||
|
|
||||||
|
/* Descriptor sizes per descriptor type */
|
||||||
|
#define USB_DT_DEVICE_SIZE 18
|
||||||
|
#define USB_DT_CONFIG_SIZE 9
|
||||||
|
#define USB_DT_INTERFACE_SIZE 9
|
||||||
|
#define USB_DT_ENDPOINT_SIZE 7
|
||||||
|
#define USB_DT_ENDPOINT_AUDIO_SIZE 9 /* Audio extension */
|
||||||
|
#define USB_DT_HUB_NONVAR_SIZE 7
|
||||||
|
|
||||||
|
/* control message request type bitmask */
|
||||||
|
#define USB_CTRLTYPE_DIR_HOST2DEVICE (0<<7)
|
||||||
|
#define USB_CTRLTYPE_DIR_DEVICE2HOST (1<<7)
|
||||||
|
#define USB_CTRLTYPE_TYPE_STANDARD (0<<5)
|
||||||
|
#define USB_CTRLTYPE_TYPE_CLASS (1<<5)
|
||||||
|
#define USB_CTRLTYPE_TYPE_VENDOR (2<<5)
|
||||||
|
#define USB_CTRLTYPE_TYPE_RESERVED (3<<5)
|
||||||
|
#define USB_CTRLTYPE_REC_DEVICE 0
|
||||||
|
#define USB_CTRLTYPE_REC_INTERFACE 1
|
||||||
|
#define USB_CTRLTYPE_REC_ENDPOINT 2
|
||||||
|
#define USB_CTRLTYPE_REC_OTHER 3
|
||||||
|
|
||||||
|
#define USB_FEATURE_ENDPOINT_HALT 0
|
||||||
|
|
||||||
|
#define USB_ENDPOINT_IN 0x80
|
||||||
|
#define USB_ENDPOINT_OUT 0x00
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
# define ATTRIBUTE_PACKED __attribute__((packed))
|
||||||
|
|
||||||
|
typedef struct _usbctrlrequest {
|
||||||
|
u8 bRequestType;
|
||||||
|
u8 bRequest;
|
||||||
|
u16 wValue;
|
||||||
|
|
||||||
|
u16 wIndex;
|
||||||
|
u16 wLength;
|
||||||
|
} ATTRIBUTE_PACKED usbctrlrequest;
|
||||||
|
|
||||||
|
typedef struct _usbendpointdesc
|
||||||
|
{
|
||||||
|
u8 bLength;
|
||||||
|
u8 bDescriptorType;
|
||||||
|
u8 bEndpointAddress;
|
||||||
|
u8 bmAttributes;
|
||||||
|
|
||||||
|
u16 wMaxPacketSize;
|
||||||
|
u8 bInterval;
|
||||||
|
u8 pad;
|
||||||
|
} ATTRIBUTE_PACKED usb_endpointdesc;
|
||||||
|
|
||||||
|
typedef struct _usbinterfacedesc
|
||||||
|
{
|
||||||
|
u8 bLength;
|
||||||
|
u8 bDescriptorType;
|
||||||
|
u8 bInterfaceNumber;
|
||||||
|
u8 bAlternateSetting;
|
||||||
|
|
||||||
|
u8 bNumEndpoints;
|
||||||
|
u8 bInterfaceClass;
|
||||||
|
u8 bInterfaceSubClass;
|
||||||
|
u8 bInterfaceProtocol;
|
||||||
|
|
||||||
|
u8 iInterface;
|
||||||
|
struct _usbendpointdesc *endpoints;
|
||||||
|
} ATTRIBUTE_PACKED usb_interfacedesc;
|
||||||
|
|
||||||
|
typedef struct _usbconfdesc
|
||||||
|
{
|
||||||
|
u8 bLength;
|
||||||
|
u8 bDescriptorType;
|
||||||
|
u16 wTotalLength;
|
||||||
|
|
||||||
|
u8 bNumInterfaces;
|
||||||
|
u8 bConfigurationValue;
|
||||||
|
u8 iConfiguration;
|
||||||
|
u8 bmAttributes;
|
||||||
|
|
||||||
|
u8 bMaxPower;
|
||||||
|
struct _usbinterfacedesc *interfaces;
|
||||||
|
} ATTRIBUTE_PACKED usb_configurationdesc;
|
||||||
|
|
||||||
|
typedef struct _usbdevdesc
|
||||||
|
{
|
||||||
|
u8 bLength;
|
||||||
|
u8 bDescriptorType;
|
||||||
|
u16 bcdUSB;
|
||||||
|
|
||||||
|
u8 bDeviceClass;
|
||||||
|
u8 bDeviceSubClass;
|
||||||
|
u8 bDeviceProtocol;
|
||||||
|
u8 bMaxPacketSize0;
|
||||||
|
|
||||||
|
u16 idVendor;
|
||||||
|
u16 idProduct;
|
||||||
|
|
||||||
|
u16 bcdDevice;
|
||||||
|
u8 iManufacturer;
|
||||||
|
u8 iProduct;
|
||||||
|
|
||||||
|
u8 iSerialNumber;
|
||||||
|
u8 bNumConfigurations;
|
||||||
|
struct _usbconfdesc *configurations;
|
||||||
|
} ATTRIBUTE_PACKED usb_devdesc;
|
||||||
|
|
||||||
|
struct ehci_device;
|
||||||
|
|
||||||
|
s32 USB_OpenDevice(const char *device,u16 vid,u16 pid,struct ehci_device **fd);
|
||||||
|
s32 USB_CloseDevice(struct ehci_device **fd);
|
||||||
|
|
||||||
|
s32 USB_GetDescriptors(struct ehci_device *fd, usb_devdesc *udd);
|
||||||
|
void USB_FreeDescriptors(usb_devdesc *udd);
|
||||||
|
|
||||||
|
s32 USB_GetDeviceDescription(struct ehci_device *fd,usb_devdesc *devdesc);
|
||||||
|
|
||||||
|
void USB_SuspendDevice(struct ehci_device *fd);
|
||||||
|
void USB_ResumeDevice(struct ehci_device *fd);
|
||||||
|
|
||||||
|
s32 USB_ReadIntrMsg(struct ehci_device *fd,u8 bEndpoint,u16 wLength,void *rpData);
|
||||||
|
|
||||||
|
s32 USB_ReadBlkMsg(struct ehci_device *fd,u8 bEndpoint,u16 wLength,void *rpData);
|
||||||
|
|
||||||
|
s32 USB_ReadCtrlMsg(struct ehci_device *fd,u8 bmRequestType,u8 bmRequest,u16 wValue,u16 wIndex,u16 wLength,void *rpData);
|
||||||
|
|
||||||
|
s32 USB_WriteIntrMsg(struct ehci_device *fd,u8 bEndpoint,u16 wLength,void *rpData);
|
||||||
|
|
||||||
|
s32 USB_WriteBlkMsg(struct ehci_device *fd,u8 bEndpoint,u16 wLength,void *rpData);
|
||||||
|
|
||||||
|
s32 USB_WriteCtrlMsg(struct ehci_device *fd,u8 bmRequestType,u8 bmRequest,u16 wValue,u16 wIndex,u16 wLength,void *rpData);
|
||||||
|
|
||||||
|
s32 USB_GetConfiguration(struct ehci_device *fd, u8 *configuration);
|
||||||
|
s32 USB_SetConfiguration(struct ehci_device *fd, u8 configuration);
|
||||||
|
s32 USB_SetAlternativeInterface(struct ehci_device *fd, u8 interface, u8 alternateSetting);
|
||||||
|
s32 USB_ClearHalt(struct ehci_device *fd, u8 endpointAddress);
|
||||||
|
s32 USB_GetDeviceList(const char *devpath,void *descr_buffer,u8 num_descr,u8 b0,u8 *cnt_descr);
|
||||||
|
|
||||||
|
/* alloc memory from the USB subsystem */
|
||||||
|
void * USB_Alloc(int size);
|
||||||
|
void USB_Free(void *ptr);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
78
usb_os.c
Normal file
78
usb_os.c
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
#include <string.h>
|
||||||
|
#include "ehci_types.h"
|
||||||
|
#include "usb.h"
|
||||||
|
#include "ehci.h"
|
||||||
|
#include "alloc.h"
|
||||||
|
|
||||||
|
void *VirtualToPhysical( void *address )
|
||||||
|
{
|
||||||
|
if( ((u32)address & 0xFFFF0000) == 0xFFFF0000 )
|
||||||
|
return (void*)address;
|
||||||
|
|
||||||
|
return (void*)((u32)address & 0x7FFFFFFF);
|
||||||
|
}
|
||||||
|
void sync_after_write( void *a, u32 v )
|
||||||
|
{
|
||||||
|
dc_flushrange( a, v );
|
||||||
|
}
|
||||||
|
void sync_before_read( void *a, u32 v )
|
||||||
|
{
|
||||||
|
dc_invalidaterange( a, v );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int usb_os_init(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
void *ehci_maligned(int size,int alignement,int crossing)
|
||||||
|
{
|
||||||
|
return (void*)malloca( size, alignement );
|
||||||
|
}
|
||||||
|
dma_addr_t ehci_virt_to_dma(void *a)
|
||||||
|
{
|
||||||
|
return (dma_addr_t)VirtualToPhysical(a);
|
||||||
|
}
|
||||||
|
dma_addr_t ehci_dma_map_to(void *buf,size_t len)
|
||||||
|
{
|
||||||
|
sync_after_write(buf, len);
|
||||||
|
return (dma_addr_t)VirtualToPhysical(buf);
|
||||||
|
}
|
||||||
|
dma_addr_t ehci_dma_map_from(void *buf,size_t len)
|
||||||
|
{
|
||||||
|
sync_after_write(buf, len);
|
||||||
|
return (dma_addr_t)VirtualToPhysical(buf);
|
||||||
|
}
|
||||||
|
dma_addr_t ehci_dma_map_bidir(void *buf,size_t len)
|
||||||
|
{
|
||||||
|
sync_after_write(buf, len);
|
||||||
|
return (dma_addr_t)VirtualToPhysical(buf);
|
||||||
|
}
|
||||||
|
void ehci_dma_unmap_to(dma_addr_t buf,size_t len)
|
||||||
|
{
|
||||||
|
sync_before_read((void*)buf, len);
|
||||||
|
}
|
||||||
|
void ehci_dma_unmap_from(dma_addr_t buf,size_t len)
|
||||||
|
{
|
||||||
|
sync_before_read((void*)buf, len);
|
||||||
|
}
|
||||||
|
void ehci_dma_unmap_bidir(dma_addr_t buf,size_t len)
|
||||||
|
{
|
||||||
|
sync_before_read((void*)buf, len);
|
||||||
|
}
|
||||||
|
void *USB_Alloc(int size)
|
||||||
|
{
|
||||||
|
//u32 val;
|
||||||
|
//__asm("mov %0,lr": "=r" (val) );
|
||||||
|
//dbgprintf("USB_Alloc(%u) LR:%08x\n", size, val );
|
||||||
|
|
||||||
|
//void *ptr = malloc(size);
|
||||||
|
//memset( ptr, 0, size );
|
||||||
|
//return ptr;
|
||||||
|
|
||||||
|
return malloc(size);
|
||||||
|
}
|
||||||
|
void USB_Free(void *ptr)
|
||||||
|
{
|
||||||
|
return free(ptr);
|
||||||
|
}
|
755
usbstorage.c
Normal file
755
usbstorage.c
Normal file
@ -0,0 +1,755 @@
|
|||||||
|
/*-------------------------------------------------------------
|
||||||
|
|
||||||
|
usbstorage.c -- Bulk-only USB mass storage support
|
||||||
|
|
||||||
|
Copyright (C) 2008
|
||||||
|
Sven Peter (svpe) <svpe@gmx.net>
|
||||||
|
|
||||||
|
quick port to ehci/ios: Kwiirk
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any
|
||||||
|
damages arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any
|
||||||
|
purpose, including commercial applications, and to alter it and
|
||||||
|
redistribute it freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you
|
||||||
|
must not claim that you wrote the original software. If you use
|
||||||
|
this software in a product, an acknowledgment in the product
|
||||||
|
documentation would be appreciated but is not required.
|
||||||
|
|
||||||
|
2. Altered source versions must be plainly marked as such, and
|
||||||
|
must not be misrepresented as being the original software.
|
||||||
|
|
||||||
|
3. This notice may not be removed or altered from any source
|
||||||
|
distribution.
|
||||||
|
|
||||||
|
-------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#define ROUNDDOWN32(v) (((u32)(v)-0x1f)&~0x1f)
|
||||||
|
|
||||||
|
#define HEAP_SIZE (32*1024)
|
||||||
|
#define TAG_START 0x1//BADC0DE
|
||||||
|
|
||||||
|
#define CBW_SIZE 31
|
||||||
|
#define CBW_SIGNATURE 0x43425355
|
||||||
|
#define CBW_IN (1 << 7)
|
||||||
|
#define CBW_OUT 0
|
||||||
|
|
||||||
|
#define CSW_SIZE 13
|
||||||
|
#define CSW_SIGNATURE 0x53425355
|
||||||
|
|
||||||
|
#define SCSI_TEST_UNIT_READY 0x00
|
||||||
|
#define SCSI_INQUIRY 0x12
|
||||||
|
#define SCSI_REQUEST_SENSE 0x03
|
||||||
|
#define SCSI_READ_CAPACITY 0x25
|
||||||
|
#define SCSI_READ_10 0x28
|
||||||
|
#define SCSI_WRITE_10 0x2A
|
||||||
|
|
||||||
|
#define SCSI_SENSE_REPLY_SIZE 18
|
||||||
|
#define SCSI_SENSE_NOT_READY 0x02
|
||||||
|
#define SCSI_SENSE_MEDIUM_ERROR 0x03
|
||||||
|
#define SCSI_SENSE_HARDWARE_ERROR 0x04
|
||||||
|
|
||||||
|
#define USB_CLASS_MASS_STORAGE 0x08
|
||||||
|
#define MASS_STORAGE_SCSI_COMMANDS 0x06
|
||||||
|
#define MASS_STORAGE_BULK_ONLY 0x50
|
||||||
|
|
||||||
|
#define USBSTORAGE_GET_MAX_LUN 0xFE
|
||||||
|
#define USBSTORAGE_RESET 0xFF
|
||||||
|
|
||||||
|
#define USB_ENDPOINT_BULK 0x02
|
||||||
|
|
||||||
|
#define USBSTORAGE_CYCLE_RETRIES 3
|
||||||
|
|
||||||
|
#define MAX_TRANSFER_SIZE 4096
|
||||||
|
|
||||||
|
#define DEVLIST_MAXSIZE 8
|
||||||
|
|
||||||
|
static s32 __usbstorage_reset(usbstorage_handle *dev);
|
||||||
|
static s32 __usbstorage_clearerrors(usbstorage_handle *dev, u8 lun);
|
||||||
|
|
||||||
|
// ehci driver has its own timeout.
|
||||||
|
static s32 __USB_BlkMsgTimeout(usbstorage_handle *dev, u8 bEndpoint, u16 wLength, void *rpData)
|
||||||
|
{
|
||||||
|
return USB_WriteBlkMsg(dev->usb_fd, bEndpoint, wLength, rpData);
|
||||||
|
}
|
||||||
|
|
||||||
|
static s32 __USB_CtrlMsgTimeout(usbstorage_handle *dev, u8 bmRequestType, u8 bmRequest, u16 wValue, u16 wIndex, u16 wLength, void *rpData)
|
||||||
|
{
|
||||||
|
return USB_WriteCtrlMsg(dev->usb_fd, bmRequestType, bmRequest, wValue, wIndex, wLength, rpData);
|
||||||
|
}
|
||||||
|
static s32 __send_cbw(usbstorage_handle *dev, u8 lun, u32 len, u8 flags, const u8 *cb, u8 cbLen)
|
||||||
|
{
|
||||||
|
s32 retval = USBSTORAGE_OK;
|
||||||
|
|
||||||
|
if(cbLen == 0 || cbLen > 16)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
memset(dev->buffer, 0, CBW_SIZE);
|
||||||
|
|
||||||
|
((u32*)dev->buffer)[0]=cpu_to_le32(CBW_SIGNATURE);
|
||||||
|
((u32*)dev->buffer)[1]=cpu_to_le32(dev->tag);
|
||||||
|
((u32*)dev->buffer)[2]=cpu_to_le32(len);
|
||||||
|
dev->buffer[12] = flags;
|
||||||
|
dev->buffer[13] = lun;
|
||||||
|
dev->buffer[14] = (cbLen > 6 ? 0x10 : 6);
|
||||||
|
|
||||||
|
memcpy(dev->buffer + 15, (void*)cb, cbLen);
|
||||||
|
|
||||||
|
retval = __USB_BlkMsgTimeout(dev, dev->ep_out, CBW_SIZE, (void *)dev->buffer);
|
||||||
|
|
||||||
|
if(retval == CBW_SIZE) return USBSTORAGE_OK;
|
||||||
|
else if(retval >= 0) return USBSTORAGE_ESHORTWRITE;
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
static s32 __read_csw(usbstorage_handle *dev, u8 *status, u32 *dataResidue)
|
||||||
|
{
|
||||||
|
s32 retval = USBSTORAGE_OK;
|
||||||
|
u32 signature, tag, _dataResidue, _status;
|
||||||
|
|
||||||
|
memset(dev->buffer, 0xff, CSW_SIZE);
|
||||||
|
|
||||||
|
retval = __USB_BlkMsgTimeout(dev, dev->ep_in, CSW_SIZE, dev->buffer);
|
||||||
|
//print_hex_dump_bytes("csv resp:",DUMP_PREFIX_OFFSET,dev->buffer,CSW_SIZE);
|
||||||
|
|
||||||
|
if(retval >= 0 && retval != CSW_SIZE) return USBSTORAGE_ESHORTREAD;
|
||||||
|
else if(retval < 0) return retval;
|
||||||
|
|
||||||
|
signature = le32_to_cpu(((u32*)dev->buffer)[0]);
|
||||||
|
tag = le32_to_cpu(((u32*)dev->buffer)[1]);
|
||||||
|
_dataResidue = le32_to_cpu(((u32*)dev->buffer)[2]);
|
||||||
|
_status = dev->buffer[12];
|
||||||
|
|
||||||
|
if(signature != CSW_SIGNATURE) {
|
||||||
|
BUG();
|
||||||
|
return USBSTORAGE_ESIGNATURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(dataResidue != NULL)
|
||||||
|
*dataResidue = _dataResidue;
|
||||||
|
if(status != NULL)
|
||||||
|
*status = _status;
|
||||||
|
|
||||||
|
if(tag != dev->tag) return USBSTORAGE_ETAG;
|
||||||
|
dev->tag++;
|
||||||
|
|
||||||
|
return USBSTORAGE_OK;
|
||||||
|
}
|
||||||
|
static s32 __cycle(usbstorage_handle *dev, u8 lun, u8 *buffer, u32 len, u8 *cb, u8 cbLen, u8 write, u8 *_status, u32 *_dataResidue)
|
||||||
|
{
|
||||||
|
s32 retval = USBSTORAGE_OK;
|
||||||
|
|
||||||
|
u8 status = 0;
|
||||||
|
u32 dataResidue = 0;
|
||||||
|
u32 thisLen;
|
||||||
|
|
||||||
|
s8 retries = USBSTORAGE_CYCLE_RETRIES + 1;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
retries--;
|
||||||
|
if(retval == USBSTORAGE_ETIMEDOUT)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if(write)
|
||||||
|
{
|
||||||
|
retval = __send_cbw(dev, lun, len, CBW_OUT, cb, cbLen);
|
||||||
|
if(retval == USBSTORAGE_ETIMEDOUT)
|
||||||
|
break;
|
||||||
|
if(retval < 0)
|
||||||
|
{
|
||||||
|
if(__usbstorage_reset(dev) == USBSTORAGE_ETIMEDOUT)
|
||||||
|
retval = USBSTORAGE_ETIMEDOUT;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
while(len > 0)
|
||||||
|
{
|
||||||
|
thisLen=len;
|
||||||
|
retval = __USB_BlkMsgTimeout(dev, dev->ep_out, thisLen, buffer);
|
||||||
|
|
||||||
|
if(retval == USBSTORAGE_ETIMEDOUT)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if(retval < 0)
|
||||||
|
{
|
||||||
|
retval = USBSTORAGE_EDATARESIDUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if(retval != thisLen && len > 0)
|
||||||
|
{
|
||||||
|
retval = USBSTORAGE_EDATARESIDUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
len -= retval;
|
||||||
|
buffer += retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(retval < 0)
|
||||||
|
{
|
||||||
|
if(__usbstorage_reset(dev) == USBSTORAGE_ETIMEDOUT)
|
||||||
|
retval = USBSTORAGE_ETIMEDOUT;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
retval = __send_cbw(dev, lun, len, CBW_IN, cb, cbLen);
|
||||||
|
|
||||||
|
if(retval == USBSTORAGE_ETIMEDOUT)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if(retval < 0)
|
||||||
|
{
|
||||||
|
if(__usbstorage_reset(dev) == USBSTORAGE_ETIMEDOUT)
|
||||||
|
retval = USBSTORAGE_ETIMEDOUT;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
while(len > 0)
|
||||||
|
{
|
||||||
|
thisLen=len;
|
||||||
|
retval = __USB_BlkMsgTimeout(dev, dev->ep_in, thisLen, buffer);
|
||||||
|
//print_hex_dump_bytes("usbs in:",DUMP_PREFIX_OFFSET,dev->buffer,36);
|
||||||
|
if(retval < 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
len -= retval;
|
||||||
|
buffer += retval;
|
||||||
|
|
||||||
|
if(retval != thisLen)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(retval < 0)
|
||||||
|
{
|
||||||
|
if(__usbstorage_reset(dev) == USBSTORAGE_ETIMEDOUT)
|
||||||
|
retval = USBSTORAGE_ETIMEDOUT;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
retval = __read_csw(dev, &status, &dataResidue);
|
||||||
|
|
||||||
|
if(retval == USBSTORAGE_ETIMEDOUT)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if(retval < 0)
|
||||||
|
{
|
||||||
|
if(__usbstorage_reset(dev) == USBSTORAGE_ETIMEDOUT)
|
||||||
|
retval = USBSTORAGE_ETIMEDOUT;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
retval = USBSTORAGE_OK;
|
||||||
|
} while(retval < 0 && retries > 0);
|
||||||
|
|
||||||
|
if(retval < 0 && retval != USBSTORAGE_ETIMEDOUT)
|
||||||
|
{
|
||||||
|
if(__usbstorage_reset(dev) == USBSTORAGE_ETIMEDOUT)
|
||||||
|
retval = USBSTORAGE_ETIMEDOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if(_status != NULL)
|
||||||
|
*_status = status;
|
||||||
|
if(_dataResidue != NULL)
|
||||||
|
*_dataResidue = dataResidue;
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
static s32 __usbstorage_clearerrors(usbstorage_handle *dev, u8 lun)
|
||||||
|
{
|
||||||
|
s32 retval;
|
||||||
|
u8 cmd[16];
|
||||||
|
u8 *sense= USB_Alloc(SCSI_SENSE_REPLY_SIZE);
|
||||||
|
u8 status = 0;
|
||||||
|
memset(cmd, 0, sizeof(cmd));
|
||||||
|
cmd[0] = SCSI_TEST_UNIT_READY;
|
||||||
|
|
||||||
|
retval = __cycle(dev, lun, NULL, 0, cmd, 1, 1, &status, NULL);
|
||||||
|
if(retval < 0) return retval;
|
||||||
|
|
||||||
|
if(status != 0)
|
||||||
|
{
|
||||||
|
cmd[0] = SCSI_REQUEST_SENSE;
|
||||||
|
cmd[1] = lun << 5;
|
||||||
|
cmd[4] = SCSI_SENSE_REPLY_SIZE;
|
||||||
|
cmd[5] = 0;
|
||||||
|
memset(sense, 0, SCSI_SENSE_REPLY_SIZE);
|
||||||
|
retval = __cycle(dev, lun, sense, SCSI_SENSE_REPLY_SIZE, cmd, 6, 0, NULL, NULL);
|
||||||
|
if(retval < 0) goto error;
|
||||||
|
|
||||||
|
status = sense[2] & 0x0F;
|
||||||
|
if(status == SCSI_SENSE_NOT_READY || status == SCSI_SENSE_MEDIUM_ERROR || status == SCSI_SENSE_HARDWARE_ERROR)
|
||||||
|
retval = USBSTORAGE_ESENSE;
|
||||||
|
}
|
||||||
|
error:
|
||||||
|
USB_Free(sense);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
static s32 __usbstorage_reset(usbstorage_handle *dev)
|
||||||
|
{
|
||||||
|
s32 retval;
|
||||||
|
|
||||||
|
if(dev->suspended == 1)
|
||||||
|
{
|
||||||
|
USB_ResumeDevice(dev->usb_fd);
|
||||||
|
dev->suspended = 0;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
retval = ehci_reset_device(dev->usb_fd);
|
||||||
|
if(retval < 0 && retval != -7004)
|
||||||
|
goto end;
|
||||||
|
*/
|
||||||
|
//debug_printf("usbstorage reset..\n");
|
||||||
|
retval = __USB_CtrlMsgTimeout(dev, (USB_CTRLTYPE_DIR_HOST2DEVICE | USB_CTRLTYPE_TYPE_CLASS | USB_CTRLTYPE_REC_INTERFACE), USBSTORAGE_RESET, 0, dev->interface, 0, NULL);
|
||||||
|
|
||||||
|
/* FIXME?: some devices return -7004 here which definitely violates the usb ms protocol but they still seem to be working... */
|
||||||
|
if(retval < 0 && retval != -7004)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
/* gives device enough time to process the reset */
|
||||||
|
msleep(10);
|
||||||
|
|
||||||
|
//debug_printf("cleat halt on bulk ep..\n");
|
||||||
|
retval = USB_ClearHalt(dev->usb_fd, dev->ep_in);
|
||||||
|
if(retval < 0)
|
||||||
|
goto end;
|
||||||
|
retval = USB_ClearHalt(dev->usb_fd, dev->ep_out);
|
||||||
|
|
||||||
|
end:
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 USBStorage_Open(usbstorage_handle *dev, struct ehci_device *fd)
|
||||||
|
{
|
||||||
|
s32 retval = -1;
|
||||||
|
u8 conf,*max_lun = NULL;
|
||||||
|
u32 iConf, iInterface, iEp;
|
||||||
|
usb_devdesc udd;
|
||||||
|
usb_configurationdesc *ucd;
|
||||||
|
usb_interfacedesc *uid;
|
||||||
|
usb_endpointdesc *ued;
|
||||||
|
|
||||||
|
max_lun = USB_Alloc(1);
|
||||||
|
if(max_lun==NULL) return -ENOMEM;
|
||||||
|
|
||||||
|
memset(dev, 0, sizeof(*dev));
|
||||||
|
|
||||||
|
dev->tag = TAG_START;
|
||||||
|
dev->usb_fd = fd;
|
||||||
|
|
||||||
|
retval = USB_GetDescriptors(dev->usb_fd, &udd);
|
||||||
|
if(retval < 0)
|
||||||
|
{
|
||||||
|
dbgprintf("USB_GetDescriptors():%d\n", retval );
|
||||||
|
goto free_and_return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dbgprintf("udd.bNumConfigurations:%u\n", udd.bNumConfigurations );
|
||||||
|
|
||||||
|
for(iConf = 0; iConf < udd.bNumConfigurations; iConf++)
|
||||||
|
{
|
||||||
|
ucd = &udd.configurations[iConf];
|
||||||
|
for(iInterface = 0; iInterface < ucd->bNumInterfaces; iInterface++)
|
||||||
|
{
|
||||||
|
uid = &ucd->interfaces[iInterface];
|
||||||
|
if(uid->bInterfaceClass == USB_CLASS_MASS_STORAGE &&
|
||||||
|
uid->bInterfaceSubClass == MASS_STORAGE_SCSI_COMMANDS &&
|
||||||
|
uid->bInterfaceProtocol == MASS_STORAGE_BULK_ONLY)
|
||||||
|
{
|
||||||
|
if(uid->bNumEndpoints < 2)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
dev->ep_in = dev->ep_out = 0;
|
||||||
|
for(iEp = 0; iEp < uid->bNumEndpoints; iEp++)
|
||||||
|
{
|
||||||
|
ued = &uid->endpoints[iEp];
|
||||||
|
if(ued->bmAttributes != USB_ENDPOINT_BULK)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if(ued->bEndpointAddress & USB_ENDPOINT_IN)
|
||||||
|
{
|
||||||
|
dev->ep_in = ued->bEndpointAddress;
|
||||||
|
dbgprintf("%08X:%08X\n", dev->ep_in, ued->bEndpointAddress );
|
||||||
|
} else {
|
||||||
|
dev->ep_out = ued->bEndpointAddress;
|
||||||
|
dbgprintf("%08X:%08X\n", dev->ep_out, ued->bEndpointAddress );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(dev->ep_in != 0 && dev->ep_out != 0)
|
||||||
|
{
|
||||||
|
dev->configuration = ucd->bConfigurationValue;
|
||||||
|
dev->interface = uid->bInterfaceNumber;
|
||||||
|
dev->altInterface = uid->bAlternateSetting;
|
||||||
|
|
||||||
|
dbgprintf("%08X:%08X\n", dev->configuration , ucd->bConfigurationValue );
|
||||||
|
dbgprintf("%08X:%08X\n", dev->interface , uid->bInterfaceNumber );
|
||||||
|
dbgprintf("%08X:%08X\n", dev->altInterface , uid->bAlternateSetting );
|
||||||
|
|
||||||
|
goto found;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
USB_FreeDescriptors(&udd);
|
||||||
|
retval = USBSTORAGE_ENOINTERFACE;
|
||||||
|
goto free_and_return;
|
||||||
|
|
||||||
|
found:
|
||||||
|
USB_FreeDescriptors(&udd);
|
||||||
|
|
||||||
|
retval = USBSTORAGE_EINIT;
|
||||||
|
if(USB_GetConfiguration(dev->usb_fd, &conf) < 0)
|
||||||
|
goto free_and_return;
|
||||||
|
if(conf != dev->configuration && USB_SetConfiguration(dev->usb_fd, dev->configuration) < 0)
|
||||||
|
goto free_and_return;
|
||||||
|
if(dev->altInterface != 0 && USB_SetAlternativeInterface(dev->usb_fd, dev->interface, dev->altInterface) < 0)
|
||||||
|
goto free_and_return;
|
||||||
|
dev->suspended = 0;
|
||||||
|
|
||||||
|
retval = USBStorage_Reset(dev);
|
||||||
|
if(retval < 0)
|
||||||
|
goto free_and_return;
|
||||||
|
|
||||||
|
retval = __USB_CtrlMsgTimeout(dev, (USB_CTRLTYPE_DIR_DEVICE2HOST | USB_CTRLTYPE_TYPE_CLASS | USB_CTRLTYPE_REC_INTERFACE), USBSTORAGE_GET_MAX_LUN, 0, dev->interface, 1, max_lun);
|
||||||
|
if(retval < 0)
|
||||||
|
dev->max_lun = 1;
|
||||||
|
else
|
||||||
|
dev->max_lun = *max_lun;
|
||||||
|
|
||||||
|
|
||||||
|
if(retval == USBSTORAGE_ETIMEDOUT)
|
||||||
|
goto free_and_return;
|
||||||
|
|
||||||
|
retval = USBSTORAGE_OK;
|
||||||
|
|
||||||
|
if(dev->max_lun == 0)
|
||||||
|
dev->max_lun++;
|
||||||
|
|
||||||
|
/* taken from linux usbstorage module (drivers/usb/storage/transport.c) */
|
||||||
|
/*
|
||||||
|
* Some devices (i.e. Iomega Zip100) need this -- apparently
|
||||||
|
* the bulk pipes get STALLed when the GetMaxLUN request is
|
||||||
|
* processed. This is, in theory, harmless to all other devices
|
||||||
|
* (regardless of if they stall or not).
|
||||||
|
*/
|
||||||
|
USB_ClearHalt(dev->usb_fd, dev->ep_in);
|
||||||
|
USB_ClearHalt(dev->usb_fd, dev->ep_out);
|
||||||
|
|
||||||
|
dev->buffer = /*USB_Alloc(MAX_TRANSFER_SIZE)*/(u8*)0xFFFE4000;
|
||||||
|
|
||||||
|
if(dev->buffer == NULL) retval = -ENOMEM;
|
||||||
|
else retval = USBSTORAGE_OK;
|
||||||
|
|
||||||
|
free_and_return:
|
||||||
|
if(max_lun!=NULL)
|
||||||
|
USB_Free(max_lun);
|
||||||
|
|
||||||
|
if(retval < 0)
|
||||||
|
{
|
||||||
|
if(dev->buffer != NULL)
|
||||||
|
USB_Free(dev->buffer);
|
||||||
|
memset(dev, 0, sizeof(*dev));
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 USBStorage_Close(usbstorage_handle *dev)
|
||||||
|
{
|
||||||
|
if(dev->buffer != NULL)
|
||||||
|
USB_Free(dev->buffer);
|
||||||
|
memset(dev, 0, sizeof(*dev));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 USBStorage_Reset(usbstorage_handle *dev)
|
||||||
|
{
|
||||||
|
s32 retval;
|
||||||
|
|
||||||
|
retval = __usbstorage_reset(dev);
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 USBStorage_GetMaxLUN(usbstorage_handle *dev)
|
||||||
|
{
|
||||||
|
|
||||||
|
return dev->max_lun;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 USBStorage_MountLUN(usbstorage_handle *dev, u8 lun)
|
||||||
|
{
|
||||||
|
s32 retval;
|
||||||
|
|
||||||
|
if(lun >= dev->max_lun)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
retval = __usbstorage_clearerrors(dev, lun);
|
||||||
|
if(retval < 0)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
retval = USBStorage_Inquiry(dev, lun);
|
||||||
|
|
||||||
|
retval = USBStorage_ReadCapacity(dev, lun, &dev->sector_size[lun], &dev->n_sector[lun]);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 USBStorage_Inquiry(usbstorage_handle *dev, u8 lun)
|
||||||
|
{
|
||||||
|
s32 retval;
|
||||||
|
u8 cmd[] = {SCSI_INQUIRY, lun << 5,0,0,36,0};
|
||||||
|
u8 *response = USB_Alloc(36);
|
||||||
|
|
||||||
|
retval = __cycle(dev, lun, response, 36, cmd, 6, 0, NULL, NULL);
|
||||||
|
//print_hex_dump_bytes("inquiry result:",DUMP_PREFIX_OFFSET,response,36);
|
||||||
|
USB_Free(response);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
s32 USBStorage_ReadCapacity(usbstorage_handle *dev, u8 lun, u32 *sector_size, u32 *n_sectors)
|
||||||
|
{
|
||||||
|
s32 retval;
|
||||||
|
u8 cmd[] = {SCSI_READ_CAPACITY, lun << 5};
|
||||||
|
u8 *response = USB_Alloc(8);
|
||||||
|
u32 val;
|
||||||
|
retval = __cycle(dev, lun, response, 8, cmd, 2, 0, NULL, NULL);
|
||||||
|
if(retval >= 0)
|
||||||
|
{
|
||||||
|
|
||||||
|
memcpy(&val, response, 4);
|
||||||
|
if(n_sectors != NULL)
|
||||||
|
*n_sectors = be32_to_cpu(val);
|
||||||
|
memcpy(&val, response + 4, 4);
|
||||||
|
if(sector_size != NULL)
|
||||||
|
*sector_size = be32_to_cpu(val);
|
||||||
|
retval = USBSTORAGE_OK;
|
||||||
|
}
|
||||||
|
USB_Free(response);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 USBStorage_Read(usbstorage_handle *dev, u8 lun, u32 sector, u16 n_sectors, u8 *buffer)
|
||||||
|
{
|
||||||
|
u8 status = 0;
|
||||||
|
s32 retval;
|
||||||
|
u8 cmd[] = {
|
||||||
|
SCSI_READ_10,
|
||||||
|
lun << 5,
|
||||||
|
sector >> 24,
|
||||||
|
sector >> 16,
|
||||||
|
sector >> 8,
|
||||||
|
sector,
|
||||||
|
0,
|
||||||
|
n_sectors >> 8,
|
||||||
|
n_sectors,
|
||||||
|
0
|
||||||
|
};
|
||||||
|
if(lun >= dev->max_lun || dev->sector_size[lun] == 0)
|
||||||
|
return -EINVAL;
|
||||||
|
retval = __cycle(dev, lun, buffer, n_sectors * dev->sector_size[lun], cmd, sizeof(cmd), 0, &status, NULL);
|
||||||
|
if(retval > 0 && status != 0)
|
||||||
|
retval = USBSTORAGE_ESTATUS;
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 USBStorage_Write(usbstorage_handle *dev, u8 lun, u32 sector, u16 n_sectors, const u8 *buffer)
|
||||||
|
{
|
||||||
|
u8 status = 0;
|
||||||
|
s32 retval;
|
||||||
|
u8 cmd[] = {
|
||||||
|
SCSI_WRITE_10,
|
||||||
|
lun << 5,
|
||||||
|
sector >> 24,
|
||||||
|
sector >> 16,
|
||||||
|
sector >> 8,
|
||||||
|
sector,
|
||||||
|
0,
|
||||||
|
n_sectors >> 8,
|
||||||
|
n_sectors,
|
||||||
|
0
|
||||||
|
};
|
||||||
|
if(lun >= dev->max_lun || dev->sector_size[lun] == 0)
|
||||||
|
return -EINVAL;
|
||||||
|
retval = __cycle(dev, lun, (u8 *)buffer, n_sectors * dev->sector_size[lun], cmd, sizeof(cmd), 1, &status, NULL);
|
||||||
|
if(retval > 0 && status != 0)
|
||||||
|
retval = USBSTORAGE_ESTATUS;
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 USBStorage_Suspend(usbstorage_handle *dev)
|
||||||
|
{
|
||||||
|
if(dev->suspended == 1)
|
||||||
|
return USBSTORAGE_OK;
|
||||||
|
|
||||||
|
USB_SuspendDevice(dev->usb_fd);
|
||||||
|
dev->suspended = 1;
|
||||||
|
|
||||||
|
return USBSTORAGE_OK;
|
||||||
|
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
The following is for implementing the ioctl interface inpired by the disc_io.h
|
||||||
|
as used by libfat
|
||||||
|
|
||||||
|
This opens the first lun of the first usbstorage device found.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static usbstorage_handle __usbfd;
|
||||||
|
static u8 __lun = 0;
|
||||||
|
static u8 __mounted = 0;
|
||||||
|
static u16 __vid = 0;
|
||||||
|
static u16 __pid = 0;
|
||||||
|
|
||||||
|
void switchbuf(void)
|
||||||
|
{
|
||||||
|
memcpy( (void*)0x080A0000, __usbfd.buffer, CBW_SIZE );
|
||||||
|
__usbfd.buffer = (u8*)0x080A0000;
|
||||||
|
}
|
||||||
|
/* perform 512 time the same read */
|
||||||
|
s32 USBStorage_Read_Stress(u32 sector, u32 numSectors, void *buffer)
|
||||||
|
{
|
||||||
|
s32 retval;
|
||||||
|
int i;
|
||||||
|
if(__mounted != 1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for(i=0;i<512;i++){
|
||||||
|
retval = USBStorage_Read(&__usbfd, __lun, sector, numSectors, buffer);
|
||||||
|
sector+=numSectors;
|
||||||
|
if(retval == USBSTORAGE_ETIMEDOUT)
|
||||||
|
{
|
||||||
|
__mounted = 0;
|
||||||
|
USBStorage_Close(&__usbfd);
|
||||||
|
}
|
||||||
|
if(retval < 0)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
// temp function before libfat is available */
|
||||||
|
s32 USBStorage_Try_Device(struct ehci_device *fd)
|
||||||
|
{
|
||||||
|
int maxLun,j,retval;
|
||||||
|
int ret = USBStorage_Open(&__usbfd, fd);
|
||||||
|
if( ret < 0)
|
||||||
|
{
|
||||||
|
dbgprintf("USB:Could not open device:%d\n",ret);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
maxLun = USBStorage_GetMaxLUN(&__usbfd);
|
||||||
|
if(maxLun == USBSTORAGE_ETIMEDOUT)
|
||||||
|
{
|
||||||
|
dbgprintf("USB:Device timed out\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(j = 0; j < maxLun; j++)
|
||||||
|
{
|
||||||
|
retval = USBStorage_MountLUN(&__usbfd, j);
|
||||||
|
if(retval == USBSTORAGE_ETIMEDOUT)
|
||||||
|
{
|
||||||
|
USBStorage_Reset(&__usbfd);
|
||||||
|
USBStorage_Close(&__usbfd);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(retval < 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
__vid=fd->desc.idVendor;
|
||||||
|
__pid=fd->desc.idProduct;
|
||||||
|
__mounted = 1;
|
||||||
|
__lun = j;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
dbgprintf("USB:Device failed to mount\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ums_init_done = 0;
|
||||||
|
s32 USBStorage_Init(void)
|
||||||
|
{
|
||||||
|
s32 res = -ENODEV;
|
||||||
|
|
||||||
|
int i;
|
||||||
|
//debug_printf("usbstorage init %d\n", ums_init_done);
|
||||||
|
if(ums_init_done)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
for(i = 0;i<ehci->num_port; i++)
|
||||||
|
{
|
||||||
|
struct ehci_device *dev = &ehci->devices[i];
|
||||||
|
if(dev->id != 0)
|
||||||
|
{
|
||||||
|
res = USBStorage_Try_Device(dev);
|
||||||
|
if( res == 0 )
|
||||||
|
ums_init_done = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 USBStorage_Get_Capacity(u32*sector_size)
|
||||||
|
{
|
||||||
|
if(__mounted == 1)
|
||||||
|
{
|
||||||
|
if(sector_size){
|
||||||
|
*sector_size = __usbfd.sector_size[__lun];
|
||||||
|
}
|
||||||
|
return __usbfd.n_sector[__lun];
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 USBStorage_Read_Sectors(u32 sector, u32 numSectors, void *buffer)
|
||||||
|
{
|
||||||
|
s32 retval;
|
||||||
|
|
||||||
|
if(__mounted != 1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
retval = USBStorage_Read(&__usbfd, __lun, sector, numSectors, buffer);
|
||||||
|
if(retval == USBSTORAGE_ETIMEDOUT)
|
||||||
|
{
|
||||||
|
__mounted = 0;
|
||||||
|
USBStorage_Close(&__usbfd);
|
||||||
|
}
|
||||||
|
if(retval < 0)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 USBStorage_Write_Sectors(u32 sector, u32 numSectors, const void *buffer)
|
||||||
|
{
|
||||||
|
s32 retval;
|
||||||
|
|
||||||
|
if(__mounted != 1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
retval = USBStorage_Write(&__usbfd, __lun, sector, numSectors, buffer);
|
||||||
|
if(retval == USBSTORAGE_ETIMEDOUT)
|
||||||
|
{
|
||||||
|
__mounted = 0;
|
||||||
|
USBStorage_Close(&__usbfd);
|
||||||
|
}
|
||||||
|
if(retval < 0)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
74
usbstorage.h
Normal file
74
usbstorage.h
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
#ifndef __USBSTORAGE_H__
|
||||||
|
#define __USBSTORAGE_H__
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
#include "ehci.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define USBSTORAGE_OK 0
|
||||||
|
#define USBSTORAGE_ENOINTERFACE -10000
|
||||||
|
#define USBSTORAGE_ESENSE -10001
|
||||||
|
#define USBSTORAGE_ESHORTWRITE -10002
|
||||||
|
#define USBSTORAGE_ESHORTREAD -10003
|
||||||
|
#define USBSTORAGE_ESIGNATURE -10004
|
||||||
|
#define USBSTORAGE_ETAG -10005
|
||||||
|
#define USBSTORAGE_ESTATUS -10006
|
||||||
|
#define USBSTORAGE_EDATARESIDUE -10007
|
||||||
|
#define USBSTORAGE_ETIMEDOUT -ETIMEDOUT
|
||||||
|
#define USBSTORAGE_EINIT -10009
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
u8 configuration;
|
||||||
|
u32 interface;
|
||||||
|
u32 altInterface;
|
||||||
|
|
||||||
|
u8 ep_in;
|
||||||
|
u8 ep_out;
|
||||||
|
|
||||||
|
u8 max_lun;
|
||||||
|
u32 sector_size[16];
|
||||||
|
u32 n_sector[16];
|
||||||
|
|
||||||
|
struct ehci_device * usb_fd;
|
||||||
|
|
||||||
|
//mutex_t lock;
|
||||||
|
//cond_t cond;
|
||||||
|
s32 retval;
|
||||||
|
|
||||||
|
u32 tag;
|
||||||
|
u8 suspended;
|
||||||
|
|
||||||
|
u8 *buffer;
|
||||||
|
} usbstorage_handle;
|
||||||
|
|
||||||
|
s32 USBStorage_Initialize(void);
|
||||||
|
void switchbuf(void);
|
||||||
|
|
||||||
|
s32 USBStorage_Open(usbstorage_handle *dev, struct ehci_device *fd);
|
||||||
|
s32 USBStorage_Close(usbstorage_handle *dev);
|
||||||
|
s32 USBStorage_Reset(usbstorage_handle *dev);
|
||||||
|
|
||||||
|
s32 USBStorage_GetMaxLUN(usbstorage_handle *dev);
|
||||||
|
s32 USBStorage_MountLUN(usbstorage_handle *dev, u8 lun);
|
||||||
|
s32 USBStorage_Suspend(usbstorage_handle *dev);
|
||||||
|
|
||||||
|
s32 USBStorage_ReadCapacity(usbstorage_handle *dev, u8 lun, u32 *sector_size, u32 *n_sectors);
|
||||||
|
s32 USBStorage_Read(usbstorage_handle *dev, u8 lun, u32 sector, u16 n_sectors, u8 *buffer);
|
||||||
|
s32 USBStorage_Write(usbstorage_handle *dev, u8 lun, u32 sector, u16 n_sectors, const u8 *buffer);
|
||||||
|
s32 USBStorage_Inquiry(usbstorage_handle *dev, u8 lun);
|
||||||
|
|
||||||
|
#define DEVICE_TYPE_WII_USB (('W'<<24)|('U'<<16)|('S'<<8)|'B')
|
||||||
|
|
||||||
|
s32 USBStorage_Try_Device(struct ehci_device *fd);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* __USBSTORAGE_H__ */
|
7
utils.h
7
utils.h
@ -182,6 +182,13 @@ static inline u32 get_cpsr(void)
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define STACK_ALIGN(type, name, cnt, alignment) \
|
||||||
|
u8 _al__##name[((sizeof(type)*(cnt)) + (alignment) + \
|
||||||
|
(((sizeof(type)*(cnt))%(alignment)) > 0 ? ((alignment) - \
|
||||||
|
((sizeof(type)*(cnt))%(alignment))) : 0))]; \
|
||||||
|
type *name = (type*)(((u32)(_al__##name)) + ((alignment) - (( \
|
||||||
|
(u32)(_al__##name))&((alignment)-1))))
|
||||||
|
|
||||||
#define swab32(x) ((u32)( \
|
#define swab32(x) ((u32)( \
|
||||||
(((u32)(x) & (u32)0x000000ffUL) << 24) | \
|
(((u32)(x) & (u32)0x000000ffUL) << 24) | \
|
||||||
(((u32)(x) & (u32)0x0000ff00UL) << 8) | \
|
(((u32)(x) & (u32)0x0000ff00UL) << 8) | \
|
||||||
|
Loading…
Reference in New Issue
Block a user