2 Copyright (C) 2008 Mathias Gottschlag
4 Permission is hereby granted, free of charge, to any person obtaining a copy of
5 this software and associated documentation files (the "Software"), to deal in the
6 Software without restriction, including without limitation the rights to use,
7 copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
8 Software, and to permit persons to whom the Software is furnished to do so,
9 subject to the following conditions:
11 The above copyright notice and this permission notice shall be included in all
12 copies or substantial portions of the Software.
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
15 INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
16 PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
17 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
18 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
19 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 #include <cdi/storage.h>
24 #include <fs/request.h>
27 #include <ke/spinlock.h>
32 struct cdi_storage_device
*device
;
34 KeSpinlock request_lock
;
38 static cdi_list_t msdevices
= 0;
40 static uint32_t cdi_storage_read(struct storage_device
*msd
, uint32_t offset
, uint32_t length
, void *buffer
)
42 struct cdi_storage_device
*device
= msd
->device
;
43 struct cdi_storage_driver
*driver
= (struct cdi_storage_driver
*)device
->dev
.driver
;
45 size_t block_size
= device
->block_size
;
47 uint64_t block_read_start
= offset
/ block_size
;
48 uint64_t block_read_end
= (offset
+ length
) / block_size
;
49 uint64_t block_read_count
= block_read_end
- block_read_start
;
51 if (((offset
% block_size
) == 0) && (((offset
+ length
) % block_size
) == 0))
53 // Only read whole blocks
54 kePrint("Reading blocks.\n");
55 if (driver
->read_blocks(device
, block_read_start
, block_read_count
, buffer
) != 0)
57 kePrint("Could not read blocks.\n");
60 kePrint("Read blocks.\n");
65 // TODO: Optimize this
67 uint8_t buffer
[block_read_count
* block_size
];
70 if (driver
->read_blocks(device
, block_read_start
, block_read_count
, buffer
) != 0)
75 // Copy data from buffer
76 memcpy(buffer
, buffer
+ (offset
% block_size
), length
);
80 static uint32_t cdi_storage_write(struct storage_device
*msd
, uint32_t offset
, uint32_t length
, void *data
)
82 struct cdi_storage_device
*device
= msd
->device
;
83 struct cdi_storage_driver
*driver
= (struct cdi_storage_driver
*)device
->dev
.driver
;
85 size_t block_size
= device
->block_size
;
86 uint64_t block_write_start
= offset
/ block_size
;
87 uint8_t buffer
[block_size
];
91 // Wenn die Startposition nicht auf einer Blockgrenze liegt, muessen wir
92 // hier zuerst den ersten Block laden, die gewuenschten Aenderungen machen,
93 // und den Block wieder Speichern.
94 blockoffset
= (offset
% block_size
);
97 tmp_size
= block_size
- blockoffset
;
98 tmp_size
= (tmp_size
> length
? length
: tmp_size
);
100 if (driver
->read_blocks(device
, block_write_start
, 1, buffer
) != 0) {
103 memcpy(data
+ blockoffset
, data
, tmp_size
);
105 // Buffer abspeichern
106 if (driver
->write_blocks(device
, block_write_start
, 1, buffer
) != 0)
116 // Jetzt wird die Menge der ganzen Blocks auf einmal geschrieben, falls
118 tmp_size
= length
/ block_size
;
120 // Buffer abspeichern
121 if (driver
->write_blocks(device
, block_write_start
, tmp_size
, data
) != 0)
125 length
-= tmp_size
* block_size
;
126 data
+= tmp_size
* block_size
;
127 block_write_start
+= block_size
;
130 // Wenn der letzte Block nur teilweise beschrieben wird, geschieht das hier
132 // Hier geschieht fast das Selbe wie oben beim ersten Block
133 if (driver
->read_blocks(device
, block_write_start
, 1, buffer
) != 0) {
136 memcpy(data
, buffer
, length
);
138 // Buffer abspeichern
139 if (driver
->write_blocks(device
, block_write_start
, 1, buffer
) != 0) {
145 static void cdi_storage_perform_request(struct storage_device
*device
,
148 switch (request
->type
)
150 case FS_REQUEST_READ
:
151 request
->return_value
= cdi_storage_read(device
, request
->offset
, request
->bufferlength
, request
->buffer
);
152 fsFinishRequest(request
);
154 case FS_REQUEST_WRITE
:
155 request
->return_value
= cdi_storage_write(device
, request
->offset
, request
->bufferlength
, request
->buffer
);
156 fsFinishRequest(request
);
158 case FS_REQUEST_IOCTL
:
160 fsFinishRequest(request
);
163 fsFinishRequest(request
);
167 static void cdi_storage_thread(struct storage_device
*device
)
169 //kePrint("Worker thread: %s\n", device->file.path);
173 keLockSpinlock(&device
->request_lock
);
174 while (cdi_list_size(device
->requests
) > 0)
176 FsRequest
*request
= cdi_list_pop(device
->requests
);
177 keUnlockSpinlock(&device
->request_lock
);
179 kePrint("Performing request on %s\n", device
->file
.path
);
180 cdi_storage_perform_request(device
, request
);
182 keLockSpinlock(&device
->request_lock
);
184 // Wait until next request
185 //kePrint("Pausing worker thread.\n");
186 device
->thread
->status
= KE_THREAD_FSREQUEST
;
187 keUnlockSpinlock(&device
->request_lock
);
188 // Schedule out of the thread
189 asm volatile("int $0x32");
190 //kePrint("Thread woke up.\n");
194 static int cdi_storage_request(struct FsDeviceFile
*file
, FsRequest
*request
)
196 struct storage_device
*device
= (struct storage_device
*)file
;
197 switch (request
->type
)
199 case FS_REQUEST_READ
:
200 case FS_REQUEST_WRITE
:
201 case FS_REQUEST_IOCTL
:
202 keLockSpinlock(&device
->request_lock
);
203 device
->requests
= cdi_list_push(device
->requests
, request
);
204 if (device
->thread
->status
== KE_THREAD_FSREQUEST
)
206 kePrint("Waking up thread.\n");
207 device
->thread
->status
= KE_THREAD_RUNNING
;
209 keUnlockSpinlock(&device
->request_lock
);
211 case FS_REQUEST_SEEK
:
220 void cdi_storage_driver_init(struct cdi_storage_driver
*driver
)
222 cdi_driver_init(&driver
->drv
);
225 void cdi_storage_driver_destroy(struct cdi_storage_driver
*driver
)
227 cdi_driver_destroy(&driver
->drv
);
230 void cdi_storage_driver_register(struct cdi_storage_driver
*driver
)
233 for (i
= 0; i
< cdi_list_size(driver
->drv
.devices
); i
++)
235 // Create device file
236 struct cdi_storage_device
*device
= cdi_list_get(driver
->drv
.devices
, i
);
237 struct storage_device
*sd
= malloc(sizeof(struct storage_device
));
239 memset(&sd
->file
, 0, sizeof(sd
->file
));
240 sd
->file
.path
= device
->dev
.name
;
241 sd
->file
.query_request
= cdi_storage_request
;
242 keInitSpinlock(&sd
->request_lock
);
243 sd
->requests
= cdi_list_create();
244 sd
->thread
= keCreateKernelThread((uintptr_t)cdi_storage_thread
, 1, sd
);
245 fsCreateDeviceFile(&sd
->file
);
246 if (!msdevices
) msdevices
= cdi_list_create();
247 msdevices
= cdi_list_push(msdevices
, sd
);
250 cdi_driver_register(&driver
->drv
);