/*
 * SCSI.C - Show SCSI Devices
 *
 *   $VER: SCSI.C 1.5 (11.11.96)
 *
 * (c) Copyright 1996 Richard Sellens.  All rights reserved.
 *
 * This software is provided as-is and is subject to change; no warranties
 * are made.  All use is at your own risk.  No liability or responsibility
 * is assumed.
 *
 * Release  Date     Change
 *
 * 1.0      02/02/96 Initial Program
 * 1.1      31/03/96 Made SCSI Device string area longer
 * 1.2      07/04/96 Added ability to select unit from List for display,
 *                   Added Locale support for most strings 
 * 1.3      05/05/96 Added ability to select controller device,
 *                   Added Locale support for remaining strings 
 * 1.4      16/06/96 Corrected Bug which cause unwanted characters to 
 *                      display on empty device
 *                   Corrected Image display in List (not showing 
 *                      complete Image)
 *                   Added ability to have 5 device TOOLTYPES 
 *                   Added code to prevent duplication of devices
 * 1.5      11/11/96 Minor Change to method used to display device 
 *                      standard
 *                   Modified Device List search to use same routine
 *                      as TOOLTYPES to add device to list.
 *                   Modified Method used to select page from list
 *                      gadget.
 *                   Modified Unit Page layout to allow for resizing
 *                      of window and hence gadgets.
 *
 */


/*------------------------------------------------------------------------*/

#define INTUITION_IOBSOLETE_H
#define CATCOMP_NUMBERS
#define CATCOMP_BLOCK
#define CATCOMP_CODE
#define REG(x) register __ ## x
#define ASM    __asm
#define SAVEDS __saveds

#include <dos/dos.h>
#include <exec/devices.h> 
#include <exec/errors.h> 
#include <exec/execbase.h>
#include <exec/memory.h>
#include <exec/types.h>
#include <graphics/gfxmacros.h>
#include <libraries/mui.h>
#include <libraries/locale.h>
#include <workbench/workbench.h>

#include <clib/alib_protos.h>
#include <clib/asl_protos.h>
#include <clib/dos_protos.h>
#include <clib/exec_protos.h>
#include <clib/graphics_protos.h>
#include <clib/icon_protos.h>
#include <clib/intuition_protos.h>
#include <clib/locale_protos.h>
#include <clib/muimaster_protos.h>
#include <clib/utility_protos.h>

#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#include <pragmas/asl_pragmas.h>
#include <pragmas/dos_pragmas.h>
#include <pragmas/exec_pragmas.h>
#include <pragmas/graphics_pragmas.h>
#include <pragmas/icon_pragmas.h>
#include <pragmas/intuition_pragmas.h>
#include <pragmas/locale_pragmas.h>
#include <pragmas/muimaster_pragmas.h>
#include <pragmas/utility_pragmas.h>

#include "Scsi_Cmd.h"

/*------------------------------------------------------------------------*/

void    Main(int argc, char **argv);
void    BailOut(APTR app, char *str);
void    GetDevList(int argc, char **argv);
int     gettooltypes(struct WBArg *, int);
BOOL    InitClasses(void);
void    ExitClasses(void);
ULONG   ScsiList_New(struct IClass *, Object *, struct opSet *);
ULONG   ScsiList_Cleanup(struct IClass *, Object *, Msg);
ULONG   ScsiList_Setup(struct IClass *, Object *, Msg);
ULONG   ScsiList_Select(struct IClass *, Object *, Msg);
void    ShowSCSI(char *);
void    ShowScsi_exit(long code, char *);
void    ListDevices(char *);
STRPTR  GetString(struct LocaleInfo *li, LONG stringNum);
STRPTR  SetStandard(int id);
STRPTR  SetDeviceType(int id);
int     AddDeviceToList(int pos, char *devname);

/*------------------------------------------------------------------------*/

extern  struct  Library         *DOSBase;
extern  struct  ExecBase        *SysBase;
extern  struct  GfxBase         *GfxBase;
extern  struct  IntuitionBase   *IntuitionBase;
extern  struct  Library         *UtilityBase;
struct  Library                 *LocaleBase;
struct  Library                 *IconBase;
struct  Library                 *MUIMasterBase  = NULL;

/*------------------------------------------------------------------------*/

#include "Scsi_Locale.h" 

/*------------------------------------------------------------------------*/

#define USE_CD_ROM_BODY
#define USE_CD_ROM_COLORS
#include "CD_Rom.h"

#define USE_HARD_DRIVE_BODY
#include "Hard_Drive.h"

#define USE_REMOVE_DRIVE_BODY
#include "Remove_Drive.h"

#define USE_NULL_BODY
#include "Null.h"

#define USE_NOUNIT_BODY
#include "NoUnit.h"

#define USE_PROCESSOR_BODY
#define USE_PROCESSOR_COLORS
#include "Processor.h"

#define USE_SCANNER_BODY
#define USE_SCANNER_COLORS
#include "Scanner.h"

#define USE_SCSI_BODY
#define USE_SCSI_COLORS
#include "ScsiImage.h"

/*------------------------------------------------------------------------*/

#ifndef MAKE_ID
#define MAKE_ID(a,b,c,d) ((ULONG) (a)<<24 | (ULONG) (b)<<16 | (ULONG) (c)<<8 | (ULONG) (d))
#endif

