📄 ata.c
字号:
/* * ata_initialize -- * Initializes all ATA devices found on initialized IDE controllers. * * PARAMETERS: * major - device major number * minor - device minor number * args - arguments * * RETURNS: * RTEMS_SUCCESSFUL on success, or error code if * error occured */rtems_device_driver ata_initialize(rtems_device_major_number major, rtems_device_minor_number minor_arg, void *args){ unsigned32 ctrl_minor; rtems_status_code status; ata_req_t areq; blkdev_request1 breq; unsigned8 i, dev = 0; unsigned16 *buffer; unsigned16 ec; char name[ATA_MAX_NAME_LENGTH]; dev_t device; ata_int_st_t *int_st; rtems_isr_entry old_isr; if (ata_initialized) return RTEMS_SUCCESSFUL; /* initialization of disk devices library */ status = rtems_disk_io_initialize(); if (status != RTEMS_SUCCESSFUL) return status; /* create queue for asynchronous requests handling */ status = rtems_message_queue_create( rtems_build_name('A', 'T', 'A', 'Q'), ATA_DRIVER_MESSAGE_QUEUE_SIZE, sizeof(ata_queue_msg_t), RTEMS_FIFO | RTEMS_LOCAL, &ata_queue_id); if (status != RTEMS_SUCCESSFUL) { rtems_disk_io_done(); return status; } /* * create ATA driver task, see comments for task implementation for * details */ status = rtems_task_create( rtems_build_name ('A', 'T', 'A', 'T'), ATA_DRIVER_TASK_PRIORITY, ATA_DRIVER_TASK_STACK_SIZE, RTEMS_PREEMPT | RTEMS_NO_TIMESLICE | RTEMS_ASR | RTEMS_INTERRUPT_LEVEL(0), RTEMS_NO_FLOATING_POINT | RTEMS_LOCAL, &ata_task_id); if (status != RTEMS_SUCCESSFUL) { rtems_message_queue_delete(ata_queue_id); rtems_disk_io_done(); return status; } /* * start ATA driver task. Actually the task will not start immediately - * it will start only after multitasking support will be started */ status = rtems_task_start(ata_task_id, ata_queue_task, 0); if (status != RTEMS_SUCCESSFUL) { rtems_task_delete(ata_task_id); rtems_message_queue_delete(ata_queue_id); rtems_disk_io_done(); return status; } buffer = (unsigned16 *)malloc(ATA_SECTOR_SIZE); if (buffer == NULL) { rtems_task_delete(ata_task_id); rtems_message_queue_delete(ata_queue_id); rtems_disk_io_done(); return RTEMS_NO_MEMORY; } ata_devs_number = 0; for (i = 0; i < (2 * IDE_CTRL_MAX_MINOR_NUMBER); i++) ata_devs[i].device = ATA_UNDEFINED_VALUE; /* prepare ATA driver for handling interrupt driven devices */ for (i = 0; i < ATA_MAX_RTEMS_INT_VEC_NUMBER; i++) Chain_Initialize_empty(&ata_int_vec[i]); /* * during ATA driver initialization EXECUTE DEVICE DIAGNOSTIC and * IDENTIFY DEVICE ATA command should be issued; for these purposes ATA * requests should be formed; ATA requests contain block device request, * so form block device request first */ memset(&breq, 0, sizeof(blkdev_request1)); breq.req.req_done = NULL; breq.req.done_arg = &breq; breq.req.bufnum = 1; breq.req.count = 1; breq.req.bufs[0].length = ATA_SECTOR_SIZE; breq.req.bufs[0].buffer = buffer; /* * for each presented IDE controller execute EXECUTE DEVICE DIAGNOSTIC * ATA command; for each found device execute IDENTIFY DEVICE ATA * command */ for (ctrl_minor = 0; ctrl_minor < IDE_Controller_Count; ctrl_minor++) if (IDE_Controller_Table[ctrl_minor].status == IDE_CTRL_INITIALIZED) { Chain_Initialize_empty(&ata_ide_ctrls[ctrl_minor].reqs); if (IDE_Controller_Table[ctrl_minor].int_driven == TRUE) { int_st = malloc(sizeof(ata_int_st_t)); if (int_st == NULL) { free(buffer); rtems_task_delete(ata_task_id); rtems_message_queue_delete(ata_queue_id); rtems_disk_io_done(); return RTEMS_NO_MEMORY; } int_st->ctrl_minor = ctrl_minor; status = rtems_interrupt_catch( ata_interrupt_handler, IDE_Controller_Table[ctrl_minor].int_vec, &old_isr); if (status != RTEMS_SUCCESSFUL) { free(int_st); free(buffer); rtems_task_delete(ata_task_id); rtems_message_queue_delete(ata_queue_id); rtems_disk_io_done(); return status; } Chain_Append( &ata_int_vec[IDE_Controller_Table[ctrl_minor].int_vec], &int_st->link); /* disable interrupts */ ide_controller_write_register(ctrl_minor, IDE_REGISTER_DEVICE_CONTROL_OFFSET, IDE_REGISTER_DEVICE_CONTROL_nIEN); } /* * Issue EXECUTE DEVICE DIAGNOSTIC ATA command for explore is * there any ATA device on the controller. */ memset(&areq, 0, sizeof(ata_req_t)); areq.type = ATA_COMMAND_TYPE_NON_DATA; areq.regs.to_write = ATA_REGISTERS_VALUE(IDE_REGISTER_COMMAND); areq.regs.regs[IDE_REGISTER_COMMAND] = ATA_COMMAND_EXECUTE_DEVICE_DIAGNOSTIC; areq.regs.to_read = ATA_REGISTERS_VALUE(IDE_REGISTER_ERROR); areq.breq = (blkdev_request *)&breq; /* * Process the request. Special processing of requests on * initialization phase is needed because at this moment there * is no multitasking enviroment */ ata_process_request_on_init_phase(ctrl_minor, &areq); /* * check status of I/O operation */ if (breq.req.status != RTEMS_SUCCESSFUL) continue; /* disassemble returned diagnostic codes */ if (breq.req.error == ATA_DEV0_PASSED_DEV1_PASSED_OR_NOT_PRSNT) { ATA_DEV_INFO(ctrl_minor, 0).present = 1; ATA_DEV_INFO(ctrl_minor,1).present = 1; } else if (breq.req.error == ATA_DEV0_PASSED_DEV1_FAILED) { ATA_DEV_INFO(ctrl_minor,0).present = 1; ATA_DEV_INFO(ctrl_minor,1).present = 0; } else if (breq.req.error < ATA_DEV1_PASSED_DEV0_FAILED) { ATA_DEV_INFO(ctrl_minor,0).present = 0; ATA_DEV_INFO(ctrl_minor,1).present = 1; } else { ATA_DEV_INFO(ctrl_minor, 0).present = 0; ATA_DEV_INFO(ctrl_minor, 1).present = 0; } /* refine the returned codes */ if (ATA_DEV_INFO(ctrl_minor, 1).present != 0) { ide_controller_read_register(ctrl_minor, IDE_REGISTER_ERROR, &ec); if (ec & ATA_DEV1_PASSED_DEV0_FAILED) ATA_DEV_INFO(ctrl_minor, 1).present = 1; else ATA_DEV_INFO(ctrl_minor, 1).present = 0; } /* for each found ATA device obtain it configuration */ for (dev = 0; dev < 2; dev++) if (ATA_DEV_INFO(ctrl_minor, dev).present) { /* * Issue DEVICE IDENTIFY ATA command and get device * configuration */ memset(&areq, 0, sizeof(ata_req_t)); areq.type = ATA_COMMAND_TYPE_PIO_IN; areq.regs.to_write = ATA_REGISTERS_VALUE(IDE_REGISTER_COMMAND); areq.regs.regs[IDE_REGISTER_COMMAND] = ATA_COMMAND_IDENTIFY_DEVICE; areq.regs.to_read = ATA_REGISTERS_VALUE(IDE_REGISTER_STATUS); areq.breq = (blkdev_request *)&breq; areq.cnt = breq.req.count; areq.regs.regs[IDE_REGISTER_DEVICE_HEAD] |= (dev << IDE_REGISTER_DEVICE_HEAD_DEV_POS); /* * Process the request. Special processing of requests on * initialization phase is needed because at this moment there * is no multitasking enviroment */ ata_process_request_on_init_phase(ctrl_minor, &areq); /* check status of I/O operation */ if (breq.req.status != RTEMS_SUCCESSFUL) continue; /* * Parse returned device configuration and fill in ATA internal * device info structure */ ATA_DEV_INFO(ctrl_minor, dev).cylinders = CF_LE_W(buffer[ATA_IDENT_WORD_NUM_OF_CURR_LOG_CLNDS]); ATA_DEV_INFO(ctrl_minor, dev).heads = CF_LE_W(buffer[ATA_IDENT_WORD_NUM_OF_CURR_LOG_HEADS]); ATA_DEV_INFO(ctrl_minor, dev).sectors = CF_LE_W(buffer[ATA_IDENT_WORD_NUM_OF_CURR_LOG_SECS]); ATA_DEV_INFO(ctrl_minor, dev).lba_sectors = (CF_LE_W(buffer[ATA_IDENT_WORD_NUM_OF_USR_SECS0]) << 16) + CF_LE_W(buffer[ATA_IDENT_WORD_NUM_OF_USR_SECS1]); ATA_DEV_INFO(ctrl_minor, dev).lba_avaible = (CF_LE_W(buffer[ATA_IDENT_WORD_CAPABILITIES]) >> 9) & 0x1; ATA_DEV_INFO(ctrl_minor, dev).max_multiple = (unsigned8) (CF_LE_W(buffer[ATA_IDENT_WORD_RW_MULT])); ATA_DEV_INFO(ctrl_minor, dev).current_multiple = (CF_LE_W(buffer[ATA_IDENT_WORD_MULT_SECS]) & 0x100) ? (unsigned8)(CF_LE_W(buffer[ATA_IDENT_WORD_MULT_SECS])) : 0; if ((CF_LE_W(buffer[ATA_IDENT_WORD_FIELD_VALIDITY]) & ATA_IDENT_BIT_VALID) == 0) { /* no "supported modes" info -> use default */ ATA_DEV_INFO(ctrl_minor, dev).mode_active = ATA_MODES_PIO3; } else { ATA_DEV_INFO(ctrl_minor, dev).modes_avaible = ((CF_LE_W(buffer[64]) & 0x1) ? ATA_MODES_PIO3 : 0) | ((CF_LE_W(buffer[64]) & 0x2) ? ATA_MODES_PIO4 : 0) | ((CF_LE_W(buffer[63]) & 0x1) ? ATA_MODES_DMA0 : 0) | ((CF_LE_W(buffer[63]) & 0x2) ? ATA_MODES_DMA0 | ATA_MODES_DMA1 : 0) | ((CF_LE_W(buffer[63]) & 0x4) ? ATA_MODES_DMA0 | ATA_MODES_DMA1 | ATA_MODES_DMA2 : 0); if (ATA_DEV_INFO(ctrl_minor, dev).modes_avaible == 0) continue; /* * choose most appropriate ATA device data I/O speed supported * by the controller */ status = ide_controller_config_io_speed( ctrl_minor, ATA_DEV_INFO(ctrl_minor, dev).modes_avaible); if (status != RTEMS_SUCCESSFUL) continue; } /* * Ok, let register new ATA device in the system */ ata_devs[ata_devs_number].ctrl_minor = ctrl_minor; ata_devs[ata_devs_number].device = dev; /* The space leaves a hole for the character. */ strcpy(name, "/dev/hd "); name[7] = 'a' + 2 * ctrl_minor + dev; device = rtems_filesystem_make_dev_t( major, (ata_devs_number * ATA_MINOR_NUM_RESERVED_PER_ATA_DEVICE)); status = rtems_disk_create_phys(device, ATA_SECTOR_SIZE, ATA_DEV_INFO(ctrl_minor, dev).lba_avaible ? ATA_DEV_INFO(ctrl_minor, dev).lba_sectors : (ATA_DEV_INFO(ctrl_minor, dev).heads * ATA_DEV_INFO(ctrl_minor, dev).cylinders * ATA_DEV_INFO(ctrl_minor, dev).sectors), (block_device_ioctl) ata_ioctl, name); if (status != RTEMS_SUCCESSFUL) { ata_devs[ata_devs_number].device = ATA_UNDEFINED_VALUE; continue; } ata_devs_number++; } if (IDE_Controller_Table[ctrl_minor].int_driven == TRUE) { ide_controller_write_register(ctrl_minor, IDE_REGISTER_DEVICE_CONTROL_OFFSET, 0x00); } } free(buffer); ata_initialized = TRUE; return RTEMS_SUCCESSFUL;}/* ata_process_request_on_init_phase -- * Process the ATA request during system initialization. Request * processing is syncronous and doesn't use multiprocessing enviroment. * * PARAMETERS: * ctrl_minor - controller identifier * areq - ATA request * * RETURNS: * NONE */static voidata_process_request_on_init_phase(rtems_device_minor_number ctrl_minor, ata_req_t *areq){ unsigned16 byte;/* emphasize that only 8 low bits is meaningful */ unsigned8 i, dev; unsigned16 val, val1; unsigned16 data_bs; /* the number of 512 bytes sectors into one * data block */ assert(areq); dev = areq->regs.regs[IDE_REGISTER_DEVICE_HEAD] & IDE_REGISTER_DEVICE_HEAD_DEV; data_bs = ATA_DEV_INFO(ctrl_minor, dev).current_multiple ? ATA_DEV_INFO(ctrl_minor, dev).current_multiple : 1; ide_controller_write_register(ctrl_minor, IDE_REGISTER_DEVICE_HEAD, areq->regs.regs[IDE_REGISTER_DEVICE_HEAD]); do { ide_controller_read_register(ctrl_minor, IDE_REGISTER_STATUS, &byte); } while ((byte & IDE_REGISTER_STATUS_BSY) || (!(byte & IDE_REGISTER_STATUS_DRDY))); for (i=0; i< ATA_MAX_CMD_REG_OFFSET; i++) { unsigned32 reg = (1 << i); if (areq->regs.to_write & reg) ide_controller_write_register(ctrl_minor, i, areq->regs.regs[i]); } do { ide_controller_read_register(ctrl_minor, IDE_REGISTER_STATUS, &byte); } while (byte & IDE_REGISTER_STATUS_BSY); ide_controller_read_register(ctrl_minor, IDE_REGISTER_STATUS, &val); ide_controller_read_register(ctrl_minor, IDE_REGISTER_ERROR, &val1); if (val & IDE_REGISTER_STATUS_ERR) { areq->breq->status = RTEMS_UNSATISFIED; areq->breq->error = RTEMS_IO_ERROR; return; } switch(areq->type) { case ATA_COMMAND_TYPE_PIO_IN: ide_controller_read_data_block( ctrl_minor, MIN(data_bs, areq->cnt) * ATA_SECTOR_SIZE, areq->breq->bufs, &areq->cbuf, &areq->pos); areq->cnt -= MIN(data_bs, areq->cnt); if (areq->cnt == 0) { areq->breq->status = RTEMS_SUCCESSFUL; } else { /* * this shouldn't happend on the initialization * phase! */ rtems_fatal_error_occurred(RTEMS_INTERNAL_ERROR); } break; case ATA_COMMAND_TYPE_NON_DATA: areq->breq->status = RTEMS_SUCCESSFUL; areq->breq->error = val1; break; default: printf("ata_queue_task: non-supported command type\n"); areq->breq->status = RTEMS_UNSATISFIED; areq->breq->error = RTEMS_NOT_IMPLEMENTED; break; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -