| | 1123 | /// Prolific USB Bridge support. (PL2773) (Probably works on PL2771 also...) |
| | 1124 | |
| | 1125 | class usbprolific_device |
| | 1126 | : public tunnelled_device< |
| | 1127 | /*implements*/ ata_device, |
| | 1128 | /*by tunnelling through a*/ scsi_device |
| | 1129 | > |
| | 1130 | { |
| | 1131 | public: |
| | 1132 | usbprolific_device(smart_interface * intf, scsi_device * scsidev, |
| | 1133 | const char * req_type); |
| | 1134 | |
| | 1135 | virtual ~usbprolific_device() throw(); |
| | 1136 | |
| | 1137 | virtual bool ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out); |
| | 1138 | }; |
| | 1139 | |
| | 1140 | |
| | 1141 | usbprolific_device::usbprolific_device(smart_interface * intf, scsi_device * scsidev, |
| | 1142 | const char * req_type) |
| | 1143 | : smart_device(intf, scsidev->get_dev_name(), "usbprolific", req_type), |
| | 1144 | tunnelled_device<ata_device, scsi_device>(scsidev) |
| | 1145 | { |
| | 1146 | set_info().info_name = strprintf("%s [USB Prolific]", scsidev->get_info_name()); |
| | 1147 | } |
| | 1148 | |
| | 1149 | usbprolific_device::~usbprolific_device() throw() |
| | 1150 | { |
| | 1151 | } |
| | 1152 | |
| | 1153 | bool usbprolific_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out) |
| | 1154 | { |
| | 1155 | if (!ata_cmd_is_supported(in, |
| | 1156 | // ata_device::supports_data_out | // Does not work - better disable for now |
| | 1157 | ata_device::supports_48bit_hi_null | |
| | 1158 | ata_device::supports_smart_status, |
| | 1159 | "Prolific" ) |
| | 1160 | ) |
| | 1161 | return false; |
| | 1162 | |
| | 1163 | scsi_cmnd_io io_hdr; |
| | 1164 | memset(&io_hdr, 0, sizeof(io_hdr)); |
| | 1165 | |
| | 1166 | switch (in.direction) { |
| | 1167 | case ata_cmd_in::no_data: |
| | 1168 | io_hdr.dxfer_dir = DXFER_NONE; |
| | 1169 | break; |
| | 1170 | case ata_cmd_in::data_in: |
| | 1171 | io_hdr.dxfer_dir = DXFER_FROM_DEVICE; |
| | 1172 | io_hdr.dxfer_len = in.size; |
| | 1173 | io_hdr.dxferp = (unsigned char *)in.buffer; |
| | 1174 | memset(in.buffer, 0, in.size); |
| | 1175 | break; |
| | 1176 | case ata_cmd_in::data_out: |
| | 1177 | io_hdr.dxfer_dir = DXFER_TO_DEVICE; |
| | 1178 | io_hdr.dxfer_len = in.size; |
| | 1179 | io_hdr.dxferp = (unsigned char *)in.buffer; |
| | 1180 | break; |
| | 1181 | default: |
| | 1182 | return set_err(EINVAL); |
| | 1183 | } |
| | 1184 | |
| | 1185 | // Based on reverse engineering of iSmart.exe with API Monitor. |
| | 1186 | // http://www.prolific.com.tw/US/supportDownload.aspx?FileType=56&FileID=88&pcid=84&Page=0 |
| | 1187 | // Seen commands: |
| | 1188 | // D0 0 0 0 06 7B 0 0 0 0 0 0 // Read Firmware info?, reads 16 bytes |
| | 1189 | // F4 0 0 0 06 7B // ?? |
| | 1190 | // D8 15 0 D8 06 7B 0 0 0 0 1 1 4F C2 A0 B0 // SMART Enable |
| | 1191 | // D8 15 0 D0 06 7B 0 0 2 0 1 1 4F C2 A0 B0 // SMART Read values |
| | 1192 | // D8 15 0 D1 06 7B 0 0 2 0 1 1 4F C2 A0 B0 // SMART Read thresholds |
| | 1193 | // D8 15 0 D4 06 7B 0 0 0 0 0 1 4F C2 A0 B0 // SMART Execute self test |
| | 1194 | // D7 0 0 0 06 7B 0 0 0 0 0 0 0 0 0 0 // Read status registers, Reads 16 bytes of data |
| | 1195 | |
| | 1196 | // Build pass through command |
| | 1197 | unsigned char cdb[16]; |
| | 1198 | cdb[ 0] = 0xD8; // Prolific ATA pass through? (OPERATION CODE) |
| | 1199 | cdb[ 1] = 0x15; // Magic? |
| | 1200 | cdb[ 2] = 0x0; // Always 0? |
| | 1201 | cdb[ 3] = in.in_regs.features; // SMART command |
| | 1202 | cdb[ 4] = 0x06; // VendorID magic? (Prolific VendorID: 0x067B) |
| | 1203 | cdb[ 5] = 0x7B; // VendorID magic? (Prolific VendorID: 0x067B) |
| | 1204 | cdb[ 6] = 0; // Always 0? |
| | 1205 | cdb[ 7] = 0; // Always 0? |
| | 1206 | cdb[ 8] = (unsigned char)(io_hdr.dxfer_len >> 8); // 2 when reading a sector |
| | 1207 | cdb[ 9] = (unsigned char)(io_hdr.dxfer_len ); // Always 0? - Seems ok |
| | 1208 | cdb[10] = in.in_regs.sector_count; // 0 when starting selftest |
| | 1209 | cdb[11] = in.in_regs.lba_low; // LBA(7:0) - Works for Log Address! |
| | 1210 | cdb[12] = in.in_regs.lba_mid; // LBA(15:8) - 0x4F |
| | 1211 | cdb[13] = in.in_regs.lba_high; // LBA(23:16) - 0xC2 |
| | 1212 | cdb[14] = 0xA0; // Is A0 for both drives attached |
| | 1213 | cdb[15] = in.in_regs.command; // ATA command |
| | 1214 | // Use '-r scsiioctl,1' to print CDB for debug purposes |
| | 1215 | |
| | 1216 | io_hdr.cmnd = cdb; |
| | 1217 | io_hdr.cmnd_len = 16; |
| | 1218 | |
| | 1219 | scsi_device * scsidev = get_tunnel_dev(); |
| | 1220 | if (!scsi_pass_through_and_check(scsidev, &io_hdr, |
| | 1221 | "usbprolific_device::ata_pass_through: ")) |
| | 1222 | return set_err(scsidev->get_err()); |
| | 1223 | |
| | 1224 | if (in.out_needed.is_set()) { |
| | 1225 | // Read ATA output registers |
| | 1226 | unsigned char regbuf[16] = {0, }; |
| | 1227 | memset(&io_hdr, 0, sizeof(io_hdr)); |
| | 1228 | io_hdr.dxfer_dir = DXFER_FROM_DEVICE; |
| | 1229 | io_hdr.dxfer_len = sizeof(regbuf); |
| | 1230 | io_hdr.dxferp = regbuf; |
| | 1231 | |
| | 1232 | memset(cdb, 0, sizeof(cdb)); |
| | 1233 | cdb[ 0] = 0xD7; // Prolific read registers? |
| | 1234 | cdb[ 4] = 0x06; // VendorID magic? (Prolific VendorID: 0x067B) |
| | 1235 | cdb[ 5] = 0x7B; // VendorID magic? (Prolific VendorID: 0x067B) |
| | 1236 | io_hdr.cmnd = cdb; |
| | 1237 | io_hdr.cmnd_len = sizeof(cdb); |
| | 1238 | |
| | 1239 | if (!scsi_pass_through_and_check(scsidev, &io_hdr, |
| | 1240 | "usbprolific_device::scsi_pass_through (get registers): ")) |
| | 1241 | return set_err(scsidev->get_err()); |
| | 1242 | |
| | 1243 | // Use '-r scsiioctl,2' to print input registers for debug purposes |
| | 1244 | // Example: 50 00 00 00 00 01 4f 00 c2 00 a0 da 00 b0 00 50 |
| | 1245 | // out.out_regs.status = regbuf[0]; // Guess: Was seen go 51 to indicate error |
| | 1246 | // out.out_regs.error = regbuf[1]; // Guess: Was seen go 04 to indicate ABRT |
| | 1247 | // out.out_regs.sector_count = regbuf[X]; // Not found... |
| | 1248 | out.out_regs.lba_low = regbuf[4]; // Found by testing Log Address |
| | 1249 | out.out_regs.lba_mid = regbuf[6]; // Needed for SMART STATUS |
| | 1250 | out.out_regs.lba_high = regbuf[8]; // Needed for SMART STATUS |
| | 1251 | out.out_regs.device = regbuf[10]; // Always A0? |
| | 1252 | // = regbuf[11]; // ATA Feature |
| | 1253 | // = regbuf[13]; // ATA Command |
| | 1254 | } |
| | 1255 | |
| | 1256 | return true; |
| | 1257 | } |
| | 1258 | |
| | 1259 | |
| | 1260 | ///////////////////////////////////////////////////////////////////////////// |
| | 1261 | |