#define MAKE_PAGE(occur)  Child, VGroup, \ 
                            Child, HGroup, GroupFrame, \
                                Child, ColGroup(2), \
                                    Child, Label2(GetString(&li, MSG_Vendor)), \
                                    Child, Sl_Vendor[occur] = TextObject, \
                                        TextFrame, \
                                        MUIA_Text_SetMax, FALSE, \
                                    End, \
                                    Child, Label2(GetString(&li, MSG_Product)), \
                                    Child, Sl_Product[occur] = TextObject, \ 
                                        TextFrame, \
                                        MUIA_Text_SetMax, FALSE, \
                                    End, \
                                    Child, Label2(GetString(&li, MSG_Revision)), \
                                    Child, Sl_Revision[occur] = TextObject, \
                                        TextFrame, \
                                        MUIA_Text_SetMax, FALSE, \
                                    End, \
                                    Child, Label2(GetString(&li, MSG_Device_Type)), \
                                    Child, Sl_DevType[occur] = TextObject, \
                                        TextFrame, \
                                        MUIA_Text_SetMax, FALSE, \
                                    End, \
                                    Child, Label2(GetString(&li, MSG_Standard)), \                                    
                                    Child, Sl_Standard[occur] = TextObject, \
                                        TextFrame, \
                                        MUIA_Text_SetMax, FALSE, \
                                    End, \
                                End, \ 
                            End, \ 
                            Child, HGroup, GroupFrame, \
                                Child, HSpace(0), \    
                                Child, ColGroup(4), \
                                    Child, Label(GetString(&li, MSG_Removable)), \
                                    Child, Sl_Removable[occur] = ImageObject, \
                                        MUIA_InputMode, MUIV_InputMode_None, \
                                        MUIA_Selected, FALSE, \
                                        MUIA_Background, MUII_ButtonBack,\
                                        MUIA_Image_Spec, MUII_CheckMark, \
                                    End, \
                                    Child, Label(GetString(&li, MSG_Rel_Addr)), \
                                    Child, Sl_Rel_Addr[occur] = ImageObject, \
                                        MUIA_InputMode, MUIV_InputMode_None, \
                                        MUIA_Selected, FALSE, \
                                        MUIA_Background, MUII_ButtonBack,\
                                        MUIA_Image_Spec, MUII_CheckMark, \
                                    End, \
                                    Child, Label(GetString(&li, MSG_16_Wide)), \ 
                                    Child, Sl_16Wide_Addr[occur] = ImageObject, \
                                        MUIA_InputMode, MUIV_InputMode_None, \
                                        MUIA_Selected, FALSE, \
                                        MUIA_Background, MUII_ButtonBack,\
                                        MUIA_Image_Spec, MUII_CheckMark, \
                                    End, \
                                    Child, Label(GetString(&li, MSG_32_Wide)), \ 
                                    Child, Sl_32Wide_Addr[occur] = ImageObject, \
                                        MUIA_InputMode, MUIV_InputMode_None, \
                                        MUIA_Selected, FALSE, \
                                        MUIA_Background, MUII_ButtonBack,\
                                        MUIA_Image_Spec, MUII_CheckMark, \
                                    End, \
                                End, \ 
                                Child, HSpace(0), \ 
                            End, \ 
                        End, 


/*------------------------------------------------------------------------*/

struct  MUI_CustomClass         *CL_ScsiList;
struct  LocaleInfo              li;

APTR    app;
APTR    win1;
enum    { ID_OK = 1, ID_SELECT, ID_Dev };
static  APTR    lv_tools;
static  APTR    lv_scsi;
static  APTR    pg_group;
static  APTR    cycle;
char    *DevList[20];
int     totitem = 0;
struct  ScsiList_Data
{
    Object  *SL_OImage_CD;
    Object  *SL_OImage_HD;
    Object  *SL_OImage_RD;
    Object  *SL_OImage_SC;
    Object  *SL_OImage_NO;
    Object  *SL_OImage_NL;
    Object  *SL_OImage_PR;
    APTR    SL_Image_CD;
    APTR    SL_Image_HD;
    APTR    SL_Image_RD;
    APTR    SL_Image_SC;
    APTR    SL_Image_NO;
    APTR    SL_Image_NL;
    APTR    SL_Image_PR;
    struct  Hook    DisplayHook;
};
struct  ScsiUnitData
{
    int     SUD_Unit;           /*  Unit Id Number                        */
    char    *SUD_Vendor;        /*  Vendor Name                           */
    char    *SUD_Product;       /*  Product Name                          */
    char    *SUD_Revision;      /*  Product Revision Id                   */
    int     SUD_Dev_type;       /*  Type of Device                        */
    int     SUD_Standard;       /*  Device Standard                       */
    BOOL    SUD_Removable;      /*  Removable Media ?                     */
    BOOL    SUD_Rel_Addr;       /*  Relative Addressing ?                 */
    BOOL    SUD_16Wide_Addr;    /*  16 Bit Wide Addressing ?              */
    BOOL    SUD_32Wide_Addr;    /*  16 Bit Wide Addressing ?              */
};
struct  MsgPort     *replymp;
struct  IOStdReq    *scsi_req;
struct  SCSICmd     scsi_cmd;
UBYTE               *scsi_sense;
UBYTE               *scsi_data      = NULL;
static  char        *Units[] = { NULL, "0", "1", "2", "3", "4", "5", "6", NULL };
static  APTR        Sl_Product[8];
static  APTR        Sl_Vendor[8];
static  APTR        Sl_Revision[8];
static  APTR        Sl_DevType[8];
static  APTR        Sl_Standard[8];
static  APTR        Sl_Removable[8];
static  APTR        Sl_Rel_Addr[8];
static  APTR        Sl_16Wide_Addr[8];
static  APTR        Sl_32Wide_Addr[8];

/*------------------------------------------------------------------------*/

ULONG __stdargs DoSuperNew(struct IClass *cl,Object *obj,ULONG tag1,...)
{
	return(DoSuperMethod(cl,obj,OM_NEW,&tag1,NULL));
}

/*------------------------------------------------------------------------*/

void main(int argc, char **argv)
{
    ULONG   signals;
    BOOL    running = TRUE;
    ULONG   entry       = 0;

    if (!(li.li_LocaleBase = LocaleBase = OpenLibrary("locale.library",0L)))
        BailOut(NULL, "Unable to open locale.library");
    
    if ((IconBase = OpenLibrary("icon.library",0L)) == NULL)
        BailOut(NULL, GetString(&li, MSG_Unable_to_Open_icon));
    
    GetDevList(argc,argv);

    li.li_Catalog = OpenCatalog(NULL, "Scsi_List.catalog", TAG_DONE);
    
    if (!(MUIMasterBase = OpenLibrary(MUIMASTER_NAME,MUIMASTER_VMIN)))
        BailOut(NULL, GetString(&li, MSG_Unable_to_Open_MUI));

    Units[0] = (char *)AllocMem(strlen(GetString(&li, MSG_List)) + 1, MEMF_ANY|MEMF_CLEAR);
    strcpy(Units[0], GetString(&li, MSG_List));

    if (!(InitClasses()))
        BailOut(NULL, GetString(&li, MSG_Unable_to_Create_Cust_Class));
        
    app = ApplicationObject,
            MUIA_Application_Title,         "Scsi List",            
		    MUIA_Application_Version,       "$VER: Scsi_List 1.5 (11.11.96)",
		    MUIA_Application_Copyright,     "@1996, Richard Sellens",
		    MUIA_Application_Author,        "Richard Sellens",
		    MUIA_Application_Description,   "Show SCSI Devices",
		    MUIA_Application_Base,          "SCSI",
            
            MUIA_Application_Window, win1 = WindowObject,
			    MUIA_Window_Title, "Scsi List",
			    MUIA_Window_ID   , MAKE_ID('S','C','S','I'),

			    WindowContents, VGroup,
                    Child, HGroup, GroupFrame,
                        MUIA_Weight, 100,
                        Child, BodychunkObject, MUIA_FixWidth, SCSI_WIDTH,
                                 MUIA_FixHeight, SCSI_HEIGHT,
                                 MUIA_Bitmap_Width, SCSI_WIDTH,
                                 MUIA_Bitmap_Height, SCSI_HEIGHT,
                                 MUIA_Bodychunk_Depth, SCSI_DEPTH,
                                 MUIA_Bodychunk_Body, (UBYTE *)Scsi_body,
                                 MUIA_Bodychunk_Compression, SCSI_COMPRESSION,
                                 MUIA_Bodychunk_Masking, SCSI_MASKING,
                                 MUIA_Bitmap_SourceColors, (ULONG *)Scsi_colors,
                                 MUIA_Bitmap_Transparent, 0,
                        End,
                        Child, ColGroup(2),
                            Child, Label1(GetString(&li, MSG_Device)),
                            Child, cycle = Cycle(DevList),
                        End,
                    End,  
                    Child, pg_group = RegisterGroup(Units),
                        MUIA_Register_Frame, TRUE,
                        Child, lv_tools = ListviewObject,
                            MUIA_Weight, 120,
                            MUIA_CycleChain, 1,
                            MUIA_Listview_Input, TRUE,
                            ReadListFrame,                             
                            MUIA_Listview_List, lv_scsi = NewObject(CL_ScsiList->mcc_Class, NULL, TAG_DONE),
                        End,
                        MAKE_PAGE(1)
                        MAKE_PAGE(2)
                        MAKE_PAGE(3)
                        MAKE_PAGE(4)
                        MAKE_PAGE(5)
                        MAKE_PAGE(6)
                        MAKE_PAGE(7)
                    End,  
                End,
            End,
        End;
       
    if (!app)
        BailOut(app, GetString(&li, MSG_Failed_to_Create_App));
    
    DoMethod(win1, MUIM_Notify, MUIA_Window_CloseRequest, TRUE,
        app,2,MUIM_Application_ReturnID, MUIV_Application_ReturnID_Quit); 
    DoMethod(lv_tools, MUIM_Notify,MUIA_Listview_DoubleClick,TRUE,
        lv_scsi,1 , ID_SELECT);  
    DoMethod(cycle,MUIM_Notify,MUIA_Cycle_Active, MUIV_EveryTime,
        app,2,MUIM_Application_ReturnID, ID_Dev); 
   
    set(win1, MUIA_Window_Open, TRUE);
  
    set(cycle, MUIA_Cycle_Active, 0);    
    ShowSCSI(DevList[0]);
   
    while (running)
    { 
        ULONG id = DoMethod(app, MUIM_Application_NewInput, &signals);
        switch (id)
        {
            case MUIV_Application_ReturnID_Quit:
                running = FALSE;
                break;
            case ID_Dev:
                get(cycle, MUIA_Cycle_Active, &entry);
                DoMethod(lv_tools, MUIM_List_Clear);
                ShowSCSI(DevList[entry]);
                set(pg_group, MUIA_Group_ActivePage, 0); 
                break;
            case ID_OK:
                break;
        }
        if (running && signals)
            Wait(signals);
    }
    
    set(win1, MUIA_Window_Open, FALSE);
    BailOut(app, NULL);
}

/*------------------------------------------------------------------------*/

void BailOut(APTR app, char *str)
{
    int loop;

    FreeMem(Units[0], strlen(GetString(&li, MSG_List)) + 1);
        
    for (loop =0; loop<(totitem +1); loop++)
    {
        FreeMem(DevList[loop], strlen(DevList[loop]) + 1);   
    }
    
    if (app)
        MUI_DisposeObject(app);

	ExitClasses();

    if (MUIMasterBase)
        CloseLibrary(MUIMasterBase);
    
    if (LocaleBase)
    {
        CloseCatalog(li.li_Catalog);
	    CloseLibrary(LocaleBase);
    }
    
    if (IconBase)
	    CloseLibrary(IconBase);
    
    if (str)
    {
        puts(str);
        exit(20);
    }
    
    exit(0);    
}

/*------------------------------------------------------------------------*/
void GetDevList(int argc, char **argv)
{
    struct  WBStartup   *WBenchMsg;
    struct  WBArg       *wbarg;
    char    *scsi_name  = "scsi";
    struct  Node        *DeviceLibNode;
    int     i           = 0;
    LONG    olddir;
    BOOL    FromWb;
    
    Forbid();
    DeviceLibNode = SysBase->DeviceList.lh_Head;
    while (DeviceLibNode->ln_Succ)
    {
        DeviceLibNode = DeviceLibNode->ln_Succ;
        if (strstr(DeviceLibNode->ln_Name, strlwr(scsi_name)))
        {
            i = AddDeviceToList(i, DeviceLibNode->ln_Name);
        }
        else
        {
            if (strstr(DeviceLibNode->ln_Name, strupr(scsi_name)))
            {
                i = AddDeviceToList(i, DeviceLibNode->ln_Name);
            }

        }
    }
    Permit();

    FromWb  = (argc==0) ?   TRUE : FALSE;
    if (FromWb)
    {
        WBenchMsg = (struct WBStartup *)argv;
        wbarg = WBenchMsg->sm_ArgList;
        olddir = -1;
        if ((wbarg->wa_Lock) && (*wbarg->wa_Name))
            olddir = CurrentDir(wbarg->wa_Lock);
        i = gettooltypes(wbarg, i);
        if (olddir != -1)
           CurrentDir(olddir); /*  CD back where we were           */
    }
    
    totitem = i - 1;
    DevList[i] = NULL;
    return;
}

/*------------------------------------------------------------------------*/

int gettooltypes(struct WBArg *wbarg, int i)
{
    struct  DiskObject  *dobj;
    char    **toolarray;
    char    *s;

    if ((*wbarg->wa_Name) && (dobj = GetDiskObject(wbarg->wa_Name)))
    {
        toolarray = (char **)dobj->do_ToolTypes;
        if (s = (char *)FindToolType(toolarray, "DEVICE"))
        {
            i = AddDeviceToList(i, s);
        } 
        if (s = (char *)FindToolType(toolarray, "DEVICE1"))
        {
            i = AddDeviceToList(i, s);
        } 
        if (s = (char *)FindToolType(toolarray, "DEVICE2"))
        {
            i = AddDeviceToList(i, s);
        } 
        if (s = (char *)FindToolType(toolarray, "DEVICE3"))
        {
            i = AddDeviceToList(i, s);
        } 
        if (s = (char *)FindToolType(toolarray, "DEVICE4"))
        {
            i = AddDeviceToList(i, s);
        } 
        FreeDiskObject(dobj);
    }
       
    return(i);   
}

/*------------------------------------------------------------------------*/

int AddDeviceToList(int pos, char *devname)
{
    int     srch_pos = 0;
    BOOL    srch_match = FALSE;
    
    while(srch_pos < pos)
    {
        if (strnicmp(devname,DevList[srch_pos],sizeof(devname)) == 0)
        {
            srch_match = TRUE;
        }
        srch_pos = srch_pos + 1;
    }
    
    if (srch_match == FALSE)
    {
        DevList[pos] = (char *)AllocMem(strlen(devname) + 1, MEMF_ANY|MEMF_CLEAR);  
        strcpy(DevList[pos], devname);
        pos = pos + 1;
    }

    return(pos);
}

/*------------------------------------------------------------------------*/

SAVEDS ASM ULONG ScsiList_Dispatcher(REG(a0) struct IClass *cl,REG(a2) Object *obj,REG(a1) Msg msg)
{
	switch (msg->MethodID)
	{
		case OM_NEW              : return(ScsiList_New    (cl,obj,(APTR)msg));
		case MUIM_Setup          : return(ScsiList_Setup  (cl,obj,(APTR)msg));
		case MUIM_Cleanup        : return(ScsiList_Cleanup(cl,obj,(APTR)msg));
        case ID_SELECT           : return(ScsiList_Select (cl,obj,(APTR)msg));
	}
	return(DoSuperMethodA(cl,obj,msg));
}

/*------------------------------------------------------------------------*/

SAVEDS ASM APTR ScsiList_ConstructFunc(REG(a1) struct ScsiUnitData *SLCF_src)
{
    struct ScsiUnitData *SLCF_dest = (struct ScsiUnitData *)AllocMem(sizeof(struct ScsiUnitData), MEMF_ANY|MEMF_CLEAR);

    SLCF_dest->SUD_Vendor = (char *)AllocMem(10, MEMF_ANY|MEMF_CLEAR);
   	SLCF_dest->SUD_Product = (char *)AllocMem(18, MEMF_ANY|MEMF_CLEAR);
    SLCF_dest->SUD_Revision = (char *)AllocMem(6, MEMF_ANY|MEMF_CLEAR); 

    SLCF_dest->SUD_Unit = SLCF_src->SUD_Unit;
    strcpy(SLCF_dest->SUD_Vendor, SLCF_src->SUD_Vendor);
    strcpy(SLCF_dest->SUD_Product, SLCF_src->SUD_Product);
    strcpy(SLCF_dest->SUD_Revision, SLCF_src->SUD_Revision);
    SLCF_dest->SUD_Dev_type = SLCF_src->SUD_Dev_type;
    SLCF_dest->SUD_Standard = SLCF_src->SUD_Standard;
    SLCF_dest->SUD_Removable = SLCF_src->SUD_Removable;
    SLCF_dest->SUD_Rel_Addr = SLCF_src->SUD_Rel_Addr;
    SLCF_dest->SUD_16Wide_Addr = SLCF_src->SUD_16Wide_Addr;
    SLCF_dest->SUD_32Wide_Addr = SLCF_src->SUD_32Wide_Addr;
     
    return(SLCF_dest);
}

/*------------------------------------------------------------------------*/

SAVEDS ASM VOID ScsiList_DestructFunc(REG(a1) struct ScsiUnitData *SLDF_data)
{
    FreeMem(SLDF_data->SUD_Vendor, 10);
    FreeMem(SLDF_data->SUD_Product, 18);
    FreeMem(SLDF_data->SUD_Revision, 6); 
    
    FreeMem(SLDF_data, sizeof(struct ScsiUnitData));
}

/*------------------------------------------------------------------------*/

SAVEDS ASM LONG ScsiList_DisplayFunc(REG(a0) struct Hook *hook,REG(a2) char **array, REG(a1) struct ScsiUnitData *data1)
{
	struct ScsiList_Data *data = (APTR)hook->h_Data;
    static char buf1[50], buf2[30], buf3[30];
    
    *array++ = "";
    
    if (!data1)
    {
		strcpy(buf2,"\33b\33u");
		strcpy(buf3,"\33b\33u");
        strcat(buf2, GetString(&li, MSG_Unit));
        strcat(buf3, GetString(&li, MSG_Product));
        *array++ = "";
        *array++ = buf2;
        *array   = buf3;
    }
    else
    {
        switch(data1->SUD_Dev_type)
        {
            case 0:
                if (data1->SUD_Removable)
                    sprintf(buf1, "\33O[%08lx]", data->SL_Image_RD);
                else
                    sprintf(buf1, "\33O[%08lx]", data->SL_Image_HD);
                break;
            case 1:
                sprintf(buf1, "\33O[%08lx]", data->SL_Image_RD);
                break;
            case 3:
                sprintf(buf1, "\33O[%08lx]", data->SL_Image_PR);
                break;
            case 4:
                sprintf(buf1, "\33O[%08lx]", data->SL_Image_CD);
                break;
            case 5:
                sprintf(buf1, "\33O[%08lx]", data->SL_Image_CD);
                break;
            case 6:
                sprintf(buf1, "\33O[%08lx]", data->SL_Image_SC);
                break;
            case 99:
                sprintf(buf1, "\33O[%08lx]", data->SL_Image_NO);
                break; 
            default:
                sprintf(buf1, "\33O[%08lx]", data->SL_Image_NL);
                break;
        }
        sprintf(buf2, "%d", data1->SUD_Unit);
        strcpy(buf3, data1->SUD_Product);
        *array++ = buf1;
        *array++ = buf2;
        *array   = buf3;
    }
    
	return(0);
}

/*------------------------------------------------------------------------*/

