/* Copyright (c) 2013 Fredrik Wikstrom. All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
**    notice, this list of conditions and the following disclaimer.
**
** 2. Redistributions in binary form must reproduce the above copyright
**    notice, this list of conditions and the following disclaimer in the
**    documentation and/or other materials provided with the distribution.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'
** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
** LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
** CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
** ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
** POSSIBILITY OF SUCH DAMAGE.
*/

#include "flite_device.h"

static const uint16 cmd_list[] = {
	NSCMD_DEVICEQUERY,
	CMD_WRITE,
	0
};

LONG libAbortIO (struct DeviceManagerInterface *Self, struct IORequest *which_io) {
	struct FliteUnit *unit;
	struct IORequest *io;
	LONG error = IOERR_SUCCESS;
	dbug(("AbortIO()\n"));

	unit = (struct FliteUnit *)which_io->io_Unit;
	IExec->ObtainSemaphore(unit->fu_SigSem);

	/* Check if the request is still in the queue, waiting to be
	   processed */

	io = (struct IORequest *)IExec->GetHead(&unit->fu_Port->mp_MsgList);
	while (io) {
		if (io == which_io) {
			/* remove it from the queue and tag it as aborted */
			IExec->Remove((struct Node *)io);
			error = io->io_Error = IOERR_ABORTED;

			/* reply the message, as usual */
			IExec->ReplyMsg(&io->io_Message);
			break;
		}
		io = (struct IORequest *)IExec->GetSucc((struct Node *)io);
	}

	IExec->ReleaseSemaphore(unit->fu_SigSem);

	return error;
}

void libBeginIO (struct DeviceManagerInterface *Self, struct IOStdReq *io) {
	struct FliteUnit *unit;

	unit = (struct FliteUnit *)io->io_Unit;

	dbug(("BeginIO()\n"));
	dbug(("unit: %ld, command: %ld\n", unit->ru_UnitNum, io->io_Command));

	switch (io->io_Command) {
		case CMD_WRITE:
			io->io_Flags &= ~IOF_QUICK;
			/* forward to unit process */
			IExec->ObtainSemaphoreShared(unit->fu_SigSem);
			IExec->PutMsg(unit->fu_Port, &io->io_Message);
			IExec->ReleaseSemaphore(unit->fu_SigSem);
			return;

		case NSCMD_DEVICEQUERY:
			if (io->io_Length < sizeof(struct NSDeviceQueryResult)) {
				io->io_Error = IOERR_BADLENGTH;
			} else {
				struct NSDeviceQueryResult *dq;
				dq = (struct NSDeviceQueryResult *)io->io_Data;
				dq->DevQueryFormat = 0;
				io->io_Actual = dq->SizeAvailable =
					sizeof(struct NSDeviceQueryResult);
				dq->DeviceType = NSDEVTYPE_UNKNOWN;
				dq->DeviceSubType = 0;
				dq->SupportedCommands = (uint16 *)cmd_list;
				io->io_Error = IOERR_SUCCESS;
			}
			break;

		default:
			/* not supported */
			dbug(("Unsupported command: %ld\n", io->io_Command));
			io->io_Error = IOERR_NOCMD;
			break;
	}

	io->io_Message.mn_Node.ln_Type = NT_MESSAGE;

	if (!(io->io_Flags & IOF_QUICK))
		IExec->ReplyMsg(&io->io_Message);
}
