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 */ 6 7 8#include "KDiskDevice.h" 9 10#include <errno.h> 11#include <fcntl.h> 12#include <stdio.h> 13#include <unistd.h> 14 15#include <KernelExport.h> 16#include <Drivers.h> 17 18#include "ddm_userland_interface.h" 19#include "KDiskDeviceUtils.h" 20#include "KPath.h" 21#include "UserDataWriter.h" 22 23 24// debugging 25//#define DBG(x) 26#define DBG(x) x 27#define OUT dprintf 28 29 30KDiskDevice::KDiskDevice(partition_id id) 31 : 32 KPartition(id), 33 fDeviceData(), 34 fFD(-1), 35 fMediaStatus(B_ERROR) 36{ 37 rw_lock_init(&fLocker, "disk device"); 38 39 Unset(); 40 fDevice = this; 41 fPublishedName = (char*)"raw"; 42} 43 44 45KDiskDevice::~KDiskDevice() 46{ 47 Unset(); 48} 49 50 51status_t 52KDiskDevice::SetTo(const char* path) 53{ 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(); 83 } 84 85 // set device flags 86 _UpdateDeviceFlags(); 87 // update partition data 88 _InitPartitionData(); 89 return B_OK; 90} 91 92 93void 94KDiskDevice::Unset() 95{ 96 if (fFD >= 0) { 97 close(fFD); 98 fFD = -1; 99 } 100 fMediaStatus = B_ERROR; 101 fDeviceData.id = -1; 102 fDeviceData.flags = 0; 103 if (fDeviceData.path) { 104 free(fDeviceData.path); 105 fDeviceData.path = NULL; 106 } 107 _ResetGeometry(); 108} 109 110 111status_t 112KDiskDevice::InitCheck() const 113{ 114 return B_OK; 115} 116 117 118bool 119KDiskDevice::ReadLock() 120{ 121 return rw_lock_read_lock(&fLocker) == B_OK; 122} 123 124 125void 126KDiskDevice::ReadUnlock() 127{ 128 rw_lock_read_unlock(&fLocker); 129} 130 131 132bool 133KDiskDevice::WriteLock() 134{ 135 return rw_lock_write_lock(&fLocker) == B_OK; 136} 137 138 139void 140KDiskDevice::WriteUnlock() 141{ 142 rw_lock_write_unlock(&fLocker); 143} 144 145 146void 147KDiskDevice::SetID(partition_id id) 148{ 149 KPartition::SetID(id); 150 fDeviceData.id = id; 151} 152 153 154status_t 155KDiskDevice::PublishDevice() 156{ 157 // PublishDevice(), UnpublishDevice() and Republish are no-ops 158 // for KDiskDevices, since they are always published. 159 return B_OK; 160} 161 162 163status_t 164KDiskDevice::UnpublishDevice() 165{ 166 // PublishDevice(), UnpublishDevice() and Republish are no-ops 167 // for KDiskDevices, since they are always published. 168 return B_OK; 169} 170 171 172status_t 173KDiskDevice::RepublishDevice() 174{ 175 // PublishDevice(), UnpublishDevice() and Republish are no-ops 176 // for KDiskDevices, since they are always published. 177 return B_OK; 178} 179 180 181void 182KDiskDevice::SetDeviceFlags(uint32 flags) 183{ 184 fDeviceData.flags = flags; 185} 186 187 188uint32 189KDiskDevice::DeviceFlags() const 190{ 191 return fDeviceData.flags; 192} 193 194 195bool 196KDiskDevice::IsReadOnlyMedia() const 197{ 198 return fDeviceData.geometry.read_only; 199} 200 201 202bool 203KDiskDevice::IsWriteOnce() const 204{ 205 return fDeviceData.geometry.write_once; 206} 207 208 209bool 210KDiskDevice::IsRemovable() const 211{ 212 return fDeviceData.geometry.removable; 213} 214 215 216bool 217KDiskDevice::HasMedia() const 218{ 219 return fMediaStatus == B_OK || fMediaStatus == B_DEV_MEDIA_CHANGED; 220} 221 222 223bool 224KDiskDevice::MediaChanged() const 225{ 226 return fMediaStatus == B_DEV_MEDIA_CHANGED; 227} 228 229 230void 231KDiskDevice::UpdateMediaStatusIfNeeded() 232{ 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); 236} 237 238 239void 240KDiskDevice::UninitializeMedia() 241{ 242 UninitializeContents(); 243 _ResetGeometry(); 244 _UpdateDeviceFlags(); 245 _InitPartitionData(); 246} 247 248 249void 250KDiskDevice::UpdateGeometry() 251{ 252 if (GetGeometry(&fDeviceData.geometry) != B_OK) 253 return; 254 255 _UpdateDeviceFlags(); 256 _InitPartitionData(); 257} 258 259 260status_t 261KDiskDevice::SetPath(const char* path) 262{ 263 return set_string(fDeviceData.path, path); 264} 265 266 267const char* 268KDiskDevice::Path() const 269{ 270 return fDeviceData.path; 271} 272 273 274status_t 275KDiskDevice::GetFileName(char* buffer, size_t size) const 276{ 277 if (strlcpy(buffer, "raw", size) >= size) 278 return B_NAME_TOO_LONG; 279 return B_OK; 280} 281 282 283status_t 284KDiskDevice::GetPath(KPath* path) const 285{ 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); 291} 292 293 294void 295KDiskDevice::SetFD(int fd) 296{ 297 fFD = fd; 298} 299 300 301int 302KDiskDevice::FD() const 303{ 304 return fFD; 305} 306 307 308disk_device_data* 309KDiskDevice::DeviceData() 310{ 311 return &fDeviceData; 312} 313 314 315const disk_device_data* 316KDiskDevice::DeviceData() const 317{ 318 return &fDeviceData; 319} 320 321 322void 323KDiskDevice::WriteUserData(UserDataWriter& writer, user_partition_data* data) 324{ 325 KPartition::WriteUserData(writer, data); 326} 327 328 329void 330KDiskDevice::WriteUserData(UserDataWriter& writer) 331{ 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); 343} 344 345 346void 347KDiskDevice::Dump(bool deep, int32 level) 348{ 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); 354} 355 356 357status_t 358KDiskDevice::GetMediaStatus(status_t* mediaStatus) 359{ 360 status_t error = B_OK; 361 if (ioctl(fFD, B_GET_MEDIA_STATUS, mediaStatus, sizeof(*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; 373 } 374 } 375 } 376 return error; 377} 378 379 380status_t 381KDiskDevice::GetGeometry(device_geometry* geometry) 382{ 383 if (ioctl(fFD, B_GET_GEOMETRY, geometry, sizeof(*geometry)) != 0) 384 return errno; 385 return B_OK; 386} 387 388 389void 390KDiskDevice::_InitPartitionData() 391{ 392 fDeviceData.id = fPartitionData.id; 393 fPartitionData.block_size = fDeviceData.geometry.bytes_per_sector; 394 fPartitionData.physical_block_size = fDeviceData.geometry.bytes_per_physical_sector; 395 fPartitionData.offset = 0; 396 fPartitionData.size = (off_t)fPartitionData.block_size 397 * fDeviceData.geometry.sectors_per_track 398 * fDeviceData.geometry.cylinder_count 399 * fDeviceData.geometry.head_count; 400 fPartitionData.flags |= B_PARTITION_IS_DEVICE; 401 402 char name[B_FILE_NAME_LENGTH]; 403 if (ioctl(fFD, B_GET_DEVICE_NAME, name, sizeof(name)) == B_OK) 404 fPartitionData.name = strdup(name); 405} 406 407 408void 409KDiskDevice::_ResetGeometry() 410{ 411 fDeviceData.geometry.bytes_per_sector = 0; 412 fDeviceData.geometry.sectors_per_track = 0; 413 fDeviceData.geometry.cylinder_count = 0; 414 fDeviceData.geometry.head_count = 0; 415 fDeviceData.geometry.device_type = B_DISK; 416 fDeviceData.geometry.removable = true; 417 fDeviceData.geometry.read_only = true; 418 fDeviceData.geometry.write_once = false; 419} 420 421 422void 423KDiskDevice::_UpdateDeviceFlags() 424{ 425 if (fDeviceData.geometry.removable) 426 SetDeviceFlags(DeviceFlags() | B_DISK_DEVICE_REMOVABLE); 427 if (HasMedia()) 428 SetDeviceFlags(DeviceFlags() | B_DISK_DEVICE_HAS_MEDIA); 429 else 430 SetDeviceFlags(DeviceFlags() & ~B_DISK_DEVICE_HAS_MEDIA); 431 432 if (fDeviceData.geometry.read_only) 433 SetDeviceFlags(DeviceFlags() | B_DISK_DEVICE_READ_ONLY); 434 if (fDeviceData.geometry.write_once) 435 SetDeviceFlags(DeviceFlags() | B_DISK_DEVICE_WRITE_ONCE); 436} 437