⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sync.c

📁 newos is new operation system
💻 C
字号:
/* ** Copyright 2002, Thomas Kurschel. All rights reserved.** Distributed under the terms of the NewOS License.*/#include "ide_internal.h"#include "sync.h"#include <string.h>#include "basic_prot.h"#include "ide_sim.h"#include "atapi.h"#include "ata.h"#include "queuing.h"void ide_dpc( void *arg ){	ide_bus_info *bus = (ide_bus_info *)arg;	ide_qrequest *qrequest;	ide_device_info *device;		SHOW_FLOW0( 3, "" );		if( bus->active_qrequest == NULL ) {		SHOW_FLOW0( 3, "irq in idle mode - possible service request" );				device = get_current_device( bus );				if( device == NULL ) {			// got an interrupt from a non-existing device			// either this is a spurious interrupt or there *is* a device			// but haven't detected it - we better ignore it silently			access_finished( bus, bus->first_device );							xpt->cont_send_bus( bus->xpt_cookie );			return;		}			// access_finished always checks the other device first, but as		// we do have a service request, we negate the negation		access_finished( bus, device->other_device );		xpt->cont_send_bus( bus->xpt_cookie );		return;					} else {		SHOW_FLOW0( 3, "continue command" );				IDE_LOCK( bus );			if( bus->dpc_id != bus->wait_id ) {			SHOW_FLOW0( 3, "waiting has been aborted - ignore irq" );						// waiting must have been aborted in some way - we don't own bus,			// so we are not allowed to do anything			IDE_UNLOCK( bus );			return;		}			IDE_UNLOCK( bus );			// make sure timeout is not delayed on other processor		// NEWOS BUG: current implementation doesn't guarantee that		//            the timer function has finished execution on return!		timer_cancel_event( &bus->timer );		//++bus->cmd_id;				qrequest = bus->active_qrequest;		device = qrequest->device;				if( device->is_atapi )			packet_dpc( qrequest );				else {			if( device->DMA_enabled )				ata_dpc_DMA( qrequest );			else				ata_dpc_PIO( qrequest );		}	}		return;	/*err:	xpt->cont_send( bus->xpt_cookie );*/}int irq_handler( ide_bus_info *bus ){		SHOW_FLOW0( 3, "" );		IDE_LOCK( bus );		SHOW_FLOW0( 3, "1" );		switch( bus->state ) {	case ide_state_async_waiting:		SHOW_FLOW0( 3, "async waiting" );				bus->state = ide_state_accessing;				bus->dpc_id = ++bus->wait_id;				bus->device_to_reconnect = NULL;				IDE_UNLOCK( bus );		xpt->schedule_dpc( bus->xpt_cookie, bus->irq_dpc,			ide_dpc, bus );				return INT_RESCHEDULE; 	case ide_state_idle:		SHOW_FLOW0( 3, "idle" );				if( bus->num_running_reqs == 0 ) {			// spurious interrupt			IDE_UNLOCK( bus );			return INT_NO_RESCHEDULE;		}				bus->state = ide_state_accessing;				bus->dpc_id = ++bus->wait_id;				IDE_UNLOCK( bus );		xpt->schedule_dpc( bus->xpt_cookie, bus->irq_dpc,			ide_dpc, bus );				return INT_RESCHEDULE; 			case ide_state_sync_waiting:		SHOW_FLOW0( 3, "sync waiting" );				bus->state = ide_state_accessing;		bus->sync_wait_timeout = false;				IDE_UNLOCK( bus );				{			int res;						// cancel timer manually, normally that's done by DPC			// POSSIBLE RACE CONDITION:			// timeout may be executed and delayed on other processor;			// cancel_timer doesn't wait for it if in IRQ handler			res = timer_cancel_event( &bus->timer );						SHOW_FLOW( 3, "timeout canceled (%s)", strerror( res ));		}				sem_release_etc( bus->sync_wait_sem, 1, SEM_FLAG_NO_RESCHED );				return INT_RESCHEDULE;	case ide_state_accessing:		SHOW_FLOW0( 3, "spurious IRQ - there is a command being executed" );				IDE_UNLOCK( bus );		return INT_NO_RESCHEDULE;			default:		SHOW_ERROR( 0, "BUG: unknown state (%i)", (int)bus->state );				IDE_UNLOCK( bus );				return INT_NO_RESCHEDULE;	}}void cancel_irq_timeout( ide_bus_info *bus ){	IDE_LOCK( bus );	++bus->wait_id;	bus->state = ide_state_accessing;	IDE_UNLOCK( bus );		timer_cancel_event( &bus->timer );}// bus must be locked// new_state must be either sync_wait or async_waitvoid start_waiting( ide_bus_info *bus, bigtime_t timeout, int new_state ){	int res;		SHOW_FLOW( 3, "timeout=%Li", timeout );	//IDE_LOCK( bus );	//bus->irq_id = ++bus->cmd_id;	bus->state = new_state;	++bus->wait_id;		res = timer_set_event( timeout/*qrequest->request->cam_timeout > 0 ? 		qrequest->request->cam_timeout : IDE_STD_TIMEOUT*/, 		TIMER_MODE_ONESHOT, &bus->timer );			SHOW_FLOW( 3, "timer set (%s)", strerror( res ));		IDE_UNLOCK( bus );}// bus must not be lockedvoid start_waiting_nolock( ide_bus_info *bus, bigtime_t timeout, int new_state ){	IDE_LOCK( bus );	start_waiting( bus, timeout, new_state );}static void ide_timeout_dpc( void *arg ){	ide_bus_info *bus = (ide_bus_info *)arg;	ide_qrequest *qrequest;		IDE_LOCK( bus );	if( bus->dpc_id != bus->wait_id ) {		IDE_UNLOCK( bus );		return;	}			IDE_UNLOCK( bus );	qrequest = bus->active_qrequest;		set_sense( qrequest->device, SCSIS_KEY_HARDWARE_ERROR, SCSIS_ASC_LUN_TIMEOUT );	if( qrequest->device->is_atapi )		adjust_atapi_result( qrequest->device, qrequest );			finish_reset_queue( qrequest );	access_finished( bus, qrequest->device );}int ide_timeout( void *arg ){	ide_bus_info *bus = (ide_bus_info *)arg;	//ide_qrequest *qrequest;		SHOW_FLOW0( 3, "" );		IDE_LOCK( bus );	switch( bus->state ) {	case ide_state_async_waiting:		SHOW_FLOW0( 3, "async" );				bus->state = ide_state_accessing;				bus->dpc_id = ++bus->wait_id;					IDE_UNLOCK( bus );					xpt->schedule_dpc( bus->xpt_cookie, bus->irq_dpc, /*qrequest->device->target_id, 0, 0,*/			ide_timeout_dpc, bus );			return INT_RESCHEDULE;			case ide_state_sync_waiting:		SHOW_FLOW0( 3, "sync" );				bus->state = ide_state_accessing;		bus->sync_wait_timeout = true;				IDE_UNLOCK( bus );				sem_release_etc( bus->sync_wait_sem, 1, SEM_FLAG_NO_RESCHED );				return INT_RESCHEDULE;	case ide_state_accessing:		SHOW_FLOW0( 3, "came too late - IRQ occured already" );		IDE_UNLOCK( bus );		return INT_NO_RESCHEDULE;			default:		SHOW_ERROR( 0, "BUG: unknown state (%i)", (int)bus->state );		IDE_UNLOCK( bus );		return INT_NO_RESCHEDULE;	}}void init_synced_pc( ide_synced_pc *pc, ide_synced_pc_func func ){	pc->func = func;	pc->registered = false;}void uninit_synced_pc( ide_synced_pc *pc ){	if( pc->registered )		panic( "Tried to clean up pending synced PC\n" );}//void access_finished( ide_device_info *device );int schedule_synced_pc( ide_bus_info *bus, ide_synced_pc *pc, void *arg ){	SHOW_FLOW0( 3, "" );		IDE_LOCK( bus );	if( pc->registered ) {		SHOW_FLOW0( 3, "already registered" );		return ERR_GENERAL;			} else if( bus->state != ide_state_idle ) {		SHOW_FLOW0( 3, "adding to pending list" );		pc->next = bus->synced_pc_list;		bus->synced_pc_list = pc;		pc->arg = arg;		pc->registered = true;				IDE_UNLOCK( bus );			return NO_ERROR;			} else {		SHOW_FLOW0( 3, "exec immediately" );		bus->state = ide_state_accessing;		IDE_UNLOCK( bus );				SHOW_FLOW0( 3, "go" );		pc->func( bus, arg );				SHOW_FLOW0( 3, "finished" );		access_finished( bus, bus->first_device );				SHOW_FLOW0( 3, "tell XPT about idle bus" );		xpt->cont_send_bus( bus->xpt_cookie );		return NO_ERROR;	}}static void exec_synced_pcs( ide_bus_info *bus, ide_synced_pc *pc_list ){	ide_synced_pc *pc;		for( pc = pc_list; pc; pc = pc->next ) {		pc->func( bus, pc->arg );	}		IDE_LOCK( bus );		for( pc = pc_list; pc; pc = pc->next ) {		pc->registered = false;	}		IDE_UNLOCK( bus );}void access_finished( ide_bus_info *bus, ide_device_info *device ){	SHOW_FLOW( 3, "bus=%p, device=%p", bus, device );		IDE_LOCK( bus );		while( 1 ) {		ide_synced_pc *synced_pc_list;		if( device ) {					if( try_service( device ))				return;		}		bus->state = ide_state_idle;		if( bus->synced_pc_list == NULL ) {			//bus->state = ide_state_idle;			IDE_UNLOCK( bus );			return;		}				synced_pc_list = bus->synced_pc_list;		bus->synced_pc_list = NULL;				IDE_UNLOCK( bus );					exec_synced_pcs( bus, synced_pc_list );	}}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -