headers/bsd: Add sys/queue.h.
[haiku.git] / src / system / kernel / disk_device_manager / KDiskDevice.cpp
blob1d74c6d0056f68009190fc971b354d2c71ff17e5
1 /*
2 * Copyright 2006-2011, Axel Dörfler, axeld@pinc-software.de.
3 * Copyright 2003-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
4 * Distributed under the terms of the MIT License.
5 */
8 #include "KDiskDevice.h"
10 #include <errno.h>
11 #include <fcntl.h>
12 #include <stdio.h>
13 #include <unistd.h>
15 #include <KernelExport.h>
16 #include <Drivers.h>
18 #include "ddm_userland_interface.h"
19 #include "KDiskDeviceUtils.h"
20 #include "KPath.h"
21 #include "UserDataWriter.h"
24 // debugging
25 //#define DBG(x)
26 #define DBG(x) x
27 #define OUT dprintf
30 KDiskDevice::KDiskDevice(partition_id id)
32 KPartition(id),
33 fDeviceData(),
34 fFD(-1),
35 fMediaStatus(B_ERROR)
37 rw_lock_init(&fLocker, "disk device");
39 Unset();
40 fDevice = this;
41 fPublishedName = (char*)"raw";
45 KDiskDevice::~KDiskDevice()
47 Unset();
51 status_t
52 KDiskDevice::SetTo(const char* path)
54 // check initialization and parameter
55 status_t error = InitCheck();
56 if (error != B_OK)
57 return error;
58 if (!path)
59 return B_BAD_VALUE;
60 Unset();
61 // set the path
62 error = set_string(fDeviceData.path, path);
63 if (error != B_OK)
64 return error;
65 // open the device
66 fFD = open(path, O_RDONLY);
67 if (fFD < 0)
68 return errno;
69 // get media status
70 error = GetMediaStatus(&fMediaStatus);
71 if (error != B_OK)
72 return error;
73 if (fMediaStatus == B_DEV_MEDIA_CHANGED)
74 fMediaStatus = B_OK;
75 // get device geometry
76 if (fMediaStatus == B_OK) {
77 error = GetGeometry(&fDeviceData.geometry);
78 if (error != B_OK)
79 return error;
80 } else {
81 // no media present: reset the geometry
82 _ResetGeometry();
85 // set device flags
86 _UpdateDeviceFlags();
87 // update partition data
88 _InitPartitionData();
89 return B_OK;
93 void
94 KDiskDevice::Unset()
96 if (fFD >= 0) {
97 close(fFD);
98 fFD = -1;
100 fMediaStatus = B_ERROR;
101 fDeviceData.id = -1;
102 fDeviceData.flags = 0;
103 if (fDeviceData.path) {
104 free(fDeviceData.path);
105 fDeviceData.path = NULL;
107 _ResetGeometry();
111 status_t
112 KDiskDevice::InitCheck() const
114 return B_OK;
118 bool
119 KDiskDevice::ReadLock()
121 return rw_lock_read_lock(&fLocker) == B_OK;
125 void
126 KDiskDevice::ReadUnlock()
128 rw_lock_read_unlock(&fLocker);
132 bool
133 KDiskDevice::WriteLock()
135 return rw_lock_write_lock(&fLocker) == B_OK;
139 void
140 KDiskDevice::WriteUnlock()
142 rw_lock_write_unlock(&fLocker);
146 void
147 KDiskDevice::SetID(partition_id id)
149 KPartition::SetID(id);
150 fDeviceData.id = id;
154 status_t
155 KDiskDevice::PublishDevice()
157 // PublishDevice(), UnpublishDevice() and Republish are no-ops
158 // for KDiskDevices, since they are always published.
159 return B_OK;
163 status_t
164 KDiskDevice::UnpublishDevice()
166 // PublishDevice(), UnpublishDevice() and Republish are no-ops
167 // for KDiskDevices, since they are always published.
168 return B_OK;
172 status_t
173 KDiskDevice::RepublishDevice()
175 // PublishDevice(), UnpublishDevice() and Republish are no-ops
176 // for KDiskDevices, since they are always published.
177 return B_OK;
181 void
182 KDiskDevice::SetDeviceFlags(uint32 flags)
184 fDeviceData.flags = flags;
188 uint32
189 KDiskDevice::DeviceFlags() const
191 return fDeviceData.flags;
195 bool
196 KDiskDevice::IsReadOnlyMedia() const
198 return fDeviceData.geometry.read_only;
202 bool
203 KDiskDevice::IsWriteOnce() const
205 return fDeviceData.geometry.write_once;
209 bool
210 KDiskDevice::IsRemovable() const
212 return fDeviceData.geometry.removable;
216 bool
217 KDiskDevice::HasMedia() const
219 return fMediaStatus == B_OK || fMediaStatus == B_DEV_MEDIA_CHANGED;
223 bool
224 KDiskDevice::MediaChanged() const
226 return fMediaStatus == B_DEV_MEDIA_CHANGED;
230 void
231 KDiskDevice::UpdateMediaStatusIfNeeded()
233 // TODO: allow a device to notify us about its media status!
234 // This will then also need to clear any B_DEV_MEDIA_CHANGED
235 GetMediaStatus(&fMediaStatus);
239 void
240 KDiskDevice::UninitializeMedia()
242 UninitializeContents();
243 _ResetGeometry();
244 _UpdateDeviceFlags();
245 _InitPartitionData();
249 void
250 KDiskDevice::UpdateGeometry()
252 if (GetGeometry(&fDeviceData.geometry) != B_OK)
253 return;
255 _UpdateDeviceFlags();
256 _InitPartitionData();
260 status_t
261 KDiskDevice::SetPath(const char* path)
263 return set_string(fDeviceData.path, path);
267 const char*
268 KDiskDevice::Path() const
270 return fDeviceData.path;
274 status_t
275 KDiskDevice::GetFileName(char* buffer, size_t size) const
277 if (strlcpy(buffer, "raw", size) >= size)
278 return B_NAME_TOO_LONG;
279 return B_OK;
283 status_t
284 KDiskDevice::GetPath(KPath* path) const
286 if (!path || path->InitCheck() != B_OK)
287 return B_BAD_VALUE;
288 if (!fDeviceData.path)
289 return B_NO_INIT;
290 return path->SetPath(fDeviceData.path);
294 void
295 KDiskDevice::SetFD(int fd)
297 fFD = fd;
302 KDiskDevice::FD() const
304 return fFD;
308 disk_device_data*
309 KDiskDevice::DeviceData()
311 return &fDeviceData;
315 const disk_device_data*
316 KDiskDevice::DeviceData() const
318 return &fDeviceData;
322 void
323 KDiskDevice::WriteUserData(UserDataWriter& writer, user_partition_data* data)
325 return KPartition::WriteUserData(writer, data);
329 void
330 KDiskDevice::WriteUserData(UserDataWriter& writer)
332 KPartition* partition = this;
333 user_disk_device_data* data
334 = writer.AllocateDeviceData(partition->CountChildren());
335 char* path = writer.PlaceString(Path());
336 if (data != NULL) {
337 data->device_flags = DeviceFlags();
338 data->path = path;
339 writer.AddRelocationEntry(&data->path);
340 partition->WriteUserData(writer, &data->device_partition_data);
341 } else
342 partition->WriteUserData(writer, NULL);
346 void
347 KDiskDevice::Dump(bool deep, int32 level)
349 OUT("device %" B_PRId32 ": %s\n", ID(), Path());
350 OUT(" media status: %s\n", strerror(fMediaStatus));
351 OUT(" device flags: %" B_PRIx32 "\n", DeviceFlags());
352 if (fMediaStatus == B_OK)
353 KPartition::Dump(deep, 0);
357 status_t
358 KDiskDevice::GetMediaStatus(status_t* mediaStatus)
360 status_t error = B_OK;
361 if (ioctl(fFD, B_GET_MEDIA_STATUS, mediaStatus) != 0)
362 error = errno;
363 // maybe the device driver doesn't implement this ioctl -- see, if getting
364 // the device geometry succeeds
365 if (error != B_OK) {
366 device_geometry geometry;
367 if (GetGeometry(&geometry) == B_OK) {
368 // if the device is not removable, we can ignore the failed ioctl
369 // and return a media status of B_OK
370 if (!geometry.removable) {
371 error = B_OK;
372 *mediaStatus = B_OK;
376 return error;
380 status_t
381 KDiskDevice::GetGeometry(device_geometry* geometry)
383 if (ioctl(fFD, B_GET_GEOMETRY, geometry) != 0)
384 return errno;
385 return B_OK;
389 void
390 KDiskDevice::_InitPartitionData()
392 fDeviceData.id = fPartitionData.id;
393 fPartitionData.block_size = fDeviceData.geometry.bytes_per_sector;
394 fPartitionData.offset = 0;
395 fPartitionData.size = (off_t)fPartitionData.block_size
396 * fDeviceData.geometry.sectors_per_track
397 * fDeviceData.geometry.cylinder_count
398 * fDeviceData.geometry.head_count;
399 fPartitionData.flags |= B_PARTITION_IS_DEVICE;
401 char name[B_FILE_NAME_LENGTH];
402 if (ioctl(fFD, B_GET_DEVICE_NAME, name, sizeof(name)) == B_OK)
403 fPartitionData.name = strdup(name);
407 void
408 KDiskDevice::_ResetGeometry()
410 fDeviceData.geometry.bytes_per_sector = 0;
411 fDeviceData.geometry.sectors_per_track = 0;
412 fDeviceData.geometry.cylinder_count = 0;
413 fDeviceData.geometry.head_count = 0;
414 fDeviceData.geometry.device_type = B_DISK;
415 fDeviceData.geometry.removable = true;
416 fDeviceData.geometry.read_only = true;
417 fDeviceData.geometry.write_once = false;
421 void
422 KDiskDevice::_UpdateDeviceFlags()
424 if (fDeviceData.geometry.removable)
425 SetDeviceFlags(DeviceFlags() | B_DISK_DEVICE_REMOVABLE);
426 if (HasMedia())
427 SetDeviceFlags(DeviceFlags() | B_DISK_DEVICE_HAS_MEDIA);
428 else
429 SetDeviceFlags(DeviceFlags() & ~B_DISK_DEVICE_HAS_MEDIA);
431 if (fDeviceData.geometry.read_only)
432 SetDeviceFlags(DeviceFlags() | B_DISK_DEVICE_READ_ONLY);
433 if (fDeviceData.geometry.write_once)
434 SetDeviceFlags(DeviceFlags() | B_DISK_DEVICE_WRITE_ONCE);