Compare commits

..

9 Commits
DML ... master

Author SHA1 Message Date
crediar@rypp.net
9ba08bec0f *Added the FatFS link map feature which should greatly decrease load times
git-svn-id: svn://localhost/Users/andi/Downloads/code/trunk@41 be6c1b03-d731-4111-a574-e37d80d43941
2014-07-02 08:34:53 +00:00
crediar@rypp.net
cb9fe32b8c -updated to version 2.10-
*Fixed a bug in the pattern detection code (DVDLowReadDiskID)


git-svn-id: svn://localhost/Users/andi/Downloads/code/trunk@40 be6c1b03-d731-4111-a574-e37d80d43941
2013-05-24 18:40:02 +00:00
crediar@rypp.net
bc58c3874f -updated to version 2.9-
*Changed patch code to prevent false hits (DVDLowReadDiskID)
*Added C_MTXLightPerspective patching (Fixes heat effects when using wide screen hack in Zelda:WW)




git-svn-id: svn://localhost/Users/andi/Downloads/code/trunk@38 be6c1b03-d731-4111-a574-e37d80d43941
2013-04-05 16:41:58 +00:00
crediar@rypp.net
7fa64ca726 -updated to version 2.8-
*Fixed a bug in GCLoader that broke the progressive patch
*Moved progressive patch back 16 bytes, this fixes PADHOOK and progressive patching not working at the same time

Thanks to FIX94 who sacrificed his school carer for testing this release!



git-svn-id: svn://localhost/Users/andi/Downloads/code/trunk@36 be6c1b03-d731-4111-a574-e37d80d43941
2013-02-24 19:16:28 +00:00
crediar@rypp.net
8e3d855eac -updated to version 2.7-
*Fixed a bug that caused a black screen when using PADHook and Progressive mode patching at the same time


git-svn-id: svn://localhost/Users/andi/Downloads/code/trunk@35 be6c1b03-d731-4111-a574-e37d80d43941
2013-02-20 13:51:24 +00:00
crediar@rypp.net
b6e6f8ca44 -updated to version 2.6-
*Reduced HDD read time out to 25 seconds
*Added two disc feature (Extracted format is unsupported)
 Use the latest DMToolBox (0.3 or higher) to install your two disc games

This will be the last version for some time, since I'm moving my focus to other things.

Always remember; Impossible is nothing!



git-svn-id: svn://localhost/Users/andi/Downloads/code/trunk@34 be6c1b03-d731-4111-a574-e37d80d43941
2012-11-30 21:46:19 +00:00
crediar@rypp.net
f808bbc8e0 Again another donation another feature. Thanks for donating!
-updated to version 2.5-

*Fixed a bug in DM that could cause a fatal read error when using devices with under 8GB size
*Added a PADHOOK pattern for Batman:Vengeance
*Added a screenshot feature
 This feature can be enabled/disabled via the DM(L) config
 Press R+Z on the fourth controller to take a screenshot any time!
 Screenshots will be saved to device:/screenshots in the YPbPr format, you can use my tool to convert them.


git-svn-id: svn://localhost/Users/andi/Downloads/code/trunk@33 be6c1b03-d731-4111-a574-e37d80d43941
2012-11-09 20:30:55 +00:00
crediar@rypp.net
894f641639 -updated to version 2.4-
*Fixed NMM for Mario Kart Double Dash. Saving ghost data works now as well
*Fixed a bug that would sometimes break cheating/debugging unless both were enabled
*Moved the VIConfigure patch to the ARM side which should fix a number of broken titles
*Changed the HDD time out to read a random sector
*Optimised the EHCI reset code
*Optimised the CARD code


git-svn-id: svn://localhost/Users/andi/Downloads/code/trunk@31 be6c1b03-d731-4111-a574-e37d80d43941
2012-10-21 21:36:35 +00:00
0xD15EA5E@gmail.com
8cebe92a4d -updated to version 2.3-
*Fixed creating NMM save file folders in FST mode
*Fixed CardFindEntryByName which incorrectly compared file names
*Added a hack for Phantasy Star Online 1&2 version 1.0
*GCLoader improvements that include warning the user if an incorrect CONFIG_VERSION is used
*Hardcoded the only worthy DVDGetDriveStatus patching, so once again the NODISC cfg doesn't do anything
*Removed unused code
*Removed unused files

git-svn-id: svn://localhost/Users/andi/Downloads/code/trunk@29 be6c1b03-d731-4111-a574-e37d80d43941
2012-09-24 14:03:20 +00:00
41 changed files with 3507 additions and 3044 deletions

View File

@ -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
//};

View File

@ -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) );

65
DVD.c
View File

@ -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 );
@ -130,7 +191,7 @@ u32 FSTInit( void )
f_lseek( &fd, 0x0420 ); f_lseek( &fd, 0x0420 );
f_read( &fd, rbuf, 0x20, &read ); f_read( &fd, rbuf, 0x20, &read );
dolOffset = *(u32*)(rbuf); dolOffset = *(u32*)(rbuf);
FSTableOffset = *(u32*)(rbuf+4); FSTableOffset = *(u32*)(rbuf+4);
FSTableSize = *(u32*)(rbuf+8); FSTableSize = *(u32*)(rbuf+8);

8
DVD.h
View File

@ -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 DVDReadConfig( void ); void DVDInit( void );
s32 DVDSelectGame( void ); void DVDReadConfig( 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
View File

@ -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
View File

@ -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;

View File

@ -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

View File

@ -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 );

39
alloc.c
View File

@ -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 to allow 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;
} }

View File

@ -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 );

View File

@ -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
View File

@ -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
View File

@ -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
{ {

View File

@ -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 );
} }

View File

@ -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
View 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
View 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
View 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
View 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
View 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

View File

@ -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)

View File

@ -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
View File

@ -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
View File

@ -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
View File

@ -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
View File

@ -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

View File

@ -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
View File

@ -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
View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
View 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
View 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
View 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
View 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
View 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
View 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
View 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__ */

View File

@ -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) | \