#include "mcdp.h"

/**
 * Copyright (C) 2001-2006 Tino Reichardt
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License Version 2, as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

/*
 * author:         Tino Reichardt <milky-mcdp@mcmilk.de>
 * status:         works for now
 *
 * details:
 * - for the linux send packet command ioctl()
 * - should work with 2.2, 2.3, 2.4, 2.5, 2.6 kernels
 *
 * todo:
 * - some simple checking for errors ?
 */

/* linux send packet command, since 2.1 ? */
#if WANT_LINUX_SEND_PACKET
int cmd_lx_sp(scmd_t *cmd)
{
	struct cdrom_generic_command io;
	struct request_sense sense;
	int r;
#if DEBUG_CDB
	char *file="LX_pc.log";
#endif

	byte_zero(&io, sizeof(io));
	byte_copy(io.cmd, cmd->cmdlen, cmd->cmd.s);

	io.sense  = &sense;
	io.buffer = (unsigned char*)cmd->buf.s;
	io.buflen = cmd->buflen;

#if KERNEL_VERSION(2,3,0) < LINUX_VERSION_CODE
	io.timeout = 1000 * MCDP_SCSI_TIMEOUT;
#endif

	if isset(cmd->flags, D_NONE)
		set(io.data_direction, CGC_DATA_NONE);

	if isset(cmd->flags, D_READ)
		set(io.data_direction, CGC_DATA_READ);

	if isset(cmd->flags, D_WRITE)
		set(io.data_direction, CGC_DATA_WRITE);

#if DEBUG_CDB
	cmd_debug(file, CDB_BEFORE);
#endif

	r=ioctl(cd->fd, CDROM_SEND_PACKET, &io);
	byte_copy(cmd->sense.s, MCDP_MAX_SENSE, io.sense);

#if DEBUG_CDB
	cmd_debug(file, CDB_AFTER);
#endif

	return r;
}
#endif /* WANT_LINUX_SEND_PACKET */

#if 0
/* 2.2.26: */
struct cdrom_generic_command
{
	unsigned char 		cmd[CDROM_PACKET_SIZE];
	unsigned char 		*buffer;
	unsigned int 		buflen;
	int			stat;
	struct request_sense	*sense;
	unsigned char		data_direction;
	void			*reserved[3];
};

/* 2.4.24 + 2.6.5 */
struct cdrom_generic_command
{
	unsigned char 		cmd[CDROM_PACKET_SIZE];
	unsigned char 		*buffer;
	unsigned int 		buflen;
	int			stat;
	struct request_sense	*sense;
	unsigned char		data_direction;
	int			quiet;
	int			timeout;
	void			*reserved[1];
};

struct request_sense {
	__u8 error_code		: 7;
	__u8 valid		: 1;
	__u8 segment_number;
	__u8 sense_key		: 4;
	__u8 reserved2		: 1;
	__u8 ili		: 1;
	__u8 reserved1		: 2;
	__u8 information[4];
	__u8 add_sense_len;
	__u8 command_info[4];
	__u8 asc;
	__u8 ascq;
	__u8 fruc;
	__u8 sks[3];
	__u8 asb[46];
};

struct request_sense {
#if defined(__BIG_ENDIAN_BITFIELD)
	__u8 valid		: 1;
	__u8 error_code		: 7;
#elif defined(__LITTLE_ENDIAN_BITFIELD)
	__u8 error_code		: 7;
	__u8 valid		: 1;
#endif
	__u8 segment_number;
#if defined(__BIG_ENDIAN_BITFIELD)
	__u8 reserved1		: 2;
	__u8 ili		: 1;
	__u8 reserved2		: 1;
	__u8 sense_key		: 4;
#elif defined(__LITTLE_ENDIAN_BITFIELD)
	__u8 sense_key		: 4;
	__u8 reserved2		: 1;
	__u8 ili		: 1;
	__u8 reserved1		: 2;
#endif
	__u8 information[4];
	__u8 add_sense_len;
	__u8 command_info[4];
	__u8 asc;
	__u8 ascq;
	__u8 fruc;
	__u8 sks[3];
	__u8 asb[46];
};

#endif

