1/* 2 * Copyright 2004-2007, Haiku, Inc. All RightsReserved. 3 * Copyright 2002/03, Thomas Kurschel. All rights reserved. 4 * 5 * Distributed under the terms of the MIT License. 6 */ 7 8//! DMA helper functions 9 10 11#include "ide_internal.h" 12 13#define CHECK_DEV_DMA_MODE(infoblock, elem, mode, this_mode, num_modes ) \ 14 if( infoblock->elem ) { \ 15 mode = this_mode; \ 16 ++num_modes; \ 17 } 18 19 20int 21get_device_dma_mode(ide_device_info *device) 22{ 23 ide_device_infoblock *infoblock = &device->infoblock; 24 25 int num_modes, mode; 26 27 mode = 0; 28 num_modes = 0; 29 30 if (!infoblock->DMA_supported) 31 return -1; 32 33 CHECK_DEV_DMA_MODE(infoblock, MDMA0_selected, mode, 0, num_modes); 34 CHECK_DEV_DMA_MODE(infoblock, MDMA1_selected, mode, 1, num_modes); 35 CHECK_DEV_DMA_MODE(infoblock, MDMA2_selected, mode, 2, num_modes); 36 37 if (infoblock->_88_valid) { 38 CHECK_DEV_DMA_MODE(infoblock, UDMA0_selected, mode, 0x10, num_modes); 39 CHECK_DEV_DMA_MODE(infoblock, UDMA1_selected, mode, 0x11, num_modes); 40 CHECK_DEV_DMA_MODE(infoblock, UDMA2_selected, mode, 0x12, num_modes); 41 CHECK_DEV_DMA_MODE(infoblock, UDMA3_selected, mode, 0x13, num_modes); 42 CHECK_DEV_DMA_MODE(infoblock, UDMA4_selected, mode, 0x14, num_modes); 43 CHECK_DEV_DMA_MODE(infoblock, UDMA5_selected, mode, 0x15, num_modes); 44 CHECK_DEV_DMA_MODE(infoblock, UDMA6_selected, mode, 0x16, num_modes); 45 } 46 47 if (num_modes != 1) 48 return -1; 49 50 SHOW_FLOW(3, "%x", mode); 51 52 return mode; 53} 54 55 56bool 57configure_dma(ide_device_info *device) 58{ 59 if (get_device_dma_mode(device) != -1) { 60 device->DMA_enabled = device->DMA_supported = device->bus->can_DMA; 61 if (device->DMA_enabled) { 62 dprintf("IDE: enabling DMA\n"); 63 } else { 64 dprintf("IDE: disabling DMA (failsafe option selected)\n"); 65 } 66 } else { 67 device->DMA_enabled = false; 68 dprintf("IDE: DMA not possible, disabling\n"); 69 } 70 71 return true; 72} 73 74 75/*! Abort DMA transmission 76 must be called _before_ start_dma_wait 77*/ 78void 79abort_dma(ide_device_info *device, ide_qrequest *qrequest) 80{ 81 ide_bus_info *bus = device->bus; 82 83 SHOW_FLOW0(0, ""); 84 85 bus->controller->finish_dma(bus->channel_cookie); 86} 87 88 89/*! Prepare DMA transmission 90 on return, DMA engine waits for device to transmit data 91 warning: doesn't set sense data on error 92*/ 93bool 94prepare_dma(ide_device_info *device, ide_qrequest *qrequest) 95{ 96 ide_bus_info *bus = device->bus; 97 scsi_ccb *request = qrequest->request; 98 status_t res; 99 100 res = bus->controller->prepare_dma(bus->channel_cookie, request->sg_list, 101 request->sg_count, qrequest->is_write); 102 if (res != B_OK) 103 return false; 104 105 return true; 106} 107 108 109/*! Start waiting for DMA to be finished */ 110void 111start_dma_wait(ide_device_info *device, ide_qrequest *qrequest) 112{ 113 ide_bus_info *bus = device->bus; 114 115 bus->controller->start_dma(bus->channel_cookie); 116 117 start_waiting(bus, qrequest->request->timeout > 0 ? 118 qrequest->request->timeout : IDE_STD_TIMEOUT, ide_state_async_waiting); 119} 120 121 122/*! Start waiting for DMA to be finished with bus lock not hold */ 123void 124start_dma_wait_no_lock(ide_device_info *device, ide_qrequest *qrequest) 125{ 126 ide_bus_info *bus = device->bus; 127 128 IDE_LOCK(bus); 129 start_dma_wait(device, qrequest); 130} 131 132 133/*! Finish dma transmission after device has fired IRQ */ 134bool 135finish_dma(ide_device_info *device) 136{ 137 ide_bus_info *bus = device->bus; 138 status_t dma_res; 139 140 dma_res = bus->controller->finish_dma(bus->channel_cookie); 141 142 return dma_res == B_OK || dma_res == B_DEV_DATA_OVERRUN; 143} 144 145