ULONG ScsiList_New(struct IClass *cl,Object *obj,struct opSet *msg)
{
	static const struct Hook ScsiList_ConstructHook = { { 0,0 }, (VOID *)ScsiList_ConstructFunc, NULL, NULL};
	static const struct Hook ScsiList_DestructHook  = { { 0,0 }, (VOID *)ScsiList_DestructFunc, NULL, NULL};

	obj=(Object *)DoSuperNew(cl,obj,
		MUIA_List_ConstructHook, &ScsiList_ConstructHook, 
		MUIA_List_DestructHook , &ScsiList_DestructHook,
		MUIA_List_Format       , ",,,",
		MUIA_List_Title        , TRUE,
		MUIA_List_MinLineHeight, CD_ROM_HEIGHT,		
        TAG_MORE,msg->ops_AttrList);

	if (obj)
	{
		struct ScsiList_Data *data = INST_DATA(cl,obj);

		data->DisplayHook.h_Entry = (VOID *)ScsiList_DisplayFunc;
		data->DisplayHook.h_Data  = (APTR)data;

		set(obj,MUIA_List_DisplayHook,&data->DisplayHook);
	}

	return((ULONG)obj);
    
}

/*------------------------------------------------------------------------*/

static Object *makescsiimage(UBYTE *body)
{
	Object *obj = BodychunkObject,
		MUIA_FixWidth             , CD_ROM_WIDTH ,
		MUIA_FixHeight            , CD_ROM_HEIGHT,
		MUIA_Bitmap_Width         , CD_ROM_WIDTH ,
		MUIA_Bitmap_Height        , CD_ROM_HEIGHT,
		MUIA_Bodychunk_Depth      , CD_ROM_DEPTH ,
		MUIA_Bodychunk_Body       , (UBYTE *)body,
		MUIA_Bodychunk_Compression, CD_ROM_COMPRESSION,
		MUIA_Bodychunk_Masking    , CD_ROM_MASKING,
		MUIA_Bitmap_SourceColors  , (ULONG *)CD_Rom_colors,
		MUIA_Bitmap_Transparent   , 0,
		End;

	return(obj);
}

/*------------------------------------------------------------------------*/

static Object *makescsiimagePR(UBYTE *body)
{
	Object *obj = BodychunkObject,
		MUIA_FixWidth             , PROCESSOR_WIDTH ,
		MUIA_FixHeight            , PROCESSOR_HEIGHT,
		MUIA_Bitmap_Width         , PROCESSOR_WIDTH ,
		MUIA_Bitmap_Height        , PROCESSOR_HEIGHT,
		MUIA_Bodychunk_Depth      , PROCESSOR_DEPTH ,
		MUIA_Bodychunk_Body       , (UBYTE *)body,
		MUIA_Bodychunk_Compression, PROCESSOR_COMPRESSION,
		MUIA_Bodychunk_Masking    , PROCESSOR_MASKING,
		MUIA_Bitmap_SourceColors  , (ULONG *)Processor_colors,
		MUIA_Bitmap_Transparent   , 0,
		End;

	return(obj);
}

/*------------------------------------------------------------------------*/

static Object *makescsiimageSC(UBYTE *body)
{
	Object *obj = BodychunkObject,
		MUIA_FixWidth             , SCANNER_WIDTH ,
		MUIA_FixHeight            , SCANNER_HEIGHT,
		MUIA_Bitmap_Width         , SCANNER_WIDTH ,
		MUIA_Bitmap_Height        , SCANNER_HEIGHT,
		MUIA_Bodychunk_Depth      , SCANNER_DEPTH ,
		MUIA_Bodychunk_Body       , (UBYTE *)body,
		MUIA_Bodychunk_Compression, SCANNER_COMPRESSION,
		MUIA_Bodychunk_Masking    , SCANNER_MASKING,
		MUIA_Bitmap_SourceColors  , (ULONG *)Scanner_colors,
		MUIA_Bitmap_Transparent   , 0,
		End;

	return(obj);
}

/*------------------------------------------------------------------------*/

ULONG ScsiList_Setup(struct IClass *cl,Object *obj,Msg msg)
{
	struct ScsiList_Data *data = INST_DATA(cl,obj);

	if (!DoSuperMethodA(cl,obj,msg))
		return(FALSE);

	data->SL_OImage_CD = makescsiimage((UBYTE *)CD_Rom_body);
	data->SL_OImage_HD = makescsiimage((UBYTE *)Hard_Drive_body);
	data->SL_OImage_PR = makescsiimagePR((UBYTE *)Processor_body);
	data->SL_OImage_RD = makescsiimage((UBYTE *)Remove_Drive_body);
	data->SL_OImage_SC = makescsiimageSC((UBYTE *)Scanner_body);
	data->SL_OImage_NO = makescsiimage((UBYTE *)NoUnit_body); 
	data->SL_OImage_NL = makescsiimage((UBYTE *)Null_body);

	data->SL_Image_CD = (APTR)DoMethod(obj,MUIM_List_CreateImage,data->SL_OImage_CD ,0);
	data->SL_Image_HD = (APTR)DoMethod(obj,MUIM_List_CreateImage,data->SL_OImage_HD ,0);
	data->SL_Image_PR = (APTR)DoMethod(obj,MUIM_List_CreateImage,data->SL_OImage_PR ,0);
	data->SL_Image_RD = (APTR)DoMethod(obj,MUIM_List_CreateImage,data->SL_OImage_RD ,0);
	data->SL_Image_SC = (APTR)DoMethod(obj,MUIM_List_CreateImage,data->SL_OImage_SC ,0);
	data->SL_Image_NO = (APTR)DoMethod(obj,MUIM_List_CreateImage,data->SL_OImage_NO ,0); 
	data->SL_Image_NL = (APTR)DoMethod(obj,MUIM_List_CreateImage,data->SL_OImage_NL ,0);

	MUI_RequestIDCMP(obj,IDCMP_MOUSEBUTTONS);

	return(TRUE);
}
/*------------------------------------------------------------------------*/

