libata-zpodd.c 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. #include <linux/libata.h>
  2. #include <linux/cdrom.h>
  3. #include "libata.h"
  4. enum odd_mech_type {
  5. ODD_MECH_TYPE_SLOT,
  6. ODD_MECH_TYPE_DRAWER,
  7. ODD_MECH_TYPE_UNSUPPORTED,
  8. };
  9. struct zpodd {
  10. enum odd_mech_type mech_type; /* init during probe, RO afterwards */
  11. struct ata_device *dev;
  12. };
  13. /* Per the spec, only slot type and drawer type ODD can be supported */
  14. static enum odd_mech_type zpodd_get_mech_type(struct ata_device *dev)
  15. {
  16. char buf[16];
  17. unsigned int ret;
  18. struct rm_feature_desc *desc = (void *)(buf + 8);
  19. struct ata_taskfile tf = {};
  20. char cdb[] = { GPCMD_GET_CONFIGURATION,
  21. 2, /* only 1 feature descriptor requested */
  22. 0, 3, /* 3, removable medium feature */
  23. 0, 0, 0,/* reserved */
  24. 0, sizeof(buf),
  25. 0, 0, 0,
  26. };
  27. tf.flags = ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
  28. tf.command = ATA_CMD_PACKET;
  29. tf.protocol = ATAPI_PROT_PIO;
  30. tf.lbam = sizeof(buf);
  31. ret = ata_exec_internal(dev, &tf, cdb, DMA_FROM_DEVICE,
  32. buf, sizeof(buf), 0);
  33. if (ret)
  34. return ODD_MECH_TYPE_UNSUPPORTED;
  35. if (be16_to_cpu(desc->feature_code) != 3)
  36. return ODD_MECH_TYPE_UNSUPPORTED;
  37. if (desc->mech_type == 0 && desc->load == 0 && desc->eject == 1)
  38. return ODD_MECH_TYPE_SLOT;
  39. else if (desc->mech_type == 1 && desc->load == 0 && desc->eject == 1)
  40. return ODD_MECH_TYPE_DRAWER;
  41. else
  42. return ODD_MECH_TYPE_UNSUPPORTED;
  43. }
  44. static bool odd_can_poweroff(struct ata_device *ata_dev)
  45. {
  46. acpi_handle handle;
  47. acpi_status status;
  48. struct acpi_device *acpi_dev;
  49. handle = ata_dev_acpi_handle(ata_dev);
  50. if (!handle)
  51. return false;
  52. status = acpi_bus_get_device(handle, &acpi_dev);
  53. if (ACPI_FAILURE(status))
  54. return false;
  55. return acpi_device_can_poweroff(acpi_dev);
  56. }
  57. void zpodd_init(struct ata_device *dev)
  58. {
  59. enum odd_mech_type mech_type;
  60. struct zpodd *zpodd;
  61. if (dev->zpodd)
  62. return;
  63. if (!odd_can_poweroff(dev))
  64. return;
  65. mech_type = zpodd_get_mech_type(dev);
  66. if (mech_type == ODD_MECH_TYPE_UNSUPPORTED)
  67. return;
  68. zpodd = kzalloc(sizeof(struct zpodd), GFP_KERNEL);
  69. if (!zpodd)
  70. return;
  71. zpodd->mech_type = mech_type;
  72. zpodd->dev = dev;
  73. dev->zpodd = zpodd;
  74. }
  75. void zpodd_exit(struct ata_device *dev)
  76. {
  77. kfree(dev->zpodd);
  78. dev->zpodd = NULL;
  79. }