ide-floppy.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,099 行 · 第 1/5 页
C
2,099 行
*/typedef struct {#if defined(__LITTLE_ENDIAN_BITFIELD) unsigned device_type :5; /* Peripheral Device Type */ unsigned reserved0_765 :3; /* Peripheral Qualifier - Reserved */ unsigned reserved1_6t0 :7; /* Reserved */ unsigned rmb :1; /* Removable Medium Bit */ unsigned ansi_version :3; /* ANSI Version */ unsigned ecma_version :3; /* ECMA Version */ unsigned iso_version :2; /* ISO Version */ unsigned response_format :4; /* Response Data Format */ unsigned reserved3_45 :2; /* Reserved */ unsigned reserved3_6 :1; /* TrmIOP - Reserved */ unsigned reserved3_7 :1; /* AENC - Reserved */#elif defined(__BIG_ENDIAN_BITFIELD) unsigned reserved0_765 :3; /* Peripheral Qualifier - Reserved */ unsigned device_type :5; /* Peripheral Device Type */ unsigned rmb :1; /* Removable Medium Bit */ unsigned reserved1_6t0 :7; /* Reserved */ unsigned iso_version :2; /* ISO Version */ unsigned ecma_version :3; /* ECMA Version */ unsigned ansi_version :3; /* ANSI Version */ unsigned reserved3_7 :1; /* AENC - Reserved */ unsigned reserved3_6 :1; /* TrmIOP - Reserved */ unsigned reserved3_45 :2; /* Reserved */ unsigned response_format :4; /* Response Data Format */#else#error "Bitfield endianness not defined! Check your byteorder.h"#endif u8 additional_length; /* Additional Length (total_length-4) */ u8 rsv5, rsv6, rsv7; /* Reserved */ u8 vendor_id[8]; /* Vendor Identification */ u8 product_id[16]; /* Product Identification */ u8 revision_level[4]; /* Revision Level */ u8 vendor_specific[20]; /* Vendor Specific - Optional */ u8 reserved56t95[40]; /* Reserved - Optional */ /* Additional information may be returned */} idefloppy_inquiry_result_t;/* * REQUEST SENSE packet command result - Data Format. */typedef struct {#if defined(__LITTLE_ENDIAN_BITFIELD) unsigned error_code :7; /* Current error (0x70) */ unsigned valid :1; /* The information field conforms to SFF-8070i */ u8 reserved1 :8; /* Reserved */ unsigned sense_key :4; /* Sense Key */ unsigned reserved2_4 :1; /* Reserved */ unsigned ili :1; /* Incorrect Length Indicator */ unsigned reserved2_67 :2;#elif defined(__BIG_ENDIAN_BITFIELD) unsigned valid :1; /* The information field conforms to SFF-8070i */ unsigned error_code :7; /* Current error (0x70) */ u8 reserved1 :8; /* Reserved */ unsigned reserved2_67 :2; unsigned ili :1; /* Incorrect Length Indicator */ unsigned reserved2_4 :1; /* Reserved */ unsigned sense_key :4; /* Sense Key */#else#error "Bitfield endianness not defined! Check your byteorder.h"#endif u32 information __attribute__ ((packed)); u8 asl; /* Additional sense length (n-7) */ u32 command_specific; /* Additional command specific information */ u8 asc; /* Additional Sense Code */ u8 ascq; /* Additional Sense Code Qualifier */ u8 replaceable_unit_code; /* Field Replaceable Unit Code */ u8 sksv[3]; u8 pad[2]; /* Padding to 20 bytes */} idefloppy_request_sense_result_t;/* * Pages of the SELECT SENSE / MODE SENSE packet commands. */#define IDEFLOPPY_CAPABILITIES_PAGE 0x1b#define IDEFLOPPY_FLEXIBLE_DISK_PAGE 0x05/* * Mode Parameter Header for the MODE SENSE packet command */typedef struct { u16 mode_data_length; /* Length of the following data transfer */ u8 medium_type; /* Medium Type */#if defined(__LITTLE_ENDIAN_BITFIELD) unsigned reserved3 :7; unsigned wp :1; /* Write protect */#elif defined(__BIG_ENDIAN_BITFIELD) unsigned wp :1; /* Write protect */ unsigned reserved3 :7;#else#error "Bitfield endianness not defined! Check your byteorder.h"#endif u8 reserved[4];} idefloppy_mode_parameter_header_t;/* * Too bad. The drive wants to send us data which we are not ready to accept. * Just throw it away. */static void idefloppy_discard_data (ide_drive_t *drive, unsigned int bcount){ while (bcount--) (void) HWIF(drive)->INB(IDE_DATA_REG);}#if IDEFLOPPY_DEBUG_BUGSstatic void idefloppy_write_zeros (ide_drive_t *drive, unsigned int bcount){ while (bcount--) HWIF(drive)->OUTB(0, IDE_DATA_REG);}#endif /* IDEFLOPPY_DEBUG_BUGS *//* * idefloppy_do_end_request is used to finish servicing a request. * * For read/write requests, we will call ide_end_request to pass to the * next buffer. */static int idefloppy_do_end_request(ide_drive_t *drive, int uptodate, int nsecs){ idefloppy_floppy_t *floppy = drive->driver_data; struct request *rq = HWGROUP(drive)->rq; int error; debug_log(KERN_INFO "Reached idefloppy_end_request\n"); switch (uptodate) { case 0: error = IDEFLOPPY_ERROR_GENERAL; break; case 1: error = 0; break; default: error = uptodate; } if (error) floppy->failed_pc = NULL; /* Why does this happen? */ if (!rq) return 0; if (!(rq->flags & REQ_SPECIAL)) { //if (!IDEFLOPPY_RQ_CMD (rq->cmd)) { /* our real local end request function */ ide_end_request(drive, uptodate, nsecs); return 0; } rq->errors = error; /* fixme: need to move this local also */ ide_end_drive_cmd(drive, 0, 0); return 0;}static void idefloppy_input_buffers (ide_drive_t *drive, idefloppy_pc_t *pc, unsigned int bcount){ struct request *rq = pc->rq; struct bio_vec *bvec; struct bio *bio; unsigned long flags; char *data; int count, i, done = 0; rq_for_each_bio(bio, rq) { bio_for_each_segment(bvec, bio, i) { if (!bcount) break; count = min(bvec->bv_len, bcount); data = bvec_kmap_irq(bvec, &flags); atapi_input_bytes(drive, data, count); bvec_kunmap_irq(data, &flags); bcount -= count; pc->b_count += count; done += count; } } idefloppy_do_end_request(drive, 1, done >> 9); if (bcount) { printk(KERN_ERR "%s: leftover data in idefloppy_input_buffers, bcount == %d\n", drive->name, bcount); idefloppy_discard_data(drive, bcount); }}static void idefloppy_output_buffers (ide_drive_t *drive, idefloppy_pc_t *pc, unsigned int bcount){ struct request *rq = pc->rq; struct bio *bio; struct bio_vec *bvec; unsigned long flags; int count, i, done = 0; char *data; rq_for_each_bio(bio, rq) { bio_for_each_segment(bvec, bio, i) { if (!bcount) break; count = min(bvec->bv_len, bcount); data = bvec_kmap_irq(bvec, &flags); atapi_output_bytes(drive, data, count); bvec_kunmap_irq(data, &flags); bcount -= count; pc->b_count += count; done += count; } } idefloppy_do_end_request(drive, 1, done >> 9); if (bcount) { printk(KERN_ERR "%s: leftover data in idefloppy_output_buffers, bcount == %d\n", drive->name, bcount); idefloppy_write_zeros(drive, bcount); }}static void idefloppy_update_buffers (ide_drive_t *drive, idefloppy_pc_t *pc){ struct request *rq = pc->rq; struct bio *bio = rq->bio; while ((bio = rq->bio) != NULL) idefloppy_do_end_request(drive, 1, 0);}/* * idefloppy_queue_pc_head generates a new packet command request in front * of the request queue, before the current request, so that it will be * processed immediately, on the next pass through the driver. */static void idefloppy_queue_pc_head (ide_drive_t *drive,idefloppy_pc_t *pc,struct request *rq){ ide_init_drive_cmd(rq); rq->buffer = (char *) pc; rq->flags = REQ_SPECIAL; //rq->cmd = IDEFLOPPY_PC_RQ; (void) ide_do_drive_cmd(drive, rq, ide_preempt);}static idefloppy_pc_t *idefloppy_next_pc_storage (ide_drive_t *drive){ idefloppy_floppy_t *floppy = drive->driver_data; if (floppy->pc_stack_index == IDEFLOPPY_PC_STACK) floppy->pc_stack_index=0; return (&floppy->pc_stack[floppy->pc_stack_index++]);}static struct request *idefloppy_next_rq_storage (ide_drive_t *drive){ idefloppy_floppy_t *floppy = drive->driver_data; if (floppy->rq_stack_index == IDEFLOPPY_PC_STACK) floppy->rq_stack_index = 0; return (&floppy->rq_stack[floppy->rq_stack_index++]);}/* * idefloppy_analyze_error is called on each failed packet command retry * to analyze the request sense. */static void idefloppy_analyze_error (ide_drive_t *drive,idefloppy_request_sense_result_t *result){ idefloppy_floppy_t *floppy = drive->driver_data; floppy->sense_key = result->sense_key; floppy->asc = result->asc; floppy->ascq = result->ascq; floppy->progress_indication = result->sksv[0] & 0x80 ? (u16)get_unaligned((u16 *)(result->sksv+1)):0x10000; if (floppy->failed_pc) debug_log(KERN_INFO "ide-floppy: pc = %x, sense key = %x, " "asc = %x, ascq = %x\n", floppy->failed_pc->c[0], result->sense_key, result->asc, result->ascq); else debug_log(KERN_INFO "ide-floppy: sense key = %x, asc = %x, " "ascq = %x\n", result->sense_key, result->asc, result->ascq);}static void idefloppy_request_sense_callback (ide_drive_t *drive){ idefloppy_floppy_t *floppy = drive->driver_data; debug_log(KERN_INFO "ide-floppy: Reached %s\n", __FUNCTION__); if (!floppy->pc->error) { idefloppy_analyze_error(drive,(idefloppy_request_sense_result_t *) floppy->pc->buffer); idefloppy_do_end_request(drive, 1, 0); } else { printk(KERN_ERR "Error in REQUEST SENSE itself - Aborting request!\n"); idefloppy_do_end_request(drive, 0, 0); }}/* * General packet command callback function. */static void idefloppy_pc_callback (ide_drive_t *drive){ idefloppy_floppy_t *floppy = drive->driver_data; debug_log(KERN_INFO "ide-floppy: Reached %s\n", __FUNCTION__); idefloppy_do_end_request(drive, floppy->pc->error ? 0 : 1, 0);}/* * idefloppy_init_pc initializes a packet command. */static void idefloppy_init_pc (idefloppy_pc_t *pc){ memset(pc->c, 0, 12); pc->retries = 0; pc->flags = 0; pc->request_transfer = 0; pc->buffer = pc->pc_buffer; pc->buffer_size = IDEFLOPPY_PC_BUFFER_SIZE; pc->callback = &idefloppy_pc_callback;}static void idefloppy_create_request_sense_cmd (idefloppy_pc_t *pc){ idefloppy_init_pc(pc); pc->c[0] = IDEFLOPPY_REQUEST_SENSE_CMD; pc->c[4] = 255; pc->request_transfer = 18; pc->callback = &idefloppy_request_sense_callback;}/* * idefloppy_retry_pc is called when an error was detected during the * last packet command. We queue a request sense packet command in * the head of the request list. */static void idefloppy_retry_pc (ide_drive_t *drive){ idefloppy_pc_t *pc; struct request *rq; atapi_error_t error; error.all = HWIF(drive)->INB(IDE_ERROR_REG); pc = idefloppy_next_pc_storage(drive); rq = idefloppy_next_rq_storage(drive); idefloppy_create_request_sense_cmd(pc); idefloppy_queue_pc_head(drive, pc, rq);}/* * idefloppy_pc_intr is the usual interrupt handler which will be called * during a packet command. */static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive){ idefloppy_floppy_t *floppy = drive->driver_data; atapi_status_t status; atapi_bcount_t bcount; atapi_ireason_t ireason; idefloppy_pc_t *pc = floppy->pc; struct request *rq = pc->rq; unsigned int temp; debug_log(KERN_INFO "ide-floppy: Reached %s interrupt handler\n", __FUNCTION__); if (test_bit(PC_DMA_IN_PROGRESS, &pc->flags)) { if (HWIF(drive)->ide_dma_end(drive)) { set_bit(PC_DMA_ERROR, &pc->flags); } else { pc->actually_transferred = pc->request_transfer; idefloppy_update_buffers(drive, pc); } debug_log(KERN_INFO "ide-floppy: DMA finished\n"); } /* Clear the interrupt */ status.all = HWIF(drive)->INB(IDE_STATUS_REG); if (!status.b.drq) { /* No more interrupts */ debug_log(KERN_INFO "Packet command completed, %d bytes " "transferred\n", pc->actually_transferred); clear_bit(PC_DMA_IN_PROGRESS, &pc->flags); local_irq_enable(); if (status.b.check || test_bit(PC_DMA_ERROR, &pc->flags)) { /* Error detected */ debug_log(KERN_INFO "ide-floppy: %s: I/O error\n", drive->name); rq->errors++; if (pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD) { printk(KERN_ERR "ide-floppy: I/O error in " "request sense command\n"); return ide_do_reset(drive); } /* Retry operation */ idefloppy_retry_pc(drive); /* queued, but not started */ return ide_stopped; } pc->error = 0; if (floppy->failed_pc == pc) floppy->failed_pc = NULL; /* Command finished - Call the callback function */ pc->callback(drive); return ide_stopped; } if (test_and_clear_bit(PC_DMA_IN_PROGRESS, &pc->flags)) { printk(KERN_ERR "ide-floppy: The floppy wants to issue " "more interrupts in DMA mode\n"); (void)__ide_dma_off(drive); return ide_do_reset(drive); } /* Get the number of bytes to transfer */ bcount.b.high = HWIF(drive)->INB(IDE_BCOUNTH_REG); bcount.b.low = HWIF(drive)->INB(IDE_BCOUNTL_REG); /* on this interrupt */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?