📄 shuttle_usbat.c
字号:
} US_DEBUGP("Bummer! %s bulk data 20 times failed.\n", direction==SCSI_DATA_WRITE ? "Writing" : "Reading"); return USB_STOR_TRANSPORT_FAILED;}/* * Write data to multiple registers at once. Not meant for large * transfers of data! */int usbat_multiple_write(struct us_data *us, unsigned char access, unsigned char *registers, unsigned char *data_out, unsigned short num_registers) { int result; unsigned char data[num_registers*2]; int i; unsigned char command[8] = { 0x40, access|0x07, 0x00, 0x00, 0x00, 0x00, LSB_of(num_registers*2), MSB_of(num_registers*2) }; for (i=0; i<num_registers; i++) { data[i<<1] = registers[i]; data[1+(i<<1)] = data_out[i]; } result = usbat_send_control(us, usb_sndctrlpipe(us->pusb_dev,0), 0x80, 0x40, 0, 0, command, 8); if (result != USB_STOR_TRANSPORT_GOOD) return result; result = usbat_bulk_transport(us, NULL, 0, SCSI_DATA_WRITE, data, num_registers*2, 0); if (result!=USB_STOR_TRANSPORT_GOOD) return result; return usbat_wait_not_busy(us, 0);}int usbat_read_user_io(struct us_data *us, unsigned char *data_flags) { int result; result = usbat_send_control(us, usb_rcvctrlpipe(us->pusb_dev,0), 0x82, 0xC0, 0, 0, data_flags, 1); return result;}int usbat_write_user_io(struct us_data *us, unsigned char enable_flags, unsigned char data_flags) { int result; result = usbat_send_control(us, usb_sndctrlpipe(us->pusb_dev,0), 0x82, 0x40, short_pack(enable_flags, data_flags), 0, NULL, 0); return result;}/* * Squeeze a potentially huge (> 65535 byte) read10 command into * a little ( <= 65535 byte) ATAPI pipe */int usbat_handle_read10(struct us_data *us, unsigned char *registers, unsigned char *data, Scsi_Cmnd *srb) { int result = USB_STOR_TRANSPORT_GOOD; unsigned char *buffer; unsigned int len; unsigned int sector; unsigned int amount; struct scatterlist *sg = NULL; int sg_segment = 0; int sg_offset = 0; US_DEBUGP("handle_read10: transfersize %d\n", srb->transfersize); if (srb->request_bufflen < 0x10000) { result = usbat_rw_block_test(us, USBAT_ATA, registers, data, 19, 0x10, 0x17, 0xFD, 0x30, SCSI_DATA_READ, srb->request_buffer, srb->request_bufflen, srb->use_sg, 1); return result; } /* * Since we're requesting more data than we can handle in * a single read command (max is 64k-1), we will perform * multiple reads, but each read must be in multiples of * a sector. Luckily the sector size is in srb->transfersize * (see linux/drivers/scsi/sr.c). */ if (data[7+0] == GPCMD_READ_CD) { len = short_pack(data[7+9], data[7+8]); len <<= 16; len |= data[7+7]; US_DEBUGP("handle_read10: GPCMD_READ_CD: len %d\n", len); srb->transfersize = srb->request_bufflen/len; } if (!srb->transfersize) { srb->transfersize = 2048; /* A guess */ US_DEBUGP("handle_read10: transfersize 0, forcing %d\n", srb->transfersize); } len = (65535/srb->transfersize) * srb->transfersize; US_DEBUGP("Max read is %d bytes\n", len); buffer = kmalloc(len, GFP_NOIO); if (buffer == NULL) // bloody hell! return USB_STOR_TRANSPORT_FAILED; sector = short_pack(data[7+3], data[7+2]); sector <<= 16; sector |= short_pack(data[7+5], data[7+4]); transferred = 0; if (srb->use_sg) { sg = (struct scatterlist *)srb->request_buffer; sg_segment = 0; // for keeping track of where we are in sg_offset = 0; // the scatter/gather list } while (transferred != srb->request_bufflen) { if (len > srb->request_bufflen - transferred) len = srb->request_bufflen - transferred; data[3] = len&0xFF; // (cylL) = expected length (L) data[4] = (len>>8)&0xFF; // (cylH) = expected length (H) // Fix up the SCSI command sector and num sectors data[7+2] = MSB_of(sector>>16); // SCSI command sector data[7+3] = LSB_of(sector>>16); data[7+4] = MSB_of(sector&0xFFFF); data[7+5] = LSB_of(sector&0xFFFF); if (data[7+0] == GPCMD_READ_CD) data[7+6] = 0; data[7+7] = MSB_of(len / srb->transfersize); // SCSI command data[7+8] = LSB_of(len / srb->transfersize); // num sectors result = usbat_rw_block_test(us, USBAT_ATA, registers, data, 19, 0x10, 0x17, 0xFD, 0x30, SCSI_DATA_READ, buffer, len, 0, 1); if (result != USB_STOR_TRANSPORT_GOOD) break; // Transfer the received data into the srb buffer if (!srb->use_sg) { memcpy(srb->request_buffer+transferred, buffer, len); } else { amount = 0; while (amount<len) { if (len - amount >= sg[sg_segment].length-sg_offset) { memcpy(sg[sg_segment].address + sg_offset, buffer + amount, sg[sg_segment].length - sg_offset); amount += sg[sg_segment].length-sg_offset; sg_segment++; sg_offset=0; } else { memcpy(sg[sg_segment].address + sg_offset, buffer + amount, len - amount); sg_offset += (len - amount); amount = len; } } } // Update the amount transferred and the sector number transferred += len; sector += len / srb->transfersize; } // while transferred != srb->request_bufflen kfree(buffer); return result;}static int hp_8200e_select_and_test_registers(struct us_data *us) { int result; int selector; unsigned char status; // try device = master, then device = slave. for (selector = 0xA0; selector <= 0xB0; selector += 0x10) { if ( (result = usbat_write(us, USBAT_ATA, 0x16, selector)) != USB_STOR_TRANSPORT_GOOD) return result; if ( (result = usbat_read(us, USBAT_ATA, 0x17, &status)) != USB_STOR_TRANSPORT_GOOD) return result; if ( (result = usbat_read(us, USBAT_ATA, 0x16, &status)) != USB_STOR_TRANSPORT_GOOD) return result; if ( (result = usbat_read(us, USBAT_ATA, 0x14, &status)) != USB_STOR_TRANSPORT_GOOD) return result; if ( (result = usbat_read(us, USBAT_ATA, 0x15, &status)) != USB_STOR_TRANSPORT_GOOD) return result; if ( (result = usbat_write(us, USBAT_ATA, 0x14, 0x55)) != USB_STOR_TRANSPORT_GOOD) return result; if ( (result = usbat_write(us, USBAT_ATA, 0x15, 0xAA)) != USB_STOR_TRANSPORT_GOOD) return result; if ( (result = usbat_read(us, USBAT_ATA, 0x14, &status)) != USB_STOR_TRANSPORT_GOOD) return result; if ( (result = usbat_read(us, USBAT_ATA, 0x15, &status)) != USB_STOR_TRANSPORT_GOOD) return result; } return result;}int init_8200e(struct us_data *us) { int result; unsigned char status; // Enable peripheral control signals if ( (result = usbat_write_user_io(us, USBAT_UIO_OE1 | USBAT_UIO_OE0, USBAT_UIO_EPAD | USBAT_UIO_1)) != USB_STOR_TRANSPORT_GOOD) return result; US_DEBUGP("INIT 1\n"); wait_ms(2000); if ( (result = usbat_read_user_io(us, &status)) != USB_STOR_TRANSPORT_GOOD) return result; US_DEBUGP("INIT 2\n"); if ( (result = usbat_read_user_io(us, &status)) != USB_STOR_TRANSPORT_GOOD) return result; US_DEBUGP("INIT 3\n"); // Reset peripheral, enable periph control signals // (bring reset signal up) if ( (result = usbat_write_user_io(us, USBAT_UIO_DRVRST | USBAT_UIO_OE1 | USBAT_UIO_OE0, USBAT_UIO_EPAD | USBAT_UIO_1)) != USB_STOR_TRANSPORT_GOOD) return result; US_DEBUGP("INIT 4\n"); // Enable periph control signals // (bring reset signal down) if ( (result = usbat_write_user_io(us, USBAT_UIO_OE1 | USBAT_UIO_OE0, USBAT_UIO_EPAD | USBAT_UIO_1)) != USB_STOR_TRANSPORT_GOOD) return result; US_DEBUGP("INIT 5\n"); wait_ms(250); // Write 0x80 to ISA port 0x3F if ( (result = usbat_write(us, USBAT_ISA, 0x3F, 0x80)) != USB_STOR_TRANSPORT_GOOD) return result; US_DEBUGP("INIT 6\n"); // Read ISA port 0x27 if ( (result = usbat_read(us, USBAT_ISA, 0x27, &status)) != USB_STOR_TRANSPORT_GOOD) return result; US_DEBUGP("INIT 7\n"); if ( (result = usbat_read_user_io(us, &status)) != USB_STOR_TRANSPORT_GOOD) return result; US_DEBUGP("INIT 8\n"); if ( (result = hp_8200e_select_and_test_registers(us)) != USB_STOR_TRANSPORT_GOOD) return result; US_DEBUGP("INIT 9\n"); if ( (result = usbat_read_user_io(us, &status)) != USB_STOR_TRANSPORT_GOOD) return result; US_DEBUGP("INIT 10\n"); // Enable periph control signals and card detect if ( (result = usbat_write_user_io(us, USBAT_UIO_ACKD |USBAT_UIO_OE1 | USBAT_UIO_OE0, USBAT_UIO_EPAD | USBAT_UIO_1)) != USB_STOR_TRANSPORT_GOOD) return result; US_DEBUGP("INIT 11\n"); if ( (result = usbat_read_user_io(us, &status)) != USB_STOR_TRANSPORT_GOOD) return result; US_DEBUGP("INIT 12\n"); wait_ms(1400); if ( (result = usbat_read_user_io(us, &status)) != USB_STOR_TRANSPORT_GOOD) return result; US_DEBUGP("INIT 13\n"); if ( (result = hp_8200e_select_and_test_registers(us)) != USB_STOR_TRANSPORT_GOOD) return result; US_DEBUGP("INIT 14\n"); if ( (result = usbat_set_shuttle_features(us, 0x83, 0x00, 0x88, 0x08, 0x15, 0x14)) != USB_STOR_TRANSPORT_GOOD) return result; US_DEBUGP("INIT 15\n"); return result;}/* * Transport for the HP 8200e */int hp8200e_transport(Scsi_Cmnd *srb, struct us_data *us){ int result; unsigned char status; unsigned char registers[32]; unsigned char data[32]; unsigned int len; int i; char string[64]; len = srb->request_bufflen; /* Send A0 (ATA PACKET COMMAND). Note: I guess we're never going to get any of the ATA commands... just ATA Packet Commands. */ registers[0] = 0x11; registers[1] = 0x12; registers[2] = 0x13; registers[3] = 0x14; registers[4] = 0x15; registers[5] = 0x16; registers[6] = 0x17; data[0] = 0x00; data[1] = 0x00; data[2] = 0x00; data[3] = len&0xFF; // (cylL) = expected length (L) data[4] = (len>>8)&0xFF; // (cylH) = expected length (H) data[5] = 0xB0; // (device sel) = slave data[6] = 0xA0; // (command) = ATA PACKET COMMAND for (i=7; i<19; i++) { registers[i] = 0x10; data[i] = (i-7 >= srb->cmd_len) ? 0 : srb->cmnd[i-7]; } result = usbat_read(us, USBAT_ATA, 0x17, &status); US_DEBUGP("Status = %02X\n", status); if (srb->cmnd[0] == TEST_UNIT_READY) transferred = 0; if (srb->sc_data_direction == SCSI_DATA_WRITE) { result = usbat_rw_block_test(us, USBAT_ATA, registers, data, 19, 0x10, 0x17, 0xFD, 0x30, SCSI_DATA_WRITE, srb->request_buffer, len, srb->use_sg, 10); if (result == USB_STOR_TRANSPORT_GOOD) { transferred += len; US_DEBUGP("Wrote %08X bytes\n", transferred); } return result; } else if (srb->cmnd[0] == READ_10 || srb->cmnd[0] == GPCMD_READ_CD) { return usbat_handle_read10(us, registers, data, srb); } if (len > 0xFFFF) { US_DEBUGP("Error: len = %08X... what do I do now?\n", len); return USB_STOR_TRANSPORT_ERROR; } if ( (result = usbat_multiple_write(us, USBAT_ATA, registers, data, 7)) != USB_STOR_TRANSPORT_GOOD) { return result; } // Write the 12-byte command header. // If the command is BLANK then set the timer for 75 minutes. // Otherwise set it for 10 minutes. // NOTE: THE 8200 DOCUMENTATION STATES THAT BLANKING A CDRW // AT SPEED 4 IS UNRELIABLE!!! if ( (result = usbat_write_block(us, USBAT_ATA, 0x10, srb->cmnd, 12, 0, srb->cmnd[0]==GPCMD_BLANK ? 75 : 10)) != USB_STOR_TRANSPORT_GOOD) { return result; } // If there is response data to be read in // then do it here. if (len != 0 && (srb->sc_data_direction == SCSI_DATA_READ)) { // How many bytes to read in? Check cylL register if ( (result = usbat_read(us, USBAT_ATA, 0x14, &status)) != USB_STOR_TRANSPORT_GOOD) { return result; } if (len>0xFF) { // need to read cylH also len = status; if ( (result = usbat_read(us, USBAT_ATA, 0x15, &status)) != USB_STOR_TRANSPORT_GOOD) { return result; } len += ((unsigned int)status)<<8; } else len = status; result = usbat_read_block(us, USBAT_ATA, 0x10, srb->request_buffer, len, srb->use_sg); /* Debug-print the first 32 bytes of the transfer */ if (!srb->use_sg) { string[0] = 0; for (i=0; i<len && i<32; i++) { sprintf(string+strlen(string), "%02X ", ((unsigned char *)srb->request_buffer)[i]); if ((i%16)==15) { US_DEBUGP("%s\n", string); string[0] = 0; } } if (string[0]!=0) US_DEBUGP("%s\n", string); } } return result;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -