shuttle_usbat.c
来自「底层驱动开发」· C语言 代码 · 共 1,680 行 · 第 1/3 页
C
1,680 行
command[6] = LSB_of(num_registers*2); command[7] = MSB_of(num_registers*2); // The setup command result = usbat_execute_command(us, command, 8); if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; // Create the reg/data, reg/data sequence for (i=0; i<num_registers; i++) { data[i<<1] = registers[i]; data[1+(i<<1)] = data_out[i]; } // Send the data result = usbat_bulk_write(us, data, num_registers*2); if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; if (usbat_get_device_type(us) == USBAT_DEV_HP8200) return usbat_wait_not_busy(us, 0); else return USB_STOR_TRANSPORT_GOOD;}/* * Conditionally read blocks from device: * Allows us to read blocks from a specific data register, based upon the * condition that a status register can be successfully masked with a status * qualifier. If this condition is not initially met, the read will wait * up until a maximum amount of time has elapsed, as specified by timeout. * The read will start when the condition is met, otherwise the command aborts. * * The qualifier defined here is not the value that is masked, it defines * conditions for the write to take place. The actual masked qualifier (and * other related details) are defined beforehand with _set_shuttle_features(). */static int usbat_read_blocks(struct us_data *us, unsigned char *buffer, int len){ int result; unsigned char *command = us->iobuf; command[0] = 0xC0; command[1] = USBAT_ATA | USBAT_CMD_COND_READ_BLOCK; command[2] = USBAT_ATA_DATA; command[3] = USBAT_ATA_STATUS; command[4] = 0xFD; // Timeout (ms); command[5] = USBAT_QUAL_FCQ; command[6] = LSB_of(len); command[7] = MSB_of(len); // Multiple block read setup command result = usbat_execute_command(us, command, 8); if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_FAILED; // Read the blocks we just asked for result = usbat_bulk_read(us, buffer, len); if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_FAILED; return USB_STOR_TRANSPORT_GOOD;}/* * Conditionally write blocks to device: * Allows us to write blocks to a specific data register, based upon the * condition that a status register can be successfully masked with a status * qualifier. If this condition is not initially met, the write will wait * up until a maximum amount of time has elapsed, as specified by timeout. * The read will start when the condition is met, otherwise the command aborts. * * The qualifier defined here is not the value that is masked, it defines * conditions for the write to take place. The actual masked qualifier (and * other related details) are defined beforehand with _set_shuttle_features(). */static int usbat_write_blocks(struct us_data *us, unsigned char *buffer, int len){ int result; unsigned char *command = us->iobuf; command[0] = 0x40; command[1] = USBAT_ATA | USBAT_CMD_COND_WRITE_BLOCK; command[2] = USBAT_ATA_DATA; command[3] = USBAT_ATA_STATUS; command[4] = 0xFD; // Timeout (ms) command[5] = USBAT_QUAL_FCQ; command[6] = LSB_of(len); command[7] = MSB_of(len); // Multiple block write setup command result = usbat_execute_command(us, command, 8); if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_FAILED; // Write the data result = usbat_bulk_write(us, buffer, len); if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_FAILED; return USB_STOR_TRANSPORT_GOOD;}/* * Read the User IO register */static int usbat_read_user_io(struct us_data *us, unsigned char *data_flags){ int result; result = usb_stor_ctrl_transfer(us, us->recv_ctrl_pipe, USBAT_CMD_UIO, 0xC0, 0, 0, data_flags, USBAT_UIO_READ); US_DEBUGP("usbat_read_user_io: UIO register reads %02X\n", (unsigned short) (*data_flags)); return result;}/* * Write to the User IO register */static int usbat_write_user_io(struct us_data *us, unsigned char enable_flags, unsigned char data_flags){ return usb_stor_ctrl_transfer(us, us->send_ctrl_pipe, USBAT_CMD_UIO, 0x40, short_pack(enable_flags, data_flags), 0, NULL, USBAT_UIO_WRITE);}/* * Reset the device * Often needed on media change. */static int usbat_device_reset(struct us_data *us){ int rc; // Reset peripheral, enable peripheral control signals // (bring reset signal up) rc = usbat_write_user_io(us, USBAT_UIO_DRVRST | USBAT_UIO_OE1 | USBAT_UIO_OE0, USBAT_UIO_EPAD | USBAT_UIO_1); if (rc != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; // Enable peripheral control signals // (bring reset signal down) rc = usbat_write_user_io(us, USBAT_UIO_OE1 | USBAT_UIO_OE0, USBAT_UIO_EPAD | USBAT_UIO_1); if (rc != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; return USB_STOR_TRANSPORT_GOOD;}/* * Enable card detect */static int usbat_device_enable_cdt(struct us_data *us){ int rc; // Enable peripheral control signals and card detect rc = usbat_write_user_io(us, USBAT_UIO_ACKD | USBAT_UIO_OE1 | USBAT_UIO_OE0, USBAT_UIO_EPAD | USBAT_UIO_1); if (rc != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; return USB_STOR_TRANSPORT_GOOD;}/* * Determine if media is present. */static int usbat_flash_check_media_present(unsigned char *uio){ if (*uio & USBAT_UIO_UI0) { US_DEBUGP("usbat_flash_check_media_present: no media detected\n"); return USBAT_FLASH_MEDIA_NONE; } return USBAT_FLASH_MEDIA_CF;}/* * Determine if media has changed since last operation */static int usbat_flash_check_media_changed(unsigned char *uio){ if (*uio & USBAT_UIO_0) { US_DEBUGP("usbat_flash_check_media_changed: media change detected\n"); return USBAT_FLASH_MEDIA_CHANGED; } return USBAT_FLASH_MEDIA_SAME;}/* * Check for media change / no media and handle the situation appropriately */static int usbat_flash_check_media(struct us_data *us, struct usbat_info *info){ int rc; unsigned char *uio = us->iobuf; rc = usbat_read_user_io(us, uio); if (rc != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; // Check for media existence rc = usbat_flash_check_media_present(uio); if (rc == USBAT_FLASH_MEDIA_NONE) { info->sense_key = 0x02; info->sense_asc = 0x3A; info->sense_ascq = 0x00; return USB_STOR_TRANSPORT_FAILED; } // Check for media change rc = usbat_flash_check_media_changed(uio); if (rc == USBAT_FLASH_MEDIA_CHANGED) { // Reset and re-enable card detect rc = usbat_device_reset(us); if (rc != USB_STOR_TRANSPORT_GOOD) return rc; rc = usbat_device_enable_cdt(us); if (rc != USB_STOR_TRANSPORT_GOOD) return rc; msleep(50); rc = usbat_read_user_io(us, uio); if (rc != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; info->sense_key = UNIT_ATTENTION; info->sense_asc = 0x28; info->sense_ascq = 0x00; return USB_STOR_TRANSPORT_FAILED; } return USB_STOR_TRANSPORT_GOOD;}/* * Determine whether we are controlling a flash-based reader/writer, * or a HP8200-based CD drive. * Sets transport functions as appropriate. */static int usbat_identify_device(struct us_data *us, struct usbat_info *info){ int rc; unsigned char status; if (!us || !info) return USB_STOR_TRANSPORT_ERROR; rc = usbat_device_reset(us); if (rc != USB_STOR_TRANSPORT_GOOD) return rc; msleep(25); /* * In attempt to distinguish between HP CDRW's and Flash readers, we now * execute the IDENTIFY PACKET DEVICE command. On ATA devices (i.e. flash * readers), this command should fail with error. On ATAPI devices (i.e. * CDROM drives), it should succeed. */ rc = usbat_write(us, USBAT_ATA, USBAT_ATA_CMD, 0xA1); if (rc != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; rc = usbat_get_status(us, &status); if (rc != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; // Check for error bit if (status & 0x01) { // Device is a CompactFlash reader/writer US_DEBUGP("usbat_identify_device: Detected Flash reader/writer\n"); info->devicetype = USBAT_DEV_FLASH; } else { // Device is HP 8200 US_DEBUGP("usbat_identify_device: Detected HP8200 CDRW\n"); info->devicetype = USBAT_DEV_HP8200; } return USB_STOR_TRANSPORT_GOOD;}/* * Set the transport function based on the device type */static int usbat_set_transport(struct us_data *us, struct usbat_info *info){ int rc; if (!info->devicetype) { rc = usbat_identify_device(us, info); if (rc != USB_STOR_TRANSPORT_GOOD) { US_DEBUGP("usbat_set_transport: Could not identify device\n"); return 1; } } if (usbat_get_device_type(us) == USBAT_DEV_HP8200) us->transport = usbat_hp8200e_transport; else if (usbat_get_device_type(us) == USBAT_DEV_FLASH) us->transport = usbat_flash_transport; return 0;}/* * Read the media capacity */static int usbat_flash_get_sector_count(struct us_data *us, struct usbat_info *info){ unsigned char registers[3] = { USBAT_ATA_SECCNT, USBAT_ATA_DEVICE, USBAT_ATA_CMD, }; unsigned char command[3] = { 0x01, 0xA0, 0xEC }; unsigned char *reply; unsigned char status; int rc; if (!us || !info) return USB_STOR_TRANSPORT_ERROR; reply = kmalloc(512, GFP_NOIO); if (!reply) return USB_STOR_TRANSPORT_ERROR; // ATAPI command : IDENTIFY DEVICE rc = usbat_multiple_write(us, registers, command, 3); if (rc != USB_STOR_XFER_GOOD) { US_DEBUGP("usbat_flash_get_sector_count: Gah! identify_device failed\n"); rc = USB_STOR_TRANSPORT_ERROR; goto leave; } // Read device status if (usbat_get_status(us, &status) != USB_STOR_XFER_GOOD) { rc = USB_STOR_TRANSPORT_ERROR; goto leave; } msleep(100); // Read the device identification data rc = usbat_read_block(us, reply, 512); if (rc != USB_STOR_TRANSPORT_GOOD) goto leave; info->sectors = ((u32)(reply[117]) << 24) | ((u32)(reply[116]) << 16) | ((u32)(reply[115]) << 8) | ((u32)(reply[114]) ); rc = USB_STOR_TRANSPORT_GOOD; leave: kfree(reply); return rc;}/* * Read data from device */static int usbat_flash_read_data(struct us_data *us, struct usbat_info *info, u32 sector, u32 sectors){ unsigned char registers[7] = { USBAT_ATA_FEATURES, USBAT_ATA_SECCNT, USBAT_ATA_SECNUM, USBAT_ATA_LBA_ME, USBAT_ATA_LBA_HI, USBAT_ATA_DEVICE, USBAT_ATA_STATUS, }; unsigned char command[7]; unsigned char *buffer; unsigned char thistime; unsigned int totallen, alloclen; int len, result; unsigned int sg_idx = 0, sg_offset = 0; result = usbat_flash_check_media(us, info); if (result != USB_STOR_TRANSPORT_GOOD) return result; // we're working in LBA mode. according to the ATA spec, // we can support up to 28-bit addressing. I don't know if Jumpshot // supports beyond 24-bit addressing. It's kind of hard to test // since it requires > 8GB CF card. if (sector > 0x0FFFFFFF) return USB_STOR_TRANSPORT_ERROR; totallen = sectors * info->ssize; // Since we don't read more than 64 KB at a time, we have to create // a bounce buffer and move the data a piece at a time between the // bounce buffer and the actual transfer buffer. alloclen = min(totallen, 65536u); buffer = kmalloc(alloclen, GFP_NOIO); if (buffer == NULL) return USB_STOR_TRANSPORT_ERROR; do { // loop, never allocate or transfer more than 64k at once // (min(128k, 255*info->ssize) is the real limit) len = min(totallen, alloclen); thistime = (len / info->ssize) & 0xff; // ATAPI command 0x20 (READ SECTORS) usbat_pack_atapi_sector_cmd(command, thistime, sector, 0x20); // Write/execute ATAPI read command result = usbat_multiple_write(us, registers, command, 7); if (result != USB_STOR_TRANSPORT_GOOD) goto leave; // Read the data we just requested result = usbat_read_blocks(us, buffer, len); if (result != USB_STOR_TRANSPORT_GOOD) goto leave; US_DEBUGP("usbat_flash_read_data: %d bytes\n", len); // Store the data in the transfer buffer usb_stor_access_xfer_buf(buffer, len, us->srb, &sg_idx, &sg_offset, TO_XFER_BUF); sector += thistime; totallen -= len; } while (totallen > 0); kfree(buffer); return USB_STOR_TRANSPORT_GOOD;leave: kfree(buffer); return USB_STOR_TRANSPORT_ERROR;}/* * Write data to device */static int usbat_flash_write_data(struct us_data *us, struct usbat_info *info, u32 sector, u32 sectors){ unsigned char registers[7] = { USBAT_ATA_FEATURES, USBAT_ATA_SECCNT, USBAT_ATA_SECNUM, USBAT_ATA_LBA_ME, USBAT_ATA_LBA_HI, USBAT_ATA_DEVICE, USBAT_ATA_STATUS, }; unsigned char command[7]; unsigned char *buffer; unsigned char thistime; unsigned int totallen, alloclen; int len, result; unsigned int sg_idx = 0, sg_offset = 0; result = usbat_flash_check_media(us, info); if (result != USB_STOR_TRANSPORT_GOOD) return result; // we're working in LBA mode. according to the ATA spec, // we can support up to 28-bit addressing. I don't know if Jumpshot // supports beyond 24-bit addressing. It's kind of hard to test // since it requires > 8GB CF card. if (sector > 0x0FFFFFFF) return USB_STOR_TRANSPORT_ERROR; totallen = sectors * info->ssize; // Since we don't write more than 64 KB at a time, we have to create // a bounce buffer and move the data a piece at a time between the // bounce buffer and the actual transfer buffer. alloclen = min(totallen, 65536u); buffer = kmalloc(alloclen, GFP_NOIO); if (buffer == NULL) return USB_STOR_TRANSPORT_ERROR; do { // loop, never allocate or transfer more than 64k at once // (min(128k, 255*info->ssize) is the real limit) len = min(totallen, alloclen); thistime = (len / info->ssize) & 0xff; // Get the data from the transfer buffer usb_stor_access_xfer_buf(buffer, len, us->srb, &sg_idx, &sg_offset, FROM_XFER_BUF); // ATAPI command 0x30 (WRITE SECTORS) usbat_pack_atapi_sector_cmd(command, thistime, sector, 0x30); // Write/execute ATAPI write command result = usbat_multiple_write(us, registers, command, 7); if (result != USB_STOR_TRANSPORT_GOOD) goto leave; // Write the data result = usbat_write_blocks(us, buffer, len); if (result != USB_STOR_TRANSPORT_GOOD) goto leave; sector += thistime; totallen -= len; } while (totallen > 0); kfree(buffer); return result;leave: kfree(buffer); return USB_STOR_TRANSPORT_ERROR;}/* * Squeeze a potentially huge (> 65535 byte) read10 command into * a little ( <= 65535 byte) ATAPI pipe
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?