ULONG ScsiList_Cleanup(struct IClass *cl,Object *obj,Msg msg)
{
	struct ScsiList_Data *data = INST_DATA(cl,obj);

	DoMethod(obj,MUIM_List_DeleteImage,data->SL_Image_CD);
	DoMethod(obj,MUIM_List_DeleteImage,data->SL_Image_HD);
	DoMethod(obj,MUIM_List_DeleteImage,data->SL_Image_PR);
	DoMethod(obj,MUIM_List_DeleteImage,data->SL_Image_RD);
	DoMethod(obj,MUIM_List_DeleteImage,data->SL_Image_SC);
	DoMethod(obj,MUIM_List_DeleteImage,data->SL_Image_NO); 
	DoMethod(obj,MUIM_List_DeleteImage,data->SL_Image_NL);

	MUI_RejectIDCMP(obj,IDCMP_MOUSEBUTTONS);

	return(DoSuperMethodA(cl,obj,msg));
}


/*------------------------------------------------------------------------*/

ULONG ScsiList_Select(struct IClass *cl,Object *obj,Msg msg)
{
    ULONG   c_pos;

    get(lv_tools, MUIA_List_Active, &c_pos);
    set(pg_group, MUIA_Group_ActivePage, (c_pos + 1)); 

	return(DoSuperMethodA(cl,obj,msg));
}

/*------------------------------------------------------------------------*/

BOOL InitClasses(VOID)
{
	CL_ScsiList   = MUI_CreateCustomClass(NULL, MUIC_List, NULL, sizeof(struct ScsiList_Data), ScsiList_Dispatcher);

	if (CL_ScsiList)
		return(TRUE);

	ExitClasses();
	return(FALSE);
}

/*------------------------------------------------------------------------*/

VOID ExitClasses(VOID)
{
	if (CL_ScsiList) 
        MUI_DeleteCustomClass(CL_ScsiList);
}

/*------------------------------------------------------------------------*/

void ShowSCSI(char *SSdevice)
{
    if (!(scsi_sense = (UBYTE *)AllocMem(252, MEMF_CHIP|MEMF_CLEAR)))
        ShowScsi_exit(20, GetString(&li, MSG_Unable_to_Allocate_Memory));

    if (!(scsi_data = (UBYTE *)AllocMem(252, MEMF_CHIP|MEMF_CLEAR)))
        ShowScsi_exit(20, GetString(&li, MSG_Unable_to_Allocate_Memory));

    if (!(replymp = (struct MsgPort *)CreatePort(NULL, 0)))
        ShowScsi_exit(20, GetString(&li, MSG_Unable_to_Create_Mess_Port));
        
    if (!(scsi_req = (struct IOStdReq *)CreateStdIO(replymp)))
        ShowScsi_exit(20, GetString(&li, MSG_Unable_to_Create_StandardIO));
    
    ListDevices(SSdevice); 
    
    ShowScsi_exit(0, NULL);
}

/*------------------------------------------------------------------------*/

void ShowScsi_exit(long code, char *errmsg)
{
    if (scsi_req)
        DeleteStdIO(scsi_req);
    
    if (replymp)
        DeletePort(replymp);
    
    if (scsi_sense)
        FreeMem(scsi_sense, 252);
    
    if (scsi_data)
        FreeMem(scsi_data, 252);
    
    if (errmsg)
        printf("\n%s\n", errmsg);
    
    return;
}

/*------------------------------------------------------------------------*/

