1 #include "include/usbld.h"
2 #include "include/ioman.h"
3 #include "include/hddsupport.h"
7 typedef struct // size = 1024
9 u32 checksum
; // HDL uses 0xdeadfeed magic here
13 u8 ops2l_compat_flags
;
21 u32 part_offset
; // in MB
22 u32 data_start
; // in sectors
23 u32 part_size
; // in KB
30 #define APA_DEVCTL_MAX_SECTORS 0x00004801 // max partition size(in sectors)
31 #define APA_DEVCTL_TOTAL_SECTORS 0x00004802
32 #define APA_DEVCTL_IDLE 0x00004803
33 #define APA_DEVCTL_FLUSH_CACHE 0x00004804
34 #define APA_DEVCTL_SWAP_TMP 0x00004805
35 #define APA_DEVCTL_DEV9_SHUTDOWN 0x00004806
36 #define APA_DEVCTL_STATUS 0x00004807
37 #define APA_DEVCTL_FORMAT 0x00004808
38 #define APA_DEVCTL_SMART_STAT 0x00004809
39 #define APA_DEVCTL_GETTIME 0x00006832
40 #define APA_DEVCTL_SET_OSDMBR 0x00006833// arg = hddSetOsdMBR_t
41 #define APA_DEVCTL_GET_SECTOR_ERROR 0x00006834
42 #define APA_DEVCTL_GET_ERROR_PART_NAME 0x00006835// bufp = namebuffer[0x20]
43 #define APA_DEVCTL_ATA_READ 0x00006836// arg = hddAtaTransfer_t
44 #define APA_DEVCTL_ATA_WRITE 0x00006837// arg = hddAtaTransfer_t
45 #define APA_DEVCTL_SCE_IDENTIFY_DRIVE 0x00006838// bufp = buffer for atadSceIdentifyDrive
46 #define APA_DEVCTL_IS_48BIT 0x00006840
47 #define APA_DEVCTL_SET_TRANSFER_MODE 0x00006841
49 static apa_partition_table_t
*ptable
= NULL
;
58 static u8 hdd_buf
[16384];
60 //-------------------------------------------------------------------------
66 ret
= fileXioDevctl("hdd0:", APA_DEVCTL_STATUS
, NULL
, 0, NULL
, 0);
68 if ((ret
>= 3) || (ret
< 0))
74 //-------------------------------------------------------------------------
75 u32
hddGetTotalSectors(void)
77 return fileXioDevctl("hdd0:", APA_DEVCTL_TOTAL_SECTORS
, NULL
, 0, NULL
, 0);
80 //-------------------------------------------------------------------------
83 return fileXioDevctl("hdd0:", APA_DEVCTL_IS_48BIT
, NULL
, 0, NULL
, 0);
86 //-------------------------------------------------------------------------
87 int hddSetTransferMode(int type
, int mode
)
91 *(u32
*)&args
[0] = type
;
92 *(u32
*)&args
[4] = mode
;
94 return fileXioDevctl("hdd0:", APA_DEVCTL_SET_TRANSFER_MODE
, args
, 8, NULL
, 0);
97 //-------------------------------------------------------------------------
98 int hddSetIdleTimeout(int timeout
)
101 // A value of zero means "timeouts are disabled": the
102 // device will not automatically enter standby mode. Values from 1
103 // to 240 specify multiples of 5 seconds, yielding timeouts from 5
104 // seconds to 20 minutes. Values from 241 to 251 specify from 1 to
105 // 11 units of 30 minutes, yielding timeouts from 30 minutes to 5.5
106 // hours. A value of 252 signifies a timeout of 21 minutes. A
107 // value of 253 sets a vendor-defined timeout period between 8 and
108 // 12 hours, and the value 254 is reserved. 255 is interpreted as
109 // 21 minutes plus 15 seconds. Note that some older drives may
110 // have very different interpretations of these values.
114 *(u32
*)&args
[0] = timeout
& 0xff;
116 return fileXioDevctl("hdd0:", APA_DEVCTL_IDLE
, args
, 4, NULL
, 0);
119 //-------------------------------------------------------------------------
120 static int hddReadSectors(u32 lba
, u32 nsectors
, void *buf
, int bufsize
)
124 *(u32
*)&args
[0] = lba
;
125 *(u32
*)&args
[4] = nsectors
;
127 if (fileXioDevctl("hdd0:", APA_DEVCTL_ATA_READ
, args
, 8, buf
, bufsize
) != 0)
133 //-------------------------------------------------------------------------
134 static int hddWriteSectors(u32 lba
, u32 nsectors
, void *buf
)
137 u8
*args
= (u8
*)hdd_buf
;
139 *(u32
*)&args
[0] = lba
;
140 *(u32
*)&args
[4] = nsectors
;
141 memcpy(&args
[8], buf
, nsectors
<< 9);
143 argsz
= 8 + (nsectors
<< 9);
145 if (fileXioDevctl("hdd0:", APA_DEVCTL_ATA_WRITE
, args
, argsz
, NULL
, 0) != 0)
151 //-------------------------------------------------------------------------
152 static int hddFlushCache(void)
154 return fileXioDevctl("hdd0:", APA_DEVCTL_FLUSH_CACHE
, NULL
, 0, NULL
, 0);
157 //-------------------------------------------------------------------------
158 int hddGetFormat(void)
160 return fileXioDevctl("hdd0:", APA_DEVCTL_FORMAT
, NULL
, 0, NULL
, 0);
163 //-------------------------------------------------------------------------
164 static int apaCheckSum(apa_header
*header
)
166 u32
*ptr
=(u32
*)header
;
170 for(i
=1; i
< 256; i
++)
175 //-------------------------------------------------------------------------
176 static int apaAddPartition(apa_partition_table_t
*table
, apa_header
*header
, int existing
)
180 if (table
->part_count
== table
->part_alloc_
) {
182 // grow buffer of 16 parts
183 nbytes
= (table
->part_alloc_
+ 16) * sizeof(apa_partition_t
);
184 apa_partition_t
*parts
= malloc(nbytes
);
187 memset(parts
, 0, nbytes
);
189 // copy existing parts
190 if (table
->parts
!= NULL
)
191 memcpy(parts
, table
->parts
, table
->part_count
* sizeof(apa_partition_t
));
193 // free old parts mem
195 table
->parts
= parts
;
196 table
->part_alloc_
+= 16;
202 // copy the part to its buffer
203 memcpy(&table
->parts
[table
->part_count
].header
, header
, sizeof(apa_header
));
204 table
->parts
[table
->part_count
].existing
= existing
;
205 table
->parts
[table
->part_count
].modified
= !existing
;
206 table
->parts
[table
->part_count
].linked
= 1;
212 //-------------------------------------------------------------------------
213 static void apaFreePartitionTable(apa_partition_table_t
*table
)
218 for (i
=0; i
<table
->part_count
; i
++) {
223 if (table
->chunks_map
)
224 free(table
->chunks_map
);
228 //-------------------------------------------------------------------------
229 static int apaSetPartitionTableStats(apa_partition_table_t
*table
)
234 table
->total_chunks
= table
->device_size_in_mb
/ 128;
235 chunks_map
= malloc(table
->total_chunks
);
236 if (chunks_map
== NULL
)
239 *chunks_map
= MAP_AVAIL
;
240 for (i
=0; i
<table
->total_chunks
; i
++)
241 chunks_map
[i
] = MAP_AVAIL
;
243 // build occupided/available space map
244 table
->allocated_chunks
= 0;
245 table
->free_chunks
= table
->total_chunks
;
246 for (i
=0; i
<table
->part_count
; i
++) {
247 apa_header
*part_hdr
= (apa_header
*)&table
->parts
[i
].header
;
248 int part_num
= part_hdr
->start
/ ((128 * 1024 * 1024) / 512);
249 int num_parts
= part_hdr
->length
/ ((128 * 1024 * 1024) / 512);
251 // "alloc" num_parts starting at part_num
253 if (chunks_map
[part_num
] == MAP_AVAIL
)
254 chunks_map
[part_num
] = (part_hdr
->main
== 0 ? MAP_MAIN
: MAP_SUB
);
256 chunks_map
[part_num
] = MAP_COLL
; // collision
259 table
->allocated_chunks
++;
260 table
->free_chunks
--;
264 if (table
->chunks_map
)
265 free(table
->chunks_map
);
267 table
->chunks_map
= (u8
*)chunks_map
;
272 //-------------------------------------------------------------------------
273 static int apaReadPartitionTable(apa_partition_table_t
**table
)
275 register u32 nsectors
, lba
;
278 // get number of sectors on device
279 nsectors
= hddGetTotalSectors();
281 // if not already done allocate space for the partition table
282 if (*table
== NULL
) {
283 *table
= malloc(sizeof(apa_partition_table_t
));
284 if (*table
== NULL
) {
288 else // if partition table was already allocated, Free all
289 apaFreePartitionTable(*table
);
291 // clear the partition table
292 memset(*table
, 0, sizeof(apa_partition_table_t
));
294 // read the partition table
297 apa_header apaHeader
;
298 // read partition header
299 ret
= hddReadSectors(lba
, sizeof(apa_header
) >> 9, &apaHeader
, sizeof(apa_header
));
301 // check checksum & header magic
302 if ((apaCheckSum(&apaHeader
) == apaHeader
.checksum
) && (apaHeader
.magic
== APA_MAGIC
)) {
303 if (apaHeader
.start
< nsectors
) {
304 //if ((apaHeader.flags == 0) && (apaHeader.type == 0x1337))
305 ret
= apaAddPartition(*table
, &apaHeader
, 1);
307 lba
= apaHeader
.next
;
310 ret
= 7; // data behind end-of-HDD
317 if ((*table
)->part_count
> 10000)
320 } while (ret
== 0 && lba
!= 0);
323 (*table
)->device_size_in_mb
= nsectors
>> 11;
324 ret
= apaSetPartitionTableStats(*table
);
327 apaFreePartitionTable(*table
);
328 ret
= 20000 + (*table
)->part_count
;
334 //-------------------------------------------------------------------------
335 static int apaCheckLinkedList(apa_partition_table_t
*table
, int flag
)
340 for (i
=0; i
<table
->part_count
; i
++) {
341 apa_partition_t
*prev
= (apa_partition_t
*)&table
->parts
[(i
> 0 ? i
- 1 : table
->part_count
- 1)];
342 apa_partition_t
*curr
= (apa_partition_t
*)&table
->parts
[i
];
343 apa_partition_t
*next
= (apa_partition_t
*)&table
->parts
[(i
+ 1 < table
->part_count
? i
+ 1 : 0)];
345 if (curr
->header
.prev
!= prev
->header
.start
) {
350 curr
->header
.prev
= prev
->header
.start
;
353 if (curr
->header
.next
!= next
->header
.start
) {
358 curr
->header
.next
= next
->header
.start
;
361 if ((flag
) && (curr
->modified
))
362 curr
->header
.checksum
= apaCheckSum(&curr
->header
);
368 //-------------------------------------------------------------------------
369 static int apaCheckPartitionTable(apa_partition_table_t
*table
)
371 register int i
, j
, k
;
373 u32 total_sectors
= table
->device_size_in_mb
* 1024 * 2;
375 for (i
=0; i
<table
->part_count
; i
++) {
376 apa_header
*part_hdr
= &table
->parts
[i
].header
;
379 if (part_hdr
->checksum
!= apaCheckSum(part_hdr
))
382 // check for data behind end of HDD
383 if (!((part_hdr
->start
< total_sectors
) && (part_hdr
->start
+ part_hdr
->length
<= total_sectors
)))
386 // check partition length is multiple of 128 MB
387 if ((part_hdr
->length
% ((128 * 1024 * 1024) / 512)) != 0)
390 // check partition start is multiple of partion length
391 if ((part_hdr
->start
% part_hdr
->length
) != 0)
394 // check all subs partitions
395 if ((part_hdr
->main
== 0) && (part_hdr
->flags
== 0) && (part_hdr
->start
!= 0)) {
398 for (j
=0; j
<table
->part_count
; j
++) {
399 apa_header
*part2_hdr
= &table
->parts
[j
].header
;
400 if (part2_hdr
->main
== part_hdr
->start
) { // sub-partition of current main partition
402 if (part2_hdr
->flags
!= APA_FLAG_SUB
)
406 for (k
=0; k
<part_hdr
->nsub
; k
++) {
407 if (part_hdr
->subs
[k
].start
== part2_hdr
->start
) { // in list
408 if (part_hdr
->subs
[k
].length
!= part2_hdr
->length
)
415 return -7; // not found in the list
420 if (count
!= part_hdr
->nsub
)
421 return -8; // wrong number of sub-partitions
425 // verify double-linked list
426 if (apaCheckLinkedList(table
, 0) < 0)
427 return -9; // bad links
429 LOG("HDD CheckPartitionTable OK!\n");
434 //-------------------------------------------------------------------------
435 static int apaWritePartitionTable(apa_partition_table_t
*table
)
439 ret
= apaCheckPartitionTable(table
);
443 for (i
=0; i
<table
->part_count
; i
++) {
445 if (table
->parts
[i
].modified
) {
446 apa_header
*part_hdr
= &table
->parts
[i
].header
;
447 LOG("HDD Writing 2 sectors at sector 0x%X\n", part_hdr
->start
);
449 ret
= hddWriteSectors(part_hdr
->start
, 2, (void *)part_hdr
);
459 //-------------------------------------------------------------------------
460 static int apaFindPartition(apa_partition_table_t
*table
, char *partname
)
466 for (i
=0; i
<table
->part_count
; i
++) {
468 apa_header
*part_hdr
= &table
->parts
[i
].header
;
470 // if part found, return its index
471 if ((part_hdr
->main
== 0) && (!strcmp(part_hdr
->id
, partname
))) {
480 //-------------------------------------------------------------------------
481 static int apaDeletePartition(apa_partition_table_t
*table
, char *partname
)
483 register int i
, part_index
;
484 register int count
= 1;
485 u32 pending_deletes
[APA_MAXSUB
];
487 LOG("HDD DeletePartition %s\n", partname
);
489 // retrieve part index
490 part_index
= apaFindPartition(table
, partname
);
494 apa_header
*part_hdr
= &table
->parts
[part_index
].header
;
496 // Do not delete system partitions
497 if (part_hdr
->type
== 1)
500 // preserve a list of starting sectors of partitions to be deleted
501 pending_deletes
[0] = part_hdr
->start
;
502 LOG("HDD Found part at %d \n", part_hdr
->start
/ 262144);
503 for (i
=0; i
<part_hdr
->nsub
; i
++) {
504 LOG("HDD Found subpart at %d \n", part_hdr
->subs
[i
].start
/ 262144);
505 pending_deletes
[count
++] = part_hdr
->subs
[i
].start
;
508 LOG("HDD Number of subpartitions=%d count=%d\n", part_hdr
->nsub
, count
);
510 // remove partitions from the double-linked list
512 while (i
<table
->part_count
) {
516 for (j
=0; j
<count
; j
++) {
517 if (table
->parts
[i
].header
.start
== pending_deletes
[j
]) {
524 // remove this partition
525 int part_num
= table
->parts
[i
].header
.start
/ 262144; // 262144 sectors == 128M
526 int num_parts
= table
->parts
[i
].header
.length
/ 262144;
528 LOG("HDD Partition found! num_parts=%d part_num=%d\n", num_parts
, part_num
);
530 memmove((void *)&table
->parts
[i
], (void *)&table
->parts
[i
+1], sizeof(apa_partition_t
) * (table
->part_count
-i
-1));
533 // "free" num_parts starting at part_num
535 table
->chunks_map
[part_num
] = MAP_AVAIL
;
538 table
->allocated_chunks
--;
539 table
->free_chunks
++;
546 apaCheckLinkedList(table
, 1);
551 //-------------------------------------------------------------------------
552 static int hddGetHDLGameInfo(apa_header
*header
, hdl_game_info_t
*ginfo
)
555 const u32 offset
= 0x101000;
559 u32 start_sector
= header
->start
+ offset
/ 512;
561 ret
= hddReadSectors(start_sector
, 2, buf
, 2 * 512);
564 hdl_apa_header
*hdl_header
= (hdl_apa_header
*)buf
;
566 // calculate total size
567 size
= header
->length
;
569 for (i
= 0; i
< header
->nsub
; i
++)
570 size
+= header
->subs
[i
].length
;
572 memcpy(ginfo
->partition_name
, header
->id
, APA_IDMAX
);
573 ginfo
->partition_name
[APA_IDMAX
] = 0;
574 strncpy(ginfo
->name
, hdl_header
->gamename
, HDL_GAME_NAME_MAX
);
575 strncpy(ginfo
->startup
, hdl_header
->startup
, 12);
576 ginfo
->hdl_compat_flags
= hdl_header
->hdl_compat_flags
;
577 ginfo
->ops2l_compat_flags
= hdl_header
->ops2l_compat_flags
;
578 ginfo
->dma_type
= hdl_header
->dma_type
;
579 ginfo
->dma_mode
= hdl_header
->dma_mode
;
580 ginfo
->layer_break
= hdl_header
->layer1_start
;
581 ginfo
->disctype
= hdl_header
->discType
;
582 ginfo
->start_sector
= start_sector
;
583 ginfo
->total_size_in_kb
= size
/ 2;
590 //-------------------------------------------------------------------------
591 int hddGetHDLGamelist(hdl_games_list_t
**game_list
)
595 ret
= apaReadPartitionTable(&ptable
);
601 if (*game_list
!= NULL
) {
602 for (i
= 0; i
< (*game_list
)->count
; i
++) {
603 if ((*game_list
)->games
!= NULL
)
604 free((*game_list
)->games
);
608 for (i
= 0; i
< ptable
->part_count
; i
++)
609 count
+= ((ptable
->parts
[i
].header
.flags
== 0) && (ptable
->parts
[i
].header
.type
== 0x1337));
611 tmp
= malloc(sizeof(hdl_game_info_t
) * count
);
614 memset(tmp
, 0, sizeof(hdl_game_info_t
) * count
);
615 *game_list
= malloc(sizeof(hdl_games_list_t
));
616 if (*game_list
!= NULL
) {
619 memset(*game_list
, 0, sizeof(hdl_games_list_t
));
620 (*game_list
)->count
= count
;
621 (*game_list
)->games
= tmp
;
622 (*game_list
)->total_chunks
= ptable
->total_chunks
;
623 (*game_list
)->free_chunks
= ptable
->free_chunks
;
625 for (i
= 0; ((ret
== 0) && (i
< ptable
->part_count
)); i
++) {
626 apa_header
*header
= &ptable
->parts
[i
].header
;
627 if ((header
->flags
== 0) && (header
->type
== 0x1337))
628 ret
= hddGetHDLGameInfo(header
, (*game_list
)->games
+ index
++);
645 //-------------------------------------------------------------------------
646 int hddFreeHDLGamelist(hdl_games_list_t
*game_list
)
650 apaFreePartitionTable(ptable
);
652 if (game_list
!= NULL
) {
653 for (i
= 0; i
< game_list
->count
; i
++) {
654 if (game_list
->games
!= NULL
)
655 free(game_list
->games
);
664 //-------------------------------------------------------------------------
665 int hddSetHDLGameInfo(hdl_game_info_t
*ginfo
)
667 const u32 offset
= 0x101000;
674 // retrieve part index
675 part_index
= apaFindPartition(ptable
, ginfo
->partition_name
);
679 apa_header
*header
= &ptable
->parts
[part_index
].header
;
683 u32 start_sector
= header
->start
+ offset
/ 512;
685 if (hddReadSectors(start_sector
, 2, buf
, 2 * 512) != 0)
688 hdl_apa_header
*hdl_header
= (hdl_apa_header
*)buf
;
690 // checking deadfeed magic & PS2 game magic
691 if (hdl_header
->checksum
!= 0xdeadfeed)
694 // just change game name and compat flags !!!
695 strncpy(hdl_header
->gamename
, ginfo
->name
, 160);
696 hdl_header
->gamename
[159] = '\0';
697 //hdl_header->hdl_compat_flags = ginfo->hdl_compat_flags;
698 hdl_header
->ops2l_compat_flags
= ginfo
->ops2l_compat_flags
;
699 hdl_header
->dma_type
= ginfo
->dma_type
;
700 hdl_header
->dma_mode
= ginfo
->dma_mode
;
702 if (hddWriteSectors(start_sector
, 2, buf
) != 0)
710 //-------------------------------------------------------------------------
711 int hddDeleteHDLGame(hdl_game_info_t
*ginfo
)
715 LOG("HDD Delete game: '%s'\n", ginfo
->name
);
720 ret
= apaDeletePartition(ptable
, ginfo
->partition_name
);
724 ret
= apaWritePartitionTable(ptable
);
730 LOG("HDD Game: '%s' deleted!\n", ginfo
->name
);