PS2SDK
PS2 Homebrew Libraries
Loading...
Searching...
No Matches
bdm.c
1#include <bdm.h>
2#include <stdio.h>
3#include <thbase.h>
4#include <thevent.h>
5
6#include <bd_cache.h>
7
8// #define DEBUG //comment out this line when not debugging
9#include "module_debug.h"
10
12{
13 struct block_device *bd; // real block device
14 struct block_device *cbd; // cached block device
15 struct file_system *fs;
16};
17
18#define MAX_CONNECTIONS 20
19static struct bdm_mounts g_mount[MAX_CONNECTIONS];
20static struct file_system *g_fs[MAX_CONNECTIONS];
21static bdm_cb g_cb = NULL;
22static int bdm_event = -1;
23static int bdm_thread_id = -1;
24
25/* Event flag bits */
26#define BDM_EVENT_CB_MOUNT 0x01
27#define BDM_EVENT_CB_UMOUNT 0x02
28#define BDM_EVENT_MOUNT 0x04
29
30void bdm_RegisterCallback(bdm_cb cb)
31{
32 int i;
33
34 M_DEBUG("%s\n", __func__);
35
36 g_cb = cb;
37
38 if (g_cb == NULL)
39 return;
40
41 // Trigger a mount callback if we already have mounts
42 for (i = 0; i < MAX_CONNECTIONS; ++i) {
43 if ((g_mount[i].bd != NULL) && (g_mount[i].fs != NULL)) {
44 SetEventFlag(bdm_event, BDM_EVENT_CB_MOUNT);
45 break;
46 }
47 }
48}
49
50void bdm_connect_bd(struct block_device *bd)
51{
52 int i;
53
54 M_PRINTF("connecting device %s%dp%d id=0x%x\n", bd->name, bd->devNr, bd->parNr, bd->parId);
55
56 for (i = 0; i < MAX_CONNECTIONS; ++i) {
57 if (g_mount[i].bd == NULL) {
58 g_mount[i].bd = bd;
59 // Create cache for entire device only (not for the partitions on it)
60 g_mount[i].cbd = (bd->parNr == 0) ? bd_cache_create(bd) : NULL;
61 // New block device, try to mount it to a filesystem
62 SetEventFlag(bdm_event, BDM_EVENT_MOUNT);
63 break;
64 }
65 }
66}
67
68void bdm_disconnect_bd(struct block_device *bd)
69{
70 int i;
71
72 M_PRINTF("disconnecting device %s%dp%d id=0x%x\n", bd->name, bd->devNr, bd->parNr, bd->parId);
73
74 for (i = 0; i < MAX_CONNECTIONS; ++i) {
75 if (g_mount[i].bd == bd) {
76 if (g_mount[i].fs != NULL) {
77 // Unmount filesystem
78 g_mount[i].fs->disconnect_bd(g_mount[i].cbd != NULL ? g_mount[i].cbd : g_mount[i].bd);
79 M_PRINTF("%s%dp%d unmounted from %s\n", bd->name, bd->devNr, bd->parNr, g_mount[i].fs->name);
80 g_mount[i].fs = NULL;
81 }
82
83 if (g_mount[i].cbd != NULL) {
84 bd_cache_destroy(g_mount[i].cbd);
85 g_mount[i].cbd = NULL;
86 }
87
88 g_mount[i].bd = NULL;
89
90 if (g_cb != NULL)
91 SetEventFlag(bdm_event, BDM_EVENT_CB_UMOUNT);
92 }
93 }
94}
95
96void bdm_connect_fs(struct file_system *fs)
97{
98 int i;
99
100 M_PRINTF("connecting fs %s\n", fs->name);
101
102 for (i = 0; i < MAX_CONNECTIONS; ++i) {
103 if (g_fs[i] == NULL) {
104 g_fs[i] = fs;
105 break;
106 }
107 }
108
109 // New filesystem, try to mount it to the block devices
110 SetEventFlag(bdm_event, BDM_EVENT_MOUNT);
111}
112
113void bdm_disconnect_fs(struct file_system *fs)
114{
115 int i;
116
117 M_PRINTF("disconnecting fs %s\n", fs->name);
118
119 // Unmount fs from block devices
120 for (i = 0; i < MAX_CONNECTIONS; ++i) {
121 if (g_mount[i].fs == fs) {
122 g_mount[i].fs = NULL;
123 if (g_cb != NULL)
124 SetEventFlag(bdm_event, BDM_EVENT_CB_UMOUNT);
125 }
126 }
127
128 // Remove fs from list
129 for (i = 0; i < MAX_CONNECTIONS; ++i) {
130 if (g_fs[i] == fs) {
131 g_fs[i] = NULL;
132 break;
133 }
134 }
135}
136
137void bdm_get_bd(struct block_device **pbd, unsigned int count)
138{
139 int i;
140
141 M_DEBUG("%s\n", __func__);
142
143 // Fill pointer array with block device pointers
144 for (i = 0; (unsigned int)i < count && i < MAX_CONNECTIONS; i++)
145 pbd[i] = g_mount[i].bd;
146}
147
148static void bdm_try_mount(struct bdm_mounts *mount)
149{
150 int i;
151
152 M_DEBUG("%s(%s%dp%d)\n", __func__, mount->bd->name, mount->bd->devNr, mount->bd->parNr);
153
154 for (i = 0; i < MAX_CONNECTIONS; ++i) {
155 if (g_fs[i] != NULL) {
156 if (g_fs[i]->connect_bd(mount->cbd != NULL ? mount->cbd : mount->bd) == 0) {
157 M_PRINTF("%s%dp%d mounted to %s\n", mount->bd->name, mount->bd->devNr, mount->bd->parNr, g_fs[i]->name);
158 mount->fs = g_fs[i];
159 if (g_cb != NULL)
160 SetEventFlag(bdm_event, BDM_EVENT_CB_MOUNT);
161 break;
162 }
163 }
164 }
165}
166
167static void bdm_thread(void *arg)
168{
169 u32 EFBits;
170 int i;
171
172 (void)arg;
173
174 M_PRINTF("BDM event thread running\n");
175
176 while (1) {
177 WaitEventFlag(bdm_event, BDM_EVENT_CB_MOUNT | BDM_EVENT_CB_UMOUNT | BDM_EVENT_MOUNT, WEF_OR | WEF_CLEAR, &EFBits);
178
179 if (EFBits & BDM_EVENT_MOUNT) {
180 // Try to mount any unmounted block devices
181 for (i = 0; i < MAX_CONNECTIONS; ++i) {
182 if ((g_mount[i].bd != NULL) && (g_mount[i].fs == NULL))
183 bdm_try_mount(&g_mount[i]);
184 }
185 }
186
187 if (EFBits & BDM_EVENT_CB_MOUNT) {
188 // Notify callback about changes
189 if (g_cb != NULL)
190 g_cb(1);
191 }
192
193 if (EFBits & BDM_EVENT_CB_UMOUNT) {
194 // Notify callback about changes
195 if (g_cb != NULL)
196 g_cb(0);
197 }
198 }
199}
200
201int bdm_init()
202{
203 int i, result;
204 iop_event_t EventFlagData;
205 iop_thread_t ThreadData;
206
207 M_DEBUG("%s\n", __func__);
208
209 for (i = 0; i < MAX_CONNECTIONS; ++i) {
210 g_mount[i].bd = NULL;
211 g_mount[i].cbd = NULL;
212 g_mount[i].fs = NULL;
213 g_fs[i] = NULL;
214 }
215
216 EventFlagData.attr = 0;
217 EventFlagData.option = 0;
218 EventFlagData.bits = 0;
219 result = bdm_event = CreateEventFlag(&EventFlagData);
220 if (result < 0) {
221 M_DEBUG("ERROR: CreateEventFlag %d\n", result);
222 return result;
223 }
224
225 ThreadData.attr = TH_C;
226 ThreadData.thread = bdm_thread;
227 ThreadData.option = 0;
228 ThreadData.priority = 0x30; // Low priority
229 ThreadData.stacksize = 0x1000; // 4KiB
230 result = bdm_thread_id = CreateThread(&ThreadData);
231 if (result < 0) {
232 M_DEBUG("ERROR: CreateThread %d\n", result);
233 DeleteEventFlag(bdm_event);
234 return result;
235 }
236
237 result = StartThread(bdm_thread_id, NULL);
238 if (result < 0) {
239 M_DEBUG("ERROR: StartThread %d\n", result);
240 DeleteThread(bdm_thread_id);
241 DeleteEventFlag(bdm_event);
242 return result;
243 }
244
245 return 0;
246}
u32 count
start sector of fragmented bd/file