void ListDevices(char *devname)
{
    int i;
    struct ScsiUnitData *SUdata = (struct ScsiUnitData *)AllocMem(sizeof(struct ScsiUnitData), MEMF_ANY|MEMF_CLEAR);
    static  UBYTE       cmd[] = { SCSI_CMD_INQ, 0, 0, 0, 252, 0, };
        
    SUdata->SUD_Vendor = (char *)AllocMem(10, MEMF_ANY|MEMF_CLEAR);
	SUdata->SUD_Product = (char *)AllocMem(18, MEMF_ANY|MEMF_CLEAR);
    SUdata->SUD_Revision = (char *)AllocMem(6, MEMF_ANY|MEMF_CLEAR);
            
    set(lv_tools, MUIA_List_Quiet, TRUE);
    for (i = 0; i < 7; i++)
    {
        SUdata->SUD_Unit = i;    
        if (OpenDevice(devname, i, scsi_req, 0))
        {
            strcpy(SUdata->SUD_Vendor, " ");
            strcpy(SUdata->SUD_Product, GetString(&li, MSG_Not_Used));
            strcpy(SUdata->SUD_Revision, " ");
            SUdata->SUD_Dev_type = 99;
            SUdata->SUD_Standard = 9;
            SUdata->SUD_Removable = FALSE;
            SUdata->SUD_Rel_Addr = FALSE;
            SUdata->SUD_16Wide_Addr = FALSE;
            SUdata->SUD_32Wide_Addr = FALSE;
        }
        else
        {
            scsi_req->io_Length         = sizeof(struct SCSICmd);
            scsi_req->io_Data           = (APTR) &scsi_cmd;
            scsi_req->io_Command        = HD_SCSICMD;
            scsi_cmd.scsi_Data          = (APTR) scsi_data;
            scsi_cmd.scsi_Length        = 252;
            scsi_cmd.scsi_SenseActual   = 0;
            scsi_cmd.scsi_SenseData     = scsi_sense;
            scsi_cmd.scsi_SenseLength   = 252;
            scsi_cmd.scsi_Command       = (UBYTE *)cmd;
            scsi_cmd.scsi_CmdLength     = sizeof(cmd);
            scsi_cmd.scsi_Flags         = SCSIF_READ|SCSIF_AUTOSENSE;
    
            DoIO((struct IOStdReq *)scsi_req);
            
            
            if (scsi_req->io_Error)
            { 
                strcpy(SUdata->SUD_Vendor," ");
                strcpy(SUdata->SUD_Product, GetString(&li, MSG_Not_Used));
                strcpy(SUdata->SUD_Revision, " ");
                SUdata->SUD_Dev_type = 99;
                SUdata->SUD_Standard = 9;
                SUdata->SUD_Removable = FALSE;
                SUdata->SUD_Rel_Addr = FALSE;
                SUdata->SUD_16Wide_Addr = FALSE;
                SUdata->SUD_32Wide_Addr = FALSE;
            }
            else
            {
                sprintf(SUdata->SUD_Vendor, "%.8s", &scsi_data[8]);
                sprintf(SUdata->SUD_Product, "%.16s", &scsi_data[16]);
                sprintf(SUdata->SUD_Revision, "%.4s", &scsi_data[32]);
                SUdata->SUD_Dev_type = (scsi_data[0] & 0x1F);
                SUdata->SUD_Standard = (scsi_data[3] & 0x0F);
                SUdata->SUD_Removable = ((scsi_data[1] & 0x80) ? TRUE : FALSE); 
                SUdata->SUD_Rel_Addr = ((scsi_data[7] & 0x80) ? TRUE : FALSE); 
                SUdata->SUD_16Wide_Addr = ((scsi_data[7] & 0x20) ? TRUE : FALSE); 
                SUdata->SUD_32Wide_Addr = ((scsi_data[7] & 0x40) ? TRUE : FALSE);
            }
            CloseDevice(scsi_req);
        } 
        DoMethod(lv_tools, MUIM_List_InsertSingle, SUdata, MUIV_List_Insert_Bottom);
        set(Sl_Product[i+1], MUIA_Text_Contents, SUdata->SUD_Product);
        set(Sl_Vendor[i+1], MUIA_Text_Contents, SUdata->SUD_Vendor);
        set(Sl_Revision[i+1], MUIA_Text_Contents, SUdata->SUD_Revision);
        set(Sl_DevType[i+1], MUIA_Text_Contents, SetDeviceType(SUdata->SUD_Dev_type));
        set(Sl_Standard[i+1], MUIA_Text_Contents, SetStandard(SUdata->SUD_Standard));
        set(Sl_Removable[i+1], MUIA_Selected, SUdata->SUD_Removable);
        set(Sl_Rel_Addr[i+1], MUIA_Selected, SUdata->SUD_Rel_Addr);
        set(Sl_16Wide_Addr[i+1], MUIA_Selected, SUdata->SUD_16Wide_Addr);
        set(Sl_32Wide_Addr[i+1], MUIA_Selected, SUdata->SUD_32Wide_Addr);
    }
    set(lv_tools, MUIA_List_Quiet, FALSE);  
    
    FreeMem(SUdata->SUD_Vendor, 10);
    FreeMem(SUdata->SUD_Product, 18);
    FreeMem(SUdata->SUD_Revision, 6);
    
    FreeMem(SUdata, sizeof(struct ScsiUnitData));
}

/*------------------------------------------------------------------------*/

STRPTR SetStandard(int id)
{
    switch(id)
    {
        case 0:
            return("SCSI-1");
            break;
        case 1:
            return("CCS");
            break;
        case 2:
            return("SCSI-2");
            break;
        default:
            return(" ");
            break; 
    }
}


/*------------------------------------------------------------------------*/

STRPTR SetDeviceType(int id)
{
    char    *empty = " ";
    
    switch(id)
    {
        case 0:
            return(GetString(&li, MSG_Direct_Access_Device));
            break;
        case 1:
            return(GetString(&li, MSG_Sequential_Access_Device));
            break;
        case 2:
            return(GetString(&li, MSG_Printer_Device));
            break;
        case 3:
            return(GetString(&li, MSG_Processor_Device));
            break;
        case 4:
            return(GetString(&li, MSG_Write_Once_Device));
            break;
        case 5:
            return(GetString(&li, MSG_CDROM_Device));
            break;
        case 6:
            return(GetString(&li, MSG_Scanner_Device));
            break;
        case 7:
            return(GetString(&li, MSG_Optical_Device));
            break;
        case 8:
            return(GetString(&li, MSG_Medium_Changer_Device));
            break;
        case 9:
            return(GetString(&li, MSG_Communications_Device));
            break;
        case 99:
            return(empty);
            break; 
        default:
            return(GetString(&li, MSG_Unknown_Device));
            break;
    }
}