The Pedigree Project  0.1
storage.cc
1 /*
2  * Copyright (c) 2007 Antoine Kaufmann
3  *
4  * This program is free software. It comes without any warranty, to
5  * the extent permitted by applicable law. You can redistribute it
6  * and/or modify it under the terms of the Do What The Fuck You Want
7  * To Public License, Version 2, as published by Sam Hocevar. See
8  * http://sam.zoy.org/projects/COPYING.WTFPL for more details.
9  */
10 
11 #include "cdi.h"
12 #include "cdi/storage.h"
13 #include "pedigree/kernel/processor/types.h"
14 #include "pedigree/kernel/utilities/utility.h"
15 
19 extern "C" {
20 void cdi_storage_driver_register(struct cdi_storage_driver* driver);
21 
22 void cdi_cpp_disk_register(struct cdi_storage_device* device);
23 
24 int cdi_storage_read(struct cdi_storage_device* device, uint64_t pos, size_t size, void* dest);
25 int cdi_storage_write(struct cdi_storage_device* device, uint64_t pos, size_t size, void* src);
26 };
27 
31 void cdi_storage_driver_init(struct cdi_storage_driver* driver)
32 {
33  cdi_driver_init(reinterpret_cast<struct cdi_driver*>(driver));
34 }
35 
39 void cdi_storage_driver_destroy(struct cdi_storage_driver* driver)
40 {
41  cdi_driver_destroy(reinterpret_cast<struct cdi_driver*>(driver));
42 }
43 
47 void cdi_storage_driver_register(struct cdi_storage_driver* driver)
48 {
49  static int initialized = 0;
50 
51  cdi_driver_register(reinterpret_cast<struct cdi_driver*>(driver));
52 }
53 
57 void cdi_storage_device_init(struct cdi_storage_device* device)
58 {
59  cdi_cpp_disk_register(device);
60 }
61 
69 int cdi_storage_read(struct cdi_storage_device* device, uint64_t pos, size_t size, void* dest)
70 {
71  struct cdi_storage_driver* driver = reinterpret_cast<struct cdi_storage_driver*>(device->dev.driver);
72  size_t block_size = device->block_size;
73  // Start- und Endblock
74  uint64_t block_read_start = pos / block_size;
75  uint64_t block_read_end = (pos + size) / block_size;
76  // Anzahl der Blocks die gelesen werden sollen
77  uint64_t block_read_count = block_read_end - block_read_start;
78 
79  // Wenn nur ganze Bloecke gelesen werden sollen, geht das etwas effizienter
80  if (((pos % block_size) == 0) && (((pos + size) % block_size) == 0)) {
81  // Nur ganze Bloecke
82  return driver->read_blocks(device, block_read_start, block_read_count, dest);
83  } else {
84  // FIXME: Das laesst sich garantiert etwas effizienter loesen
85  block_read_count++;
86  uint8_t *buffer = new uint8_t[block_read_count * block_size];
87 
88  // In Zwischenspeicher einlesen
89  if (driver->read_blocks(device, block_read_start, block_read_count, buffer) != 0)
90  {
91  delete [] buffer;
92  return -1;
93  }
94 
95  // Bereich aus dem Zwischenspeicher kopieren
96  MemoryCopy(dest, buffer + (pos % block_size), size);
97  delete [] buffer;
98  }
99  return 0;
100 }
101 
109 int cdi_storage_write(struct cdi_storage_device* device, uint64_t pos,
110  size_t size, void* src)
111 {
112  struct cdi_storage_driver* driver = reinterpret_cast<struct cdi_storage_driver*>(device->dev.driver);
113 
114  size_t block_size = device->block_size;
115  uint64_t block_write_start = pos / block_size;
116  uint8_t *source = reinterpret_cast<uint8_t*>(src);
117  uint8_t *buffer = new uint8_t[block_size];
118  size_t offset;
119  size_t tmp_size;
120 
121  // Wenn die Startposition nicht auf einer Blockgrenze liegt, muessen wir
122  // hier zuerst den ersten Block laden, die gewuenschten Aenderungen machen,
123  // und den Block wieder Speichern.
124  offset = (pos % block_size);
125  if (offset != 0) {
126  tmp_size = block_size - offset;
127  tmp_size = (tmp_size > size ? size : tmp_size);
128 
129  if (driver->read_blocks(device, block_write_start, 1, buffer) != 0) {
130  delete [] buffer;
131  return -1;
132  }
133  MemoryCopy(buffer + offset, source, tmp_size);
134 
135  // Buffer abspeichern
136  if (driver->write_blocks(device, block_write_start, 1, buffer) != 0) {
137  delete [] buffer;
138  return -1;
139  }
140 
141  size -= tmp_size;
142  source += tmp_size;
143  block_write_start++;
144  }
145 
146  // Jetzt wird die Menge der ganzen Blocks auf einmal geschrieben, falls
147  // welche existieren
148  tmp_size = size / block_size;
149  if (tmp_size != 0) {
150  // Buffer abspeichern
151  if (driver->write_blocks(device, block_write_start, tmp_size, source)
152  != 0)
153  {
154  delete [] buffer;
155  return -1;
156  }
157  size -= tmp_size * block_size;
158  source += tmp_size * block_size;
159  block_write_start += block_size;
160  }
161 
162  // Wenn der letzte Block nur teilweise beschrieben wird, geschieht das hier
163  if (size != 0) {
164  // Hier geschieht fast das Selbe wie oben beim ersten Block
165  if (driver->read_blocks(device, block_write_start, 1, buffer) != 0) {
166  delete [] buffer;
167  return -1;
168  }
169  MemoryCopy(buffer, source, size);
170 
171  // Buffer abspeichern
172  if (driver->write_blocks(device, block_write_start, 1, buffer) != 0) {
173  delete [] buffer;
174  return -1;
175  }
176  }
177  delete [] buffer;
178  return 0;
179 }