1 /* 2 * storage_common.c -- Common definitions for mass storage functionality 3 * 4 * Copyright (C) 2003-2008 Alan Stern 5 * Copyeight (C) 2009 Samsung Electronics 6 * Author: Michal Nazarewicz (mina86@mina86.com) 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 */ 13 14 /* 15 * This file requires the following identifiers used in USB strings to 16 * be defined (each of type pointer to char): 17 * - fsg_string_interface -- name of the interface 18 */ 19 20 /* 21 * When USB_GADGET_DEBUG_FILES is defined the module param num_buffers 22 * sets the number of pipeline buffers (length of the fsg_buffhd array). 23 * The valid range of num_buffers is: num >= 2 && num <= 4. 24 */ 25 26 #include <linux/module.h> 27 #include <linux/blkdev.h> 28 #include <linux/file.h> 29 #include <linux/fs.h> 30 #include <linux/usb/composite.h> 31 32 #include "storage_common.h" 33 34 /* There is only one interface. */ 35 36 struct usb_interface_descriptor fsg_intf_desc = { 37 .bLength = sizeof fsg_intf_desc, 38 .bDescriptorType = USB_DT_INTERFACE, 39 40 .bNumEndpoints = 2, /* Adjusted during fsg_bind() */ 41 .bInterfaceClass = USB_CLASS_MASS_STORAGE, 42 .bInterfaceSubClass = USB_SC_SCSI, /* Adjusted during fsg_bind() */ 43 .bInterfaceProtocol = USB_PR_BULK, /* Adjusted during fsg_bind() */ 44 .iInterface = FSG_STRING_INTERFACE, 45 }; 46 EXPORT_SYMBOL_GPL(fsg_intf_desc); 47 48 /* 49 * Three full-speed endpoint descriptors: bulk-in, bulk-out, and 50 * interrupt-in. 51 */ 52 53 struct usb_endpoint_descriptor fsg_fs_bulk_in_desc = { 54 .bLength = USB_DT_ENDPOINT_SIZE, 55 .bDescriptorType = USB_DT_ENDPOINT, 56 57 .bEndpointAddress = USB_DIR_IN, 58 .bmAttributes = USB_ENDPOINT_XFER_BULK, 59 /* wMaxPacketSize set by autoconfiguration */ 60 }; 61 EXPORT_SYMBOL_GPL(fsg_fs_bulk_in_desc); 62 63 struct usb_endpoint_descriptor fsg_fs_bulk_out_desc = { 64 .bLength = USB_DT_ENDPOINT_SIZE, 65 .bDescriptorType = USB_DT_ENDPOINT, 66 67 .bEndpointAddress = USB_DIR_OUT, 68 .bmAttributes = USB_ENDPOINT_XFER_BULK, 69 /* wMaxPacketSize set by autoconfiguration */ 70 }; 71 EXPORT_SYMBOL_GPL(fsg_fs_bulk_out_desc); 72 73 struct usb_descriptor_header *fsg_fs_function[] = { 74 (struct usb_descriptor_header *) &fsg_intf_desc, 75 (struct usb_descriptor_header *) &fsg_fs_bulk_in_desc, 76 (struct usb_descriptor_header *) &fsg_fs_bulk_out_desc, 77 NULL, 78 }; 79 EXPORT_SYMBOL_GPL(fsg_fs_function); 80 81 82 /* 83 * USB 2.0 devices need to expose both high speed and full speed 84 * descriptors, unless they only run at full speed. 85 * 86 * That means alternate endpoint descriptors (bigger packets). 87 */ 88 struct usb_endpoint_descriptor fsg_hs_bulk_in_desc = { 89 .bLength = USB_DT_ENDPOINT_SIZE, 90 .bDescriptorType = USB_DT_ENDPOINT, 91 92 /* bEndpointAddress copied from fs_bulk_in_desc during fsg_bind() */ 93 .bmAttributes = USB_ENDPOINT_XFER_BULK, 94 .wMaxPacketSize = cpu_to_le16(512), 95 }; 96 EXPORT_SYMBOL_GPL(fsg_hs_bulk_in_desc); 97 98 struct usb_endpoint_descriptor fsg_hs_bulk_out_desc = { 99 .bLength = USB_DT_ENDPOINT_SIZE, 100 .bDescriptorType = USB_DT_ENDPOINT, 101 102 /* bEndpointAddress copied from fs_bulk_out_desc during fsg_bind() */ 103 .bmAttributes = USB_ENDPOINT_XFER_BULK, 104 .wMaxPacketSize = cpu_to_le16(512), 105 .bInterval = 1, /* NAK every 1 uframe */ 106 }; 107 EXPORT_SYMBOL_GPL(fsg_hs_bulk_out_desc); 108 109 110 struct usb_descriptor_header *fsg_hs_function[] = { 111 (struct usb_descriptor_header *) &fsg_intf_desc, 112 (struct usb_descriptor_header *) &fsg_hs_bulk_in_desc, 113 (struct usb_descriptor_header *) &fsg_hs_bulk_out_desc, 114 NULL, 115 }; 116 EXPORT_SYMBOL_GPL(fsg_hs_function); 117 118 struct usb_endpoint_descriptor fsg_ss_bulk_in_desc = { 119 .bLength = USB_DT_ENDPOINT_SIZE, 120 .bDescriptorType = USB_DT_ENDPOINT, 121 122 /* bEndpointAddress copied from fs_bulk_in_desc during fsg_bind() */ 123 .bmAttributes = USB_ENDPOINT_XFER_BULK, 124 .wMaxPacketSize = cpu_to_le16(1024), 125 }; 126 EXPORT_SYMBOL_GPL(fsg_ss_bulk_in_desc); 127 128 struct usb_ss_ep_comp_descriptor fsg_ss_bulk_in_comp_desc = { 129 .bLength = sizeof(fsg_ss_bulk_in_comp_desc), 130 .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, 131 132 /*.bMaxBurst = DYNAMIC, */ 133 }; 134 EXPORT_SYMBOL_GPL(fsg_ss_bulk_in_comp_desc); 135 136 struct usb_endpoint_descriptor fsg_ss_bulk_out_desc = { 137 .bLength = USB_DT_ENDPOINT_SIZE, 138 .bDescriptorType = USB_DT_ENDPOINT, 139 140 /* bEndpointAddress copied from fs_bulk_out_desc during fsg_bind() */ 141 .bmAttributes = USB_ENDPOINT_XFER_BULK, 142 .wMaxPacketSize = cpu_to_le16(1024), 143 }; 144 EXPORT_SYMBOL_GPL(fsg_ss_bulk_out_desc); 145 146 struct usb_ss_ep_comp_descriptor fsg_ss_bulk_out_comp_desc = { 147 .bLength = sizeof(fsg_ss_bulk_in_comp_desc), 148 .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, 149 150 /*.bMaxBurst = DYNAMIC, */ 151 }; 152 EXPORT_SYMBOL_GPL(fsg_ss_bulk_out_comp_desc); 153 154 struct usb_descriptor_header *fsg_ss_function[] = { 155 (struct usb_descriptor_header *) &fsg_intf_desc, 156 (struct usb_descriptor_header *) &fsg_ss_bulk_in_desc, 157 (struct usb_descriptor_header *) &fsg_ss_bulk_in_comp_desc, 158 (struct usb_descriptor_header *) &fsg_ss_bulk_out_desc, 159 (struct usb_descriptor_header *) &fsg_ss_bulk_out_comp_desc, 160 NULL, 161 }; 162 EXPORT_SYMBOL_GPL(fsg_ss_function); 163 164 165 /*-------------------------------------------------------------------------*/ 166 167 /* 168 * If the next two routines are called while the gadget is registered, 169 * the caller must own fsg->filesem for writing. 170 */ 171 172 void fsg_lun_close(struct fsg_lun *curlun) 173 { 174 if (curlun->filp) { 175 LDBG(curlun, "close backing file\n"); 176 fput(curlun->filp); 177 curlun->filp = NULL; 178 } 179 } 180 EXPORT_SYMBOL_GPL(fsg_lun_close); 181 182 int fsg_lun_open(struct fsg_lun *curlun, const char *filename) 183 { 184 int ro; 185 struct file *filp = NULL; 186 int rc = -EINVAL; 187 struct inode *inode = NULL; 188 loff_t size; 189 loff_t num_sectors; 190 loff_t min_sectors; 191 unsigned int blkbits; 192 unsigned int blksize; 193 194 /* R/W if we can, R/O if we must */ 195 ro = curlun->initially_ro; 196 if (!ro) { 197 filp = filp_open(filename, O_RDWR | O_LARGEFILE, 0); 198 if (PTR_ERR(filp) == -EROFS || PTR_ERR(filp) == -EACCES) 199 ro = 1; 200 } 201 if (ro) 202 filp = filp_open(filename, O_RDONLY | O_LARGEFILE, 0); 203 if (IS_ERR(filp)) { 204 LINFO(curlun, "unable to open backing file: %s\n", filename); 205 return PTR_ERR(filp); 206 } 207 208 if (!(filp->f_mode & FMODE_WRITE)) 209 ro = 1; 210 211 inode = file_inode(filp); 212 if ((!S_ISREG(inode->i_mode) && !S_ISBLK(inode->i_mode))) { 213 LINFO(curlun, "invalid file type: %s\n", filename); 214 goto out; 215 } 216 217 /* 218 * If we can't read the file, it's no good. 219 * If we can't write the file, use it read-only. 220 */ 221 if (!(filp->f_mode & FMODE_CAN_READ)) { 222 LINFO(curlun, "file not readable: %s\n", filename); 223 goto out; 224 } 225 if (!(filp->f_mode & FMODE_CAN_WRITE)) 226 ro = 1; 227 228 size = i_size_read(inode->i_mapping->host); 229 if (size < 0) { 230 LINFO(curlun, "unable to find file size: %s\n", filename); 231 rc = (int) size; 232 goto out; 233 } 234 235 if (curlun->cdrom) { 236 blksize = 2048; 237 blkbits = 11; 238 } else if (inode->i_bdev) { 239 blksize = bdev_logical_block_size(inode->i_bdev); 240 blkbits = blksize_bits(blksize); 241 } else { 242 blksize = 512; 243 blkbits = 9; 244 } 245 246 num_sectors = size >> blkbits; /* File size in logic-block-size blocks */ 247 min_sectors = 1; 248 if (curlun->cdrom) { 249 min_sectors = 300; /* Smallest track is 300 frames */ 250 if (num_sectors >= 256*60*75) { 251 num_sectors = 256*60*75 - 1; 252 LINFO(curlun, "file too big: %s\n", filename); 253 LINFO(curlun, "using only first %d blocks\n", 254 (int) num_sectors); 255 } 256 } 257 if (num_sectors < min_sectors) { 258 LINFO(curlun, "file too small: %s\n", filename); 259 rc = -ETOOSMALL; 260 goto out; 261 } 262 263 if (fsg_lun_is_open(curlun)) 264 fsg_lun_close(curlun); 265 266 curlun->blksize = blksize; 267 curlun->blkbits = blkbits; 268 curlun->ro = ro; 269 curlun->filp = filp; 270 curlun->file_length = size; 271 curlun->num_sectors = num_sectors; 272 LDBG(curlun, "open backing file: %s\n", filename); 273 return 0; 274 275 out: 276 fput(filp); 277 return rc; 278 } 279 EXPORT_SYMBOL_GPL(fsg_lun_open); 280 281 282 /*-------------------------------------------------------------------------*/ 283 284 /* 285 * Sync the file data, don't bother with the metadata. 286 * This code was copied from fs/buffer.c:sys_fdatasync(). 287 */ 288 int fsg_lun_fsync_sub(struct fsg_lun *curlun) 289 { 290 struct file *filp = curlun->filp; 291 292 if (curlun->ro || !filp) 293 return 0; 294 return vfs_fsync(filp, 1); 295 } 296 EXPORT_SYMBOL_GPL(fsg_lun_fsync_sub); 297 298 void store_cdrom_address(u8 *dest, int msf, u32 addr) 299 { 300 if (msf) { 301 /* Convert to Minutes-Seconds-Frames */ 302 addr >>= 2; /* Convert to 2048-byte frames */ 303 addr += 2*75; /* Lead-in occupies 2 seconds */ 304 dest[3] = addr % 75; /* Frames */ 305 addr /= 75; 306 dest[2] = addr % 60; /* Seconds */ 307 addr /= 60; 308 dest[1] = addr; /* Minutes */ 309 dest[0] = 0; /* Reserved */ 310 } else { 311 /* Absolute sector */ 312 put_unaligned_be32(addr, dest); 313 } 314 } 315 EXPORT_SYMBOL_GPL(store_cdrom_address); 316 317 /*-------------------------------------------------------------------------*/ 318 319 320 ssize_t fsg_show_ro(struct fsg_lun *curlun, char *buf) 321 { 322 return sprintf(buf, "%d\n", fsg_lun_is_open(curlun) 323 ? curlun->ro 324 : curlun->initially_ro); 325 } 326 EXPORT_SYMBOL_GPL(fsg_show_ro); 327 328 ssize_t fsg_show_nofua(struct fsg_lun *curlun, char *buf) 329 { 330 return sprintf(buf, "%u\n", curlun->nofua); 331 } 332 EXPORT_SYMBOL_GPL(fsg_show_nofua); 333 334 ssize_t fsg_show_file(struct fsg_lun *curlun, struct rw_semaphore *filesem, 335 char *buf) 336 { 337 char *p; 338 ssize_t rc; 339 340 down_read(filesem); 341 if (fsg_lun_is_open(curlun)) { /* Get the complete pathname */ 342 p = file_path(curlun->filp, buf, PAGE_SIZE - 1); 343 if (IS_ERR(p)) 344 rc = PTR_ERR(p); 345 else { 346 rc = strlen(p); 347 memmove(buf, p, rc); 348 buf[rc] = '\n'; /* Add a newline */ 349 buf[++rc] = 0; 350 } 351 } else { /* No file, return 0 bytes */ 352 *buf = 0; 353 rc = 0; 354 } 355 up_read(filesem); 356 return rc; 357 } 358 EXPORT_SYMBOL_GPL(fsg_show_file); 359 360 ssize_t fsg_show_cdrom(struct fsg_lun *curlun, char *buf) 361 { 362 return sprintf(buf, "%u\n", curlun->cdrom); 363 } 364 EXPORT_SYMBOL_GPL(fsg_show_cdrom); 365 366 ssize_t fsg_show_removable(struct fsg_lun *curlun, char *buf) 367 { 368 return sprintf(buf, "%u\n", curlun->removable); 369 } 370 EXPORT_SYMBOL_GPL(fsg_show_removable); 371 372 ssize_t fsg_show_inquiry_string(struct fsg_lun *curlun, char *buf) 373 { 374 return sprintf(buf, "%s\n", curlun->inquiry_string); 375 } 376 EXPORT_SYMBOL_GPL(fsg_show_inquiry_string); 377 378 /* 379 * The caller must hold fsg->filesem for reading when calling this function. 380 */ 381 static ssize_t _fsg_store_ro(struct fsg_lun *curlun, bool ro) 382 { 383 if (fsg_lun_is_open(curlun)) { 384 LDBG(curlun, "read-only status change prevented\n"); 385 return -EBUSY; 386 } 387 388 curlun->ro = ro; 389 curlun->initially_ro = ro; 390 LDBG(curlun, "read-only status set to %d\n", curlun->ro); 391 392 return 0; 393 } 394 395 ssize_t fsg_store_ro(struct fsg_lun *curlun, struct rw_semaphore *filesem, 396 const char *buf, size_t count) 397 { 398 ssize_t rc; 399 bool ro; 400 401 rc = strtobool(buf, &ro); 402 if (rc) 403 return rc; 404 405 /* 406 * Allow the write-enable status to change only while the 407 * backing file is closed. 408 */ 409 down_read(filesem); 410 rc = _fsg_store_ro(curlun, ro); 411 if (!rc) 412 rc = count; 413 up_read(filesem); 414 415 return rc; 416 } 417 EXPORT_SYMBOL_GPL(fsg_store_ro); 418 419 ssize_t fsg_store_nofua(struct fsg_lun *curlun, const char *buf, size_t count) 420 { 421 bool nofua; 422 int ret; 423 424 ret = strtobool(buf, &nofua); 425 if (ret) 426 return ret; 427 428 /* Sync data when switching from async mode to sync */ 429 if (!nofua && curlun->nofua) 430 fsg_lun_fsync_sub(curlun); 431 432 curlun->nofua = nofua; 433 434 return count; 435 } 436 EXPORT_SYMBOL_GPL(fsg_store_nofua); 437 438 ssize_t fsg_store_file(struct fsg_lun *curlun, struct rw_semaphore *filesem, 439 const char *buf, size_t count) 440 { 441 int rc = 0; 442 443 if (curlun->prevent_medium_removal && fsg_lun_is_open(curlun)) { 444 LDBG(curlun, "eject attempt prevented\n"); 445 return -EBUSY; /* "Door is locked" */ 446 } 447 448 /* Remove a trailing newline */ 449 if (count > 0 && buf[count-1] == '\n') 450 ((char *) buf)[count-1] = 0; /* Ugh! */ 451 452 /* Load new medium */ 453 down_write(filesem); 454 if (count > 0 && buf[0]) { 455 /* fsg_lun_open() will close existing file if any. */ 456 rc = fsg_lun_open(curlun, buf); 457 if (rc == 0) 458 curlun->unit_attention_data = 459 SS_NOT_READY_TO_READY_TRANSITION; 460 } else if (fsg_lun_is_open(curlun)) { 461 fsg_lun_close(curlun); 462 curlun->unit_attention_data = SS_MEDIUM_NOT_PRESENT; 463 } 464 up_write(filesem); 465 return (rc < 0 ? rc : count); 466 } 467 EXPORT_SYMBOL_GPL(fsg_store_file); 468 469 ssize_t fsg_store_cdrom(struct fsg_lun *curlun, struct rw_semaphore *filesem, 470 const char *buf, size_t count) 471 { 472 bool cdrom; 473 int ret; 474 475 ret = strtobool(buf, &cdrom); 476 if (ret) 477 return ret; 478 479 down_read(filesem); 480 ret = cdrom ? _fsg_store_ro(curlun, true) : 0; 481 482 if (!ret) { 483 curlun->cdrom = cdrom; 484 ret = count; 485 } 486 up_read(filesem); 487 488 return ret; 489 } 490 EXPORT_SYMBOL_GPL(fsg_store_cdrom); 491 492 ssize_t fsg_store_removable(struct fsg_lun *curlun, const char *buf, 493 size_t count) 494 { 495 bool removable; 496 int ret; 497 498 ret = strtobool(buf, &removable); 499 if (ret) 500 return ret; 501 502 curlun->removable = removable; 503 504 return count; 505 } 506 EXPORT_SYMBOL_GPL(fsg_store_removable); 507 508 ssize_t fsg_store_inquiry_string(struct fsg_lun *curlun, const char *buf, 509 size_t count) 510 { 511 const size_t len = min(count, sizeof(curlun->inquiry_string)); 512 513 if (len == 0 || buf[0] == '\n') { 514 curlun->inquiry_string[0] = 0; 515 } else { 516 snprintf(curlun->inquiry_string, 517 sizeof(curlun->inquiry_string), "%-28s", buf); 518 if (curlun->inquiry_string[len-1] == '\n') 519 curlun->inquiry_string[len-1] = ' '; 520 } 521 522 return count; 523 } 524 EXPORT_SYMBOL_GPL(fsg_store_inquiry_string); 525 526 MODULE_LICENSE("GPL"); 527