2 meinOS - A unix-like x86 microkernel operating system
3 Copyright (C) 2008 Janosch Gräf <janosch.graef@gmx.net>
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include <sys/types.h>
23 #include <cdi/storage.h>
29 * Writes old block to disk and loads new block to buffer
30 * @param device CDI Storage Device
31 * @param newpos New position to load
34 static int cdi_storage_swapbuffer(struct cdi_storage_device
* device
,uint64_t newpos
) {
35 struct cdi_storage_driver
*driver
= (struct cdi_storage_driver
*)(device
->dev
.driver
);
36 if (device
->buffer
==NULL
) device
->buffer
= malloc(device
->block_size
);
37 if (device
->buffer_curblock
!=newpos
/device
->block_size
|| !device
->buffer_loaded
) {
38 if (device
->buffer_loaded
&& driver
->write_blocks
!=NULL
&& device
->buffer_dirty
) {
39 if (driver
->write_blocks(device
,device
->buffer_curblock
/device
->block_size
,1,device
->buffer
)==-1) return -1;
41 if (driver
->read_blocks
!=NULL
) {
42 if (driver
->read_blocks(device
,newpos
/device
->block_size
,1,device
->buffer
)==-1) return -1;
43 device
->buffer_dirty
= 0;
44 device
->buffer_loaded
= 1;
46 device
->buffer_curblock
= newpos
/device
->block_size
;
52 * Reads from storage via Callback
53 * @param buffer Buffer to store data in
54 * @param count How many bytes to read
55 * @param dev DevFS device
56 * @return How many bytes read
58 static int cdi_storage_read(devfs_dev_t
*dev
,void *buffer
,size_t count
,off_t pos
) {
59 CDI_DEBUG("storage: read(0x%x,0x%x,0x%x,0x%x)\n",dev
,buffer
,count
,pos
);
60 struct cdi_storage_device
* device
= dev
->user_data
;
63 //if (pos>device->block_count*device->block_size) return -1;
64 //if (pos+count>device->block_count*device->block_size) count = device->block_count*device->block_size-pos;
66 uint64_t offset
= pos
%device
->block_size
;
67 uint64_t blockpos
= pos
-offset
;
68 size_t blocks
= (count
+offset
-1)/device
->block_size
+1;
70 for (i
=0;i
<blocks
;i
++) {
71 size_t count_cur
= device
->block_size
-offset
;
72 count_cur
= count_cur
>count
?count
:count_cur
;
74 cdi_storage_swapbuffer(device
,blockpos
);
75 memcpy(buffer
+i
*device
->block_size
,device
->buffer
+offset
,count_cur
);
77 blockpos
+= device
->block_size
;
85 * Writes to storage via Callback
86 * @param buffer Buffer to read data from
87 * @param count How many bytes to write
88 * @param dev DevFS device
89 * @return How many bytes written
91 static int cdi_storage_write(devfs_dev_t
*dev
,void *buffer
,size_t count
,off_t pos
) {
92 struct cdi_storage_device
* device
= dev
->user_data
;
95 //if (pos>device->block_count*device->block_size) return -1;
96 //if (pos+count>device->block_count*device->block_size) count = device->block_count*device->block_size-pos;
98 uint64_t offset
= pos
%device
->block_size
;
99 uint64_t blockpos
= pos
-offset
;
100 size_t blocks
= (count
+offset
-1)/device
->block_size
+1;
102 for (i
=0;i
<blocks
;i
++) {
103 size_t count_cur
= device
->block_size
-offset
;
104 count_cur
= count_cur
>count
?count
:count_cur
;
106 cdi_storage_swapbuffer(device
,blockpos
);
107 memcpy(buffer
+i
*device
->block_size
,device
->buffer
+offset
,count_cur
);
108 device
->buffer_dirty
= 1;
110 blockpos
+= device
->block_size
;
118 * Initializes CDI Storage Driver
119 * @param driver CDI Storage Driver
121 void cdi_storage_driver_init(struct cdi_storage_driver
* driver
) {
122 cdi_driver_init((struct cdi_driver
*)driver
);
126 * Destroys CDI Storage Driver
127 * @param driver CDI Storage Driver
129 void cdi_storage_driver_destroy(struct cdi_storage_driver
* driver
) {
130 struct cdi_storage_device
* device
;
133 for (i
=0;(device
= cdi_list_get(driver
->drv
.devices
,i
));i
++) {
134 devfs_removedev(device
->devfs
);
135 free(device
->buffer
);
137 cdi_driver_destroy((struct cdi_driver
*)driver
);
141 * Registers CDI Storage Driver
142 * @param driver CDI Storage Driver
143 * @todo Fixme: Create device later. After driver->init() call
145 void cdi_storage_driver_register(struct cdi_storage_driver
* driver
) {
146 struct cdi_storage_device
* device
;
149 for (i
=0;(device
= cdi_list_get(driver
->drv
.devices
,i
));i
++) {
150 device
->devfs
= devfs_createdev(device
->dev
.name
);
151 if (device
->devfs
!=NULL
) {
152 device
->devfs
->user_data
= device
;
153 devfs_onread(device
->devfs
,cdi_storage_read
);
154 devfs_onwrite(device
->devfs
,cdi_storage_write
);
156 device
->buffer
= NULL
;
157 device
->buffer_curblock
= 0;
158 device
->buffer_loaded
= 0;
159 device
->buffer_dirty
= 0;
161 cdi_driver_register((struct cdi_driver
*)driver
);