#ifndef __BLKTOOL_H__
#define __BLKTOOL_H__

#include <glib.h>

#define FREE_ON_EXIT

#define MSG_USAGE "usage: blktool DEVICE COMMAND [args...]\n"
#define MSG_NOT_BLKDEV "%s is not a block device\n"
#define MSG_UNKNOWN_CMD "unknown command '%s'\n"
#define MSG_INVALID_ARG "invalid argument '%s' passed to command '%s'\n"
#define MSG_INVALID_CMD_ARGS "invalid arguments passed to command '%s'\n"
#define MSG_INVALID_CMD_NOREAD "it is not possible to query settings via command '%s'\n"
#define MSG_VERSION "blktool version %s\n"
#define MSG_UNKNOWN_ID "blktool does not know how to dump this type of device\n"

#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))

#define IOCTL(cmd,arg) ioctl_call(cmd, #cmd, arg)

#ifndef SCSI_IOCTL_GET_PCI
#define SCSI_IOCTL_GET_PCI 0x5387
#endif

struct command;

typedef void (*handler_t)(int argc, char **argv, struct command *);

#define DEF_HANDLER_PROTO(func) \
	void handle_##func (int, char **, struct command *)

typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned long long u64;

enum ata_commands {
	ATA_CMD_MEDIA_LOCK	= 0xDE,
	ATA_CMD_MEDIA_UNLOCK	= 0xDF,
	ATA_CMD_SET_FEATURES	= 0xEF,
	ATA_CMD_SLEEP		= 0xE6,
	ATA_CMD_SLEEP_2		= 0x99,
	ATA_CMD_STANDBY		= 0xE0,
	ATA_CMD_STANDBY_2	= 0x94,
};

enum ata_set_features {
	SETFEAT_APM_ON		= 0x05,
	SETFEAT_APM_OFF		= 0x85,
	SETFEAT_DEFECT_MGMT_ON	= 0x04, /* obsolete */
	SETFEAT_DEFECT_MGMT_OFF	= 0x84, /* obsolete */
	SETFEAT_READ_AHEAD	= 0xAA,
	SETFEAT_READ_AHEAD_OFF	= 0x55,
	SETFEAT_REVERT_TO_DEF	= 0xCC,
	SETFEAT_REVERT_TO_DEF_OFF = 0x66,
	SETFEAT_WCACHE_ON	= 0x02,
	SETFEAT_WCACHE_OFF	= 0x82,
};

typedef enum dev_class_enum {
	dc_unknown,
	dc_any = dc_unknown,
	dc_ata,
	dc_scsi,
	dc_i2o,
} dev_class_t;

enum cmd_types {
	ct_void,
	ct_bool,
	ct_enum,
	ct_int,
};

struct command {
	const char		*cmd;
	enum cmd_types		cmd_type;
	handler_t		handler;
	dev_class_t		class_required;

	int			read_ioctl;
	const char		*read_ioctl_name;

	int			write_ioctl;
	const char		*write_ioctl_name;
};

enum bc_arg_type {
	bc_arg_int,
	bc_arg_int_ptr,
};

struct bool_command {
	struct command		cmd;

	const char		*str_false;
	const char		*str_true;

	enum bc_arg_type arg_type;
};

struct class_operations {
	void (*id)(void);
	void (*media)(int val);
	void (*read_ahead)(int val);
	void (*standby)(void);
	void (*wcache)(int val);
};

/* blktool.c */
extern int blkdev;
extern GPtrArray *flag_arr;
extern struct class_operations *ops;

/* util.c */
extern void pdie(const char *msg, int perr);
extern void ioctl_call(int cmd, const char *cmd_name, void *arg);
extern void flag_push(const char *flag_str);
extern void list_dump(const char *list_name, GPtrArray *arr);
extern int parse_bool(int argc, char **argv, struct bool_command *bcm);
extern int parse_int(int argc, char **argv, struct command *cmd);
extern void noread_arg_check(int argc, char **argv);
extern int get_bool(int argc, char **argv, struct command *cmd);
extern int get_int(int argc, char **argv, struct command *cmd);

/* ata.c */
extern void ata_init(void);
extern DEF_HANDLER_PROTO(defect_mgmt);
extern DEF_HANDLER_PROTO(dev_keep_settings);
extern DEF_HANDLER_PROTO(pm_mode);
extern DEF_HANDLER_PROTO(sleep);
extern DEF_HANDLER_PROTO(reset);

/* scsi.c */
extern void scsi_init(void);
extern DEF_HANDLER_PROTO(bus_id);
extern struct class_operations scsi_operations;

#endif /* __BLKTOOL_H__ */
