From 5f6452189f3212dba1fa7e22a22ad508ac7c95d8 Mon Sep 17 00:00:00 2001 From: platon42 Date: Thu, 11 Jun 2009 19:02:07 +0000 Subject: [PATCH] Initial import of work-in-progress of Poseidon port. This includes the following components: - main poseidon.library - AddUSBClasses, AddUSBHardware, PsdDevLister, PsdErrorlog and PsdStackloader shell executables - Trident MUI Prefs - hub.class - bootmouse.class - bootkeyboard.class - massstorage.class (without mounting code) - pciusb.device Feedback and fixes to the mmakefiles and other parts of the source is appreciated. All files are copyrighted by Chris Hodges and not redistributable outside the AROS team until the bounty is completed and the code is licensed under the AROS Public License. git-svn-id: https://svn.aros.org/svn/aros/trunk/AROS@31400 fb15a70f-31f2-0310-bbcc-cdcc74a49acc --- rom/usb/classes/bootkeyboard/bootkeyboard.class.c | 1208 +++ rom/usb/classes/bootkeyboard/bootkeyboard.class.h | 36 + rom/usb/classes/bootkeyboard/bootkeyboard.conf | 19 + rom/usb/classes/bootkeyboard/bootkeyboard.h | 84 + rom/usb/classes/bootkeyboard/common.h | 55 + rom/usb/classes/bootkeyboard/debug.c | 38 + rom/usb/classes/bootkeyboard/debug.h | 22 + rom/usb/classes/bootkeyboard/mmakefile.src | 13 + rom/usb/classes/bootmouse/bootmouse.class.c | 1034 +++ rom/usb/classes/bootmouse/bootmouse.class.h | 37 + rom/usb/classes/bootmouse/bootmouse.conf | 19 + rom/usb/classes/bootmouse/bootmouse.h | 81 + rom/usb/classes/bootmouse/common.h | 55 + rom/usb/classes/bootmouse/debug.c | 38 + rom/usb/classes/bootmouse/debug.h | 22 + rom/usb/classes/bootmouse/mmakefile.src | 13 + rom/usb/classes/hub/common.h | 55 + rom/usb/classes/hub/debug.c | 38 + rom/usb/classes/hub/debug.h | 22 + rom/usb/classes/hub/hub.class.c | 1437 +++ rom/usb/classes/hub/hub.class.h | 33 + rom/usb/classes/hub/hub.conf | 19 + rom/usb/classes/hub/hub.h | 59 + rom/usb/classes/hub/mmakefile.src | 13 + rom/usb/classes/massstorage/common.h | 55 + rom/usb/classes/massstorage/debug.c | 38 + rom/usb/classes/massstorage/debug.h | 24 + rom/usb/classes/massstorage/dev.c | 443 + rom/usb/classes/massstorage/dev.h | 65 + rom/usb/classes/massstorage/massstorage.class.c | 6098 +++++++++++++ rom/usb/classes/massstorage/massstorage.class.h | 102 + rom/usb/classes/massstorage/massstorage.conf | 19 + rom/usb/classes/massstorage/massstorage.h | 305 + rom/usb/classes/massstorage/mmakefile.src | 13 + rom/usb/classes/mmakefile | 353 + rom/usb/classes/mmakefile.src | 12 + rom/usb/classes/usbclass.conf | 26 + rom/usb/classes/usbclass.doc | 607 ++ rom/usb/pciusb/debug.c | 38 + rom/usb/pciusb/debug.h | 22 + rom/usb/pciusb/dev.c | 262 + rom/usb/pciusb/ehcichip.h | 315 + rom/usb/pciusb/hccommon.h | 23 + rom/usb/pciusb/mmakefile.src | 11 + rom/usb/pciusb/ohcichip.h | 324 + rom/usb/pciusb/pci_aros.c | 1281 +++ rom/usb/pciusb/pci_aros.h | 50 + rom/usb/pciusb/pciusb.conf | 16 + rom/usb/pciusb/pciusb.h | 196 + rom/usb/pciusb/uhcichip.h | 243 + rom/usb/pciusb/uhwcmd.c | 5411 ++++++++++++ rom/usb/pciusb/uhwcmd.h | 93 + rom/usb/poseidon/AddUSBClasses.c | 167 + rom/usb/poseidon/AddUSBHardware.c | 146 + rom/usb/poseidon/PsdDevLister.c | 535 ++ rom/usb/poseidon/PsdErrorlog.c | 116 + rom/usb/poseidon/PsdStackLoader.c | 32 + rom/usb/poseidon/debug.c | 38 + rom/usb/poseidon/debug.h | 26 + rom/usb/poseidon/mmakefile.src | 31 + rom/usb/poseidon/numtostr.c | 2317 +++++ rom/usb/poseidon/numtostr.h | 25 + rom/usb/poseidon/popo.gui.c | 1578 ++++ rom/usb/poseidon/popo.gui.h | 60 + rom/usb/poseidon/poseidon.conf | 141 + rom/usb/poseidon/poseidon.doc | 2425 +++++ rom/usb/poseidon/poseidon.library.c | 9287 ++++++++++++++++++++ rom/usb/poseidon/poseidon.library.h | 141 + rom/usb/poseidon/poseidon_intern.h | 911 ++ rom/usb/poseidon/usbhardware.doc | 674 ++ rom/usb/trident/ActionClass.c | 5460 ++++++++++++ rom/usb/trident/ActionClass.h | 287 + rom/usb/trident/CfgListClass.c | 372 + rom/usb/trident/CfgListClass.h | 19 + rom/usb/trident/DevWinClass.c | 930 ++ rom/usb/trident/DevWinClass.h | 69 + rom/usb/trident/IconListClass.c | 212 + rom/usb/trident/IconListClass.h | 23 + rom/usb/trident/MasonIcons/Class_Audio | Bin 0 -> 422 bytes rom/usb/trident/MasonIcons/Class_Bluetooth | Bin 0 -> 402 bytes rom/usb/trident/MasonIcons/Class_CDCControl | Bin 0 -> 404 bytes rom/usb/trident/MasonIcons/Class_CDCData | Bin 0 -> 406 bytes rom/usb/trident/MasonIcons/Class_ChipSmartCard | Bin 0 -> 422 bytes rom/usb/trident/MasonIcons/Class_CommDevice | Bin 0 -> 398 bytes rom/usb/trident/MasonIcons/Class_HID | Bin 0 -> 412 bytes rom/usb/trident/MasonIcons/Class_Hub | Bin 0 -> 400 bytes rom/usb/trident/MasonIcons/Class_MassStorage | Bin 0 -> 404 bytes rom/usb/trident/MasonIcons/Class_None | Bin 0 -> 422 bytes rom/usb/trident/MasonIcons/Class_Physical | Bin 0 -> 406 bytes rom/usb/trident/MasonIcons/Class_Printer | Bin 0 -> 422 bytes rom/usb/trident/MasonIcons/Class_Security | Bin 0 -> 416 bytes rom/usb/trident/MasonIcons/Class_StillImage | Bin 0 -> 400 bytes rom/usb/trident/MasonIcons/Class_Vendor | Bin 0 -> 418 bytes rom/usb/trident/MasonIcons/Classes | Bin 0 -> 418 bytes rom/usb/trident/MasonIcons/Devices | Bin 0 -> 424 bytes rom/usb/trident/MasonIcons/General | Bin 0 -> 424 bytes rom/usb/trident/MasonIcons/GreenLED | Bin 0 -> 402 bytes rom/usb/trident/MasonIcons/Hardware | Bin 0 -> 420 bytes rom/usb/trident/MasonIcons/MI_Class_Audio.c | 68 + rom/usb/trident/MasonIcons/MI_Class_Bluetooth.c | 68 + rom/usb/trident/MasonIcons/MI_Class_CDCControl.c | 67 + rom/usb/trident/MasonIcons/MI_Class_CDCData.c | 67 + .../trident/MasonIcons/MI_Class_ChipSmartCard.c | 68 + rom/usb/trident/MasonIcons/MI_Class_CommDevice.c | 66 + rom/usb/trident/MasonIcons/MI_Class_HID.c | 67 + rom/usb/trident/MasonIcons/MI_Class_Hub.c | 67 + rom/usb/trident/MasonIcons/MI_Class_MassStorage.c | 67 + rom/usb/trident/MasonIcons/MI_Class_None.c | 68 + rom/usb/trident/MasonIcons/MI_Class_Physical.c | 67 + rom/usb/trident/MasonIcons/MI_Class_Printer.c | 68 + rom/usb/trident/MasonIcons/MI_Class_Security.c | 68 + rom/usb/trident/MasonIcons/MI_Class_StillImage.c | 68 + rom/usb/trident/MasonIcons/MI_Class_Vendor.c | 68 + rom/usb/trident/MasonIcons/MI_Classes.c | 68 + rom/usb/trident/MasonIcons/MI_Devices.c | 68 + rom/usb/trident/MasonIcons/MI_General.c | 68 + rom/usb/trident/MasonIcons/MI_GreenLED.c | 68 + rom/usb/trident/MasonIcons/MI_Hardware.c | 68 + rom/usb/trident/MasonIcons/MI_Online.c | 68 + rom/usb/trident/MasonIcons/MI_OrangeLED.c | 68 + rom/usb/trident/MasonIcons/MI_OrangeLEDQ.c | 68 + rom/usb/trident/MasonIcons/MI_Popup.c | 67 + rom/usb/trident/MasonIcons/MI_Settings.c | 68 + rom/usb/trident/MasonIcons/Online | Bin 0 -> 404 bytes rom/usb/trident/MasonIcons/OrangeLED | Bin 0 -> 398 bytes rom/usb/trident/MasonIcons/OrangeLEDQ | Bin 0 -> 400 bytes rom/usb/trident/MasonIcons/Popup | Bin 0 -> 386 bytes rom/usb/trident/MasonIcons/Settings | Bin 0 -> 428 bytes rom/usb/trident/Trident.c | 537 ++ rom/usb/trident/Trident.h | 72 + rom/usb/trident/debug.c | 38 + rom/usb/trident/debug.h | 22 + rom/usb/trident/mmakefile.src | 13 + rom/usb/trident/neptune8logo.c | 828 ++ 134 files changed, 50118 insertions(+) create mode 100644 rom/usb/classes/bootkeyboard/bootkeyboard.class.c create mode 100644 rom/usb/classes/bootkeyboard/bootkeyboard.class.h create mode 100644 rom/usb/classes/bootkeyboard/bootkeyboard.conf create mode 100644 rom/usb/classes/bootkeyboard/bootkeyboard.h create mode 100644 rom/usb/classes/bootkeyboard/common.h create mode 100644 rom/usb/classes/bootkeyboard/debug.c create mode 100644 rom/usb/classes/bootkeyboard/debug.h create mode 100644 rom/usb/classes/bootkeyboard/mmakefile.src create mode 100644 rom/usb/classes/bootmouse/bootmouse.class.c create mode 100644 rom/usb/classes/bootmouse/bootmouse.class.h create mode 100644 rom/usb/classes/bootmouse/bootmouse.conf create mode 100644 rom/usb/classes/bootmouse/bootmouse.h create mode 100644 rom/usb/classes/bootmouse/common.h create mode 100644 rom/usb/classes/bootmouse/debug.c create mode 100644 rom/usb/classes/bootmouse/debug.h create mode 100644 rom/usb/classes/bootmouse/mmakefile.src create mode 100644 rom/usb/classes/hub/common.h create mode 100644 rom/usb/classes/hub/debug.c create mode 100644 rom/usb/classes/hub/debug.h create mode 100644 rom/usb/classes/hub/hub.class.c create mode 100644 rom/usb/classes/hub/hub.class.h create mode 100644 rom/usb/classes/hub/hub.conf create mode 100644 rom/usb/classes/hub/hub.h create mode 100644 rom/usb/classes/hub/mmakefile.src create mode 100644 rom/usb/classes/massstorage/common.h create mode 100644 rom/usb/classes/massstorage/debug.c create mode 100644 rom/usb/classes/massstorage/debug.h create mode 100644 rom/usb/classes/massstorage/dev.c create mode 100644 rom/usb/classes/massstorage/dev.h create mode 100644 rom/usb/classes/massstorage/massstorage.class.c create mode 100644 rom/usb/classes/massstorage/massstorage.class.h create mode 100644 rom/usb/classes/massstorage/massstorage.conf create mode 100644 rom/usb/classes/massstorage/massstorage.h create mode 100644 rom/usb/classes/massstorage/mmakefile.src create mode 100644 rom/usb/classes/mmakefile create mode 100644 rom/usb/classes/mmakefile.src create mode 100644 rom/usb/classes/usbclass.conf create mode 100644 rom/usb/classes/usbclass.doc create mode 100644 rom/usb/pciusb/debug.c create mode 100644 rom/usb/pciusb/debug.h create mode 100644 rom/usb/pciusb/dev.c create mode 100644 rom/usb/pciusb/ehcichip.h create mode 100644 rom/usb/pciusb/hccommon.h create mode 100644 rom/usb/pciusb/mmakefile.src create mode 100644 rom/usb/pciusb/ohcichip.h create mode 100644 rom/usb/pciusb/pci_aros.c create mode 100644 rom/usb/pciusb/pci_aros.h create mode 100644 rom/usb/pciusb/pciusb.conf create mode 100644 rom/usb/pciusb/pciusb.h create mode 100644 rom/usb/pciusb/uhcichip.h create mode 100644 rom/usb/pciusb/uhwcmd.c create mode 100644 rom/usb/pciusb/uhwcmd.h create mode 100644 rom/usb/poseidon/AddUSBClasses.c create mode 100644 rom/usb/poseidon/AddUSBHardware.c create mode 100644 rom/usb/poseidon/PsdDevLister.c create mode 100644 rom/usb/poseidon/PsdErrorlog.c create mode 100644 rom/usb/poseidon/PsdStackLoader.c create mode 100644 rom/usb/poseidon/debug.c create mode 100644 rom/usb/poseidon/debug.h create mode 100644 rom/usb/poseidon/mmakefile.src create mode 100644 rom/usb/poseidon/numtostr.c create mode 100644 rom/usb/poseidon/numtostr.h create mode 100644 rom/usb/poseidon/popo.gui.c create mode 100644 rom/usb/poseidon/popo.gui.h create mode 100644 rom/usb/poseidon/poseidon.conf create mode 100644 rom/usb/poseidon/poseidon.doc create mode 100644 rom/usb/poseidon/poseidon.library.c create mode 100644 rom/usb/poseidon/poseidon.library.h create mode 100644 rom/usb/poseidon/poseidon_intern.h create mode 100644 rom/usb/poseidon/usbhardware.doc create mode 100644 rom/usb/trident/ActionClass.c create mode 100644 rom/usb/trident/ActionClass.h create mode 100644 rom/usb/trident/CfgListClass.c create mode 100644 rom/usb/trident/CfgListClass.h create mode 100644 rom/usb/trident/DevWinClass.c create mode 100644 rom/usb/trident/DevWinClass.h create mode 100644 rom/usb/trident/IconListClass.c create mode 100644 rom/usb/trident/IconListClass.h create mode 100644 rom/usb/trident/MasonIcons/Class_Audio create mode 100644 rom/usb/trident/MasonIcons/Class_Bluetooth create mode 100644 rom/usb/trident/MasonIcons/Class_CDCControl create mode 100644 rom/usb/trident/MasonIcons/Class_CDCData create mode 100644 rom/usb/trident/MasonIcons/Class_ChipSmartCard create mode 100644 rom/usb/trident/MasonIcons/Class_CommDevice create mode 100644 rom/usb/trident/MasonIcons/Class_HID create mode 100644 rom/usb/trident/MasonIcons/Class_Hub create mode 100644 rom/usb/trident/MasonIcons/Class_MassStorage create mode 100644 rom/usb/trident/MasonIcons/Class_None create mode 100644 rom/usb/trident/MasonIcons/Class_Physical create mode 100644 rom/usb/trident/MasonIcons/Class_Printer create mode 100644 rom/usb/trident/MasonIcons/Class_Security create mode 100644 rom/usb/trident/MasonIcons/Class_StillImage create mode 100644 rom/usb/trident/MasonIcons/Class_Vendor create mode 100644 rom/usb/trident/MasonIcons/Classes create mode 100644 rom/usb/trident/MasonIcons/Devices create mode 100644 rom/usb/trident/MasonIcons/General create mode 100644 rom/usb/trident/MasonIcons/GreenLED create mode 100644 rom/usb/trident/MasonIcons/Hardware create mode 100644 rom/usb/trident/MasonIcons/MI_Class_Audio.c create mode 100644 rom/usb/trident/MasonIcons/MI_Class_Bluetooth.c create mode 100644 rom/usb/trident/MasonIcons/MI_Class_CDCControl.c create mode 100644 rom/usb/trident/MasonIcons/MI_Class_CDCData.c create mode 100644 rom/usb/trident/MasonIcons/MI_Class_ChipSmartCard.c create mode 100644 rom/usb/trident/MasonIcons/MI_Class_CommDevice.c create mode 100644 rom/usb/trident/MasonIcons/MI_Class_HID.c create mode 100644 rom/usb/trident/MasonIcons/MI_Class_Hub.c create mode 100644 rom/usb/trident/MasonIcons/MI_Class_MassStorage.c create mode 100644 rom/usb/trident/MasonIcons/MI_Class_None.c create mode 100644 rom/usb/trident/MasonIcons/MI_Class_Physical.c create mode 100644 rom/usb/trident/MasonIcons/MI_Class_Printer.c create mode 100644 rom/usb/trident/MasonIcons/MI_Class_Security.c create mode 100644 rom/usb/trident/MasonIcons/MI_Class_StillImage.c create mode 100644 rom/usb/trident/MasonIcons/MI_Class_Vendor.c create mode 100644 rom/usb/trident/MasonIcons/MI_Classes.c create mode 100644 rom/usb/trident/MasonIcons/MI_Devices.c create mode 100644 rom/usb/trident/MasonIcons/MI_General.c create mode 100644 rom/usb/trident/MasonIcons/MI_GreenLED.c create mode 100644 rom/usb/trident/MasonIcons/MI_Hardware.c create mode 100644 rom/usb/trident/MasonIcons/MI_Online.c create mode 100644 rom/usb/trident/MasonIcons/MI_OrangeLED.c create mode 100644 rom/usb/trident/MasonIcons/MI_OrangeLEDQ.c create mode 100644 rom/usb/trident/MasonIcons/MI_Popup.c create mode 100644 rom/usb/trident/MasonIcons/MI_Settings.c create mode 100644 rom/usb/trident/MasonIcons/Online create mode 100644 rom/usb/trident/MasonIcons/OrangeLED create mode 100644 rom/usb/trident/MasonIcons/OrangeLEDQ create mode 100644 rom/usb/trident/MasonIcons/Popup create mode 100644 rom/usb/trident/MasonIcons/Settings create mode 100644 rom/usb/trident/Trident.c create mode 100644 rom/usb/trident/Trident.h create mode 100644 rom/usb/trident/debug.c create mode 100644 rom/usb/trident/debug.h create mode 100644 rom/usb/trident/mmakefile.src create mode 100644 rom/usb/trident/neptune8logo.c diff --git a/rom/usb/classes/bootkeyboard/bootkeyboard.class.c b/rom/usb/classes/bootkeyboard/bootkeyboard.class.c new file mode 100644 index 000000000..be8850430 --- /dev/null +++ b/rom/usb/classes/bootkeyboard/bootkeyboard.class.c @@ -0,0 +1,1208 @@ +/* + *---------------------------------------------------------------------------- + * bootkeyboard class for poseidon + *---------------------------------------------------------------------------- + * By Chris Hodges + */ + +#include "debug.h" + +#include "bootkeyboard.class.h" + +/* /// "Lib Stuff" */ +static const STRPTR libname = MOD_NAME_STRING; + +static int libInit(LIBBASETYPEPTR nh) +{ + KPRINTF(10, ("libInit nh: 0x%08lx SysBase: 0x%08lx\n", nh, SysBase)); + + nh->nh_UtilityBase = OpenLibrary("utility.library", 39); + +#define UtilityBase nh->nh_UtilityBase + + if(!UtilityBase) + { + KPRINTF(20, ("libInit: OpenLibrary(\"utility.library\", 39) failed!\n")); + return FALSE; + } + + KPRINTF(10, ("libInit: Ok\n")); + return TRUE; +} + +static int libOpen(LIBBASETYPEPTR nh) +{ + KPRINTF(10, ("libOpen nh: 0x%08lx\n", nh)); + nLoadClassConfig(nh); + + return TRUE; +} + +static int libExpunge(LIBBASETYPEPTR nh) +{ + KPRINTF(10, ("libExpunge nh: 0x%08lx SysBase: 0x%08lx\n", nh, SysBase)); + + CloseLibrary(UtilityBase); + nh->nh_UtilityBase = NULL; + + return TRUE; +} + +ADD2INITLIB(libInit, 0) +ADD2OPENLIB(libOpen, 0) +ADD2EXPUNGELIB(libExpunge, 0) +/* \\\ */ + +/* + * *********************************************************************** + * * Library functions * + * *********************************************************************** + */ + +/* /// "usbAttemptInterfaceBinding()" */ +struct NepClassHid * usbAttemptInterfaceBinding(struct NepHidBase *nh, struct PsdInterface *pif) +{ + struct Library *ps; + ULONG ifclass; + ULONG subclass; + ULONG proto; + + KPRINTF(1, ("nepHidAttemptInterfaceBinding(%08lx)\n", pif)); + if((ps = OpenLibrary("poseidon.library", 4))) + { + psdGetAttrs(PGA_INTERFACE, pif, + IFA_Class, &ifclass, + IFA_SubClass, &subclass, + IFA_Protocol, &proto, + TAG_DONE); + CloseLibrary(ps); + if((ifclass == HID_CLASSCODE) && (subclass == HID_BOOT_SUBCLASS) && (proto == HID_PROTO_KEYBOARD)) + { + return(usbForceInterfaceBinding(nh, pif)); + } + } + return(NULL); +} +/* \\\ */ + +/* /// "usbForceInterfaceBinding()" */ +struct NepClassHid * usbForceInterfaceBinding(struct NepHidBase *nh, struct PsdInterface *pif) +{ + struct Library *ps; + struct NepClassHid *nch; + struct PsdConfig *pc; + struct PsdDevice *pd; + STRPTR devname; + UBYTE buf[64]; + struct Task *tmptask; + + KPRINTF(1, ("nepHidAttemptInterfaceBinding(%08lx)\n", pif)); + if((ps = OpenLibrary("poseidon.library", 4))) + { + if((nch = psdAllocVec(sizeof(struct NepClassHid)))) + { + nch->nch_ClsBase = nh; + nch->nch_Device = NULL; + nch->nch_Interface = pif; + + nLoadClassConfig(nh); + + psdSafeRawDoFmt(buf, 64, "bootkeyboard.class<%08lx>", nch); + nch->nch_ReadySignal = SIGB_SINGLE; + nch->nch_ReadySigTask = FindTask(NULL); + SetSignal(0, SIGF_SINGLE); + if((tmptask = psdSpawnSubTask(buf, nHidTask, nch))) + { + psdBorrowLocksWait(tmptask, 1UL<nch_ReadySignal); + if(nch->nch_Task) + { + nch->nch_ReadySigTask = NULL; + //FreeSignal(nch->nch_ReadySignal); + psdGetAttrs(PGA_INTERFACE, pif, IFA_Config, &pc, TAG_END); + psdGetAttrs(PGA_CONFIG, pc, CA_Device, &pd, TAG_END); + psdGetAttrs(PGA_DEVICE, pd, DA_ProductName, &devname, TAG_END); + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, + "I've got my fingers on '%s'!", + devname); + + CloseLibrary(ps); + return(nch); + } + } + nch->nch_ReadySigTask = NULL; + //FreeSignal(nch->nch_ReadySignal); + psdFreeVec(nch); + } + CloseLibrary(ps); + } + return(NULL); +} +/* \\\ */ + +/* /// "usbReleaseInterfaceBinding()" */ +void usbReleaseInterfaceBinding(struct NepHidBase *nh, struct NepClassHid *nch) +{ + struct Library *ps; + struct PsdConfig *pc; + struct PsdDevice *pd; + STRPTR devname; + + KPRINTF(1, ("nepHidReleaseInterfaceBinding(%08lx)\n", nch)); + if((ps = OpenLibrary("poseidon.library", 4))) + { + Forbid(); + nch->nch_ReadySignal = SIGB_SINGLE; + nch->nch_ReadySigTask = FindTask(NULL); + if(nch->nch_Task) + { + Signal(nch->nch_Task, SIGBREAKF_CTRL_C); + } + Permit(); + while(nch->nch_Task) + { + Wait(1L<nch_ReadySignal); + } + //FreeSignal(nch->nch_ReadySignal); + psdGetAttrs(PGA_INTERFACE, nch->nch_Interface, IFA_Config, &pc, TAG_END); + psdGetAttrs(PGA_CONFIG, pc, CA_Device, &pd, TAG_END); + psdGetAttrs(PGA_DEVICE, pd, DA_ProductName, &devname, TAG_END); + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, + "I lost my keys to '%s'!", + devname); + psdFreeVec(nch); + CloseLibrary(ps); + } +} +/* \\\ */ + +/* /// "usbGetAttrsA()" */ +AROS_LH3(LONG, usbGetAttrsA, + AROS_LHA(ULONG, type, D0), + AROS_LHA(APTR, usbstruct, A0), + AROS_LHA(struct TagItem *, tags, A1), + LIBBASETYPEPTR, nh, 5, nep) +{ + AROS_LIBFUNC_INIT + + struct TagItem *ti; + LONG count = 0; + + KPRINTF(1, ("nepHidGetAttrsA(%ld, %08lx, %08lx)\n", type, usbstruct, tags)); + switch(type) + { + case UGA_CLASS: + if((ti = FindTagItem(UCCA_Priority, tags))) + { + *((IPTR *) ti->ti_Data) = -100; + count++; + } + if((ti = FindTagItem(UCCA_Description, tags))) + { + *((STRPTR *) ti->ti_Data) = "Support for keyboards in boot protocol mode"; + count++; + } + if((ti = FindTagItem(UCCA_HasClassCfgGUI, tags))) + { + *((IPTR *) ti->ti_Data) = TRUE; + count++; + } + if((ti = FindTagItem(UCCA_HasBindingCfgGUI, tags))) + { + *((IPTR *) ti->ti_Data) = FALSE; + count++; + } + if((ti = FindTagItem(UCCA_AfterDOSRestart, tags))) + { + *((IPTR *) ti->ti_Data) = TRUE; + count++; + } + if((ti = FindTagItem(UCCA_UsingDefaultCfg, tags))) + { + *((IPTR *) ti->ti_Data) = nh->nh_UsingDefaultCfg; + count++; + } + break; + + case UGA_BINDING: + if((ti = FindTagItem(UCBA_UsingDefaultCfg, tags))) + { + *((IPTR *) ti->ti_Data) = FALSE; + count++; + } + break; + } + return(count); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "usbSetAttrsA()" */ +AROS_LH3(LONG, usbSetAttrsA, + AROS_LHA(ULONG, type, D0), + AROS_LHA(APTR, usbstruct, A0), + AROS_LHA(struct TagItem *, tags, A1), + LIBBASETYPEPTR, nh, 6, nep) +{ + AROS_LIBFUNC_INIT + return(0); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "usbDoMethodA()" */ +AROS_LH2(IPTR, usbDoMethodA, + AROS_LHA(ULONG, methodid, D0), + AROS_LHA(IPTR *, methoddata, A1), + LIBBASETYPEPTR, nh, 7, nep) +{ + AROS_LIBFUNC_INIT + + KPRINTF(10, ("Do Method %ld\n", methodid)); + switch(methodid) + { + case UCM_AttemptInterfaceBinding: + return((IPTR) usbAttemptInterfaceBinding(nh, (struct PsdInterface *) methoddata[0])); + + case UCM_ForceInterfaceBinding: + return((IPTR) usbForceInterfaceBinding(nh, (struct PsdInterface *) methoddata[0])); + + case UCM_ReleaseInterfaceBinding: + usbReleaseInterfaceBinding(nh, (struct NepClassHid *) methoddata[0]); + return(TRUE); + + case UCM_OpenCfgWindow: + return(nOpenCfgWindow(nh)); + + case UCM_ConfigChangedEvent: + nLoadClassConfig(nh); + return(TRUE); + + default: + break; + } + return(0); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "nLoadClassConfig()" */ +BOOL nLoadClassConfig(struct NepHidBase *nh) +{ + struct Library *ps; + struct ClsGlobalCfg *cgc; + struct PsdIFFContext *pic; + + KPRINTF(10, ("Loading Class Config...\n")); + if(nh->nh_GUITask) + { + return(FALSE); + } + if(!(ps = OpenLibrary("poseidon.library", 4))) + { + return(FALSE); + } + Forbid(); + /* Create default config */ + nh->nh_CurrentCGC.cgc_ChunkID = AROS_LONG2BE(MAKE_ID('B','K','E','Y')); + nh->nh_CurrentCGC.cgc_Length = AROS_LONG2BE(sizeof(struct ClsGlobalCfg)-8); + nh->nh_CurrentCGC.cgc_RHEnable = TRUE; + nh->nh_CurrentCGC.cgc_ResetDelay = 10; + nh->nh_CurrentCGC.cgc_CapsLock = FALSE; + nh->nh_CurrentCGC.cgc_ISAMap = FALSE; + nh->nh_CurrentCGC.cgc_ExtraEmulDisable = FALSE; + nh->nh_UsingDefaultCfg = TRUE; + pic = psdGetClsCfg(libname); + if(pic) + { + if((cgc = psdGetCfgChunk(pic, nh->nh_CurrentCGC.cgc_ChunkID))) + { + CopyMem(((UBYTE *) cgc) + 8, ((UBYTE *) &nh->nh_CurrentCGC) + 8, min(AROS_LONG2BE(cgc->cgc_Length), AROS_LONG2BE(nh->nh_CurrentCGC.cgc_Length))); + psdFreeVec(cgc); + nh->nh_UsingDefaultCfg = FALSE; + } + } + Permit(); + CloseLibrary(ps); + return(FALSE); +} +/* \\\ */ + +/* /// "nOpenCfgWindow()" */ +LONG nOpenCfgWindow(struct NepHidBase *nh) +{ + struct Library *ps; + KPRINTF(10, ("Opening GUI...\n")); + if(!(ps = OpenLibrary("poseidon.library", 4))) + { + return(FALSE); + } + Forbid(); + if(!nh->nh_GUITask) + { + if((nh->nh_GUITask = psdSpawnSubTask(MOD_NAME_STRING " GUI", nGUITask, nh))) + { + Permit(); + CloseLibrary(ps); + return(TRUE); + } + } + Permit(); + CloseLibrary(ps); + return(FALSE); +} +/* \\\ */ + +/**************************************************************************/ + +/* /// "Keymap Table" */ +static const UBYTE usbkeymap[] = +{ + 0xff, 0xff, 0xff, 0xff, 0x20, 0x35, 0x33, 0x22, /* 0x00 */ + 0x12, 0x23, 0x24, 0x25, 0x17, 0x26, 0x27, 0x28, /* 0x08 */ + 0x37, 0x36, 0x18, 0x19, 0x10, 0x13, 0x21, 0x14, /* 0x10 */ + 0x16, 0x34, 0x11, 0x32, 0x15, 0x31, 0x01, 0x02, /* 0x18 */ + 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, /* 0x20 */ + 0x44, 0x45, 0x41, 0x42, 0x40, 0x0b, 0x0c, 0x1a, /* 0x28 */ + 0x1b, 0x0d, 0x2b, 0x29, 0x2a, 0x00, 0x38, 0x39, /* 0x30 */ + 0x3a, 0x62, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, /* 0x38 */ + 0x56, 0x57, 0x58, 0x59, 0xff, 0x5f, 0xff, 0xff, /* 0x40 */ + 0xff, 0xff, 0xff, 0xff, 0x46, 0xff, 0xff, 0x4e, /* 0x48 */ + 0x4f, 0x4d, 0x4c, 0xff, 0x5c, 0x5d, 0x4a, 0x5e, /* 0x50 */ + 0x43, 0x1d, 0x1e, 0x1f, 0x2d, 0x2e, 0x2f, 0x3d, /* 0x58 */ + 0x3e, 0x3f, 0x0f, 0x3c, 0x30, 0xff, 0xff, 0xff, /* 0x60 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x68 F13-F24 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x70 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x78 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x80 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x88 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x90 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x44, 0xff, /* 0x98 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xa0 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xa8 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xb0 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xb8 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xc0 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xc8 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xd0 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xd8 */ + 0x63, 0x60, 0x64, 0x66, 0x63, 0x61, 0x65, 0x67, /* 0xe0 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xe8 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xf0 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff /* 0xf8 */ +}; + +static const UBYTE usbisakeymap[] = +{ + 0xff, 0xff, 0xff, 0xff, 0x20, 0x35, 0x33, 0x22, /* 0x00 */ + 0x12, 0x23, 0x24, 0x25, 0x17, 0x26, 0x27, 0x28, /* 0x08 */ + 0x37, 0x36, 0x18, 0x19, 0x10, 0x13, 0x21, 0x14, /* 0x10 */ + 0x16, 0x34, 0x11, 0x32, 0x15, 0x31, 0x01, 0x02, /* 0x18 */ + 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, /* 0x20 */ + 0x44, 0x45, 0x41, 0x42, 0x40, 0x0b, 0x0c, 0x1a, /* 0x28 */ + 0x1b, 0x0d, 0x2b, 0x29, 0x2a, 0x00, 0x38, 0x39, /* 0x30 */ + 0x3a, 0x62, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, /* 0x38 */ + 0x56, 0x57, 0x58, 0x59, 0x4b, 0x6f, 0xff, 0xff, /* 0x40 */ + 0x6e, 0x47, 0x70, 0x48, 0x46, 0x71, 0x49, 0x4e, /* 0x48 */ + 0x4f, 0x4d, 0x4c, 0xff, 0x5c, 0x5d, 0x4a, 0x5e, /* 0x50 */ + 0x43, 0x1d, 0x1e, 0x1f, 0x2d, 0x2e, 0x2f, 0x3d, /* 0x58 */ + 0x3e, 0x3f, 0x0f, 0x3c, 0x30, 0xff, 0xff, 0xff, /* 0x60 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x68 F13-F24 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x70 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x78 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x80 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x88 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x90 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x44, 0xff, /* 0x98 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xa0 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xa8 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xb0 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xb8 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xc0 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xc8 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xd0 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xd8 */ + 0x63, 0x60, 0x64, 0x66, 0x63, 0x61, 0x65, 0x67, /* 0xe0 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xe8 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xf0 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff /* 0xf8 */ +}; +/* \\\ */ + +#undef ps +#define ps nch->nch_Base + +/* /// "nHidTask()" */ +AROS_UFH0(void, nHidTask) +{ + AROS_USERFUNC_INIT + + struct NepClassHid *nch; + struct PsdPipe *pp; + ULONG sigmask; + ULONG sigs; + UBYTE *buf; + LONG ioerr; + + if((nch = nAllocHid())) + { + Forbid(); + if(nch->nch_ReadySigTask) + { + Signal(nch->nch_ReadySigTask, 1L<nch_ReadySignal); + } + Permit(); + sigmask = (1L<nch_TaskMsgPort->mp_SigBit)|SIGBREAKF_CTRL_C; + buf = nch->nch_EP1Buf; + psdSendPipe(nch->nch_EP1Pipe, buf, nch->nch_EP1PktSize); + do + { + sigs = Wait(sigmask); + while((pp = (struct PsdPipe *) GetMsg(nch->nch_TaskMsgPort))) + { + if(pp == nch->nch_EP1Pipe) + { + if(!(ioerr = psdGetPipeError(pp))) + { + nParseKeys(nch, buf); + } else { + KPRINTF(1, ("Int Pipe failed %ld\n", ioerr)); + psdDelayMS(200); + } + psdSendPipe(nch->nch_EP1Pipe, buf, nch->nch_EP1PktSize); + break; + } + } + } while(!(sigs & SIGBREAKF_CTRL_C)); + KPRINTF(20, ("Going down the river!\n")); + memset(buf, 0, 8); + nParseKeys(nch, buf); + + psdAbortPipe(nch->nch_EP1Pipe); + psdWaitPipe(nch->nch_EP1Pipe); + nFreeHid(nch); + } + AROS_USERFUNC_EXIT +} +/* \\\ */ + +/* /// "nParseKeys()" */ +void nParseKeys(struct NepClassHid *nch, UBYTE *buf) +{ + UWORD iecode; + UWORD qualcode = 0; + ULONG oldqual; + ULONG qualifier = 0; + UWORD keyqual = buf[0]; + UWORD nkey, nkey2; + UWORD keycode; + BOOL keydown; + BOOL keyup; + BOOL bonuskey; + BOOL sentkey = FALSE; + + if(keyqual & 0x11) qualifier |= IEQUALIFIER_CONTROL; + if(keyqual & 0x02) qualifier |= IEQUALIFIER_LSHIFT; + if(keyqual & 0x04) qualifier |= IEQUALIFIER_LALT; + if(keyqual & 0x08) qualifier |= IEQUALIFIER_LCOMMAND; + if(keyqual & 0x20) qualifier |= IEQUALIFIER_RSHIFT; + if(keyqual & 0x40) qualifier |= IEQUALIFIER_RALT; + if(keyqual & 0x80) qualifier |= IEQUALIFIER_RCOMMAND; + if(!nch->nch_ClsBase->nh_CurrentCGC.cgc_CapsLock) + { + if(qualifier & (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT)) + { + nch->nch_CapsLock = FALSE; + } + } + if(nch->nch_CapsLock) qualifier |= IEQUALIFIER_CAPSLOCK; + if((qualifier & (IEQUALIFIER_CONTROL|IEQUALIFIER_LCOMMAND|IEQUALIFIER_RCOMMAND)) == + (IEQUALIFIER_CONTROL|IEQUALIFIER_LCOMMAND|IEQUALIFIER_RCOMMAND)) + { + struct MsgPort *mp; + struct IOStdReq *ioreq; + struct Interrupt tempint; + struct Node *node; + struct List *listhead = NULL; + KPRINTF(20, ("Reboot!\n")); + + if(nch->nch_ClsBase->nh_CurrentCGC.cgc_RHEnable) + { + if((mp = CreateMsgPort())) + { + if((ioreq = (struct IOStdReq *) CreateIORequest(mp, sizeof(struct IOStdReq)))) + { + if(!OpenDevice("keyboard.device", 0, (struct IORequest *) ioreq, 0)) + { + /* Find list header of reset handlers */ + tempint.is_Node.ln_Pred = NULL; + tempint.is_Node.ln_Succ = NULL; + tempint.is_Node.ln_Pri = 32; + tempint.is_Code = NULL; + ioreq->io_Command = KBD_ADDRESETHANDLER; + ioreq->io_Data = &tempint; + Forbid(); + DoIO((struct IORequest *) ioreq); + if((node = tempint.is_Node.ln_Pred)) + { + while(node->ln_Pred) + { + node = node->ln_Pred; + } + listhead = (struct List *) node; + } + ioreq->io_Command = KBD_REMRESETHANDLER; + DoIO((struct IORequest *) ioreq); + Permit(); + if(listhead) + { + node = listhead->lh_Head; + while(node->ln_Succ) + { + KPRINTF(20, ("Kicking %s\n", node->ln_Name)); + Cause((struct Interrupt *) node); + node = node->ln_Succ; + } + KPRINTF(20, ("Done... awaiting doom\n")); + psdDelayMS(nch->nch_ClsBase->nh_CurrentCGC.cgc_ResetDelay*1000); + } else { + KPRINTF(20, ("Reset handler list not found!\n")); + } + CloseDevice((struct IORequest *) ioreq); + } + DeleteIORequest((struct IORequest *) ioreq); + } + DeleteMsgPort(mp); + } + } + ColdReboot(); + } + if(qualifier != nch->nch_OldQualifier) + { + switch(qualifier^nch->nch_OldQualifier) + { + case IEQUALIFIER_LSHIFT: + qualcode = 0x60; + break; + case IEQUALIFIER_RSHIFT: + qualcode = 0x61; + break; + case IEQUALIFIER_CAPSLOCK: + qualcode = 0x62; + break; + case IEQUALIFIER_CONTROL: + qualcode = 0x63; + break; + case IEQUALIFIER_LALT: + qualcode = 0x64; + break; + case IEQUALIFIER_RALT: + qualcode = 0x65; + break; + case IEQUALIFIER_LCOMMAND: + qualcode = 0x66; + break; + case IEQUALIFIER_RCOMMAND: + qualcode = 0x67; + break; + default: + qualcode = 0xFF; + break; + } + } + + KPRINTF(1, ("Qualifier %08lx\n", qualifier)); + for(nkey = 2; nkey < 8; nkey++) + { + keycode = nch->nch_OldKeyArray[nkey]; + if(!keycode) + { + continue; + } + /* Check, if key is still there */ + keyup = TRUE; + for(nkey2 = 2; nkey2 < 8; nkey2++) + { + if(buf[nkey2] == keycode) + { + keyup = FALSE; + break; + } + } + if(keyup) + { + KPRINTF(1, ("Key up: %08lx\n", keycode)); + iecode = nch->nch_ClsBase->nh_CurrentCGC.cgc_ISAMap ? usbisakeymap[keycode] : usbkeymap[keycode]; + oldqual = qualifier; + if(!nch->nch_ClsBase->nh_CurrentCGC.cgc_ExtraEmulDisable) + { + bonuskey = TRUE; + switch(keycode) + { + case 0x49: /* Insert */ + iecode = usbkeymap[0x19]; + qualifier |= IEQUALIFIER_RCOMMAND; + qualcode = 0x67; + break; + case 0x4A: /* Pos 1 */ + iecode = usbkeymap[0x50]; + qualifier |= IEQUALIFIER_LSHIFT; + qualcode = 0x60; + break; + case 0x4D: /* End */ + iecode = usbkeymap[0x4F]; + qualifier |= IEQUALIFIER_LSHIFT; + qualcode = 0x60; + break; + case 0x4B: /* Page Up */ + iecode = usbkeymap[0x52]; + qualifier |= IEQUALIFIER_LSHIFT; + qualcode = 0x60; + break; + case 0x4E: /* Page Down */ + iecode = usbkeymap[0x51]; + qualifier |= IEQUALIFIER_LSHIFT; + qualcode = 0x60; + break; + case 0x48: /* Pause / Break */ + /* *** FIXME *** should be a vanilla key for keymapping compatibility */ + iecode = usbkeymap[0x06]; + qualifier |= IEQUALIFIER_CONTROL; + qualcode = 0x63; + break; + default: + bonuskey = FALSE; + } + } else { + bonuskey = FALSE; + } + nch->nch_FakeEvent.ie_Class = IECLASS_RAWKEY; + nch->nch_FakeEvent.ie_SubClass = 0; + nch->nch_FakeEvent.ie_Code = iecode|IECODE_UP_PREFIX; + nch->nch_FakeEvent.ie_NextEvent = NULL; + nch->nch_FakeEvent.ie_Qualifier = qualifier; + nch->nch_InpIOReq->io_Data = &nch->nch_FakeEvent; + nch->nch_InpIOReq->io_Length = sizeof(struct InputEvent); + nch->nch_InpIOReq->io_Command = IND_WRITEEVENT; + DoIO((struct IORequest *) nch->nch_InpIOReq); + if(bonuskey) + { + qualifier = oldqual; + nch->nch_FakeEvent.ie_Class = IECLASS_RAWKEY; + nch->nch_FakeEvent.ie_SubClass = 0; + nch->nch_FakeEvent.ie_Code = qualcode|IECODE_UP_PREFIX; + nch->nch_FakeEvent.ie_NextEvent = NULL; + nch->nch_FakeEvent.ie_Qualifier = qualifier; + nch->nch_InpIOReq->io_Data = &nch->nch_FakeEvent; + nch->nch_InpIOReq->io_Length = sizeof(struct InputEvent); + nch->nch_InpIOReq->io_Command = IND_WRITEEVENT; + DoIO((struct IORequest *) nch->nch_InpIOReq); + } + sentkey = TRUE; + } + + } + + for(nkey = 2; nkey < 8; nkey++) + { + keycode = buf[nkey]; + if(!keycode) + { + continue; + } + KPRINTF(1, ("Key down: %08lx\n", keycode)); + /* Check, if key was there previously */ + keydown = TRUE; + for(nkey2 = 2; nkey2 < 8; nkey2++) + { + if(nch->nch_OldKeyArray[nkey2] == keycode) + { + keydown = FALSE; + break; + } + } + if(keydown) + { + iecode = nch->nch_ClsBase->nh_CurrentCGC.cgc_ISAMap ? usbisakeymap[keycode] : usbkeymap[keycode]; + if(!nch->nch_ClsBase->nh_CurrentCGC.cgc_ExtraEmulDisable) + { + switch(keycode) + { + case 0x49: /* Insert */ + iecode = usbkeymap[0x19]; + qualifier |= IEQUALIFIER_RCOMMAND; + break; + case 0x4A: /* Pos 1 */ + iecode = usbkeymap[0x50]; + qualifier |= IEQUALIFIER_LSHIFT; + break; + case 0x4D: /* End */ + iecode = usbkeymap[0x4F]; + qualifier |= IEQUALIFIER_LSHIFT; + break; + case 0x4B: /* Page Up */ + iecode = usbkeymap[0x52]; + qualifier |= IEQUALIFIER_LSHIFT; + break; + case 0x4E: /* Page Down */ + iecode = usbkeymap[0x51]; + qualifier |= IEQUALIFIER_LSHIFT; + break; + case 0x48: /* Pause / Break */ + /* *** FIXME *** should be a vanilla key for keymapping compatibility */ + iecode = usbkeymap[0x06]; + qualifier |= IEQUALIFIER_CONTROL; + break; + } + } + if(keycode == 0x39) /* Caps Lock */ + { + if(nch->nch_ClsBase->nh_CurrentCGC.cgc_CapsLock) + { + nch->nch_CapsLock = !nch->nch_CapsLock; + } else { + nch->nch_CapsLock = TRUE; + } + if(nch->nch_CapsLock) + { + qualifier |= IEQUALIFIER_CAPSLOCK; + } + } + + nch->nch_FakeEvent.ie_Class = IECLASS_RAWKEY; + nch->nch_FakeEvent.ie_SubClass = 0; + nch->nch_FakeEvent.ie_Code = iecode; + nch->nch_FakeEvent.ie_NextEvent = NULL; + nch->nch_FakeEvent.ie_Qualifier = qualifier; + nch->nch_InpIOReq->io_Data = &nch->nch_FakeEvent; + nch->nch_InpIOReq->io_Length = sizeof(struct InputEvent); + nch->nch_InpIOReq->io_Command = IND_WRITEEVENT; + DoIO((struct IORequest *) nch->nch_InpIOReq); + nch->nch_FakeEvent.ie_position.ie_dead.ie_prev2DownCode = nch->nch_FakeEvent.ie_position.ie_dead.ie_prev1DownCode; + nch->nch_FakeEvent.ie_position.ie_dead.ie_prev2DownQual = nch->nch_FakeEvent.ie_position.ie_dead.ie_prev1DownQual; + nch->nch_FakeEvent.ie_position.ie_dead.ie_prev1DownCode = iecode; + nch->nch_FakeEvent.ie_position.ie_dead.ie_prev1DownQual = qualifier; + sentkey = TRUE; + break; + } + } + /* copy old keymap */ + for(nkey = 2; nkey < nch->nch_EP1PktSize; nkey++) + { + nch->nch_OldKeyArray[nkey] = buf[nkey]; + } + if((!sentkey) && (nch->nch_OldQualifier != qualifier)) + { + nch->nch_FakeEvent.ie_Class = IECLASS_RAWKEY; + nch->nch_FakeEvent.ie_SubClass = 0; + nch->nch_FakeEvent.ie_Code = qualcode; + nch->nch_FakeEvent.ie_NextEvent = NULL; + nch->nch_FakeEvent.ie_Qualifier = qualifier; + nch->nch_InpIOReq->io_Data = &nch->nch_FakeEvent; + nch->nch_InpIOReq->io_Length = sizeof(struct InputEvent); + nch->nch_InpIOReq->io_Command = IND_WRITEEVENT; + DoIO((struct IORequest *) nch->nch_InpIOReq); + } + nch->nch_OldQualifier = qualifier; +} +/* \\\ */ + +/* /// "nAllocHid()" */ +struct NepClassHid * nAllocHid(void) +{ + struct Task *thistask; + struct NepClassHid *nch; + LONG ioerr; + + thistask = FindTask(NULL); + nch = thistask->tc_UserData; + do + { + if(!(nch->nch_Base = OpenLibrary("poseidon.library", 4))) + { + Alert(AG_OpenLib); + break; + } + psdGetAttrs(PGA_INTERFACE, nch->nch_Interface, + IFA_Config, &nch->nch_Config, + IFA_InterfaceNum, &nch->nch_IfNum, + TAG_END); + psdGetAttrs(PGA_CONFIG, nch->nch_Config, + CA_Device, &nch->nch_Device, + TAG_END); + + nch->nch_EP1 = psdFindEndpoint(nch->nch_Interface, NULL, + EA_IsIn, TRUE, + EA_TransferType, USEAF_INTERRUPT, + TAG_END); + if(!nch->nch_EP1) + { + KPRINTF(1, ("Ooops!?! No Endpoints defined?\n")); + break; + } + psdGetAttrs(PGA_ENDPOINT, nch->nch_EP1, + EA_MaxPktSize, &nch->nch_EP1PktSize, + TAG_END); + if((nch->nch_InpMsgPort = CreateMsgPort())) + { + if((nch->nch_InpIOReq = (struct IOStdReq *) CreateIORequest(nch->nch_InpMsgPort, sizeof(struct IOStdReq)))) + { + if(!OpenDevice("input.device", 0, (struct IORequest *) nch->nch_InpIOReq, 0)) + { + nch->nch_InputBase = (struct Library *) nch->nch_InpIOReq->io_Device; + if((nch->nch_TaskMsgPort = CreateMsgPort())) + { + if((nch->nch_EP0Pipe = psdAllocPipe(nch->nch_Device, nch->nch_TaskMsgPort, NULL))) + { + if((nch->nch_EP1Pipe = psdAllocPipe(nch->nch_Device, nch->nch_TaskMsgPort, nch->nch_EP1))) + { + psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_INTERFACE, + UHR_SET_PROTOCOL, HID_PROTO_BOOT, nch->nch_IfNum); + ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0); + if(!ioerr) + { + psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_INTERFACE, + UHR_SET_IDLE, 0, nch->nch_IfNum); + ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0); + if(ioerr) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "SET_IDLE=0 failed: %s (%ld)!", + psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + } + if((nch->nch_EP1Buf = psdAllocVec(nch->nch_EP1PktSize))) + { + nch->nch_Task = thistask; + return(nch); + } + } else { + psdAddErrorMsg(RETURN_FAIL, (STRPTR) libname, + "SET_PROTOCOL=BOOT failed: %s (%ld)!", + (APTR) psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + } + psdFreePipe(nch->nch_EP1Pipe); + } + psdFreePipe(nch->nch_EP0Pipe); + } + DeleteMsgPort(nch->nch_TaskMsgPort); + } + CloseDevice((struct IORequest *) nch->nch_InpIOReq); + } + DeleteIORequest((struct IORequest *) nch->nch_InpIOReq); + } + DeleteMsgPort(nch->nch_InpMsgPort); + } + } while(FALSE); + CloseLibrary(nch->nch_Base); + Forbid(); + nch->nch_Task = NULL; + if(nch->nch_ReadySigTask) + { + Signal(nch->nch_ReadySigTask, 1L<nch_ReadySignal); + } + return(NULL); +} +/* \\\ */ + +/* /// "nFreeHid()" */ +void nFreeHid(struct NepClassHid *nch) +{ + psdFreeVec(nch->nch_EP1Buf); + psdFreePipe(nch->nch_EP1Pipe); + psdFreePipe(nch->nch_EP0Pipe); + DeleteMsgPort(nch->nch_TaskMsgPort); + CloseDevice((struct IORequest *) nch->nch_InpIOReq); + DeleteIORequest((struct IORequest *) nch->nch_InpIOReq); + DeleteMsgPort(nch->nch_InpMsgPort); + CloseLibrary(nch->nch_Base); + Forbid(); + nch->nch_Task = NULL; + if(nch->nch_ReadySigTask) + { + Signal(nch->nch_ReadySigTask, 1L<nch_ReadySignal); + } +} +/* \\\ */ + +/**************************************************************************/ + +#undef ps +#define ps nh->nh_PsdBase +#undef IntuitionBase +#define IntuitionBase nh->nh_IntBase +#undef MUIMasterBase +#define MUIMasterBase nh->nh_MUIBase + +/* /// "nGUITask()" */ +AROS_UFH0(void, nGUITask) +{ + AROS_USERFUNC_INIT + + struct Task *thistask; + struct NepHidBase *nh; + APTR pic; + + thistask = FindTask(NULL); + + nh = thistask->tc_UserData; + ++nh->nh_Library.lib_OpenCnt; + if(!(MUIMasterBase = OpenLibrary(MUIMASTER_NAME, MUIMASTER_VMIN))) + { + KPRINTF(10, ("Couldn't open muimaster.library.\n")); + nGUITaskCleanup(nh); + return; + } + + if(!(IntuitionBase = OpenLibrary("intuition.library", 39))) + { + KPRINTF(10, ("Couldn't open intuition.library.\n")); + nGUITaskCleanup(nh); + return; + } + if(!(ps = OpenLibrary("poseidon.library", 4))) + { + KPRINTF(10, ("Couldn't open poseidon.library.\n")); + nGUITaskCleanup(nh); + return; + } + + nh->nh_App = ApplicationObject, + MUIA_Application_Title , libname, + MUIA_Application_Version , VERSION_STRING, + MUIA_Application_Copyright , "©2002-2009 Chris Hodges", + MUIA_Application_Author , "Chris Hodges ", + MUIA_Application_Description, "Settings for the bootkeyboard.class", + MUIA_Application_Base , "BOOTKEYBOARD", + MUIA_Application_HelpFile , "HELP:Poseidon.guide", + MUIA_Application_Menustrip , MenustripObject, + Child, MenuObjectT("Project"), + Child, nh->nh_AboutMI = MenuitemObject, + MUIA_Menuitem_Title, "About...", + MUIA_Menuitem_Shortcut, "?", + End, + End, + Child, MenuObjectT("Settings"), + Child, nh->nh_UseMI = MenuitemObject, + MUIA_Menuitem_Title, "Save", + MUIA_Menuitem_Shortcut, "S", + End, + Child, MenuitemObject, + MUIA_Menuitem_Title, NM_BARLABEL, + End, + Child, nh->nh_MUIPrefsMI = MenuitemObject, + MUIA_Menuitem_Title, "MUI Settings", + MUIA_Menuitem_Shortcut, "M", + End, + End, + End, + + SubWindow, nh->nh_MainWindow = WindowObject, + MUIA_Window_ID , MAKE_ID('M','A','I','N'), + MUIA_Window_Title, libname, + MUIA_HelpNode, libname, + + WindowContents, VGroup, + Child, ColGroup(2), GroupFrameT("Global Settings"), + Child, Label((IPTR) "Hijack ResetHandlers:"), + Child, HGroup, + Child, nh->nh_RHEnableObj = ImageObject, ImageButtonFrame, + MUIA_Background, MUII_ButtonBack, + MUIA_CycleChain, 1, + MUIA_InputMode, MUIV_InputMode_Toggle, + MUIA_Image_Spec, MUII_CheckMark, + MUIA_Image_FreeVert, TRUE, + MUIA_Selected, nh->nh_CurrentCGC.cgc_RHEnable, + MUIA_ShowSelState, FALSE, + End, + Child, HSpace(0), + End, + Child, Label((IPTR) "Reset delay:"), + Child, nh->nh_ResetDelayObj = SliderObject, SliderFrame, + MUIA_CycleChain, 1, + MUIA_Numeric_Min, 0, + MUIA_Numeric_Max, 60, + MUIA_Numeric_Value, nh->nh_CurrentCGC.cgc_ResetDelay, + MUIA_Numeric_Format, "%ldsec", + End, + Child, Label((IPTR) "Amiga CapsLock behaviour:"), + Child, HGroup, + Child, nh->nh_CapsLockObj = ImageObject, ImageButtonFrame, + MUIA_Background, MUII_ButtonBack, + MUIA_CycleChain, 1, + MUIA_InputMode, MUIV_InputMode_Toggle, + MUIA_Image_Spec, MUII_CheckMark, + MUIA_Image_FreeVert, TRUE, + MUIA_Selected, nh->nh_CurrentCGC.cgc_CapsLock, + MUIA_ShowSelState, FALSE, + End, + Child, HSpace(0), + End, + Child, Label((IPTR) "Use standard ISA mapping:"), + Child, HGroup, + Child, nh->nh_ISAMapObj = ImageObject, ImageButtonFrame, + MUIA_Background, MUII_ButtonBack, + MUIA_CycleChain, 1, + MUIA_InputMode, MUIV_InputMode_Toggle, + MUIA_Image_Spec, MUII_CheckMark, + MUIA_Image_FreeVert, TRUE, + MUIA_Selected, nh->nh_CurrentCGC.cgc_ISAMap, + MUIA_ShowSelState, FALSE, + End, + Child, HSpace(0), + End, + Child, Label((IPTR) "Disable extra key emulation:"), + Child, HGroup, + Child, nh->nh_ExtraEmulObj = ImageObject, ImageButtonFrame, + MUIA_Background, MUII_ButtonBack, + MUIA_CycleChain, 1, + MUIA_InputMode, MUIV_InputMode_Toggle, + MUIA_Image_Spec, MUII_CheckMark, + MUIA_Image_FreeVert, TRUE, + MUIA_Selected, nh->nh_CurrentCGC.cgc_ExtraEmulDisable, + MUIA_ShowSelState, FALSE, + End, + Child, HSpace(0), + End, + End, + Child, VSpace(0), + Child, HGroup, + MUIA_Group_SameWidth, TRUE, + Child, nh->nh_UseObj = TextObject, ButtonFrame, + MUIA_Background, MUII_ButtonBack, + MUIA_CycleChain, 1, + MUIA_InputMode, MUIV_InputMode_RelVerify, + MUIA_Text_Contents, "\33c Save ", + End, + Child, nh->nh_CloseObj = TextObject, ButtonFrame, + MUIA_Background, MUII_ButtonBack, + MUIA_CycleChain, 1, + MUIA_InputMode, MUIV_InputMode_RelVerify, + MUIA_Text_Contents, "\33c Use ", + End, + End, + End, + End, + End; + + if(!nh->nh_App) + { + KPRINTF(10, ("Couldn't create application\n")); + nGUITaskCleanup(nh); + return; + } + DoMethod(nh->nh_MainWindow, MUIM_Notify, MUIA_Window_CloseRequest, TRUE, + nh->nh_App, 2, MUIM_Application_ReturnID, MUIV_Application_ReturnID_Quit); + DoMethod(nh->nh_UseObj, MUIM_Notify, MUIA_Pressed, FALSE, + nh->nh_App, 2, MUIM_Application_ReturnID, ID_STORE_CONFIG); + DoMethod(nh->nh_CloseObj, MUIM_Notify, MUIA_Pressed, FALSE, + nh->nh_App, 2, MUIM_Application_ReturnID, MUIV_Application_ReturnID_Quit); + + DoMethod(nh->nh_AboutMI, MUIM_Notify, MUIA_Menuitem_Trigger, MUIV_EveryTime, + nh->nh_App, 2, MUIM_Application_ReturnID, ID_ABOUT); + DoMethod(nh->nh_UseMI, MUIM_Notify, MUIA_Menuitem_Trigger, MUIV_EveryTime, + nh->nh_App, 2, MUIM_Application_ReturnID, ID_STORE_CONFIG); + DoMethod(nh->nh_RestoreDefMI, MUIM_Notify, MUIA_Menuitem_Trigger, MUIV_EveryTime, + nh->nh_App, 2, MUIM_Application_ReturnID, ID_RESTORE_DEF); + DoMethod(nh->nh_MUIPrefsMI, MUIM_Notify, MUIA_Menuitem_Trigger, MUIV_EveryTime, + nh->nh_App, 2, MUIM_Application_OpenConfigWindow, 0); + + { + ULONG isopen; + ULONG iconify; + ULONG sigs; + ULONG sigmask; + LONG retid; + + get(nh->nh_App, MUIA_Application_Iconified, &iconify); + set(nh->nh_MainWindow, MUIA_Window_Open, TRUE); + get(nh->nh_MainWindow, MUIA_Window_Open, &isopen); + if(!(isopen || iconify)) + { + nGUITaskCleanup(nh); + return; + } + sigmask = 0; + do + { + retid = DoMethod(nh->nh_App, MUIM_Application_NewInput, &sigs); + switch(retid) + { + case ID_STORE_CONFIG: + case MUIV_Application_ReturnID_Quit: + get(nh->nh_RHEnableObj, MUIA_Selected, &nh->nh_CurrentCGC.cgc_RHEnable); + get(nh->nh_ResetDelayObj, MUIA_Numeric_Value, &nh->nh_CurrentCGC.cgc_ResetDelay); + get(nh->nh_CapsLockObj, MUIA_Selected, &nh->nh_CurrentCGC.cgc_CapsLock); + get(nh->nh_ISAMapObj, MUIA_Selected, &nh->nh_CurrentCGC.cgc_ISAMap); + get(nh->nh_ExtraEmulObj, MUIA_Selected, &nh->nh_CurrentCGC.cgc_ExtraEmulDisable); + pic = psdGetClsCfg(libname); + if(!pic) + { + psdSetClsCfg(libname, NULL); + pic = psdGetClsCfg(libname); + } + if(pic) + { + if(psdAddCfgEntry(pic, &nh->nh_CurrentCGC)) + { + if(retid != MUIV_Application_ReturnID_Quit) + { + psdSaveCfgToDisk(NULL, FALSE); + } + retid = MUIV_Application_ReturnID_Quit; + } + } + break; + + case ID_ABOUT: + MUI_RequestA(nh->nh_App, nh->nh_MainWindow, 0, NULL, "Amazing!", VERSION_STRING, NULL); + break; + } + if(retid == MUIV_Application_ReturnID_Quit) + { + break; + } + if(sigs) + { + sigs = Wait(sigs | sigmask | SIGBREAKF_CTRL_C); + if(sigs & SIGBREAKF_CTRL_C) + { + break; + } + } + } while(TRUE); + set(nh->nh_MainWindow, MUIA_Window_Open, FALSE); + } + nGUITaskCleanup(nh); + + AROS_USERFUNC_EXIT +} +/* \\\ */ + +/* /// "nGUITaskCleanup()" */ +void nGUITaskCleanup(struct NepHidBase *nh) +{ + if(nh->nh_App) + { + MUI_DisposeObject(nh->nh_App); + nh->nh_App = NULL; + } + if(MUIMasterBase) + { + CloseLibrary(MUIMasterBase); + MUIMasterBase = NULL; + } + if(IntuitionBase) + { + CloseLibrary(IntuitionBase); + IntuitionBase = NULL; + } + if(ps) + { + CloseLibrary(ps); + ps = NULL; + } + Forbid(); + nh->nh_GUITask = NULL; + --nh->nh_Library.lib_OpenCnt; +} +/* \\\ */ + diff --git a/rom/usb/classes/bootkeyboard/bootkeyboard.class.h b/rom/usb/classes/bootkeyboard/bootkeyboard.class.h new file mode 100644 index 000000000..3b3ea94d6 --- /dev/null +++ b/rom/usb/classes/bootkeyboard/bootkeyboard.class.h @@ -0,0 +1,36 @@ +#ifndef BOOTKEYBOARD_CLASS_H +#define BOOTKEYBOARD_CLASS_H + +/* + *---------------------------------------------------------------------------- + * Includes for Bootkeyboard class + *---------------------------------------------------------------------------- + * By Chris Hodges + */ + +#include "common.h" + +#include + +#include "bootkeyboard.h" + +/* Protos */ + +struct NepClassHid * usbAttemptInterfaceBinding(struct NepHidBase *nh, struct PsdInterface *pif); +struct NepClassHid * usbForceInterfaceBinding(struct NepHidBase *nh, struct PsdInterface *pif); +void usbReleaseInterfaceBinding(struct NepHidBase *nh, struct NepClassHid *nch); + +void nParseKeys(struct NepClassHid *nch, UBYTE *buf); + +struct NepClassHid * nAllocHid(void); +void nFreeHid(struct NepClassHid *nch); + +BOOL nLoadClassConfig(struct NepHidBase *nh); +LONG nOpenCfgWindow(struct NepHidBase *nh); + +void nGUITaskCleanup(struct NepHidBase *nh); + +AROS_UFP0(void, nHidTask); +AROS_UFP0(void, nGUITask); + +#endif /* BOOTKEYBOARD_CLASS_H */ diff --git a/rom/usb/classes/bootkeyboard/bootkeyboard.conf b/rom/usb/classes/bootkeyboard/bootkeyboard.conf new file mode 100644 index 000000000..65eb3273d --- /dev/null +++ b/rom/usb/classes/bootkeyboard/bootkeyboard.conf @@ -0,0 +1,19 @@ +##begin config +version 4.3 +libbase nh +libbasetype struct NepHidBase +libbasetypeextern struct Library +residentpri 39 +basename nep +##end config + +##begin cdef +#include +#include "bootkeyboard.h" +##end cdef + +##begin functionlist +LONG usbGetAttrsA(ULONG type, APTR usbstruct, struct TagItem *taglist) (D0,A0,A1) +LONG usbSetAttrsA(ULONG type, APTR usbstruct, struct TagItem *taglist) (D0,A0,A1) +IPTR usbDoMethodA(ULONG methodid, IPTR *methoddata) (D0,A1) +##end functionlist diff --git a/rom/usb/classes/bootkeyboard/bootkeyboard.h b/rom/usb/classes/bootkeyboard/bootkeyboard.h new file mode 100644 index 000000000..30b2249bd --- /dev/null +++ b/rom/usb/classes/bootkeyboard/bootkeyboard.h @@ -0,0 +1,84 @@ +#ifndef BOOTKEYBOARD_H +#define BOOTKEYBOARD_H + +#include +#include +#include +#include +#include + +#define ID_ABOUT 0x55555555 +#define ID_STORE_CONFIG 0xaaaaaaaa +#define ID_RESTORE_DEF 0x12345678 +#define ID_LOAD_LAST 0x56789abc + +struct ClsGlobalCfg +{ + ULONG cgc_ChunkID; + ULONG cgc_Length; + IPTR cgc_RHEnable; + IPTR cgc_ResetDelay; + IPTR cgc_CapsLock; + IPTR cgc_ISAMap; + IPTR cgc_ExtraEmulDisable; +}; + +struct NepHidBase +{ + struct Library nh_Library; /* standard */ + UWORD nh_Flags; /* various flags */ + struct Library *nh_UtilityBase; /* utility base */ + + struct Library *nh_MUIBase; /* MUI master base */ + struct Library *nh_PsdBase; /* Poseidon base */ + struct Library *nh_IntBase; /* Intuition base */ + struct Task *nh_GUITask; /* GUI Task */ + + struct ClsGlobalCfg nh_CurrentCGC; + + BOOL nh_UsingDefaultCfg; + Object *nh_App; + Object *nh_MainWindow; + Object *nh_RHEnableObj; + Object *nh_ResetDelayObj; + Object *nh_CapsLockObj; + Object *nh_ISAMapObj; + Object *nh_ExtraEmulObj; + Object *nh_UseObj; + Object *nh_CloseObj; + + Object *nh_AboutMI; + Object *nh_UseMI; + Object *nh_RestoreDefMI; + Object *nh_LoadLastMI; + Object *nh_MUIPrefsMI; +}; + +struct NepClassHid +{ + struct Node nch_Node; /* Node linkage */ + struct NepHidBase *nch_ClsBase; /* Up linkage */ + struct Library *nch_Base; /* Poseidon base */ + struct PsdDevice *nch_Device; /* Up linkage */ + struct PsdConfig *nch_Config; /* Up linkage */ + struct PsdInterface *nch_Interface; /* Up linkage */ + struct PsdPipe *nch_EP0Pipe; /* Endpoint 0 pipe */ + struct PsdEndpoint *nch_EP1; /* Endpoint 1 */ + struct PsdPipe *nch_EP1Pipe; /* Endpoint 1 pipe */ + IPTR nch_EP1PktSize; /* Size of EP1 packets */ + UBYTE *nch_EP1Buf; /* Packet buffer for EP1 */ + struct Task *nch_ReadySigTask; /* Task to send ready signal to */ + LONG nch_ReadySignal; /* Signal to send when ready */ + struct Task *nch_Task; /* Subtask */ + struct MsgPort *nch_TaskMsgPort; /* Message Port of Subtask */ + struct MsgPort *nch_InpMsgPort; /* input.device MsgPort */ + struct IOStdReq *nch_InpIOReq; /* input.device IORequest */ + struct InputEvent nch_FakeEvent; /* Input Event */ + struct Library *nch_InputBase; /* Pointer to input.device base */ + IPTR nch_IfNum; /* Interface Number */ + BOOL nch_CapsLock; /* Caps Lock pressed */ + UBYTE nch_OldKeyArray[8]; /* Last keys pressed */ + ULONG nch_OldQualifier; /* Previous qualifiers */ +}; + +#endif /* BOOTKEYBOARD_H */ diff --git a/rom/usb/classes/bootkeyboard/common.h b/rom/usb/classes/bootkeyboard/common.h new file mode 100644 index 000000000..feae1e480 --- /dev/null +++ b/rom/usb/classes/bootkeyboard/common.h @@ -0,0 +1,55 @@ + +#include LC_LIBDEFS_FILE + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define NewList NEWLIST + +#include + +#define min(x,y) (((x) < (y)) ? (x) : (y)) +#define max(x,y) (((x) > (y)) ? (x) : (y)) + diff --git a/rom/usb/classes/bootkeyboard/debug.c b/rom/usb/classes/bootkeyboard/debug.c new file mode 100644 index 000000000..f29021b6b --- /dev/null +++ b/rom/usb/classes/bootkeyboard/debug.c @@ -0,0 +1,38 @@ +#include "debug.h" + +#ifdef DEBUG +void dumpmem(void *mem, unsigned long int len) +{ + unsigned char *p; + + if (!mem || !len) { return; } + + p = (unsigned char *) mem; + + bug("\n"); + + do + { + unsigned char b, c, str[17]; + + for (b = 0; b < 16; b++) + { + c = *p++; + str[b] = ((c >= ' ') && (c <= 'z')) ? c : '.'; + str[b + 1] = 0; + bug("%02lx ", c); + if (--len == 0) break; + } + + while (++b < 16) + { + bug(" "); + } + + bug(" %s\n", str); + } while (len); + + bug("\n\n"); +} + +#endif /* DEBUG */ diff --git a/rom/usb/classes/bootkeyboard/debug.h b/rom/usb/classes/bootkeyboard/debug.h new file mode 100644 index 000000000..6d5cb840e --- /dev/null +++ b/rom/usb/classes/bootkeyboard/debug.h @@ -0,0 +1,22 @@ +#ifndef __DEBUG_H__ +#define __DEBUG_H__ + +#define DB_LEVEL 1 + +#define DEBUG 1 + +#include + +#ifdef DEBUG +#define KPRINTF(l, x) do { if ((l) >= DB_LEVEL) \ + { bug("%s:%s/%lu: ", __FILE__, __FUNCTION__, __LINE__); bug x;} } while (0) +#define DB(x) x + void dumpmem(void *mem, unsigned long int len); +#else /* !DEBUG */ + +#define KPRINTF(l, x) ((void) 0) +#define DB(x) + +#endif /* DEBUG */ + +#endif /* __DEBUG_H__ */ diff --git a/rom/usb/classes/bootkeyboard/mmakefile.src b/rom/usb/classes/bootkeyboard/mmakefile.src new file mode 100644 index 000000000..f28c847d0 --- /dev/null +++ b/rom/usb/classes/bootkeyboard/mmakefile.src @@ -0,0 +1,13 @@ +# $Id: mmakefile.src $ +include $(TOP)/config/make.cfg + +FILES := bootkeyboard.class debug + +#MM- rom-usb-classes-bootkeyboard : rom-usb-usbclass rom-usb-poseidon + +%build_module mmake=rom-usb-classes-bootkeyboard \ + modname=bootkeyboard modtype=usbclass modsuffix="class" \ + files="$(FILES)" \ + uselibs="amiga rom mui" + +%common diff --git a/rom/usb/classes/bootmouse/bootmouse.class.c b/rom/usb/classes/bootmouse/bootmouse.class.c new file mode 100644 index 000000000..44c91ed47 --- /dev/null +++ b/rom/usb/classes/bootmouse/bootmouse.class.c @@ -0,0 +1,1034 @@ +/* + *---------------------------------------------------------------------------- + * bootmouse class for poseidon + *---------------------------------------------------------------------------- + * By Chris Hodges + */ + +#include "debug.h" + +#include "bootmouse.class.h" + +/* /// "Lib Stuff" */ +static const STRPTR libname = MOD_NAME_STRING; + +static int libInit(LIBBASETYPEPTR nh) +{ + KPRINTF(10, ("libInit nh: 0x%08lx SysBase: 0x%08lx\n", nh, SysBase)); + + nh->nh_UtilityBase = OpenLibrary("utility.library", 39); + +#define UtilityBase nh->nh_UtilityBase + + if(UtilityBase) + { + struct NepClassHid *nch; + NewList(&nh->nh_Bindings); + nch = &nh->nh_DummyNCH; + nch->nch_ClsBase = nh; + nch->nch_Interface = NULL; + nch->nch_CDC = AllocVec(sizeof(struct ClsDevCfg), MEMF_PUBLIC|MEMF_CLEAR); + if(!nch->nch_CDC) + { + return FALSE; + } + } else { + KPRINTF(20, ("libInit: OpenLibrary(\"utility.library\", 39) failed!\n")); + return FALSE; + } + + KPRINTF(10, ("libInit: Ok\n")); + return TRUE; +} + +static int libOpen(LIBBASETYPEPTR nh) +{ + KPRINTF(10, ("libOpen nh: 0x%08lx\n", nh)); + nLoadClassConfig(nh); + + return TRUE; +} + +static int libExpunge(LIBBASETYPEPTR nh) +{ + KPRINTF(10, ("libExpunge nh: 0x%08lx SysBase: 0x%08lx\n", nh, SysBase)); + + CloseLibrary(UtilityBase); + nh->nh_UtilityBase = NULL; + FreeVec(nh->nh_DummyNCH.nch_CDC); + + return TRUE; +} + +ADD2INITLIB(libInit, 0) +ADD2OPENLIB(libOpen, 0) +ADD2EXPUNGELIB(libExpunge, 0) +/* \\\ */ + +/* + * *********************************************************************** + * * Library functions * + * *********************************************************************** + */ + +/* /// "usbAttemptInterfaceBinding()" */ +struct NepClassHid * usbAttemptInterfaceBinding(struct NepHidBase *nh, struct PsdInterface *pif) +{ + struct Library *ps; + ULONG ifclass; + ULONG subclass; + ULONG proto; + + KPRINTF(1, ("nepHidAttemptInterfaceBinding(%08lx)\n", pif)); + if((ps = OpenLibrary("poseidon.library", 4))) + { + psdGetAttrs(PGA_INTERFACE, pif, + IFA_Class, (ULONG) &ifclass, + IFA_SubClass, (ULONG) &subclass, + IFA_Protocol, (ULONG) &proto, + TAG_DONE); + CloseLibrary(ps); + + if((ifclass == HID_CLASSCODE) && (subclass == HID_BOOT_SUBCLASS) && (proto == HID_PROTO_MOUSE)) + { + return(usbForceInterfaceBinding(nh, pif)); + } + } + return(NULL); +} +/* \\\ */ + +/* /// "usbForceInterfaceBinding()" */ +struct NepClassHid * usbForceInterfaceBinding(struct NepHidBase *nh, struct PsdInterface *pif) +{ + struct Library *ps; + struct NepClassHid *nch; + struct PsdConfig *pc; + struct PsdDevice *pd; + STRPTR devname; + STRPTR ifidstr; + STRPTR devidstr; + UBYTE buf[64]; + struct Task *tmptask; + + KPRINTF(1, ("nepHidForceInterfaceBinding(%08lx)\n", pif)); + if((ps = OpenLibrary("poseidon.library", 4))) + { + psdGetAttrs(PGA_INTERFACE, pif, + IFA_Config, &pc, + IFA_IDString, &ifidstr, + TAG_DONE); + psdGetAttrs(PGA_CONFIG, pc, + CA_Device, &pd, + TAG_END); + psdGetAttrs(PGA_DEVICE, pd, + DA_ProductName, &devname, + DA_IDString, &devidstr, + TAG_END); + if((nch = psdAllocVec(sizeof(struct NepClassHid)))) + { + nch->nch_ClsBase = nh; + nch->nch_CDC = psdAllocVec(sizeof(struct ClsDevCfg)); + if(!nch->nch_CDC) + { + psdFreeVec(nch); + CloseLibrary(ps); + return(NULL); + } + + nch->nch_Device = pd; + nch->nch_Interface = pif; + nch->nch_DevIDString = devidstr; + nch->nch_IfIDString = ifidstr; + + nLoadBindingConfig(nch); + + psdSafeRawDoFmt(buf, 64, "bootmouse.class<%08lx>", nch); + nch->nch_ReadySignal = SIGB_SINGLE; + nch->nch_ReadySigTask = FindTask(NULL); + SetSignal(0, SIGF_SINGLE); + if((tmptask = psdSpawnSubTask(buf, nHidTask, nch))) + { + psdBorrowLocksWait(tmptask, 1UL<nch_ReadySignal); + if(nch->nch_Task) + { + nch->nch_ReadySigTask = NULL; + //FreeSignal(nch->nch_ReadySignal); + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, + "I'm pleased to introduce a mouse alliance to '%s'!", + devname); + + Forbid(); + AddTail(&nh->nh_Bindings, &nch->nch_Node); + Permit(); + CloseLibrary(ps); + return(nch); + } + } + nch->nch_ReadySigTask = NULL; + //FreeSignal(nch->nch_ReadySignal); + psdFreeVec(nch->nch_CDC); + psdFreeVec(nch); + } + CloseLibrary(ps); + } + return(NULL); + +} +/* \\\ */ + +/* /// "usbReleaseInterfaceBinding()" */ +void usbReleaseInterfaceBinding(struct NepHidBase *nh, struct NepClassHid *nch) +{ + struct Library *ps; + struct PsdConfig *pc; + struct PsdDevice *pd; + STRPTR devname; + + KPRINTF(1, ("nepHidReleaseInterfaceBinding(%08lx)\n", nch)); + if((ps = OpenLibrary("poseidon.library", 4))) + { + Forbid(); + nch->nch_ReadySignal = SIGB_SINGLE; + nch->nch_ReadySigTask = FindTask(NULL); + if(nch->nch_GUITask) + { + Signal(nch->nch_GUITask, SIGBREAKF_CTRL_C); + } + Permit(); + while(nch->nch_GUITask) + { + Wait(1L<nch_ReadySignal); + } + + Forbid(); + if(nch->nch_Task) + { + Signal(nch->nch_Task, SIGBREAKF_CTRL_C); + } + Permit(); + while(nch->nch_Task) + { + Wait(1L<nch_ReadySignal); + } + //FreeSignal(nch->nch_ReadySignal); + psdGetAttrs(PGA_INTERFACE, nch->nch_Interface, IFA_Config, (ULONG) &pc, TAG_END); + psdGetAttrs(PGA_CONFIG, pc, CA_Device, (ULONG) &pd, TAG_END); + psdGetAttrs(PGA_DEVICE, pd, DA_ProductName, (ULONG) &devname, TAG_END); + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, + "A cat ate my mouse '%s'!", + devname); + Forbid(); + Remove(&nch->nch_Node); + Permit(); + psdFreeVec(nch->nch_CDC); + psdFreeVec(nch); + CloseLibrary(ps); + } +} +/* \\\ */ + +/* /// "usbGetAttrsA()" */ +AROS_LH3(LONG, usbGetAttrsA, + AROS_LHA(ULONG, type, D0), + AROS_LHA(APTR, usbstruct, A0), + AROS_LHA(struct TagItem *, tags, A1), + LIBBASETYPEPTR, nh, 5, nep) +{ + AROS_LIBFUNC_INIT + + struct TagItem *ti; + LONG count = 0; + + KPRINTF(1, ("nepHidGetAttrsA(%ld, %08lx, %08lx)\n", type, usbstruct, tags)); + switch(type) + { + case UGA_CLASS: + if((ti = FindTagItem(UCCA_Priority, tags))) + { + *((IPTR *) ti->ti_Data) = -100; + count++; + } + if((ti = FindTagItem(UCCA_Description, tags))) + { + *((STRPTR *) ti->ti_Data) = "Support for mice/tablets in boot protocol mode"; + count++; + } + if((ti = FindTagItem(UCCA_HasClassCfgGUI, tags))) + { + *((IPTR *) ti->ti_Data) = TRUE; + count++; + } + if((ti = FindTagItem(UCCA_HasBindingCfgGUI, tags))) + { + *((IPTR *) ti->ti_Data) = TRUE; + count++; + } + if((ti = FindTagItem(UCCA_AfterDOSRestart, tags))) + { + *((IPTR *) ti->ti_Data) = TRUE; + count++; + } + if((ti = FindTagItem(UCCA_UsingDefaultCfg, tags))) + { + *((IPTR *) ti->ti_Data) = nh->nh_DummyNCH.nch_UsingDefaultCfg; + count++; + } + break; + + case UGA_BINDING: + if((ti = FindTagItem(UCBA_UsingDefaultCfg, tags))) + { + *((IPTR *) ti->ti_Data) = ((struct NepClassHid *) usbstruct)->nch_UsingDefaultCfg; + count++; + } + break; + } + return(count); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "usbSetAttrsA()" */ +AROS_LH3(LONG, usbSetAttrsA, + AROS_LHA(ULONG, type, D0), + AROS_LHA(APTR, usbstruct, A0), + AROS_LHA(struct TagItem *, tags, A1), + LIBBASETYPEPTR, nh, 6, nep) +{ + AROS_LIBFUNC_INIT + return(0); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "usbDoMethodA()" */ +AROS_LH2(IPTR, usbDoMethodA, + AROS_LHA(ULONG, methodid, D0), + AROS_LHA(IPTR *, methoddata, A1), + LIBBASETYPEPTR, nh, 7, nep) +{ + AROS_LIBFUNC_INIT + + struct NepClassHid *nch; + + KPRINTF(10, ("Do Method %ld\n", methodid)); + switch(methodid) + { + case UCM_AttemptInterfaceBinding: + return((IPTR) usbAttemptInterfaceBinding(nh, (struct PsdInterface *) methoddata[0])); + + case UCM_ForceInterfaceBinding: + return((IPTR) usbForceInterfaceBinding(nh, (struct PsdInterface *) methoddata[0])); + + case UCM_ReleaseInterfaceBinding: + usbReleaseInterfaceBinding(nh, (struct NepClassHid *) methoddata[0]); + return(TRUE); + + case UCM_OpenCfgWindow: + return(nOpenBindingCfgWindow(nh, &nh->nh_DummyNCH)); + + case UCM_OpenBindingCfgWindow: + return(nOpenBindingCfgWindow(nh, (struct NepClassHid *) methoddata[0])); + + case UCM_ConfigChangedEvent: + nLoadClassConfig(nh); + Forbid(); + nch = (struct NepClassHid *) nh->nh_Bindings.lh_Head; + while(nch->nch_Node.ln_Succ) + { + nLoadBindingConfig(nch); + nch = (struct NepClassHid *) nch->nch_Node.ln_Succ; + } + Permit(); + return(TRUE); + + default: + break; + } + return(0); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "nLoadClassConfig()" */ +BOOL nLoadClassConfig(struct NepHidBase *nh) +{ + struct NepClassHid *nch = &nh->nh_DummyNCH; + struct Library *ps; + struct ClsDevCfg *cdc; + struct PsdIFFContext *pic; + + KPRINTF(10, ("Loading Class Config...\n")); + if(nch->nch_GUITask) + { + return(FALSE); + } + if(!(ps = OpenLibrary("poseidon.library", 4))) + { + return(FALSE); + } + + Forbid(); + /* Create default config */ + nch->nch_CDC->cdc_ChunkID = AROS_LONG2BE(MAKE_ID('B','M','S','E')); + nch->nch_CDC->cdc_Length = AROS_LONG2BE(sizeof(struct ClsDevCfg)-8); + nch->nch_CDC->cdc_Wheelmouse = FALSE; + nch->nch_UsingDefaultCfg = TRUE; + /* try to load default config */ + pic = psdGetClsCfg(libname); + if(pic) + { + cdc = psdGetCfgChunk(pic, nch->nch_CDC->cdc_ChunkID); + if(cdc) + { + CopyMem(((UBYTE *) cdc) + 8, ((UBYTE *) nch->nch_CDC) + 8, min(AROS_LONG2BE(cdc->cdc_Length), AROS_LONG2BE(nch->nch_CDC->cdc_Length))); + psdFreeVec(cdc); + nch->nch_UsingDefaultCfg = FALSE; + } + } + Permit(); + CloseLibrary(ps); + return(FALSE); +} +/* \\\ */ + +/* /// "nLoadBindingConfig()" */ +BOOL nLoadBindingConfig(struct NepClassHid *nch) +{ + struct NepHidBase *nh = nch->nch_ClsBase; + struct Library *ps; + struct ClsDevCfg *cdc; + struct PsdIFFContext *pic; + + KPRINTF(10, ("Loading Binding Config...\n")); + if(nch->nch_GUITask) + { + return(FALSE); + } + //nLoadClassConfig(nh); + *nch->nch_CDC = *nh->nh_DummyNCH.nch_CDC; + nch->nch_UsingDefaultCfg = TRUE; + + if(!(ps = OpenLibrary("poseidon.library", 4))) + { + return(FALSE); + } + + Forbid(); + /* Load config */ + pic = psdGetUsbDevCfg(libname, nch->nch_DevIDString, nch->nch_IfIDString); + if(pic) + { + cdc = psdGetCfgChunk(pic, nch->nch_CDC->cdc_ChunkID); + if(cdc) + { + CopyMem(((UBYTE *) cdc) + 8, ((UBYTE *) nch->nch_CDC) + 8, min(AROS_LONG2BE(cdc->cdc_Length), AROS_LONG2BE(nch->nch_CDC->cdc_Length))); + psdFreeVec(cdc); + nch->nch_UsingDefaultCfg = FALSE; + } + } + Permit(); + CloseLibrary(ps); + return(FALSE); +} +/* \\\ */ + +/* /// "nOpenBindingCfgWindow()" */ +LONG nOpenBindingCfgWindow(struct NepHidBase *nh, struct NepClassHid *nch) +{ + struct Library *ps; + KPRINTF(10, ("Opening GUI...\n")); + if(!(ps = OpenLibrary("poseidon.library", 4))) + { + return(FALSE); + } + Forbid(); + if(!nch->nch_GUITask) + { + if((nch->nch_GUITask = psdSpawnSubTask(MOD_NAME_STRING " GUI", nGUITask, nch))) + { + Permit(); + CloseLibrary(ps); + return(TRUE); + } + } + Permit(); + CloseLibrary(ps); + return(FALSE); +} +/* \\\ */ + +/**************************************************************************/ + +#undef ps +#define ps nch->nch_Base + +/* /// "nHidTask()" */ +AROS_UFH0(void, nHidTask) +{ + AROS_USERFUNC_INIT + + struct NepClassHid *nch; + struct PsdPipe *pp; + ULONG sigmask; + ULONG sigs; + UWORD iecode; + UWORD qualifier; + UWORD buts; + UWORD oldbuts = 0; + WORD wheel = 0; + WORD oldwheel = 0; + UWORD wheeliecode; + UWORD wheeldist; + BOOL newmouse; + UBYTE *buf; + UBYTE *bufreal; + LONG ioerr; + BOOL firstpkt = TRUE; + + if((nch = nAllocHid())) + { + Forbid(); + if(nch->nch_ReadySigTask) + { + Signal(nch->nch_ReadySigTask, 1L<nch_ReadySignal); + } + Permit(); + sigmask = (1L<nch_TaskMsgPort->mp_SigBit)|SIGBREAKF_CTRL_C; + bufreal = buf = nch->nch_EP1Buf; + psdSendPipe(nch->nch_EP1Pipe, buf, nch->nch_EP1PktSize); + do + { + sigs = Wait(sigmask); + while((pp = (struct PsdPipe *) GetMsg(nch->nch_TaskMsgPort))) + { + if(pp == nch->nch_EP1Pipe) + { + if(!(ioerr = psdGetPipeError(pp))) + { + if(firstpkt) + { + if(*buf == 0x01) + { + bufreal++; + } + firstpkt = 0; + } + KPRINTF(1, ("Data: %08lx %08lx\n", (*(ULONG *) bufreal), ((ULONG *) bufreal)[1])); + newmouse = FALSE; + qualifier = IEQUALIFIER_RELATIVEMOUSE; + buts = bufreal[0]; + iecode = wheeliecode = IECODE_NOBUTTON; + wheeldist = 0; + if(buts & 1) + { + qualifier |= IEQUALIFIER_LEFTBUTTON; + } + if(buts & 2) + { + qualifier |= IEQUALIFIER_RBUTTON; + } + if(buts & 4) + { + qualifier |= IEQUALIFIER_MIDBUTTON; + } + if(nch->nch_CDC->cdc_Wheelmouse) + { + wheel = ((BYTE *) bufreal)[3]; + if(wheel != oldwheel) + { + if(oldwheel > 0) + { + wheeliecode = RAWKEY_NM_WHEEL_UP|IECODE_UP_PREFIX; + newmouse = TRUE; + } + else if(oldwheel < 0) + { + wheeliecode = RAWKEY_NM_WHEEL_DOWN|IECODE_UP_PREFIX; + newmouse = TRUE; + } + oldwheel = wheel; + } + if(wheel > 0) + { + wheeliecode = RAWKEY_NM_WHEEL_UP; + wheeldist = wheel; + newmouse = TRUE; + } + else if(wheel < 0) + { + wheeliecode = RAWKEY_NM_WHEEL_DOWN; + wheeldist = -wheel; + newmouse = TRUE; + } + } + + if((buts^oldbuts) & 1) + { + iecode = (buts & 1) ? IECODE_LBUTTON : IECODE_LBUTTON|IECODE_UP_PREFIX; + oldbuts ^= 1; + } + else if((buts^oldbuts) & 2) + { + iecode = (buts & 2) ? IECODE_RBUTTON : IECODE_RBUTTON|IECODE_UP_PREFIX; + oldbuts ^= 2; + } + else if((buts^oldbuts) & 4) + { + iecode = (buts & 4) ? IECODE_MBUTTON : IECODE_MBUTTON|IECODE_UP_PREFIX; + oldbuts ^= 4; + } + nch->nch_FakeEvent.ie_X = ((BYTE *) bufreal)[1]; + nch->nch_FakeEvent.ie_Y = ((BYTE *) bufreal)[2]; + nch->nch_FakeEvent.ie_Class = IECLASS_RAWMOUSE; + nch->nch_FakeEvent.ie_SubClass = 0; + nch->nch_FakeEvent.ie_Code = iecode; + nch->nch_FakeEvent.ie_NextEvent = NULL; + nch->nch_FakeEvent.ie_Qualifier = qualifier; + nch->nch_InpIOReq->io_Data = &nch->nch_FakeEvent; + nch->nch_InpIOReq->io_Length = sizeof(struct InputEvent); + nch->nch_InpIOReq->io_Command = IND_WRITEEVENT; + DoIO((struct IORequest *) nch->nch_InpIOReq); + if(newmouse) + { + while(wheeldist--) + { + KPRINTF(1, ("Doing wheel %ld\n", wheel)); + nch->nch_FakeEvent.ie_Class = IECLASS_RAWKEY; + nch->nch_FakeEvent.ie_SubClass = 0; + nch->nch_FakeEvent.ie_Code = wheeliecode; + nch->nch_FakeEvent.ie_NextEvent = NULL; + nch->nch_FakeEvent.ie_Qualifier = qualifier; + nch->nch_InpIOReq->io_Data = &nch->nch_FakeEvent; + nch->nch_InpIOReq->io_Length = sizeof(struct InputEvent); + nch->nch_InpIOReq->io_Command = IND_WRITEEVENT; + DoIO((struct IORequest *) nch->nch_InpIOReq); + + nch->nch_FakeEvent.ie_Class = IECLASS_NEWMOUSE; + nch->nch_FakeEvent.ie_SubClass = 0; + nch->nch_FakeEvent.ie_Code = wheeliecode; + nch->nch_FakeEvent.ie_NextEvent = NULL; + nch->nch_FakeEvent.ie_Qualifier = qualifier; + nch->nch_InpIOReq->io_Data = &nch->nch_FakeEvent; + nch->nch_InpIOReq->io_Length = sizeof(struct InputEvent); + nch->nch_InpIOReq->io_Command = IND_WRITEEVENT; + DoIO((struct IORequest *) nch->nch_InpIOReq); + } + } + } else { + KPRINTF(1, ("Int Pipe failed %ld\n", ioerr)); + psdDelayMS(20); + } + psdSendPipe(nch->nch_EP1Pipe, buf, nch->nch_EP1PktSize); + break; + } + } + } while(!(sigs & SIGBREAKF_CTRL_C)); + KPRINTF(20, ("Going down the river!\n")); + psdAbortPipe(nch->nch_EP1Pipe); + psdWaitPipe(nch->nch_EP1Pipe); + nFreeHid(nch); + } + AROS_USERFUNC_EXIT +} +/* \\\ */ + +/* /// "nAllocHid()" */ +struct NepClassHid * nAllocHid(void) +{ + struct Task *thistask; + struct NepClassHid *nch; + LONG ioerr; + + thistask = FindTask(NULL); + nch = thistask->tc_UserData; + do + { + if(!(nch->nch_Base = OpenLibrary("poseidon.library", 4))) + { + Alert(AG_OpenLib); + break; + } + psdGetAttrs(PGA_INTERFACE, nch->nch_Interface, + IFA_Config, &nch->nch_Config, + IFA_InterfaceNum, &nch->nch_IfNum, + TAG_END); + psdGetAttrs(PGA_CONFIG, nch->nch_Config, + CA_Device, &nch->nch_Device, + TAG_END); + + nch->nch_EP1 = psdFindEndpoint(nch->nch_Interface, NULL, + EA_IsIn, TRUE, + EA_TransferType, USEAF_INTERRUPT, + TAG_END); + if(!nch->nch_EP1) + { + KPRINTF(1, ("Ooops!?! No Endpoints defined?\n")); + break; + } + psdGetAttrs(PGA_ENDPOINT, nch->nch_EP1, + EA_MaxPktSize, (ULONG) &nch->nch_EP1PktSize, + TAG_END); + if((nch->nch_InpMsgPort = CreateMsgPort())) + { + if((nch->nch_InpIOReq = (struct IOStdReq *) CreateIORequest(nch->nch_InpMsgPort, sizeof(struct IOStdReq)))) + { + if(!OpenDevice("input.device", 0, (struct IORequest *) nch->nch_InpIOReq, 0)) + { + if((nch->nch_TaskMsgPort = CreateMsgPort())) + { + if((nch->nch_EP0Pipe = psdAllocPipe(nch->nch_Device, nch->nch_TaskMsgPort, NULL))) + { + if((nch->nch_EP1Pipe = psdAllocPipe(nch->nch_Device, nch->nch_TaskMsgPort, nch->nch_EP1))) + { + psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_INTERFACE, + UHR_SET_PROTOCOL, HID_PROTO_BOOT, nch->nch_IfNum); + ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0); + if(!ioerr) + { + psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_INTERFACE, + UHR_SET_IDLE, 0, nch->nch_IfNum); + ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0); + if(ioerr) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "SET_IDLE=0 failed: %s (%ld)!", + psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + } + if((nch->nch_EP1Buf = psdAllocVec(nch->nch_EP1PktSize))) + { + psdSetAttrs(PGA_PIPE, nch->nch_EP1Pipe, + PPA_AllowRuntPackets, TRUE, + TAG_END); + nch->nch_Task = thistask; + return(nch); + } + } else { + psdAddErrorMsg(RETURN_FAIL, (STRPTR) libname, + "SET_PROTOCOL=BOOT failed: %s (%ld)!", + psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + } + psdFreePipe(nch->nch_EP1Pipe); + } + psdFreePipe(nch->nch_EP0Pipe); + } + DeleteMsgPort(nch->nch_TaskMsgPort); + } + CloseDevice((struct IORequest *) nch->nch_InpIOReq); + } + DeleteIORequest((struct IORequest *) nch->nch_InpIOReq); + } + DeleteMsgPort(nch->nch_InpMsgPort); + } + } while(FALSE); + CloseLibrary(nch->nch_Base); + Forbid(); + nch->nch_Task = NULL; + if(nch->nch_ReadySigTask) + { + Signal(nch->nch_ReadySigTask, 1L<nch_ReadySignal); + } + return(NULL); +} +/* \\\ */ + +/* /// "nFreeHid()" */ +void nFreeHid(struct NepClassHid *nch) +{ + psdFreeVec(nch->nch_EP1Buf); + psdFreePipe(nch->nch_EP1Pipe); + psdFreePipe(nch->nch_EP0Pipe); + DeleteMsgPort(nch->nch_TaskMsgPort); + CloseDevice((struct IORequest *) nch->nch_InpIOReq); + DeleteIORequest((struct IORequest *) nch->nch_InpIOReq); + DeleteMsgPort(nch->nch_InpMsgPort); + CloseLibrary(nch->nch_Base); + Forbid(); + nch->nch_Task = NULL; + if(nch->nch_ReadySigTask) + { + Signal(nch->nch_ReadySigTask, 1L<nch_ReadySignal); + } +} +/* \\\ */ + +/**************************************************************************/ + +#undef ps +#define ps nch->nch_PsdBase +#undef IntuitionBase +#define IntuitionBase nch->nch_IntBase +#undef MUIMasterBase +#define MUIMasterBase nch->nch_MUIBase + +/* /// "nGUITask()" */ +AROS_UFH0(void, nGUITask) +{ + AROS_USERFUNC_INIT + + struct Task *thistask; + struct NepHidBase *nh; + struct NepClassHid *nch; + APTR pic; + + thistask = FindTask(NULL); + nch = thistask->tc_UserData; + nh = nch->nch_ClsBase; + + ++nh->nh_Library.lib_OpenCnt; + if(!(MUIMasterBase = OpenLibrary(MUIMASTER_NAME, MUIMASTER_VMIN))) + { + KPRINTF(10, ("Couldn't open muimaster.library.\n")); + nGUITaskCleanup(nch); + return; + } + + if(!(IntuitionBase = OpenLibrary("intuition.library", 39))) + { + KPRINTF(10, ("Couldn't open intuition.library.\n")); + nGUITaskCleanup(nch); + return; + } + if(!(ps = OpenLibrary("poseidon.library", 4))) + { + KPRINTF(10, ("Couldn't open poseidon.library.\n")); + nGUITaskCleanup(nch); + return; + } + + nch->nch_App = ApplicationObject, + MUIA_Application_Title , libname, + MUIA_Application_Version , VERSION_STRING, + MUIA_Application_Copyright , "©2002-2009 Chris Hodges", + MUIA_Application_Author , "Chris Hodges ", + MUIA_Application_Description, "Settings for the bootmouse.class", + MUIA_Application_Base , "BOOTMOUSE", + MUIA_Application_HelpFile , "HELP:Poseidon.guide", + MUIA_Application_Menustrip , MenustripObject, + Child, MenuObjectT("Project"), + Child, nch->nch_AboutMI = MenuitemObject, + MUIA_Menuitem_Title, "About...", + MUIA_Menuitem_Shortcut, "?", + End, + End, + Child, MenuObjectT("Settings"), + Child, nch->nch_UseMI = MenuitemObject, + MUIA_Menuitem_Title, "Save", + MUIA_Menuitem_Shortcut, "S", + End, + Child, nch->nch_SetDefaultMI = MenuitemObject, + MUIA_Menuitem_Title, "Save as Default", + MUIA_Menuitem_Shortcut, "D", + End, + Child, MenuitemObject, + MUIA_Menuitem_Title, NM_BARLABEL, + End, + Child, nch->nch_MUIPrefsMI = MenuitemObject, + MUIA_Menuitem_Title, "MUI Settings", + MUIA_Menuitem_Shortcut, "M", + End, + End, + End, + + SubWindow, nch->nch_MainWindow = WindowObject, + MUIA_Window_ID , MAKE_ID('M','A','I','N'), + MUIA_Window_Title, libname, + MUIA_HelpNode, libname, + + WindowContents, VGroup, + Child, HGroup, GroupFrameT(nch->nch_Interface ? "Device Settings" : "Default Device Settings"), + Child, HSpace(0), + Child, ColGroup(2), + Child, Label((IPTR) "Experimental Wheelmouse support:"), + Child, HGroup, + Child, nch->nch_WheelmouseObj = ImageObject, ImageButtonFrame, + MUIA_Background, MUII_ButtonBack, + MUIA_CycleChain, 1, + MUIA_InputMode, MUIV_InputMode_Toggle, + MUIA_Image_Spec, MUII_CheckMark, + MUIA_Image_FreeVert, TRUE, + MUIA_Selected, nch->nch_CDC->cdc_Wheelmouse, + MUIA_ShowSelState, FALSE, + End, + Child, HSpace(0), + End, + End, + Child, HSpace(0), + End, + Child, VSpace(0), + Child, HGroup, + MUIA_Group_SameWidth, TRUE, + Child, nch->nch_UseObj = TextObject, ButtonFrame, + MUIA_ShowMe, nch->nch_Interface, + MUIA_Background, MUII_ButtonBack, + MUIA_CycleChain, 1, + MUIA_InputMode, MUIV_InputMode_RelVerify, + MUIA_Text_Contents, "\33c Save ", + End, + Child, nch->nch_SetDefaultObj = TextObject, ButtonFrame, + MUIA_Background, MUII_ButtonBack, + MUIA_CycleChain, 1, + MUIA_InputMode, MUIV_InputMode_RelVerify, + MUIA_Text_Contents, nch->nch_Interface ? "\33c Save as Default " : "\33c Save Defaults ", + End, + Child, nch->nch_CloseObj = TextObject, ButtonFrame, + MUIA_Background, MUII_ButtonBack, + MUIA_CycleChain, 1, + MUIA_InputMode, MUIV_InputMode_RelVerify, + MUIA_Text_Contents, "\33c Use ", + End, + End, + End, + End, + End; + + if(!nch->nch_App) + { + KPRINTF(10, ("Couldn't create application\n")); + nGUITaskCleanup(nch); + return; + } + + DoMethod(nch->nch_MainWindow, MUIM_Notify, MUIA_Window_CloseRequest, TRUE, + nch->nch_App, 2, MUIM_Application_ReturnID, MUIV_Application_ReturnID_Quit); + DoMethod(nch->nch_UseObj, MUIM_Notify, MUIA_Pressed, FALSE, + nch->nch_App, 2, MUIM_Application_ReturnID, ID_STORE_CONFIG); + DoMethod(nch->nch_SetDefaultObj, MUIM_Notify, MUIA_Pressed, FALSE, + nch->nch_App, 2, MUIM_Application_ReturnID, ID_DEF_CONFIG); + DoMethod(nch->nch_CloseObj, MUIM_Notify, MUIA_Pressed, FALSE, + nch->nch_App, 2, MUIM_Application_ReturnID, MUIV_Application_ReturnID_Quit); + + DoMethod(nch->nch_AboutMI, MUIM_Notify, MUIA_Menuitem_Trigger, MUIV_EveryTime, + nch->nch_App, 2, MUIM_Application_ReturnID, ID_ABOUT); + DoMethod(nch->nch_UseMI, MUIM_Notify, MUIA_Menuitem_Trigger, MUIV_EveryTime, + nch->nch_App, 2, MUIM_Application_ReturnID, ID_STORE_CONFIG); + DoMethod(nch->nch_SetDefaultMI, MUIM_Notify, MUIA_Menuitem_Trigger, MUIV_EveryTime, + nch->nch_App, 2, MUIM_Application_ReturnID, ID_DEF_CONFIG); + DoMethod(nch->nch_MUIPrefsMI, MUIM_Notify, MUIA_Menuitem_Trigger, MUIV_EveryTime, + nch->nch_App, 2, MUIM_Application_OpenConfigWindow, 0); + { + IPTR isopen; + IPTR iconify; + ULONG sigs; + ULONG sigmask; + LONG retid; + + get(nch->nch_App, MUIA_Application_Iconified, &iconify); + set(nch->nch_MainWindow, MUIA_Window_Open, TRUE); + get(nch->nch_MainWindow, MUIA_Window_Open, &isopen); + if(!(isopen || iconify)) + { + nGUITaskCleanup(nch); + return; + } + sigmask = 0; + do + { + retid = DoMethod(nch->nch_App, MUIM_Application_NewInput, &sigs); + switch(retid) + { + case ID_DEF_CONFIG: + case ID_STORE_CONFIG: + case MUIV_Application_ReturnID_Quit: + get(nch->nch_WheelmouseObj, MUIA_Selected, &nch->nch_CDC->cdc_Wheelmouse); + + if(retid == ID_DEF_CONFIG) + { + pic = psdGetClsCfg(libname); + if(!pic) + { + psdSetClsCfg(libname, NULL); + pic = psdGetClsCfg(libname); + } + if(pic) + { + if(psdAddCfgEntry(pic, nch->nch_CDC)) + { + psdSaveCfgToDisk(NULL, FALSE); + } + } + } + if(nch->nch_Interface) + { + pic = psdGetUsbDevCfg(libname, nch->nch_DevIDString, nch->nch_IfIDString); + if(!pic) + { + psdSetUsbDevCfg(libname, nch->nch_DevIDString, nch->nch_IfIDString, NULL); + pic = psdGetUsbDevCfg(libname, nch->nch_DevIDString, nch->nch_IfIDString); + } + if(pic) + { + if(psdAddCfgEntry(pic, nch->nch_CDC)) + { + if(retid != MUIV_Application_ReturnID_Quit) + { + psdSaveCfgToDisk(NULL, FALSE); + } + retid = MUIV_Application_ReturnID_Quit; + } + } + } else { + retid = MUIV_Application_ReturnID_Quit; + } + break; + + case ID_ABOUT: + MUI_RequestA(nch->nch_App, nch->nch_MainWindow, 0, NULL, "Blimey!", VERSION_STRING, NULL); + break; + } + if(retid == MUIV_Application_ReturnID_Quit) + { + break; + } + if(sigs) + { + sigs = Wait(sigs | sigmask | SIGBREAKF_CTRL_C); + if(sigs & SIGBREAKF_CTRL_C) + { + break; + } + } + } while(TRUE); + set(nch->nch_MainWindow, MUIA_Window_Open, FALSE); + } + nGUITaskCleanup(nch); + + AROS_USERFUNC_EXIT +} +/* \\\ */ + +/* /// "nGUITaskCleanup()" */ +void nGUITaskCleanup(struct NepClassHid *nch) +{ + if(nch->nch_App) + { + MUI_DisposeObject(nch->nch_App); + nch->nch_App = NULL; + } + if(MUIMasterBase) + { + CloseLibrary(MUIMasterBase); + MUIMasterBase = NULL; + } + if(IntuitionBase) + { + CloseLibrary(IntuitionBase); + IntuitionBase = NULL; + } + if(ps) + { + CloseLibrary(ps); + ps = NULL; + } + Forbid(); + nch->nch_GUIBinding = NULL; + nch->nch_GUITask = NULL; + if(nch->nch_ReadySigTask) + { + Signal(nch->nch_ReadySigTask, 1L<nch_ReadySignal); + } + --nch->nch_ClsBase->nh_Library.lib_OpenCnt; +} +/* \\\ */ + diff --git a/rom/usb/classes/bootmouse/bootmouse.class.h b/rom/usb/classes/bootmouse/bootmouse.class.h new file mode 100644 index 000000000..30070fbe3 --- /dev/null +++ b/rom/usb/classes/bootmouse/bootmouse.class.h @@ -0,0 +1,37 @@ +#ifndef BOOTMOUSE_CLASS_H +#define BOOTMOUSE_CLASS_H + +/* + *---------------------------------------------------------------------------- + * Includes for Bootmouse class + *---------------------------------------------------------------------------- + * By Chris Hodges + */ + +#include "common.h" + +#include +#include + +#include "bootmouse.h" + +/* Protos */ + +struct NepClassHid * usbAttemptInterfaceBinding(struct NepHidBase *nh, struct PsdInterface *pif); +struct NepClassHid * usbForceInterfaceBinding(struct NepHidBase *nh, struct PsdInterface *pif); +void usbReleaseInterfaceBinding(struct NepHidBase *nh, struct NepClassHid *nch); + +struct NepClassHid * nAllocHid(void); +void nFreeHid(struct NepClassHid *nch); + +BOOL nLoadClassConfig(struct NepHidBase *nh); +BOOL nLoadBindingConfig(struct NepClassHid *nch); + +LONG nOpenBindingCfgWindow(struct NepHidBase *nh, struct NepClassHid *nch); + +void nGUITaskCleanup(struct NepClassHid *nch); + +AROS_UFP0(void, nHidTask); +AROS_UFP0(void, nGUITask); + +#endif /* BOOTMOUSE_CLASS_H */ diff --git a/rom/usb/classes/bootmouse/bootmouse.conf b/rom/usb/classes/bootmouse/bootmouse.conf new file mode 100644 index 000000000..63c68913c --- /dev/null +++ b/rom/usb/classes/bootmouse/bootmouse.conf @@ -0,0 +1,19 @@ +##begin config +version 4.3 +libbase nh +libbasetype struct NepHidBase +libbasetypeextern struct Library +residentpri 39 +basename nep +##end config + +##begin cdef +#include +#include "bootmouse.h" +##end cdef + +##begin functionlist +LONG usbGetAttrsA(ULONG type, APTR usbstruct, struct TagItem *taglist) (D0,A0,A1) +LONG usbSetAttrsA(ULONG type, APTR usbstruct, struct TagItem *taglist) (D0,A0,A1) +IPTR usbDoMethodA(ULONG methodid, IPTR *methoddata) (D0,A1) +##end functionlist diff --git a/rom/usb/classes/bootmouse/bootmouse.h b/rom/usb/classes/bootmouse/bootmouse.h new file mode 100644 index 000000000..c47896d98 --- /dev/null +++ b/rom/usb/classes/bootmouse/bootmouse.h @@ -0,0 +1,81 @@ +#ifndef BOOTMOUSE_H +#define BOOTMOUSE_H + +#include +#include +#include +#include + +#define ID_ABOUT 0x55555555 +#define ID_STORE_CONFIG 0xaaaaaaaa +#define ID_DEF_CONFIG 0xaaaaaaab + +struct ClsDevCfg +{ + ULONG cdc_ChunkID; + ULONG cdc_Length; + IPTR cdc_Wheelmouse; +}; + +struct NepClassHid +{ + struct Node nch_Node; /* Node linkage */ + struct NepHidBase *nch_ClsBase; /* Up linkage */ + struct Library *nch_Base; /* Poseidon base */ + struct PsdDevice *nch_Device; /* Up linkage */ + struct PsdConfig *nch_Config; /* Up linkage */ + struct PsdInterface *nch_Interface; /* Up linkage */ + struct PsdPipe *nch_EP0Pipe; /* Endpoint 0 pipe */ + struct PsdEndpoint *nch_EP1; /* Endpoint 1 */ + struct PsdPipe *nch_EP1Pipe; /* Endpoint 1 pipe */ + IPTR nch_EP1PktSize; /* Size of EP1 packets */ + UBYTE *nch_EP1Buf; /* Packet buffer for EP1 */ + struct Task *nch_ReadySigTask; /* Task to send ready signal to */ + LONG nch_ReadySignal; /* Signal to send when ready */ + struct Task *nch_Task; /* Subtask */ + struct MsgPort *nch_TaskMsgPort; /* Message Port of Subtask */ + struct MsgPort *nch_InpMsgPort; /* input.device MsgPort */ + struct IOStdReq *nch_InpIOReq; /* input.device IORequest */ + struct InputEvent nch_FakeEvent; /* Input Event */ + struct Library *nch_InputBase; /* Pointer to input.device base */ + IPTR nch_IfNum; /* Interface number */ + + STRPTR nch_DevIDString; /* Device ID String */ + STRPTR nch_IfIDString; /* Interface ID String */ + + BOOL nch_UsingDefaultCfg; + struct ClsDevCfg *nch_CDC; + + struct Library *nch_MUIBase; /* MUI master base */ + struct Library *nch_PsdBase; /* Poseidon base */ + struct Library *nch_IntBase; /* Intuition base */ + struct Task *nch_GUITask; /* GUI Task */ + struct NepClassHid *nch_GUIBinding; /* Window of binding that's open */ + + Object *nch_App; + Object *nch_MainWindow; + Object *nch_WheelmouseObj; + + Object *nch_UseObj; + Object *nch_SetDefaultObj; + Object *nch_CloseObj; + + Object *nch_AboutMI; + Object *nch_UseMI; + Object *nch_SetDefaultMI; + Object *nch_MUIPrefsMI; +}; + +struct NepHidBase +{ + struct Library nh_Library; /* standard */ + UWORD nh_Flags; /* various flags */ + + struct Library *nh_UtilityBase; /* Utility base */ + + struct List nh_Bindings; /* List of bindings created */ + + struct NepClassHid nh_DummyNCH; /* Dummy NCH for default config */ +}; + +#endif /* BOOTMOUSE_H */ diff --git a/rom/usb/classes/bootmouse/common.h b/rom/usb/classes/bootmouse/common.h new file mode 100644 index 000000000..feae1e480 --- /dev/null +++ b/rom/usb/classes/bootmouse/common.h @@ -0,0 +1,55 @@ + +#include LC_LIBDEFS_FILE + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define NewList NEWLIST + +#include + +#define min(x,y) (((x) < (y)) ? (x) : (y)) +#define max(x,y) (((x) > (y)) ? (x) : (y)) + diff --git a/rom/usb/classes/bootmouse/debug.c b/rom/usb/classes/bootmouse/debug.c new file mode 100644 index 000000000..f29021b6b --- /dev/null +++ b/rom/usb/classes/bootmouse/debug.c @@ -0,0 +1,38 @@ +#include "debug.h" + +#ifdef DEBUG +void dumpmem(void *mem, unsigned long int len) +{ + unsigned char *p; + + if (!mem || !len) { return; } + + p = (unsigned char *) mem; + + bug("\n"); + + do + { + unsigned char b, c, str[17]; + + for (b = 0; b < 16; b++) + { + c = *p++; + str[b] = ((c >= ' ') && (c <= 'z')) ? c : '.'; + str[b + 1] = 0; + bug("%02lx ", c); + if (--len == 0) break; + } + + while (++b < 16) + { + bug(" "); + } + + bug(" %s\n", str); + } while (len); + + bug("\n\n"); +} + +#endif /* DEBUG */ diff --git a/rom/usb/classes/bootmouse/debug.h b/rom/usb/classes/bootmouse/debug.h new file mode 100644 index 000000000..6d5cb840e --- /dev/null +++ b/rom/usb/classes/bootmouse/debug.h @@ -0,0 +1,22 @@ +#ifndef __DEBUG_H__ +#define __DEBUG_H__ + +#define DB_LEVEL 1 + +#define DEBUG 1 + +#include + +#ifdef DEBUG +#define KPRINTF(l, x) do { if ((l) >= DB_LEVEL) \ + { bug("%s:%s/%lu: ", __FILE__, __FUNCTION__, __LINE__); bug x;} } while (0) +#define DB(x) x + void dumpmem(void *mem, unsigned long int len); +#else /* !DEBUG */ + +#define KPRINTF(l, x) ((void) 0) +#define DB(x) + +#endif /* DEBUG */ + +#endif /* __DEBUG_H__ */ diff --git a/rom/usb/classes/bootmouse/mmakefile.src b/rom/usb/classes/bootmouse/mmakefile.src new file mode 100644 index 000000000..e17651f78 --- /dev/null +++ b/rom/usb/classes/bootmouse/mmakefile.src @@ -0,0 +1,13 @@ +# $Id: mmakefile.src $ +include $(TOP)/config/make.cfg + +FILES := bootmouse.class debug + +#MM- rom-usb-classes-bootmouse : rom-usb-usbclass rom-usb-poseidon + +%build_module mmake=rom-usb-classes-bootmouse \ + modname=bootmouse modtype=usbclass modsuffix="class" \ + files="$(FILES)" \ + uselibs="amiga rom mui" + +%common diff --git a/rom/usb/classes/hub/common.h b/rom/usb/classes/hub/common.h new file mode 100644 index 000000000..feae1e480 --- /dev/null +++ b/rom/usb/classes/hub/common.h @@ -0,0 +1,55 @@ + +#include LC_LIBDEFS_FILE + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define NewList NEWLIST + +#include + +#define min(x,y) (((x) < (y)) ? (x) : (y)) +#define max(x,y) (((x) > (y)) ? (x) : (y)) + diff --git a/rom/usb/classes/hub/debug.c b/rom/usb/classes/hub/debug.c new file mode 100644 index 000000000..f29021b6b --- /dev/null +++ b/rom/usb/classes/hub/debug.c @@ -0,0 +1,38 @@ +#include "debug.h" + +#ifdef DEBUG +void dumpmem(void *mem, unsigned long int len) +{ + unsigned char *p; + + if (!mem || !len) { return; } + + p = (unsigned char *) mem; + + bug("\n"); + + do + { + unsigned char b, c, str[17]; + + for (b = 0; b < 16; b++) + { + c = *p++; + str[b] = ((c >= ' ') && (c <= 'z')) ? c : '.'; + str[b + 1] = 0; + bug("%02lx ", c); + if (--len == 0) break; + } + + while (++b < 16) + { + bug(" "); + } + + bug(" %s\n", str); + } while (len); + + bug("\n\n"); +} + +#endif /* DEBUG */ diff --git a/rom/usb/classes/hub/debug.h b/rom/usb/classes/hub/debug.h new file mode 100644 index 000000000..6d5cb840e --- /dev/null +++ b/rom/usb/classes/hub/debug.h @@ -0,0 +1,22 @@ +#ifndef __DEBUG_H__ +#define __DEBUG_H__ + +#define DB_LEVEL 1 + +#define DEBUG 1 + +#include + +#ifdef DEBUG +#define KPRINTF(l, x) do { if ((l) >= DB_LEVEL) \ + { bug("%s:%s/%lu: ", __FILE__, __FUNCTION__, __LINE__); bug x;} } while (0) +#define DB(x) x + void dumpmem(void *mem, unsigned long int len); +#else /* !DEBUG */ + +#define KPRINTF(l, x) ((void) 0) +#define DB(x) + +#endif /* DEBUG */ + +#endif /* __DEBUG_H__ */ diff --git a/rom/usb/classes/hub/hub.class.c b/rom/usb/classes/hub/hub.class.c new file mode 100644 index 000000000..2a8aec03e --- /dev/null +++ b/rom/usb/classes/hub/hub.class.c @@ -0,0 +1,1437 @@ +/* + *---------------------------------------------------------------------------- + * hub class for poseidon + *---------------------------------------------------------------------------- + * By Chris Hodges + */ + +#include "debug.h" + +#include "hub.class.h" + +/* /// "Lib Stuff" */ +static const STRPTR libname = MOD_NAME_STRING; + +static int libInit(LIBBASETYPEPTR nh) +{ + KPRINTF(10, ("libInit nh: 0x%08lx SysBase: 0x%08lx\n", nh, SysBase)); + + nh->nh_UtilityBase = OpenLibrary("utility.library", 39); + +#define UtilityBase nh->nh_UtilityBase + + if(UtilityBase) + { + NewList(&nh->nh_Bindings); + InitSemaphore(&nh->nh_Adr0Sema); + } else { + KPRINTF(20, ("libInit: OpenLibrary(\"utility.library\", 39) failed!\n")); + return FALSE; + } + + KPRINTF(10, ("libInit: Ok\n")); + return TRUE; +} + +static int libExpunge(LIBBASETYPEPTR nh) +{ + KPRINTF(10, ("libExpunge nh: 0x%08lx SysBase: 0x%08lx\n", nh, SysBase)); + + CloseLibrary(UtilityBase); + nh->nh_UtilityBase = NULL; + + return TRUE; +} + +ADD2INITLIB(libInit, 0) +ADD2EXPUNGELIB(libExpunge, 0) +/* \\\ */ + +/* + * *********************************************************************** + * * Library functions * + * *********************************************************************** + */ + +/* /// "usbAttemptDeviceBinding()" */ +struct NepClassHub * usbAttemptDeviceBinding(struct NepHubBase *nh, struct PsdDevice *pd) +{ + struct Library *ps; + IPTR devclass; + + KPRINTF(1, ("nepHubAttemptDeviceBinding(%08lx)\n", pd)); + + if((ps = OpenLibrary("poseidon.library", 4))) + { + psdGetAttrs(PGA_DEVICE, pd, + DA_Class, &devclass, + TAG_DONE); + CloseLibrary(ps); + if(devclass == HUB_CLASSCODE) + { + return(usbForceDeviceBinding(nh, pd)); + } + } + return(NULL); +} +/* \\\ */ + +/* /// "usbForceDeviceBinding()" */ +struct NepClassHub * usbForceDeviceBinding(struct NepHubBase * nh, struct PsdDevice *pd) +{ + struct Library *ps; + struct NepClassHub *nch; + STRPTR devname; + char buf[64]; + struct Task *tmptask; + + KPRINTF(1, ("nepHubAttemptDeviceBinding(%08lx)\n", pd)); + + if((ps = OpenLibrary("poseidon.library", 4))) + { + psdGetAttrs(PGA_DEVICE, pd, + DA_ProductName, &devname, + TAG_DONE); + if((nch = psdAllocVec(sizeof(struct NepClassHub)))) + { + nch->nch_HubBase = nh; + nch->nch_SysBase = SysBase; + nch->nch_Device = pd; + psdSafeRawDoFmt(buf, 64, "hub.class<%08lx>", nch); + nch->nch_ReadySignal = SIGB_SINGLE; + nch->nch_ReadySigTask = FindTask(NULL); + SetSignal(0, SIGF_SINGLE); + if((tmptask = psdSpawnSubTask(buf, nHubTask, nch))) + { + psdBorrowLocksWait(tmptask, 1UL<nch_ReadySignal); + if(nch->nch_Task) + { + nch->nch_ReadySigTask = NULL; + //FreeSignal(nch->nch_ReadySignal); + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, + "I'm in love with hub '%s'.", + devname); + + Forbid(); + AddTail(&nh->nh_Bindings, nch); + Permit(); + CloseLibrary(ps); + return(nch); + } + } + nch->nch_ReadySigTask = NULL; + //FreeSignal(nch->nch_ReadySignal); + psdFreeVec(nch); + } + CloseLibrary(ps); + } + return(NULL); +} +/* \\\ */ + +/* /// "usbReleaseDeviceBinding()" */ +void usbReleaseDeviceBinding(struct NepHubBase *nh, struct NepClassHub *nch) +{ + struct Library *ps; + STRPTR devname; + + KPRINTF(1, ("nepHubReleaseDeviceBinding(%08lx)\n", nch)); + if((ps = OpenLibrary("poseidon.library", 4))) + { + Forbid(); + nch->nch_ReadySignal = SIGB_SINGLE; + nch->nch_ReadySigTask = FindTask(NULL); + if(nch->nch_Task) + { + KPRINTF(1, ("Sending Break\n")); + Signal(nch->nch_Task, SIGBREAKF_CTRL_C); + } + Permit(); + while(nch->nch_Task) + { + psdBorrowLocksWait(nch->nch_Task, 1UL<nch_ReadySignal); + } + KPRINTF(1, ("Task gone\n")); + //FreeSignal(nch->nch_ReadySignal); + psdGetAttrs(PGA_DEVICE, nch->nch_Device, DA_ProductName, &devname, TAG_END); + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, + "Time to get rid of '%s'!", + devname); + Forbid(); + Remove(nch); + Permit(); + + psdFreeVec(nch); + CloseLibrary(ps); + } +} +/* \\\ */ + +/* /// "usbGetAttrsA()" */ +AROS_LH3(LONG, usbGetAttrsA, + AROS_LHA(ULONG, type, D0), + AROS_LHA(APTR, usbstruct, A0), + AROS_LHA(struct TagItem *, tags, A1), + LIBBASETYPEPTR, nh, 5, nep) +{ + AROS_LIBFUNC_INIT + + struct TagItem *ti; + LONG count = 0; + + KPRINTF(1, ("nepHubGetAttrsA(%ld, %08lx, %08lx)\n", type, usbstruct, tags)); + switch(type) + { + case UGA_CLASS: + if((ti = FindTagItem(UCCA_Priority, tags))) + { + *((IPTR *) ti->ti_Data) = 0; + count++; + } + if((ti = FindTagItem(UCCA_Description, tags))) + { + *((STRPTR *) ti->ti_Data) = "Root/external hub base class"; + count++; + } + if((ti = FindTagItem(UCCA_HasClassCfgGUI, tags))) + { + *((IPTR *) ti->ti_Data) = FALSE; + count++; + } + if((ti = FindTagItem(UCCA_HasBindingCfgGUI, tags))) + { + *((IPTR *) ti->ti_Data) = FALSE; + count++; + } + if((ti = FindTagItem(UCCA_AfterDOSRestart, tags))) + { + *((IPTR *) ti->ti_Data) = FALSE; + count++; + } + if((ti = FindTagItem(UCCA_UsingDefaultCfg, tags))) + { + *((IPTR *) ti->ti_Data) = TRUE; + count++; + } + if((ti = FindTagItem(UCCA_SupportsSuspend, tags))) + { + *((IPTR *) ti->ti_Data) = TRUE; + count++; + } + break; + + case UGA_BINDING: + if((ti = FindTagItem(UCBA_UsingDefaultCfg, tags))) + { + *((IPTR *) ti->ti_Data) = TRUE; + count++; + } + break; + } + return(count); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "usbSetAttrsA()" */ +AROS_LH3(LONG, usbSetAttrsA, + AROS_LHA(ULONG, type, D0), + AROS_LHA(APTR, usbstruct, A0), + AROS_LHA(struct TagItem *, tags, A1), + LIBBASETYPEPTR, nh, 6, nep) +{ + AROS_LIBFUNC_INIT + return(0); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "usbDoMethodA()" */ +AROS_LH2(IPTR, usbDoMethodA, + AROS_LHA(ULONG, methodid, D0), + AROS_LHA(IPTR *, methoddata, A1), + LIBBASETYPEPTR, nh, 7, nep) +{ + AROS_LIBFUNC_INIT + + struct NepClassHub *nch; + + KPRINTF(10, ("Do Method %ld\n", methodid)); + switch(methodid) + { + case UCM_AttemptDeviceBinding: + return(usbAttemptDeviceBinding(nh, (struct PsdDevice *) methoddata[0])); + + case UCM_ForceDeviceBinding: + return(usbForceDeviceBinding(nh, (struct PsdDevice *) methoddata[0])); + + case UCM_ReleaseDeviceBinding: + usbReleaseDeviceBinding(nh, (struct NepClassHub *) methoddata[0]); + return(TRUE); + + case UCM_HubPowerCyclePort: + case UCM_HubDisablePort: + { + struct PsdDevice *pd = (struct PsdDevice *) methoddata[0]; + ULONG port = (ULONG) methoddata[1]; + if(!(pd && port)) + { + KPRINTF(20, ("HubPowerCycle/DisablePort Params Null!\n")); + return(FALSE); + } + Forbid(); + nch = (struct NepClassHub *) nh->nh_Bindings.lh_Head; + while(nch->nch_Node.ln_Succ) + { + if(nch->nch_Device == pd) + { + KPRINTF(20, ("HubPowerCycle/DisablePort Dev found (port %ld)!\n", port)); + if(port <= nch->nch_NumPorts) + { + nch->nch_DisablePort |= 1UL<nch_PowerCycle |= 1UL<nch_Task) + { + Signal(nch->nch_Task, (1L<nch_TaskMsgPort->mp_SigBit)); + } + Permit(); + return(TRUE); + } + break; + } + nch = (struct NepClassHub *) nch->nch_Node.ln_Succ; + } + Permit(); + return(FALSE); + } + + case UCM_HubClassScan: + { + nch = (struct NepClassHub *) methoddata[0]; + Forbid(); + nch->nch_ClassScan = TRUE; + if(nch->nch_Task) + { + Signal(nch->nch_Task, (1L<nch_TaskMsgPort->mp_SigBit)); + } + Permit(); + return(TRUE); + } + + case UCM_AttemptSuspendDevice: + case UCM_AttemptResumeDevice: + case UCM_HubClaimAppBinding: + case UCM_HubReleaseIfBinding: + case UCM_HubReleaseDevBinding: + case UCM_HubSuspendDevice: + case UCM_HubResumeDevice: + { + struct NepHubMsg nhm; + struct Library *ps; + nch = (struct NepClassHub *) methoddata[0]; + nhm.nhm_Result = NULL; + nhm.nhm_MethodID = methodid; + nhm.nhm_Params = methoddata; + if((ps = OpenLibrary("poseidon.library", 4))) + { + if(nch->nch_Task == FindTask(NULL)) + { + // if we would send the message to ourself, we would deadlock, so handle this directly + nHandleHubMethod(nch, &nhm); + } else { + nhm.nhm_Msg.mn_ReplyPort = CreateMsgPort(); + nhm.nhm_Msg.mn_Length = sizeof(struct NepHubMsg); + Forbid(); + if(nch->nch_Task && nhm.nhm_Msg.mn_ReplyPort) + { + PutMsg(nch->nch_CtrlMsgPort, &nhm.nhm_Msg); + Permit(); + while(!GetMsg(nhm.nhm_Msg.mn_ReplyPort)) + { + psdBorrowLocksWait(nch->nch_Task, 1UL<mp_SigBit); + } + } else { + Permit(); + } + DeleteMsgPort(nhm.nhm_Msg.mn_ReplyPort); + } + CloseLibrary(ps); + } + return(nhm.nhm_Result); + } + + default: + break; + } + return(0); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +#undef ps +#define ps nch->nch_Base + +/* /// "nHubTask()" */ +AROS_UFH0(void, nHubTask) +{ + AROS_USERFUNC_INIT + + struct NepClassHub *nch; + struct PsdPipe *pp; + ULONG sigmask; + ULONG sigs; + UWORD num; + LONG ioerr; + struct UsbPortStatus uhps; + struct UsbHubStatus uhhs; + ULONG count; + struct PsdDevice *pd; + STRPTR devname; + struct NepHubMsg *nhm; + + if((nch = nAllocHub())) + { + Forbid(); + if(nch->nch_ReadySigTask) + { + Signal(nch->nch_ReadySigTask, 1L<nch_ReadySignal); + } + Permit(); + count = 0; + for(num = 1; num <= nch->nch_NumPorts; num++) + { + if(((nch->nch_Downstream)[num-1] = pd = nConfigurePort(nch, num))) + { + psdGetAttrs(PGA_DEVICE, pd, DA_ProductName, &devname, TAG_END); + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, + "Detected device '%s' at port %ld. I like it.", + devname, num); + count++; + } + } + if(count) + { + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, + "Hub has added %ld device(s). That'll be fun!", + count); + } + // do a class scan + for(num = 1; num <= nch->nch_NumPorts; num++) + { + if((pd = (nch->nch_Downstream)[num-1])) + { + psdHubClassScan(pd); + } + } + sigmask = (1L<nch_TaskMsgPort->mp_SigBit)|(1L<nch_CtrlMsgPort->mp_SigBit)|SIGBREAKF_CTRL_C; + nch->nch_Running = TRUE; + nch->nch_IOStarted = FALSE; + do + { + if(nch->nch_Running && (!nch->nch_IOStarted)) + { + psdSendPipe(nch->nch_EP1Pipe, nch->nch_PortChanges, 1); + nch->nch_IOStarted = TRUE; + } + sigs = Wait(sigmask); + while((nhm = (struct NepHubMsg *) GetMsg(nch->nch_CtrlMsgPort))) + { + nHandleHubMethod(nch, nhm); + + ReplyMsg(nhm); + } + if(nch->nch_DisablePort) + { + for(num = 1; num <= nch->nch_NumPorts; num++) + { + if((nch->nch_DisablePort) & (1L<nch_DisablePort &= ~(1L<nch_Downstream)[num-1])) + { + psdSetAttrs(PGA_DEVICE, pd, DA_IsConnected, FALSE, TAG_END); + psdGetAttrs(PGA_DEVICE, pd, DA_ProductName, &devname, TAG_END); + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, + "Zapping device '%s' at port %ld!", + devname, num); + psdFreeDevice(pd); + psdSendEvent(EHMB_REMDEVICE, pd, NULL); + (nch->nch_Downstream)[num-1] = NULL; + pd = NULL; + /* disable port */ + psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER, + USR_CLEAR_FEATURE, UFS_PORT_ENABLE, (ULONG) num); + ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0); + if(ioerr) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "CLEAR_PORT_ENABLE failed: %s (%ld)", + psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + KPRINTF(1, ("CLEAR_PORT_ENABLE failed %ld.\n", ioerr)); + } + } + if(nch->nch_PowerCycle & (1<nch_PowerCycle &= ~(1L<nch_Downstream)[num-1] = pd = nConfigurePort(nch, num))) + { + psdGetAttrs(PGA_DEVICE, pd, DA_ProductName, &devname, TAG_END); + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, + "Device '%s' returned. Happy happy joy joy.", + devname); + psdHubClassScan(pd); + } + } + } + } + } + if(nch->nch_ClassScan) + { + nch->nch_ClassScan = FALSE; + for(num = 1; num <= nch->nch_NumPorts; num++) + { + if((pd = (nch->nch_Downstream)[num-1])) + { + psdGetAttrs(PGA_DEVICE, pd, DA_ProductName, &devname, TAG_END); + psdHubClassScan(pd); + } + } + } + while((pp = (struct PsdPipe *) GetMsg(nch->nch_TaskMsgPort))) + { + if(pp == nch->nch_EP1Pipe) + { + nch->nch_IOStarted = FALSE; + ioerr = psdGetPipeError(nch->nch_EP1Pipe); + if(ioerr == UHIOERR_TIMEOUT) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "Hub involuntarily gone! Disconnecting..."); + psdSetAttrs(PGA_DEVICE, nch->nch_Device, + DA_IsConnected, FALSE, + TAG_END); + nch->nch_PortChanges[0] = 0xff; + sigs |= SIGBREAKF_CTRL_C; + } + if((!ioerr) || (ioerr == UHIOERR_TIMEOUT)) + { + KPRINTF(2, ("Port changed at %08lx, Numports=%ld!\n", nch->nch_PortChanges[0], nch->nch_NumPorts)); + + if(nch->nch_PortChanges[0] & 1) + { + psdPipeSetup(nch->nch_EP0Pipe, URTF_IN|URTF_CLASS|URTF_DEVICE, + USR_GET_STATUS, 0, 0); + ioerr = psdDoPipe(nch->nch_EP0Pipe, &uhhs, sizeof(struct UsbHubStatus)); + uhhs.wHubStatus = AROS_WORD2LE(uhhs.wHubStatus); + uhhs.wHubChange = AROS_WORD2LE(uhhs.wHubChange); + if(!ioerr) + { + if(uhhs.wHubStatus & UHSF_OVER_CURRENT) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "Hub over-current situation detected! Unpowering ALL ports!"); + for(num = 1; num <= nch->nch_NumPorts; num++) + { + psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER, + USR_CLEAR_FEATURE, UFS_PORT_POWER, (ULONG) num); + ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0); + if(ioerr) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "PORT_POWER for port %ld failed: %s (%ld)", + num, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + KPRINTF(1, ("PORT_POWER for port %ld failed %ld!\n", num, ioerr)); + } + + psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER, + USR_CLEAR_FEATURE, UFS_C_PORT_OVER_CURRENT, (ULONG) num); + psdDoPipe(nch->nch_EP0Pipe, NULL, 0); + } + psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_DEVICE, + USR_CLEAR_FEATURE, UFS_C_HUB_OVER_CURRENT, 0); + psdDoPipe(nch->nch_EP0Pipe, NULL, 0); + } + if(uhhs.wHubChange & UHSF_LOCAL_POWER_LOST) + { + struct PsdConfig *pc = NULL; + struct PsdHardware *phw = NULL; + psdGetAttrs(PGA_DEVICE, nch->nch_Device, + DA_Config, &pc, + DA_Hardware, &phw, + TAG_END); + if(uhhs.wHubStatus & UHSF_LOCAL_POWER_LOST) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "Hub is no longer self-powered! Low power conditions may occur."); + + if(pc && phw) + { + psdSetAttrs(PGA_CONFIG, pc, CA_SelfPowered, FALSE, TAG_END); + psdCalculatePower(phw); + } + } else { + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, + "Hub is now self-powered! Yay!"); + if(pc && phw) + { + psdSetAttrs(PGA_CONFIG, pc, CA_SelfPowered, TRUE, TAG_END); + psdCalculatePower(phw); + } + } + psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_DEVICE, + USR_CLEAR_FEATURE, UFS_C_HUB_LOCAL_POWER, 0); + psdDoPipe(nch->nch_EP0Pipe, NULL, 0); + } + } + } + + for(num = 1; num <= nch->nch_NumPorts; num++) + { + if(nch->nch_PortChanges[0] & (1L<nch_EP0Pipe, URTF_IN|URTF_CLASS|URTF_OTHER, + USR_GET_STATUS, 0, (ULONG) num); + ioerr = psdDoPipe(nch->nch_EP0Pipe, &uhps, sizeof(struct UsbPortStatus)); + uhps.wPortStatus = AROS_WORD2LE(uhps.wPortStatus); + uhps.wPortChange = AROS_WORD2LE(uhps.wPortChange); + if(ioerr == UHIOERR_TIMEOUT) + { + uhps.wPortStatus = 0; + uhps.wPortChange = 0xffff; + ioerr = 0; + } else { + nClearPortStatus(nch, num); + } + if(!ioerr) + { + pd = (nch->nch_Downstream)[num-1]; + if(uhps.wPortStatus & UPSF_PORT_OVER_CURRENT) + { + if(pd) + { + psdGetAttrs(PGA_DEVICE, pd, DA_ProductName, &devname, TAG_END); + } else { + devname = "a ghost"; + } + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "Over-current situation detected with %s at port %ld! Unpowering port!", + devname, num); + psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER, + USR_CLEAR_FEATURE, UFS_PORT_POWER, (ULONG) num); + ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0); + if(ioerr) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "PORT_POWER for port %ld failed: %s (%ld)", + num, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + KPRINTF(1, ("PORT_POWER for port %ld failed %ld!\n", num, ioerr)); + } + + psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER, + USR_CLEAR_FEATURE, UFS_C_PORT_OVER_CURRENT, (ULONG) num); + psdDoPipe(nch->nch_EP0Pipe, NULL, 0); + } + if(uhps.wPortChange & UPSF_PORT_SUSPEND) + { + if((!(uhps.wPortStatus & UPSF_PORT_SUSPEND)) && pd) + { + IPTR oldsusp = 0; + psdGetAttrs(PGA_DEVICE, pd, DA_IsSuspended, &oldsusp, TAG_END); + psdSetAttrs(PGA_DEVICE, pd, DA_IsSuspended, FALSE, TAG_END); + psdGetAttrs(PGA_DEVICE, pd, DA_ProductName, &devname, TAG_END); + if(oldsusp) + { + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, + "Device '%s' at port %ld resumed from remote!", + devname, num); + psdSendEvent(EHMB_DEVRESUMED, pd, NULL); + psdResumeBindings(pd); + } + } + else if((uhps.wPortStatus & UPSF_PORT_SUSPEND) && pd) + { + psdSetAttrs(PGA_DEVICE, pd, DA_IsSuspended, FALSE, TAG_END); + psdGetAttrs(PGA_DEVICE, pd, DA_ProductName, &devname, TAG_END); + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, + "Device '%s' at port %ld suspended!", + devname, num); + } else { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "Bogus suspend/resume change on port %ld.", + num); + } + } + if(uhps.wPortChange & UPSF_PORT_CONNECTION) + { + /* Remove device */ + if((!(uhps.wPortStatus & UPSF_PORT_CONNECTION)) && pd) + { + psdSetAttrs(PGA_DEVICE, pd, DA_IsConnected, FALSE, TAG_END); + psdGetAttrs(PGA_DEVICE, pd, DA_ProductName, &devname, TAG_END); + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, + "Device '%s' at port %ld is gone!", + devname, num); + psdFreeDevice(pd); + psdSendEvent(EHMB_REMDEVICE, pd, NULL); + (nch->nch_Downstream)[num-1] = NULL; + pd = NULL; + } + /* add new device */ + if((uhps.wPortStatus & UPSF_PORT_CONNECTION) && (!pd)) + { + /* Wait for device to settle */ + psdDelayMS(100); + if(((nch->nch_Downstream)[num-1] = pd = nConfigurePort(nch, num))) + { + psdGetAttrs(PGA_DEVICE, pd, DA_ProductName, &devname, TAG_END); + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, + "New device '%s' at port %ld. Very nice.", + devname, num); + psdClassScan(); + } + } + } + } + } + } + /* Bail out on time out. */ + if(nch->nch_PortChanges[0] == 0xff) + { + break; + } + psdDelayMS(50); + } else { + if(ioerr != IOERR_ABORTED) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "Something weird happened to the status packet, it failed: %s (%ld)", + psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + psdDelayMS(200); + } + } + break; + } else { + KPRINTF(20, ("Bogus message received!\n")); + } + } + } while(!(sigs & SIGBREAKF_CTRL_C)); + KPRINTF(20, ("Going down the river!\n")); + if(nch->nch_IOStarted) + { + psdAbortPipe(nch->nch_EP1Pipe); + psdWaitPipe(nch->nch_EP1Pipe); + } + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, "Oh no! I've been shot! Arrggghh..."); + nFreeHub(nch); + } + AROS_USERFUNC_EXIT +} +/* \\\ */ + +/* /// "nAllocHub()" */ +struct NepClassHub * nAllocHub(void) +{ + struct UsbHubDesc *uhd; + struct Task *thistask; + struct NepClassHub *nch; + struct UsbHubStatus uhhs; + LONG ioerr; + ULONG len; + UWORD num; + UBYTE buf; + IPTR ishighspeed = 0; + IPTR prodid; + IPTR vendid; + BOOL overcurrent = FALSE; + + thistask = FindTask(NULL); + nch = thistask->tc_UserData; + do + { + if(!(nch->nch_Base = OpenLibrary("poseidon.library", 4))) + { + Alert(AG_OpenLib); + break; + } + + psdGetAttrs(PGA_DEVICE, nch->nch_Device, + DA_Hardware, &nch->nch_Hardware, + DA_IsHighspeed, &ishighspeed, + DA_ProductID, &prodid, + DA_VendorID, &vendid, + TAG_END); + nch->nch_IsUSB20 = ishighspeed; + // try to select multi TT interface first + nch->nch_Interface = psdFindInterface(nch->nch_Device, NULL, + IFA_Class, HUB_CLASSCODE, + IFA_Protocol, 2, + IFA_AlternateNum, 0xffffffff, + TAG_END); + if(!nch->nch_Interface) + { + // any will do + nch->nch_Interface = psdFindInterface(nch->nch_Device, NULL, + IFA_Class, HUB_CLASSCODE, + TAG_END); + } + if((vendid == 0x05E3) && ishighspeed) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, "Genesys Logic hubs are broken and will cause failures with USB 2.0 devices."); + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, "If you encounter problems, try the device without the hub."); + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, "If this solves the problem, you need to buy a different USB 2.0 hub."); + } + + if(!nch->nch_Interface) + { + KPRINTF(1, ("Ooops!?! No interfaces defined?\n")); + break; + } + nch->nch_EP1 = psdFindEndpoint(nch->nch_Interface, NULL, + EA_IsIn, TRUE, + EA_TransferType, USEAF_INTERRUPT, + TAG_END); + + if(!nch->nch_EP1) + { + psdAddErrorMsg(RETURN_FAIL, (STRPTR) libname, "Ooops!?! No endpoints defined?"); + KPRINTF(1, ("Ooops!?! No Endpoints defined?\n")); + break; + } + if((nch->nch_CtrlMsgPort = CreateMsgPort())) + { + if((nch->nch_TaskMsgPort = CreateMsgPort())) + { + if((nch->nch_EP0Pipe = psdAllocPipe(nch->nch_Device, nch->nch_TaskMsgPort, NULL))) + { + psdSetAttrs(PGA_PIPE, nch->nch_EP0Pipe, + PPA_NakTimeout, TRUE, + PPA_NakTimeoutTime, 1000, + TAG_END); + psdSetAltInterface(nch->nch_EP0Pipe, nch->nch_Interface); + if((nch->nch_EP1Pipe = psdAllocPipe(nch->nch_Device, nch->nch_TaskMsgPort, nch->nch_EP1))) + { + psdPipeSetup(nch->nch_EP0Pipe, URTF_IN|URTF_CLASS|URTF_DEVICE, + USR_GET_DESCRIPTOR, UDT_HUB<<8, 0); + ioerr = psdDoPipe(nch->nch_EP0Pipe, &buf, 1); + if((!ioerr) || (ioerr == UHIOERR_OVERFLOW)) + { + len = buf; + if((uhd = psdAllocVec(len))) + { + ioerr = psdDoPipe(nch->nch_EP0Pipe, uhd, len); + if(!ioerr) + { + nch->nch_NumPorts = uhd->bNbrPorts; + nch->nch_HubAttr = AROS_WORD2LE(uhd->wHubCharacteristics); + nch->nch_PwrGoodTime = uhd->bPwrOn2PwrGood<<1; + nch->nch_HubCurrent = uhd->bHubContrCurrent; + nch->nch_Removable = 0; + if(nch->nch_HubAttr & UHCM_THINK_TIME) + { + psdSetAttrs(PGA_DEVICE, nch->nch_Device, + DA_HubThinkTime, (nch->nch_HubAttr & UHCM_THINK_TIME)>>UHCS_THINK_TIME, + TAG_END); + } + + for(num = 0; num < ((nch->nch_NumPorts + 7)>>3); num++) + { + nch->nch_Removable |= ((&uhd->DeviceRemovable)[num])<<(num<<3); + } + KPRINTF(1, ("Hub with %ld ports\n" + " PowerGood after %ld ms\n" + " Power consumption %ld mA\n", + nch->nch_NumPorts, + nch->nch_PwrGoodTime, nch->nch_HubCurrent)); + psdFreeVec(uhd); + + psdPipeSetup(nch->nch_EP0Pipe, URTF_IN|URTF_CLASS|URTF_DEVICE, + USR_GET_STATUS, 0, 0); + ioerr = psdDoPipe(nch->nch_EP0Pipe, &uhhs, sizeof(struct UsbHubStatus)); + uhhs.wHubStatus = AROS_WORD2LE(uhhs.wHubStatus); + uhhs.wHubChange = AROS_WORD2LE(uhhs.wHubChange); + if(!ioerr) + { + struct PsdConfig *pc = NULL; + struct PsdHardware *phw = NULL; + if(uhhs.wHubStatus & UHSF_OVER_CURRENT) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "Hub over-current situation detected! Resolve this first!"); + //overcurrent = TRUE; + } + + psdGetAttrs(PGA_DEVICE, nch->nch_Device, + DA_Config, &pc, + DA_Hardware, &phw, + TAG_END); + if(uhhs.wHubStatus & UHSF_LOCAL_POWER_LOST) + { + if(pc && phw) + { + psdSetAttrs(PGA_CONFIG, pc, CA_SelfPowered, FALSE, TAG_END); + psdCalculatePower(phw); + } + } else { + if(pc && phw) + { + psdSetAttrs(PGA_CONFIG, pc, CA_SelfPowered, TRUE, TAG_END); + psdCalculatePower(phw); + } + } + } + if(!overcurrent) + { + if((nch->nch_Downstream = psdAllocVec((ULONG) nch->nch_NumPorts*sizeof(APTR)))) + { + /*for(num = 1; num <= nch->nch_NumPorts; num++) + { + nClearPortStatus(nch, num); + } + psdDelayMS(20);*/ + for(num = 1; num <= nch->nch_NumPorts; num++) + { + psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER, + USR_SET_FEATURE, UFS_PORT_POWER, (ULONG) num); + ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0); + if(ioerr) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "PORT_POWER for port %ld failed: %s (%ld)", + num, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + KPRINTF(1, ("PORT_POWER for port %ld failed %ld!\n", num, ioerr)); + } + } + psdDelayMS((ULONG) nch->nch_PwrGoodTime + 15); + + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, + "Hub with %ld ports successfully configured.", + nch->nch_NumPorts); + + KPRINTF(10, ("%s ready!\n", thistask->tc_Node.ln_Name)); + nch->nch_Task = thistask; + return(nch); + } else { + KPRINTF(1, ("No downstream port array memory!\n")); + } + } + } else { + psdFreeVec(uhd); + psdAddErrorMsg(RETURN_FAIL, (STRPTR) libname, + "GET_HUB_DESCRIPTOR (%ld) failed: %s (%ld)", + len, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + KPRINTF(1, ("GET_HUB_DESCRIPTOR (%ld) failed %ld!\n", len, ioerr)); + } + } else { + KPRINTF(1, ("No Hub Descriptor memory!\n")); + } + } else { + psdAddErrorMsg(RETURN_FAIL, (STRPTR) libname, + "GET_HUB_DESCRIPTOR (%ld) failed: %s (%ld)", + 1, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + KPRINTF(1, ("GET_HUB_DESCRIPTOR (1) failed %ld!\n", ioerr)); + } + psdFreePipe(nch->nch_EP1Pipe); + } + psdFreePipe(nch->nch_EP0Pipe); + } + DeleteMsgPort(nch->nch_TaskMsgPort); + } + DeleteMsgPort(nch->nch_CtrlMsgPort); + } + } while(FALSE); + CloseLibrary(nch->nch_Base); + Forbid(); + nch->nch_Task = NULL; + if(nch->nch_ReadySigTask) + { + Signal(nch->nch_ReadySigTask, 1L<nch_ReadySignal); + } + return(NULL); +} +/* \\\ */ + +/* /// "nFreeHub()" */ +void nFreeHub(struct NepClassHub *nch) +{ + UWORD num; + LONG ioerr; + struct PsdDevice *pd; + STRPTR devname; + IPTR isconnected; + struct Message *msg; + + KPRINTF(1, ("FreeHub\n")); + psdGetAttrs(PGA_DEVICE, nch->nch_Device, DA_IsConnected, &isconnected, TAG_END); + for(num = 1; num <= nch->nch_NumPorts; num++) + { + KPRINTF(1, ("Iterating Port %ld\n", num)); + /* Remove downstream device */ + pd = (nch->nch_Downstream)[num-1]; + if(pd) + { + if(!isconnected) + { + psdSetAttrs(PGA_DEVICE, pd, DA_IsConnected, FALSE, TAG_END); + } + psdGetAttrs(PGA_DEVICE, pd, DA_ProductName, &devname, TAG_END); + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, + "My death killed device '%s' at port %ld!", + devname, num); + KPRINTF(1, ("FreeDevice %08lx\n", pd)); + psdFreeDevice(pd); + psdSendEvent(EHMB_REMDEVICE, pd, NULL); + (nch->nch_Downstream)[num-1] = NULL; + } + /* There's no sense trying to send out commands if the hub is already gone! */ + if(isconnected) + { + /* power down for port */ + psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER, + USR_CLEAR_FEATURE, UFS_PORT_POWER, (ULONG) num); + ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0); + if(ioerr) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "PORT_POWER for port %ld failed: %s (%ld)", + num, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + KPRINTF(1, ("PORT_POWER for port %ld failed %ld!\n", num, ioerr)); + } + } + } + KPRINTF(1, ("FreePipes\n")); + psdFreePipe(nch->nch_EP1Pipe); + psdFreePipe(nch->nch_EP0Pipe); + psdFreeVec(nch->nch_Downstream); + KPRINTF(1, ("Entering Forbid\n")); + Forbid(); + // clear queue + while((msg = GetMsg(nch->nch_CtrlMsgPort))) + { + ReplyMsg(msg); + } + DeleteMsgPort(nch->nch_TaskMsgPort); + DeleteMsgPort(nch->nch_CtrlMsgPort); + CloseLibrary(nch->nch_Base); + nch->nch_Task = NULL; + if(nch->nch_ReadySigTask) + { + Signal(nch->nch_ReadySigTask, 1L<nch_ReadySignal); + } + KPRINTF(1, ("Really gone now!\n")); +} +/* \\\ */ + +/* *** HUB Class *** */ + +/* /// "nClearPortStatus()" */ +LONG nClearPortStatus(struct NepClassHub *nch, UWORD port) +{ + LONG ioerr; + psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER, + USR_CLEAR_FEATURE, UFS_C_PORT_CONNECTION, (ULONG) port); + if((ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0))) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "CLEAR_PORT_FEATURE (C_PORT_CONNECTION) failed: %s (%ld)", + psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + KPRINTF(10, ("Some error occurred clearing hub status bits!\n")); + return(ioerr); + } + + psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER, + USR_CLEAR_FEATURE, UFS_C_PORT_ENABLE, (ULONG) port); + if((ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0))) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "CLEAR_PORT_FEATURE (C_PORT_ENABLE) failed: %s (%ld)", + psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + KPRINTF(10, ("Some error occurred clearing hub status bits!\n")); + return(ioerr); + } + + psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER, + USR_CLEAR_FEATURE, UFS_C_PORT_SUSPEND, (ULONG) port); + if((ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0))) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "CLEAR_PORT_FEATURE (C_PORT_SUSPEND) failed: %s (%ld)", + psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + KPRINTF(10, ("Some error occurred clearing hub status bits!\n")); + return(ioerr); + } + + psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER, + USR_CLEAR_FEATURE, UFS_C_PORT_OVER_CURRENT, (ULONG) port); + if((ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0))) + { + /*psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "CLEAR_PORT_FEATURE (C_OVER_CURRENT) failed: %s (%ld)", + psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);*/ + KPRINTF(10, ("Some error occurred clearing hub status bits!\n")); + } + + psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER, + USR_CLEAR_FEATURE, UFS_C_PORT_RESET, (ULONG) port); + if((ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0))) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "CLEAR_PORT_FEATURE (C_PORT_RESET) failed: %s (%ld)", + psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + KPRINTF(10, ("Some error occurred clearing hub status bits!\n")); + return(ioerr); + } + return(0); +} +/* \\\ */ + +/* /// "nConfigurePort()" */ +struct PsdDevice * nConfigurePort(struct NepClassHub *nch, UWORD port) +{ + LONG ioerr; + LONG delayretries; + LONG resetretries; + ULONG delaytime = 10; + struct UsbPortStatus uhps; + struct PsdDevice *pd; + struct PsdPipe *pp; + BOOL washighspeed = FALSE; + BOOL islowspeed = FALSE; + + psdPipeSetup(nch->nch_EP0Pipe, URTF_IN|URTF_CLASS|URTF_OTHER, + USR_GET_STATUS, UFS_PORT_CONNECTION, (ULONG) port); + ioerr = psdDoPipe(nch->nch_EP0Pipe, &uhps, sizeof(struct UsbPortStatus)); + uhps.wPortStatus = AROS_WORD2LE(uhps.wPortStatus); + uhps.wPortChange = AROS_WORD2LE(uhps.wPortChange); + if(!ioerr) + { + if(uhps.wPortStatus & UPSF_PORT_ENABLE) + { + psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER, + USR_CLEAR_FEATURE, UFS_PORT_ENABLE, (ULONG) port); + ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0); + if(ioerr) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "CLEAR_PORT_ENABLE failed: %s (%ld)", + psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + KPRINTF(1, ("CLEAR_PORT_ENABLE failed %ld.\n", ioerr)); + } else { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "Disabling port %ld.", port); + } + } + if(uhps.wPortStatus & UPSF_PORT_CONNECTION) + { + KPRINTF(1, ("There's something at port %ld!\n", port)); + Forbid(); + if((pd = psdAllocDevice(nch->nch_Hardware))) + { + psdLockWriteDevice(pd); + Permit(); + /* Hub reference */ + psdSetAttrs(PGA_DEVICE, pd, + DA_HubDevice, (ULONG) nch->nch_Device, + DA_IsConnected, TRUE, + DA_AtHubPortNumber, port, + TAG_END); + if(uhps.wPortStatus & UPSF_PORT_LOW_SPEED) + { + psdSetAttrs(PGA_DEVICE, pd, DA_IsLowspeed, TRUE, TAG_END); + KPRINTF(1, (" It's a lowspeed device!\n")); + islowspeed = TRUE; + } + ObtainSemaphore(&nch->nch_HubBase->nh_Adr0Sema); + for(resetretries = 0; resetretries < 3; resetretries++) + { + psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER, + USR_SET_FEATURE, UFS_PORT_RESET, (ULONG) port); + ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0); + if(ioerr) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "PORT_RESET for port %ld failed: %s (%ld)", + port, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + KPRINTF(1, ("PORT_RESET failed %ld.\n", ioerr)); + break; + } + for(delayretries = 0; delayretries < 500; delayretries += delaytime) + { + psdDelayMS(delaytime); + psdPipeSetup(nch->nch_EP0Pipe, URTF_IN|URTF_CLASS|URTF_OTHER, + USR_GET_STATUS, UFS_PORT_CONNECTION, (ULONG) port); + ioerr = psdDoPipe(nch->nch_EP0Pipe, &uhps, sizeof(struct UsbPortStatus)); + uhps.wPortStatus = AROS_WORD2LE(uhps.wPortStatus); + uhps.wPortChange = AROS_WORD2LE(uhps.wPortChange); + if(ioerr) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "GET_PORT_CONNECTION for port %ld failed: %s (%ld)", + port, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + KPRINTF(1, ("GET_PORT_CONNECTION failed %ld.\n", ioerr)); + break; + } + if(!(uhps.wPortStatus & UPSF_PORT_CONNECTION)) + { + break; + } + if((uhps.wPortStatus & + (UPSF_PORT_RESET|UPSF_PORT_CONNECTION|UPSF_PORT_ENABLE|UPSF_PORT_POWER|UPSF_PORT_OVER_CURRENT)) == + (UPSF_PORT_CONNECTION|UPSF_PORT_ENABLE|UPSF_PORT_POWER)) + { + if((uhps.wPortStatus & UPSF_PORT_HIGH_SPEED) || washighspeed) + { + psdSetAttrs(PGA_DEVICE, pd, DA_IsHighspeed, TRUE, TAG_END); + washighspeed = TRUE; + KPRINTF(1, (" It's a highspeed device!\n")); + } else { + IPTR needssplit = 0; + // inherit needs split from hub + psdGetAttrs(PGA_DEVICE, nch->nch_Device, DA_NeedsSplitTrans, &needssplit, TAG_END); + if(nch->nch_IsUSB20) /* this is a low/full speed device connected to a 2.0 hub! */ + { + needssplit = TRUE; + } + psdSetAttrs(PGA_DEVICE, pd, DA_NeedsSplitTrans, needssplit, TAG_END); + } + nClearPortStatus(nch, port); + psdDelayMS((ULONG) (islowspeed ? 1000 : 100)); + if((pp = psdAllocPipe(pd, nch->nch_TaskMsgPort, NULL))) + { + if(psdEnumerateDevice(pp)) + { + KPRINTF(1, (" Device successfully added!\n")); + psdFreePipe(pp); + psdUnlockDevice(pd); + psdSendEvent(EHMB_ADDDEVICE, pd, NULL); + ReleaseSemaphore(&nch->nch_HubBase->nh_Adr0Sema); + return(pd); + } + psdFreePipe(pp); + } + break; + } else { + if(!(uhps.wPortStatus & UPSF_PORT_RESET)) + { + psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname, + "Wrong port status %04lx for port %ld!", + uhps.wPortStatus, port); + KPRINTF(1, ("Wrong port status %04lx for port %ld.\n", uhps.wPortStatus, port)); + } + } + if(delayretries > 20) + { + delaytime = 300; + } + } + if((uhps.wPortStatus & + (UPSF_PORT_RESET|UPSF_PORT_CONNECTION|UPSF_PORT_ENABLE|UPSF_PORT_POWER|UPSF_PORT_OVER_CURRENT|UPSF_PORT_LOW_SPEED)) == + (UPSF_PORT_CONNECTION|UPSF_PORT_POWER|UPSF_PORT_LOW_SPEED)) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "Strange port response, power-cycling port %ld", + port); + psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER, + USR_CLEAR_FEATURE, UFS_PORT_POWER, (ULONG) port); + ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0); + if(ioerr) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "PORT_POWER for port %ld failed: %s (%ld)", + port, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + KPRINTF(1, ("PORT_POWER for port %ld failed %ld!\n", port, ioerr)); + } + psdDelayMS(50); + psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER, + USR_SET_FEATURE, UFS_PORT_POWER, (ULONG) port); + ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0); + if(ioerr) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "PORT_POWER for port %ld failed: %s (%ld)", + port, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + KPRINTF(1, ("PORT_POWER for port %ld failed %ld!\n", port, ioerr)); + } + psdDelayMS((ULONG) nch->nch_PwrGoodTime + 15); + + } + delaytime = 200; + } + psdUnlockDevice(pd); + psdFreeDevice(pd); + /* Disable port! It's too dangerous having a connection with + crazy devices on the bus open */ + psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER, + USR_CLEAR_FEATURE, UFS_PORT_ENABLE, (ULONG) port); + ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0); + if(ioerr) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "CLEAR_PORT_ENABLE failed: %s (%ld)", + psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + KPRINTF(1, ("CLEAR_PORT_ENABLE failed %ld.\n", ioerr)); + } + ReleaseSemaphore(&nch->nch_HubBase->nh_Adr0Sema); + nClearPortStatus(nch, port); + } else { + Permit(); + KPRINTF(1, ("AllocDevice() failed.\n")); + } + } + } else { + psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname, + "GET_PORT_CONNECTION failed: %s (%ld)", + psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + KPRINTF(1, ("GET_PORT_CONNECTION failed %ld.\n", ioerr)); + } + return(NULL); +} +/* \\\ */ + +/* /// "nHandleHubMethod()" */ +void nHandleHubMethod(struct NepClassHub *nch, struct NepHubMsg *nhm) +{ + ULONG num; + struct PsdDevice *pd; + nhm->nhm_Result = 0; + switch(nhm->nhm_MethodID) + { + case UCM_HubClaimAppBinding: + nhm->nhm_Result = (ULONG) psdHubClaimAppBindingA((struct TagItem *) nhm->nhm_Params[1]); + break; + + case UCM_HubReleaseIfBinding: + { + psdHubReleaseIfBinding((struct PsdInterface *) nhm->nhm_Params[1]); + break; + } + case UCM_HubReleaseDevBinding: + psdHubReleaseDevBinding((struct PsdDevice *) nhm->nhm_Params[1]); + break; + + case UCM_AttemptSuspendDevice: + { + BOOL res = TRUE; + for(num = 1; num <= nch->nch_NumPorts; num++) + { + if((pd = (nch->nch_Downstream)[num-1])) + { + res &= psdSuspendDevice(pd); + } + } + if(res) + { + // suspending of all downstream devices successful, so stop all activity, too. + psdAbortPipe(nch->nch_EP1Pipe); + nch->nch_Running = FALSE; + nhm->nhm_Result = TRUE; + } + break; + } + + case UCM_AttemptResumeDevice: + if(!nch->nch_Running) + { + psdWaitPipe(nch->nch_EP1Pipe); + psdSendPipe(nch->nch_EP1Pipe, nch->nch_PortChanges, 1); + nch->nch_Running = TRUE; + } + nhm->nhm_Result = TRUE; + for(num = 1; num <= nch->nch_NumPorts; num++) + { + if((pd = (nch->nch_Downstream)[num-1])) + { + psdResumeDevice(pd); + } + } + break; + + case UCM_HubSuspendDevice: + nhm->nhm_Result = nHubSuspendDevice(nch, (struct PsdDevice *) nhm->nhm_Params[1]); + break; + + case UCM_HubResumeDevice: + nhm->nhm_Result = nHubResumeDevice(nch, (struct PsdDevice *) nhm->nhm_Params[1]); + break; + + } +} +/* \\\ */ + +/* /// "nHubSuspendDevice()" */ +BOOL nHubSuspendDevice(struct NepClassHub *nch, struct PsdDevice *pd) +{ + APTR binding = NULL; + APTR puc = NULL; + ULONG num; + BOOL result = FALSE; + LONG ioerr; + + psdGetAttrs(PGA_DEVICE, pd, + DA_Binding, &binding, + DA_BindingClass, &puc, + TAG_END); + + for(num = 1; num <= nch->nch_NumPorts; num++) + { + if(pd == (nch->nch_Downstream)[num-1]) + { + psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER, + USR_SET_FEATURE, UFS_PORT_SUSPEND, num); + + ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0); + if(ioerr) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "SET_PORT_SUSPEND failed: %s (%ld)", + psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + KPRINTF(1, ("SET_PORT_SUSPEND failed %ld.\n", ioerr)); + } else { + result = TRUE; + psdSetAttrs(PGA_DEVICE, pd, DA_IsSuspended, TRUE, TAG_END); + psdSendEvent(EHMB_DEVSUSPENDED, pd, NULL); + } + } + } + return result; +} +/* \\\ */ + +/* /// "nHubResumeDevice()" */ +BOOL nHubResumeDevice(struct NepClassHub *nch, struct PsdDevice *pd) +{ + ULONG num; + BOOL result = FALSE; + LONG ioerr; + + for(num = 1; num <= nch->nch_NumPorts; num++) + { + if(pd == (nch->nch_Downstream)[num-1]) + { + psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER, + USR_CLEAR_FEATURE, UFS_PORT_SUSPEND, (ULONG) num); + + ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0); + if(ioerr) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "CLEAR_PORT_SUSPEND failed: %s (%ld)", + psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + KPRINTF(1, ("CLEAR_PORT_SUSPEND failed %ld.\n", ioerr)); + } else { + psdSetAttrs(PGA_DEVICE, pd, DA_IsSuspended, FALSE, TAG_END); + psdSendEvent(EHMB_DEVRESUMED, pd, NULL); + result = TRUE; + psdDelayMS(30); + } + } + } + return result; +} +/* \\\ */ diff --git a/rom/usb/classes/hub/hub.class.h b/rom/usb/classes/hub/hub.class.h new file mode 100644 index 000000000..3a207b2e4 --- /dev/null +++ b/rom/usb/classes/hub/hub.class.h @@ -0,0 +1,33 @@ +#ifndef HUB_CLASS_H +#define HUB_CLASS_H + +/* + *---------------------------------------------------------------------------- + * Includes for hub class + *---------------------------------------------------------------------------- + * By Chris Hodges + */ + +#include "common.h" + +#include + +#include "hub.h" + +/* Protos */ + +struct NepClassHub * usbAttemptDeviceBinding(struct NepHubBase *nh, struct PsdDevice *pd); +struct NepClassHub * usbForceDeviceBinding(struct NepHubBase * nh, struct PsdDevice *pd); +void usbReleaseDeviceBinding(struct NepHubBase *nh, struct NepClassHub *nch); + +struct NepClassHub * nAllocHub(void); +void nFreeHub(struct NepClassHub *nch); +struct PsdDevice * nConfigurePort(struct NepClassHub *nch, UWORD port); +LONG nClearPortStatus(struct NepClassHub *nch, UWORD port); +BOOL nHubSuspendDevice(struct NepClassHub *nch, struct PsdDevice *pd); +BOOL nHubResumeDevice(struct NepClassHub *nch, struct PsdDevice *pd); +void nHandleHubMethod(struct NepClassHub *nch, struct NepHubMsg *nhm); + +AROS_UFP0(void, nHubTask); + +#endif /* HUB_CLASS_H */ diff --git a/rom/usb/classes/hub/hub.conf b/rom/usb/classes/hub/hub.conf new file mode 100644 index 000000000..2075e8204 --- /dev/null +++ b/rom/usb/classes/hub/hub.conf @@ -0,0 +1,19 @@ +##begin config +version 4.3 +libbase nh +libbasetype struct NepHubBase +libbasetypeextern struct Library +residentpri 47 +basename nep +##end config + +##begin cdef +#include +#include "hub.h" +##end cdef + +##begin functionlist +LONG usbGetAttrsA(ULONG type, APTR usbstruct, struct TagItem *taglist) (D0,A0,A1) +LONG usbSetAttrsA(ULONG type, APTR usbstruct, struct TagItem *taglist) (D0,A0,A1) +IPTR usbDoMethodA(ULONG methodid, IPTR *methoddata) (D0,A1) +##end functionlist diff --git a/rom/usb/classes/hub/hub.h b/rom/usb/classes/hub/hub.h new file mode 100644 index 000000000..e2c029c0a --- /dev/null +++ b/rom/usb/classes/hub/hub.h @@ -0,0 +1,59 @@ +#ifndef HUB_H +#define HUB_H + +#include +#include +#include + +struct NepHubBase +{ + struct Library nh_Library; /* standard */ + UWORD nh_Flags; /* various flags */ + + struct Library *nh_UtilityBase; /* utility base */ + struct List nh_Bindings; + struct SignalSemaphore nh_Adr0Sema; /* Address 0 Semaphore */ +}; + +struct NepClassHub +{ + struct Node nch_Node; /* Node linkage */ + struct NepHubBase *nch_HubBase; /* hub.class base */ + struct Library *nch_SysBase; /* cached execbase */ + struct Library *nch_Base; /* Poseidon base */ + struct PsdHardware *nch_Hardware; /* Up linkage */ + struct PsdDevice *nch_Device; /* Up linkage */ + struct PsdConfig *nch_Config; /* Up linkage */ + struct PsdInterface *nch_Interface; /* Up linkage */ + struct PsdEndpoint *nch_EP1; /* Endpoint 1 */ + struct PsdPipe *nch_EP0Pipe; /* Endpoint 0 pipe */ + struct PsdPipe *nch_EP1Pipe; /* Endpoint 1 pipe */ + BOOL nch_IOStarted; /* IO Running */ + BOOL nch_Running; /* Not suspended */ + struct Task *nch_ReadySigTask; /* Task to send ready signal to */ + LONG nch_ReadySignal; /* Signal to send when ready */ + struct Task *nch_Task; /* Subtask */ + struct MsgPort *nch_TaskMsgPort; /* Message Port of Subtask */ + struct MsgPort *nch_CtrlMsgPort; /* Message Port for control messages */ + UWORD nch_NumPorts; /* Number of ports at this hub */ + BOOL nch_IsUSB20; /* Is this a highspeed hub? */ + UWORD nch_HubAttr; /* Hub Characteristics (see UHCF flags) */ + UWORD nch_PwrGoodTime; /* Time in ms for power to become good */ + UWORD nch_HubCurrent; /* Max hub current in mA */ + ULONG nch_Removable; /* Bitmask for device removable */ + ULONG nch_PowerCycle; /* Bitmask of devices to powercycle */ + ULONG nch_DisablePort; /* Bitmask of devices to disable */ + BOOL nch_ClassScan; /* Flag to cause class scan */ + UBYTE nch_PortChanges[2]; /* Buffer for port changes */ + struct PsdDevice **nch_Downstream; /* Pointer to array of down stream device pointers */ +}; + +struct NepHubMsg +{ + struct Message nhm_Msg; /* Message body */ + ULONG nhm_MethodID; /* The method ID (see usbclass.h) */ + ULONG *nhm_Params; /* Pointer to parameters of the method (all of them!) */ + ULONG nhm_Result; /* Result of call */ +}; + +#endif /* HUB_H */ diff --git a/rom/usb/classes/hub/mmakefile.src b/rom/usb/classes/hub/mmakefile.src new file mode 100644 index 000000000..a8e69afea --- /dev/null +++ b/rom/usb/classes/hub/mmakefile.src @@ -0,0 +1,13 @@ +# $Id: mmakefile.src $ +include $(TOP)/config/make.cfg + +FILES := hub.class debug + +#MM- rom-usb-classes-hub : rom-usb-usbclass rom-usb-poseidon + +%build_module mmake=rom-usb-classes-hub \ + modname=hub modtype=usbclass modsuffix="class" \ + files="$(FILES)" \ + uselibs="amiga rom" + +%common diff --git a/rom/usb/classes/massstorage/common.h b/rom/usb/classes/massstorage/common.h new file mode 100644 index 000000000..feae1e480 --- /dev/null +++ b/rom/usb/classes/massstorage/common.h @@ -0,0 +1,55 @@ + +#include LC_LIBDEFS_FILE + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define NewList NEWLIST + +#include + +#define min(x,y) (((x) < (y)) ? (x) : (y)) +#define max(x,y) (((x) > (y)) ? (x) : (y)) + diff --git a/rom/usb/classes/massstorage/debug.c b/rom/usb/classes/massstorage/debug.c new file mode 100644 index 000000000..f29021b6b --- /dev/null +++ b/rom/usb/classes/massstorage/debug.c @@ -0,0 +1,38 @@ +#include "debug.h" + +#ifdef DEBUG +void dumpmem(void *mem, unsigned long int len) +{ + unsigned char *p; + + if (!mem || !len) { return; } + + p = (unsigned char *) mem; + + bug("\n"); + + do + { + unsigned char b, c, str[17]; + + for (b = 0; b < 16; b++) + { + c = *p++; + str[b] = ((c >= ' ') && (c <= 'z')) ? c : '.'; + str[b + 1] = 0; + bug("%02lx ", c); + if (--len == 0) break; + } + + while (++b < 16) + { + bug(" "); + } + + bug(" %s\n", str); + } while (len); + + bug("\n\n"); +} + +#endif /* DEBUG */ diff --git a/rom/usb/classes/massstorage/debug.h b/rom/usb/classes/massstorage/debug.h new file mode 100644 index 000000000..08002f5da --- /dev/null +++ b/rom/usb/classes/massstorage/debug.h @@ -0,0 +1,24 @@ +#ifndef __DEBUG_H__ +#define __DEBUG_H__ + +#define DB_LEVEL 1 + +#define DEBUG 1 + +#include + +#ifdef DEBUG +#define XPRINTF(l, x) do { if ((l) >= DB_LEVEL) \ + { bug("%s:%s/%lu: ", __FILE__, __FUNCTION__, __LINE__); bug x;} } while (0) +#define KPRINTF(l, x) +#define DB(x) x + void dumpmem(void *mem, unsigned long int len); +#else /* !DEBUG */ + +#define KPRINTF(l, x) +#define XPRINTF(l, x) +#define DB(x) + +#endif /* DEBUG */ + +#endif /* __DEBUG_H__ */ diff --git a/rom/usb/classes/massstorage/dev.c b/rom/usb/classes/massstorage/dev.c new file mode 100644 index 000000000..e5834c30b --- /dev/null +++ b/rom/usb/classes/massstorage/dev.c @@ -0,0 +1,443 @@ +/* dev.c - usbscsi.device by Chris Hodges +*/ + +#include "debug.h" + +#include "massstorage.class.h" + +AROS_UFH3(DEVBASETYPEPTR, devInit, + AROS_UFHA(DEVBASETYPEPTR, base, D0), + AROS_UFHA(BPTR, seglist, A0), + AROS_UFHA(struct ExecBase *, SysBase, A6)) +{ + AROS_USERFUNC_INIT + + /*KPRINTF(10, ("devInit base: 0x%08lx seglist: 0x%08lx SysBase: 0x%08lx\n", + base, seglist, SysBase));*/ + + base->np_Library.lib_Node.ln_Type = NT_DEVICE; + base->np_Library.lib_Node.ln_Name = DEVNAME; + base->np_Library.lib_Flags = LIBF_SUMUSED | LIBF_CHANGED; + base->np_Library.lib_Version = VERSION_NUMBER; + base->np_Library.lib_Revision = REVISION_NUMBER; + base->np_Library.lib_IdString = VERSION_STRING; + + /* Store segment */ + base->np_SegList = seglist; + + return(base); + + AROS_USERFUNC_EXIT +} + +AROS_LH3(DEVBASETYPEPTR, devOpen, + AROS_LHA(struct IORequest *, ioreq, A1), + AROS_LHA(ULONG, unitnum, D0), + AROS_LHA(ULONG, flags, D1), + DEVBASETYPEPTR, base, 1, dev); +{ + AROS_LIBFUNC_INIT + + struct NepClassMS *ncm; + + KPRINTF(10, ("devOpen ioreq: 0x%08lx unit: %ld flags: 0x%08lx base: 0x%08lx\n", + ioreq, unit, flags, base)); + + if(!base->np_UtilityBase) + { + if(!(base->np_UtilityBase = OpenLibrary("utility.library", 0))) + { + ioreq->io_Error = IOERR_OPENFAIL; + return(NULL); + } + } + + ++base->np_Library.lib_OpenCnt; + base->np_Library.lib_Flags &= ~LIBF_DELEXP; + + KPRINTF(10, ("devOpen: openCnt = %ld\n", base->np_Library.lib_OpenCnt)); + + /* Damn f*cking programs which leave this field to zero! */ + if(ioreq->io_Message.mn_Length && + (ioreq->io_Message.mn_Length < sizeof(struct IOStdReq))) + { + KPRINTF(20, ("devOpen: invalid MN_LENGTH (%ld < %ld)!\n", + ioreq->io_Message.mn_Length, sizeof(struct IOStdReq))); + + ioreq->io_Error = IOERR_BADLENGTH; + } else { + + /* Default to open failure. */ + ioreq->io_Error = IOERR_OPENFAIL; + + ioreq->io_Unit = NULL; + ncm = (struct NepClassMS *) base->np_ClsBase->nh_Units.lh_Head; + while(ncm->ncm_Unit.unit_MsgPort.mp_Node.ln_Succ) + { + if(ncm->ncm_UnitNo == unitnum) + { + if(!ncm->ncm_DenyRequests) + { + ioreq->io_Unit = (struct Unit *) ncm; + break; + } + } + ncm = (struct NepClassMS *) ncm->ncm_Unit.unit_MsgPort.mp_Node.ln_Succ; + } + + if(!ioreq->io_Unit) + { + ioreq->io_Error = IOERR_OPENFAIL; + KPRINTF(20, ("devOpen: could not open unit!\n")); + } else { + + /* Opended ok! + */ + ioreq->io_Message.mn_Node.ln_Type = NT_REPLYMSG; + ioreq->io_Error = 0; + ioreq->io_Unit->unit_OpenCnt++; + + return base; + } + } + + ioreq->io_Unit = (APTR) -1; + ioreq->io_Device = (APTR) -1; + base->np_Library.lib_OpenCnt--; + + return(NULL); + + AROS_LIBFUNC_EXIT +} + + +AROS_LH1(BPTR, devClose, + AROS_LHA(struct IORequest *, ioreq, A1), + DEVBASETYPEPTR, base, 2, dev); +{ + AROS_LIBFUNC_INIT + + BPTR ret; + struct NepClassMS *unit = (struct NepClassMS *) ioreq->io_Unit; + + KPRINTF(10, ("devClose ioreq: 0x%08lx base: 0x%08lx\n", ioreq, base)); + + ret = NULL; + unit->ncm_Unit.unit_OpenCnt--; + ioreq->io_Unit = (APTR) -1; + ioreq->io_Device = (APTR) -1; + + if(--base->np_Library.lib_OpenCnt == 0) + { + if(base->np_Library.lib_Flags & LIBF_DELEXP) + { + KPRINTF(5, ("devClose: calling expunge...\n")); + ret = AROS_LC1(BPTR, devExpunge, + AROS_LCA(DEVBASETYPEPTR, base, D0), + DEVBASETYPEPTR, base, 3, dev); + } + } + + KPRINTF(5, ("devClose: lib_OpenCnt = %ld\n", base->np_Library.lib_OpenCnt)); + + return(ret); + + AROS_LIBFUNC_EXIT +} + + +AROS_LH1(BPTR, devExpunge, + AROS_LHA(DEVBASETYPEPTR, extralh, D0), + DEVBASETYPEPTR, base, 3, dev); +{ + AROS_LIBFUNC_INIT + + BPTR ret; + + KPRINTF(10, ("devExpunge base: 0x%08lx\n", base)); + + ret = NULL; + + if(base->np_Library.lib_OpenCnt == 0) + { + KPRINTF(5, ("devExpunge: Unloading...\n")); + + CloseLibrary(base->np_UtilityBase); + + ret = base->np_SegList; + + KPRINTF(5, ("devExpunge: removing device node 0x%08lx\n", + &base->np_Library.lib_Node)); + Remove(&base->np_Library.lib_Node); + + KPRINTF(5, ("devExpunge: FreeMem()...\n")); + FreeMem((char *) base - base->np_Library.lib_NegSize, + (ULONG) (base->np_Library.lib_NegSize + base->np_Library.lib_PosSize)); + + KPRINTF(5, ("devExpunge: Unloading done! " DEVNAME " expunged!\n\n")); + + return(ret); + } + else + { + KPRINTF(5, ("devExpunge: Could not expunge, LIBF_DELEXP set!\n")); + base->np_Library.lib_Flags |= LIBF_DELEXP; + } + + return(NULL); + + AROS_LIBFUNC_EXIT +} + +AROS_LH0(DEVBASETYPEPTR, devReserved, + DEVBASETYPEPTR, base, 4, dev) +{ + AROS_LIBFUNC_INIT + return NULL; + AROS_LIBFUNC_EXIT +} + +AROS_LH1(void, devBeginIO, + AROS_LHA(struct IOStdReq *, ioreq, A1), + DEVBASETYPEPTR, base, 5, dev); +{ + AROS_LIBFUNC_INIT + + struct NepClassMS *unit = (struct NepClassMS *) ioreq->io_Unit; + WORD ret = IOERR_NOCMD; + + KPRINTF(5, ("devBeginIO ioreq: 0x%08lx base: 0x%08lx cmd: %lu\n", ioreq, base, ioreq->io_Command)); + + ioreq->io_Message.mn_Node.ln_Type = NT_MESSAGE; + ioreq->io_Error = 0; + + if(ioreq->io_Command < NSCMD_DEVICEQUERY) + { + switch (ioreq->io_Command) + { + case TD_ADDCHANGEINT: + Forbid(); + AddTail(&unit->ncm_DCInts, (struct Node *) ioreq); + Permit(); + ret = RC_DONTREPLY; + break; + + case TD_REMCHANGEINT: + Forbid(); + Remove((struct Node *) ioreq); + Permit(); + ret = 0; + ioreq->io_Flags &= ~IOF_QUICK; + break; + + case TD_CHANGENUM: + ioreq->io_Actual = unit->ncm_ChangeCount; + ret = 0; + break; + + case TD_CHANGESTATE: + ioreq->io_Actual = unit->ncm_UnitReady ? 0 : ~0; + ret = 0; + break; + + case TD_PROTSTATUS: + ioreq->io_Actual = unit->ncm_WriteProtect ? ~0 : 0; + ret = 0; + break; + + case CMD_START: + case CMD_STOP: + case CMD_RESET: + case CMD_FLUSH: + case CMD_READ: + case CMD_WRITE: + case TD_SEEK: + case TD_FORMAT: + case TD_GETGEOMETRY: + case TD_EJECT: + case TD_READ64: + case TD_WRITE64: + case TD_SEEK64: + case TD_FORMAT64: + case HD_SCSICMD: + if(unit->ncm_DenyRequests) + { + ret = TDERR_DiskChanged; + } else { + ioreq->io_Flags &= ~IOF_QUICK; + ret = RC_DONTREPLY; + PutMsg(&unit->ncm_Unit.unit_MsgPort, (struct Message *) ioreq); + } + break; + + /* NOPs */ + case CMD_CLEAR: + case CMD_UPDATE: + case TD_MOTOR: + ret = 0; + break; + + default: + ret = IOERR_NOCMD; + break; + } + } else { + switch(ioreq->io_Command) + { + case NSCMD_DEVICEQUERY: + ret = cmdNSDeviceQuery((struct IOStdReq *) ioreq, unit, base); + break; + + case NSCMD_TD_READ64: + case NSCMD_TD_WRITE64: + case NSCMD_TD_FORMAT64: + case NSCMD_TD_SEEK64: + if(unit->ncm_DenyRequests) + { + ret = IOERR_ABORTED; + } else { + ioreq->io_Flags &= ~IOF_QUICK; + ret = RC_DONTREPLY; + PutMsg(&unit->ncm_Unit.unit_MsgPort, (struct Message *) ioreq); + } + break; + + default: + ret = IOERR_NOCMD; + break; + } + } + + if(ret != RC_DONTREPLY) + { + KPRINTF(1, ("TermIO\n")); + if (ret != RC_OK) + { + /* Set error codes */ + ioreq->io_Error = ret & 0xff; + } + /* Terminate the iorequest */ + TermIO(ioreq, base); + } + + AROS_LIBFUNC_EXIT +} + +AROS_LH1(LONG, devAbortIO, + AROS_LHA(struct IOStdReq *, ioreq, A1), + DEVBASETYPEPTR, base, 6, dev) +{ + AROS_LIBFUNC_INIT + + struct NepClassMS *unit = (struct NepClassMS *) ioreq->io_Unit; + struct IOStdReq *iocmp; + + KPRINTF(5, ("devAbortIO ioreq: 0x%08lx\n", ioreq)); + + /* Is it pending? */ + if(ioreq->io_Message.mn_Node.ln_Type == NT_MESSAGE) + { + if(unit->ncm_XFerPending == ioreq) + { + unit->ncm_XFerPending = NULL; + ioreq->io_Error = IOERR_ABORTED; + ReplyMsg(&ioreq->io_Message); + return(0); + } + iocmp = (struct IOStdReq *) unit->ncm_XFerQueue.lh_Head; + while(iocmp->io_Message.mn_Node.ln_Succ) + { + if(iocmp == ioreq) + { + Remove((struct Node *) ioreq); + ioreq->io_Error = IOERR_ABORTED; + ReplyMsg(&ioreq->io_Message); + return(0); + } + iocmp = (struct IOStdReq *) iocmp->io_Message.mn_Node.ln_Succ; + } + } + return(-1); + + AROS_LIBFUNC_EXIT +} + +/* NSD stuff */ + +static +const UWORD NSDSupported[] = +{ + CMD_CLEAR, CMD_RESET, + CMD_FLUSH, CMD_READ, + CMD_WRITE, CMD_START, + CMD_STOP, CMD_UPDATE, + TD_SEEK, + TD_MOTOR, TD_EJECT, + TD_CHANGENUM, TD_PROTSTATUS, + TD_CHANGESTATE, + TD_FORMAT, + TD_GETGEOMETRY, + TD_ADDCHANGEINT, TD_REMCHANGEINT, + TD_READ64, TD_WRITE64, TD_SEEK64, + TD_FORMAT64, + HD_SCSICMD, + NSCMD_TD_READ64, + NSCMD_TD_WRITE64, + NSCMD_TD_FORMAT64, + NSCMD_TD_SEEK64, + NSCMD_DEVICEQUERY, 0 +}; + +WORD cmdNSDeviceQuery(struct IOStdReq *ioreq, + struct NepClassMS *unit, + struct NepMSDevBase *base) +{ + struct my_NSDeviceQueryResult *query; + + query = (struct my_NSDeviceQueryResult *) ioreq->io_Data; + + KPRINTF(10, ("NSCMD_DEVICEQUERY ioreq: 0x%08lx query: 0x%08lx\n", ioreq, query)); + + /* NULL ptr? + Enough data? + Valid request? + */ + if((!query) || + (ioreq->io_Length < sizeof(struct my_NSDeviceQueryResult)) || + (query->DevQueryFormat != 0) || + (query->SizeAvailable != 0)) + { + /* Return error. This is special handling, since iorequest is only + guaranteed to be sizeof(struct IOStdReq). If we'd let our + devBeginIO dispatcher return the error, it would trash some + memory past end of the iorequest (ios2_WireError field). + */ + ioreq->io_Error = IOERR_NOCMD; + TermIO((struct IOStdReq *) ioreq, base); + + /* Don't reply, we already did. */ + return RC_DONTREPLY; + } + + ioreq->io_Actual = query->SizeAvailable + = sizeof(struct my_NSDeviceQueryResult); + query->DeviceType = NSDEVTYPE_TRACKDISK; + query->DeviceSubType = 0; + query->SupportedCommands = NSDSupported; + + /* Return success (note that this will NOT poke ios2_WireError). + */ + return RC_OK; +} + +void TermIO(struct IOStdReq *ioreq, + struct NepMSDevBase *base) +{ + ioreq->io_Message.mn_Node.ln_Type = NT_FREEMSG; + + /* If not quick I/O, reply the message */ + if(!(ioreq->io_Flags & IOF_QUICK)) + { + ReplyMsg(&ioreq->io_Message); + } +} diff --git a/rom/usb/classes/massstorage/dev.h b/rom/usb/classes/massstorage/dev.h new file mode 100644 index 000000000..b6f18499a --- /dev/null +++ b/rom/usb/classes/massstorage/dev.h @@ -0,0 +1,65 @@ + +/* DEVICE STUFF */ + +#define DEVNAME "usbscsi.device" + +#define DEVBASETYPEPTR struct NepMSDevBase * + +/* local protos */ + +AROS_UFP3(DEVBASETYPEPTR, devInit, + AROS_UFPA(DEVBASETYPEPTR, base, D0), + AROS_UFPA(BPTR, seglist, A0), + AROS_UFPA(struct ExecBase *, SysBase, A6)); + +AROS_LD3(DEVBASETYPEPTR, devOpen, + AROS_LDA(struct IORequest *, ioreq, A1), + AROS_LDA(ULONG, unitnum, D0), + AROS_LDA(ULONG, flags, D1), + DEVBASETYPEPTR, base, 1, dev); + +AROS_LD1(BPTR, devClose, + AROS_LDA(struct IORequest *, ioreq, A1), + DEVBASETYPEPTR, base, 2, dev); + +AROS_LD1(BPTR, devExpunge, + AROS_LDA(DEVBASETYPEPTR, extralh, D0), + DEVBASETYPEPTR, base, 3, dev); + +AROS_LD0(DEVBASETYPEPTR, devReserved, + DEVBASETYPEPTR, base, 4, dev); + +AROS_LD1(void, devBeginIO, + AROS_LDA(struct IOStdReq *, ioreq, A1), + DEVBASETYPEPTR, base, 5, dev); + +AROS_LD1(LONG, devAbortIO, + AROS_LDA(struct IOStdReq *, ioreq, A1), + DEVBASETYPEPTR, base, 6, dev); + +/* Device stuff */ + +/* Reply the iorequest with success */ +#define RC_OK 0 + +/* Magic cookie, don't set error fields & don't reply the ioreq */ +#define RC_DONTREPLY -1 + +struct Unit *Open_Unit(struct IOStdReq *ioreq, + LONG unitnr, + struct NepMSDevBase *base); +void Close_Unit(struct NepMSDevBase *base, struct NepClassMS *unit, + struct IOStdReq *ioreq); + +WORD cmdNSDeviceQuery(struct IOStdReq *ioreq, struct NepClassMS *unit, struct NepMSDevBase *base); + +void TermIO(struct IOStdReq *ioreq, struct NepMSDevBase *base); + +struct my_NSDeviceQueryResult +{ + ULONG DevQueryFormat; /* this is type 0 */ + ULONG SizeAvailable; /* bytes available */ + UWORD DeviceType; /* what the device does */ + UWORD DeviceSubType; /* depends on the main type */ + const UWORD *SupportedCommands; /* 0 terminated list of cmd's */ +}; diff --git a/rom/usb/classes/massstorage/massstorage.class.c b/rom/usb/classes/massstorage/massstorage.class.c new file mode 100644 index 000000000..8fc667257 --- /dev/null +++ b/rom/usb/classes/massstorage/massstorage.class.c @@ -0,0 +1,6098 @@ +/* + *---------------------------------------------------------------------------- + * massstorage class for poseidon + *---------------------------------------------------------------------------- + * By Chris Hodges + */ + +#include "debug.h" + +#include "massstorage.class.h" + +/* /// "Lib Stuff" */ +static const STRPTR libname = MOD_NAME_STRING; + +static +const APTR DevFuncTable[] = +{ + &AROS_SLIB_ENTRY(devOpen, dev), + &AROS_SLIB_ENTRY(devClose, dev), + &AROS_SLIB_ENTRY(devExpunge, dev), + &AROS_SLIB_ENTRY(devReserved, dev), + &AROS_SLIB_ENTRY(devBeginIO, dev), + &AROS_SLIB_ENTRY(devAbortIO, dev), + (APTR) -1, +}; + +static int libInit(LIBBASETYPEPTR nh) +{ + struct ClsDevCfg *cdc = NULL; + struct ClsUnitCfg *cuc = NULL; + struct NepClassMS *ncm; + struct NepMSBase *ret = NULL; + KPRINTF(10, ("libInit nh: 0x%08lx SysBase: 0x%08lx\n", + nh, SysBase)); + +#define UtilityBase nh->nh_UtilityBase + nh->nh_UtilityBase = OpenLibrary("utility.library", 39); + if(UtilityBase) + { + /* Initialize device node & library struct */ + KPRINTF(1, ("UtilityOkay\n")); + NewList(&nh->nh_Units); + InitSemaphore(&nh->nh_TaskLock); + + ncm = &nh->nh_DummyNCM; + ncm->ncm_ClsBase = nh; + ncm->ncm_Interface = NULL; + strcpy(ncm->ncm_LUNIDStr, "Default"); + strcpy(ncm->ncm_LUNNumStr, "All"); + ncm->ncm_CDC = cdc = AllocVec(sizeof(struct ClsDevCfg), MEMF_PUBLIC|MEMF_CLEAR); + ncm->ncm_CUC = cuc = AllocVec(sizeof(struct ClsUnitCfg), MEMF_PUBLIC|MEMF_CLEAR); + if(cdc && cuc) + { + KPRINTF(1, ("MakeLibrary\n")); + if((nh->nh_DevBase = (struct NepMSDevBase *) MakeLibrary((APTR) DevFuncTable, NULL, (APTR) devInit, + sizeof(struct NepMSDevBase), NULL))) + { + KPRINTF(1,("AddDevice\n")); + nh->nh_DevBase->np_ClsBase = nh; + Forbid(); + AddDevice((struct Device *) nh->nh_DevBase); + nh->nh_DevBase->np_Library.lib_OpenCnt++; + Permit(); + ret = nh; + } else { + KPRINTF(20, ("failed to create usbscsi.device\n")); + } + } + } else { + KPRINTF(20, ("libInit: OpenLibrary(\"utility.library\", 39) failed!\n")); + } + if(!ret) + { + FreeVec(cdc); + FreeVec(cuc); + CloseLibrary(UtilityBase); + } + KPRINTF(10, ("libInit: Ok\n")); + return(ret ? TRUE : FALSE); +} + +static int libOpen(LIBBASETYPEPTR nh) +{ + KPRINTF(10, ("libOpen nh: 0x%08lx\n", nh)); + nLoadClassConfig(nh); + + return(TRUE); +} + +static int libClose(LIBBASETYPEPTR nh) +{ + if(nh->nh_Library.lib_OpenCnt == 0) // FIXME is this 0 or 1? Does AROS decrease it before calling libClose? + { + ObtainSemaphore(&nh->nh_TaskLock); + Forbid(); + nh->nh_ReadySignal = SIGB_SINGLE; + nh->nh_ReadySigTask = FindTask(NULL); + if(nh->nh_RemovableTask) + { + Signal(nh->nh_RemovableTask, SIGBREAKF_CTRL_C); + } + Permit(); + while(nh->nh_RemovableTask) + { + Wait(1L<nh_ReadySignal); + } + //FreeSignal(nh->nh_ReadySignal); + ReleaseSemaphore(&nh->nh_TaskLock); + } + KPRINTF(5, ("libClose: lib_OpenCnt = %ld\n", nh->nh_Library.lib_OpenCnt)); + return(TRUE); +} + +static int libExpunge(LIBBASETYPEPTR nh) +{ + struct NepClassMS *ncm; + + KPRINTF(10, ("libExpunge nh: 0x%08lx\n", nh)); + + if((nh->nh_DevBase->np_Library.lib_OpenCnt == 1)) + { + KPRINTF(1, ("libExpunge: closelibrary utilitybase 0x%08lx\n", + UtilityBase)); + CloseLibrary((struct Library *) UtilityBase); + KPRINTF(5, ("libExpunge: removing library node 0x%08lx\n", + &nh->nh_Library.lib_Node)); + Remove(&nh->nh_Library.lib_Node); + ncm = (struct NepClassMS *) nh->nh_Units.lh_Head; + while(ncm->ncm_Unit.unit_MsgPort.mp_Node.ln_Succ) + { + Remove((struct Node *) ncm); + FreeVec(ncm->ncm_CDC); + FreeVec(ncm->ncm_CUC); + FreeVec(ncm->ncm_DevIDString); + FreeVec(ncm->ncm_IfIDString); + FreeVec(ncm); + ncm = (struct NepClassMS *) nh->nh_Units.lh_Head; + } + + ncm = &nh->nh_DummyNCM; + FreeVec(ncm->ncm_CDC); + FreeVec(ncm->ncm_CUC); + + nh->nh_DevBase->np_Library.lib_OpenCnt--; + RemDevice((struct Device *) nh->nh_DevBase); + KPRINTF(5, ("libExpunge: Unloading done! massstorage.class expunged!\n\n")); + } else { + KPRINTF(5, ("libExpunge: Could not expunge, LIBF_DELEXP set!\n")); + return(FALSE); + } + + return(TRUE); +} + +ADD2INITLIB(libInit, 0) +ADD2OPENLIB(libOpen, 0) +ADD2CLOSELIB(libClose, 0) +ADD2EXPUNGELIB(libExpunge, 0) +/* \\\ */ + +/* + * *********************************************************************** + * * Library functions * + * *********************************************************************** + */ + +/* /// "usbAttemptInterfaceBinding()" */ +struct NepClassMS * usbAttemptInterfaceBinding(struct NepMSBase *nh, struct PsdInterface *pif) +{ + struct Library *ps; + ULONG ifclass; + ULONG subclass; + ULONG proto; + + KPRINTF(1, ("nepMSAttemptInterfaceBinding(%08lx)\n", pif)); + if((ps = OpenLibrary("poseidon.library", 4))) + { + psdGetAttrs(PGA_INTERFACE, pif, + IFA_Class, &ifclass, + IFA_SubClass, &subclass, + IFA_Protocol, &proto, + TAG_END); + + CloseLibrary(ps); + if((ifclass == MASSSTORE_CLASSCODE) && + ((subclass == MS_SCSI_SUBCLASS) || + (subclass == MS_RBC_SUBCLASS) || + (subclass == MS_ATAPI_SUBCLASS) || + (subclass == MS_FDDATAPI_SUBCLASS) || + (subclass == MS_UFI_SUBCLASS)) && + ((proto == MS_PROTO_BULK) || + (proto == MS_PROTO_CB) || + (proto == MS_PROTO_CBI))) + { + return(usbForceInterfaceBinding(nh, pif)); + } + } + return(NULL); +} +/* \\\ */ + +/* /// "usbForceInterfaceBinding()" */ +struct NepClassMS * usbForceInterfaceBinding(struct NepMSBase *nh, struct PsdInterface *pif) +{ + struct Library *ps; + struct Task *subtask; + struct NepClassMS *ncm; + struct NepClassMS *firstncm = NULL; + struct NepClassMS *tmpncm; + struct MsgPort *mp; + struct PsdConfig *pc; + struct PsdDevice *pd; + struct PsdPipe *pp; + struct ClsDevCfg *cdc; + struct ClsUnitCfg *cuc; + STRPTR devname; + ULONG ifclass; + ULONG subclass; + ULONG proto; + ULONG ifnum; + ULONG cfgnum; + ULONG prodid; + ULONG vendid; + ULONG unitno; + STRPTR devidstr; + STRPTR ifidstr; + BOOL unitfound; + UBYTE buf[64]; + UBYTE maxlun; + UWORD lunnum; + LONG ioerr; + LONG retry; + ULONG patchflags = 0; + BOOL delayedstore = FALSE; + + KPRINTF(1, ("nepMSAttemptInterfaceBinding(%08lx)\n", pif)); + if(!(mp = CreateMsgPort())) + { + return(NULL); + } + if((ps = OpenLibrary("poseidon.library", 4))) + { + psdGetAttrs(PGA_INTERFACE, pif, + IFA_Class, &ifclass, + IFA_SubClass, &subclass, + IFA_Protocol, &proto, + IFA_InterfaceNum, &ifnum, + IFA_Config, &pc, + IFA_IDString, &ifidstr, + TAG_DONE); + psdGetAttrs(PGA_CONFIG, pc, + CA_Device, &pd, + CA_ConfigNum, &cfgnum, + TAG_END); + psdGetAttrs(PGA_DEVICE, pd, + DA_ProductID, &prodid, + DA_VendorID, &vendid, + DA_ProductName, &devname, + DA_IDString, &devidstr, + TAG_END); + maxlun = 0; + /* Patches and fixes */ + if((proto != MS_PROTO_BULK) && (proto != MS_PROTO_CB) && (proto != MS_PROTO_CBI)) + { + proto = MS_PROTO_BULK; + } + if((subclass != MS_SCSI_SUBCLASS) && + (subclass != MS_RBC_SUBCLASS) && + (subclass != MS_ATAPI_SUBCLASS) && + (subclass != MS_FDDATAPI_SUBCLASS) && + (subclass != MS_UFI_SUBCLASS)) + { + subclass = MS_SCSI_SUBCLASS; + } + + if(proto == MS_PROTO_BULK) + { + if(vendid == 0x05e3) /* 2.5 HD Wrapper by Eagle Tec */ + { + patchflags |= PFF_FIX_INQ36|PFF_SIMPLE_SCSI|PFF_DELAY_DATA; + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, + "Broken Genesys firmware data phase delay activated. Performance loss!"); + } + if((vendid == 0x0d7d) && (prodid == 0x1600)) /* HAMA Memory stick */ + { + patchflags |= PFF_SIMPLE_SCSI; + } + if(((vendid == 0x04cb) && (prodid == 0x0100)) || /* Fujifilm FinePix 1400Zoom */ + ((vendid == 0x0204) && (prodid == 0x6025)) || /* Brock's EXIGO Flashstick */ + ((vendid == 0x0aec) && (prodid == 0x5010))) /* SOYO Multislot Reader */ + { + patchflags |= PFF_FIX_INQ36; + } + if(((vendid == 0x0c76) && (prodid == 0x0005)) || /* JetFlash */ + ((vendid == 0x066f) && (prodid == 0x8000))) /* Aiptek_mp3-310_128MB.txt */ + { + patchflags |= PFF_NO_RESET; + } + + if(((vendid == 0x059b) && (prodid == 0x0031)) || /* ZIP 100 */ + //((vendid == 0x0aec) && (prodid == 0x5010)) || /* Neodio CF-Reader */ + ((vendid == 0x058f) && (prodid == 0x9380)) || /* guido's stick */ + ((vendid == 0x3579) && (prodid == 0x6901))) + //((vendid == 0x07c4) && (prodid == 0xb00b))) /* USB Memory Stick */ + { + patchflags |= PFF_SINGLE_LUN; + } + if(patchflags) + { + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, + "Preconfig patchflags 0x%04lx", patchflags); + } + } + lunnum = 0; + while(lunnum <= maxlun) + { + /*if(firstncm) + { + unitno = firstncm->ncm_UnitNo + lunnum; + } else { + unitno = lunnum; + }*/ + Forbid(); + unitfound = FALSE; + ncm = (struct NepClassMS *) nh->nh_Units.lh_Head; + while(ncm->ncm_Unit.unit_MsgPort.mp_Node.ln_Succ) + { + if((strcmp(devidstr, ncm->ncm_DevIDString) == 0) && + (strcmp(ifidstr, ncm->ncm_IfIDString) == 0) && + (ncm->ncm_UnitLUN == lunnum)) + { + unitno = ncm->ncm_UnitNo; + unitfound = TRUE; + break; + } + ncm = (struct NepClassMS *) ncm->ncm_Unit.unit_MsgPort.mp_Node.ln_Succ; + } + if(!unitfound) + { + /* as units are freed in the expunge-vector, the memory is + outside the scope of the poseidon library */ + if(!(ncm = AllocVec(sizeof(struct NepClassMS), MEMF_PUBLIC|MEMF_CLEAR))) + { + Permit(); + DeleteMsgPort(mp); + CloseLibrary(ps); + return(NULL); + } + ncm->ncm_ClsBase = nh; + ncm->ncm_UnitNo = (ULONG) ~0; + ncm->ncm_CDC = cdc = AllocVec(sizeof(struct ClsDevCfg), MEMF_PUBLIC|MEMF_CLEAR); + ncm->ncm_CUC = cuc = AllocVec(sizeof(struct ClsUnitCfg), MEMF_PUBLIC|MEMF_CLEAR); + ncm->ncm_DevIDString = AllocVec((ULONG) strlen(devidstr)+1, MEMF_PUBLIC|MEMF_CLEAR); + ncm->ncm_IfIDString = AllocVec((ULONG) strlen(ifidstr)+1, MEMF_PUBLIC|MEMF_CLEAR); + if(!(cdc && cuc && ncm->ncm_DevIDString && ncm->ncm_IfIDString)) + { + FreeVec(cdc); + FreeVec(cuc); + FreeVec(ncm->ncm_DevIDString); + FreeVec(ncm->ncm_IfIDString); + FreeVec(ncm); + Permit(); + DeleteMsgPort(mp); + CloseLibrary(ps); + return(NULL); + } + /* IORequests may be queued even if the task is gone. */ + NewList(&ncm->ncm_Unit.unit_MsgPort.mp_MsgList); + NewList(&ncm->ncm_XFerQueue); + NewList(&ncm->ncm_DCInts); + InitSemaphore(&ncm->ncm_XFerLock); + AddTail(&nh->nh_Units, &ncm->ncm_Unit.unit_MsgPort.mp_Node); + strcpy(ncm->ncm_DevIDString, devidstr); + strcpy(ncm->ncm_IfIDString, ifidstr); + + } + ncm->ncm_Interface = pif; + ncm->ncm_Device = pd; + ncm->ncm_Config = pc; + ncm->ncm_UnitLUN = lunnum; + ncm->ncm_UnitIfNum = ifnum; + ncm->ncm_UnitCfgNum = cfgnum; + ncm->ncm_UnitProdID = prodid; + ncm->ncm_UnitVendorID = vendid; + ncm->ncm_TPType = proto; + ncm->ncm_CSType = subclass; + ncm->ncm_BlockSize = 0; + ncm->ncm_BlockShift = 9; + psdSafeRawDoFmt(ncm->ncm_LUNNumStr, 4, "%ld", ncm->ncm_UnitLUN); + + if(!firstncm) + { + firstncm = ncm; + } + ncm->ncm_UnitLUN0 = firstncm; + + nLoadBindingConfig(ncm); + if(ncm->ncm_UsingDefaultCfg) + { + ncm->ncm_CDC->cdc_PatchFlags |= nh->nh_DummyNCM.ncm_CDC->cdc_PatchFlags; + } else { + patchflags = 0; // specific flags override defaults, ALL defaults. + } + + patchflags |= ncm->ncm_CDC->cdc_PatchFlags; + if((vendid == 0x090a) && (prodid == 0x1100)) + { + patchflags |= PFF_CLEAR_EP; + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, "Enabling clear endpoint halt mode for this device!"); + } + if(vendid == 0x07b4) /* Olympus C-xx */ + { + patchflags |= PFF_CSS_BROKEN; + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, "Workaround for broken Olympus cameras enabled."); + } + if(vendid == 0x067b) /* Prolific */ + { + patchflags |= PFF_CSS_BROKEN; + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, "Workaround for broken Prolific signature enabled."); + } + if((vendid == 0x0c76) && (prodid == 0x0005)) + { + patchflags |= PFF_FIX_INQ36|PFF_FAKE_INQUIRY|PFF_MODE_XLATE; + } + + // do this for the first LUN only + if(lunnum == 0) + { + if((pp = psdAllocPipe(pd, mp, NULL))) + { + psdSetAttrs(PGA_PIPE, pp, + PPA_NakTimeout, TRUE, + PPA_NakTimeoutTime, 1000, + TAG_END); + if(((vendid == 0x04e6) && ((prodid == 0x0002) || (prodid == 0x000b) || (prodid == 0x000c))) || + ((vendid == 0x050d) && (prodid == 0x0115)) || + ((vendid == 0x07af) && ((prodid == 0x0004) || (prodid == 0x0005)))) + { + UBYTE databyte = 0x01; + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, + "Attempting to do special eUSCSI init..."); + + psdPipeSetup(pp, URTF_VENDOR|URTF_INTERFACE, 0x0c, 0x01, ifnum); + ioerr = psdDoPipe(pp, &databyte, 1); + if(ioerr) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "eUSCSI_init failed: %s (%ld)", + psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + } + } + if((vendid == 0x1019) && (prodid == 0x0C55)) + { + struct UsbMSCmdBlkWrapper umscbw; + struct UsbMSCmdStatusWrapper umscsw; + struct PsdPipe *outep, *inep; + struct PsdPipe *outpp, *inpp; + + inep = psdFindEndpoint(pif, NULL, + EA_IsIn, TRUE, + EA_TransferType, USEAF_BULK, + TAG_END); + outep = psdFindEndpoint(pif, NULL, + EA_IsIn, FALSE, + EA_TransferType, USEAF_BULK, + TAG_END); + if(inep && outep) + { + inpp = psdAllocPipe(pd, mp, inep); + outpp = psdAllocPipe(pd, mp, outep); + if(inpp && outpp) + { + psdSetAttrs(PGA_PIPE, inpp, + PPA_NakTimeout, TRUE, + PPA_NakTimeoutTime, 5000, + TAG_END); + psdSetAttrs(PGA_PIPE, outpp, + PPA_NakTimeout, TRUE, + PPA_NakTimeoutTime, 5000, + PPA_NoShortPackets, TRUE, + TAG_END); + + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, + "Attempting to do special UCR-61S2B init..."); + umscbw.dCBWSignature = AROS_LONG2LE(0x43425355); + umscbw.dCBWTag = 0; + umscbw.dCBWDataTransferLength = 0; + umscbw.bmCBWFlags = 0; + umscbw.bCBWLUN = 0; + umscbw.bCBWCBLength = 12; + memset(umscbw.CBWCB, 0, 16); + CopyMem("\xec\x0a\x06\x00$PCCHIPS", umscbw.CBWCB, (ULONG) umscbw.bCBWCBLength); + ioerr = psdDoPipe(outpp, &umscbw, UMSCBW_SIZEOF); + if(ioerr) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "UCR-61S2B init command failed: %s (%ld)", + psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + } + ioerr = psdDoPipe(inpp, &umscsw, UMSCSW_SIZEOF); + if(ioerr) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "UCR-61S2B init status failed: %s (%ld)", + psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + } + } + if(inpp) + { + psdFreePipe(inpp); + } + if(outpp) + { + psdFreePipe(outpp); + } + } + } + + if(!(patchflags & PFF_SINGLE_LUN)) + { + retry = 3; + maxlun = 0; + do + { + psdPipeSetup(pp, URTF_IN|URTF_CLASS|URTF_INTERFACE, + UMSR_GET_MAX_LUN, 0, ifnum); + ioerr = psdDoPipe(pp, &maxlun, 1); + if(ioerr) + { + maxlun = 0; + if((retry > 1) && (ioerr != UHIOERR_NAKTIMEOUT) && (ioerr != UHIOERR_TIMEOUT)) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "GET_MAX_LUN failed: %s (%ld), retrying in 0.5secs.", + psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + psdDelayMS(500); + } else { + psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname, + "GET_MAX_LUN failed: %s (%ld)", + psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + } + } else { + /*psdAddErrorMsg(RETURN_OK, (STRPTR) libname, + "Number of logical units: %ld", (ULONG) maxlun+1);*/ + break; + } + } while(--retry); + if(ioerr) + { + if((!(patchflags & PFF_NO_FALLBACK)) && (!(patchflags & PFF_SINGLE_LUN))) + { + patchflags |= PFF_SINGLE_LUN; + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "Fallback: Enabling SingleLUN."); + delayedstore = TRUE; + } + } + if(maxlun > 7) + { + psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname, + "MaxLUN value %ld does not seem reasonable. Reducing to %ld.", maxlun, 3); + maxlun = 3; + } + } else { + maxlun = 0; + } + psdFreePipe(pp); + } + } + ncm->ncm_MaxLUN = maxlun; + + /* Find next free unit number */ + if(ncm->ncm_UnitNo == (ULONG) ~0) + { + unitno = ncm->ncm_CUC->cuc_DefaultUnit; + tmpncm = (struct NepClassMS *) nh->nh_Units.lh_Head; + while(tmpncm->ncm_Unit.unit_MsgPort.mp_Node.ln_Succ) + { + if(tmpncm->ncm_UnitNo == unitno) + { + unitno++; + tmpncm = (struct NepClassMS *) nh->nh_Units.lh_Head; + } else { + tmpncm = (struct NepClassMS *) tmpncm->ncm_Unit.unit_MsgPort.mp_Node.ln_Succ; + } + } + ncm->ncm_UnitNo = unitno; + } + ncm->ncm_CDC->cdc_PatchFlags = patchflags; + Permit(); + + if(delayedstore) + { + ncm->ncm_Base = ps; + nStoreConfig(ncm); + delayedstore = FALSE; + } + psdSafeRawDoFmt(buf, 64, "massstorage.class<%08lx,%ld>", ncm, lunnum); + ncm->ncm_ReadySignal = SIGB_SINGLE; + ncm->ncm_ReadySigTask = FindTask(NULL); + SetSignal(0, SIGF_SINGLE); + subtask = psdSpawnSubTask(buf, (APTR) nMSTask, ncm); + if(subtask) + { + psdBorrowLocksWait(subtask, 1UL<ncm_ReadySignal); + if(ncm->ncm_Task) + { + //ncm->ncm_ReadySigTask = NULL; + //FreeSignal(ncm->ncm_ReadySignal); + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, + "MSD '%s' LUN %ld available through %s unit %ld!", + devname, lunnum, nh->nh_DevBase->np_Library.lib_Node.ln_Name, + ncm->ncm_UnitNo); + //lunnum++; + //continue; + } + } + ncm->ncm_ReadySigTask = NULL; + //FreeSignal(ncm->ncm_ReadySignal); + /* Get rid of unit structure */ + /* Well, actually don't. maybe we will be able to get back to it later */ + /*Forbid(); + Remove(ncm); + Permit(); + FreeVec(ncm); + if(firstncm == ncm) + { + firstncm = NULL; + }*/ + lunnum++; + } + CloseLibrary(ps); + } + DeleteMsgPort(mp); + return(firstncm); +} +/* \\\ */ + +/* /// "usbReleaseInterfaceBinding()" */ +void usbReleaseInterfaceBinding(struct NepMSBase *nh, struct NepClassMS *ncm) +{ + struct Library *ps; + STRPTR devname; + struct NepClassMS *ncmhead; + + KPRINTF(1, ("nepMSReleaseInterfaceBinding(%08lx)\n", ncm)); + if((ps = OpenLibrary("poseidon.library", 4))) + { + Forbid(); + if(ncm->ncm_GUITask) + { + Signal(ncm->ncm_GUITask, SIGBREAKF_CTRL_C); + } + Permit(); + psdGetAttrs(PGA_DEVICE, ncm->ncm_Device, DA_ProductName, &devname, TAG_END); + ncmhead = ncm; + ncm = (struct NepClassMS *) nh->nh_Units.lh_Head; + while(ncm->ncm_Unit.unit_MsgPort.mp_Node.ln_Succ) + { + KPRINTF(10, ("ncm = %08lx, ncmhead = %08lx, unit0 = %08lx\n", ncm, ncmhead, ncm->ncm_UnitLUN0)); + if((ncm->ncm_UnitLUN0 == ncmhead) && (ncm->ncm_Task)) + { + /*ncm->ncm_UnitLUN0 = NULL;*/ + Forbid(); + ncm->ncm_ReadySignal = SIGB_SINGLE; + ncm->ncm_ReadySigTask = FindTask(NULL); + ncm->ncm_DenyRequests = TRUE; + if(ncm->ncm_Task) + { + Signal(ncm->ncm_Task, SIGBREAKF_CTRL_C); + } + Permit(); + while(ncm->ncm_Task) + { + psdBorrowLocksWait(ncm->ncm_Task, 1UL<ncm_ReadySignal); + } + //FreeSignal(ncm->ncm_ReadySignal); + } + ncm = (struct NepClassMS *) ncm->ncm_Unit.unit_MsgPort.mp_Node.ln_Succ; + } + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, + "'%s' retreated, pitful coward.", + devname); + CloseLibrary(ps); + } +} +/* \\\ */ + +/* /// "usbGetAttrsA()" */ +AROS_LH3(LONG, usbGetAttrsA, + AROS_LHA(ULONG, type, D0), + AROS_LHA(APTR, usbstruct, A0), + AROS_LHA(struct TagItem *, tags, A1), + LIBBASETYPEPTR, nh, 5, nep) +{ + AROS_LIBFUNC_INIT + + struct TagItem *ti; + LONG count = 0; + + KPRINTF(1, ("nepMSGetAttrsA(%ld, %08lx, %08lx)\n", type, usbstruct, tags)); + switch(type) + { + case UGA_CLASS: + if((ti = FindTagItem(UCCA_Priority, tags))) + { + *((IPTR *) ti->ti_Data) = 0; + count++; + } + if((ti = FindTagItem(UCCA_Description, tags))) + { + *((STRPTR *) ti->ti_Data) = "Supports storage devices via usbscsi.device"; + count++; + } + if((ti = FindTagItem(UCCA_HasClassCfgGUI, tags))) + { + *((IPTR *) ti->ti_Data) = TRUE; + count++; + } + if((ti = FindTagItem(UCCA_HasBindingCfgGUI, tags))) + { + *((IPTR *) ti->ti_Data) = TRUE; + count++; + } + if((ti = FindTagItem(UCCA_AfterDOSRestart, tags))) + { + *((IPTR *) ti->ti_Data) = FALSE; + count++; + } + if((ti = FindTagItem(UCCA_UsingDefaultCfg, tags))) + { + *((IPTR *) ti->ti_Data) = nh->nh_DummyNCM.ncm_UsingDefaultCfg; + count++; + } + if((ti = FindTagItem(UCCA_SupportsSuspend, tags))) + { + *((IPTR *) ti->ti_Data) = TRUE; + count++; + } + break; + + case UGA_BINDING: + if((ti = FindTagItem(UCBA_UsingDefaultCfg, tags))) + { + *((IPTR *) ti->ti_Data) = ((struct NepClassMS *) usbstruct)->ncm_UsingDefaultCfg; + count++; + } + break; + + } + return(count); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "usbSetAttrsA()" */ +AROS_LH3(LONG, usbSetAttrsA, + AROS_LHA(ULONG, type, D0), + AROS_LHA(APTR, usbstruct, A0), + AROS_LHA(struct TagItem *, tags, A1), + LIBBASETYPEPTR, nh, 6, nep) +{ + AROS_LIBFUNC_INIT + return(0); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "usbDoMethodA()" */ +AROS_LH2(IPTR, usbDoMethodA, + AROS_LHA(ULONG, methodid, D0), + AROS_LHA(IPTR *, methoddata, A1), + LIBBASETYPEPTR, nh, 7, nep) +{ + AROS_LIBFUNC_INIT + + struct NepClassMS *ncm; + + KPRINTF(10, ("Do Method %ld\n", methodid)); + switch(methodid) + { + case UCM_AttemptInterfaceBinding: + return((IPTR) usbAttemptInterfaceBinding(nh, (struct PsdInterface *) methoddata[0])); + + case UCM_ForceInterfaceBinding: + return((IPTR) usbForceInterfaceBinding(nh, (struct PsdInterface *) methoddata[0])); + + case UCM_ReleaseInterfaceBinding: + usbReleaseInterfaceBinding(nh, (struct NepClassMS *) methoddata[0]); + return(TRUE); + + case UCM_OpenCfgWindow: + return(nOpenBindingCfgWindow(nh, &nh->nh_DummyNCM)); + + case UCM_OpenBindingCfgWindow: + return(nOpenBindingCfgWindow(nh, (struct NepClassMS *) methoddata[0])); + + case UCM_ConfigChangedEvent: + nLoadClassConfig(nh); + Forbid(); + ncm = (struct NepClassMS *) nh->nh_Units.lh_Head; + while(ncm->ncm_Unit.unit_MsgPort.mp_Node.ln_Succ) + { + nLoadBindingConfig(ncm); + ncm = (struct NepClassMS *) ncm->ncm_Unit.unit_MsgPort.mp_Node.ln_Succ; + } + Permit(); + return(TRUE); + + case UCM_AttemptSuspendDevice: + ncm = (struct NepClassMS *) methoddata[0]; + ncm->ncm_Running = FALSE; + return(TRUE); + + case UCM_AttemptResumeDevice: + ncm = (struct NepClassMS *) methoddata[0]; + ncm->ncm_Running = TRUE; + Signal(ncm->ncm_Task, (1L<ncm_TaskMsgPort->mp_SigBit)); + return(TRUE); + + default: + break; + } + return(0); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "nLoadClassConfig()" */ +BOOL nLoadClassConfig(struct NepMSBase *nh) +{ + struct NepClassMS *ncm = &nh->nh_DummyNCM; + struct Library *ps; + struct ClsDevCfg *cdc; + struct ClsUnitCfg *cuc; + struct PsdIFFContext *pic; + + KPRINTF(10, ("Loading Class Config...\n")); + if(ncm->ncm_GUITask) + { + return(FALSE); + } + if(!(ps = OpenLibrary("poseidon.library", 4))) + { + return(FALSE); + } + + Forbid(); + /* Create default config */ + cdc = ncm->ncm_CDC; + cdc->cdc_ChunkID = AROS_LONG2BE(MAKE_ID('M','S','D','C')); + cdc->cdc_Length = AROS_LONG2BE(sizeof(struct ClsDevCfg)-8); + cdc->cdc_NakTimeout = 50; + cdc->cdc_PatchFlags = PFF_MODE_XLATE|PFF_NO_RESET|PFF_FIX_INQ36|PFF_SIMPLE_SCSI; + cdc->cdc_FATDosType = 0x46415401; + cdc->cdc_StartupDelay = 0; + cdc->cdc_MaxTransfer = 5; + strcpy(cdc->cdc_FATFSName, "fat.handler"); + strcpy(cdc->cdc_FATControl, ""); // FIXME + + cdc->cdc_CDDosType = 0x43444653; // FIXME + strcpy(cdc->cdc_CDFSName, "cdrom.handler"); // FIXME + strcpy(cdc->cdc_CDControl, ""); // FIXME + cdc->cdc_NTFSDosType = 0x4e544653; // FIXME + strcpy(cdc->cdc_NTFSName, "ntfs.handler"); // FIXME + + cuc = ncm->ncm_CUC; + cuc->cuc_ChunkID = AROS_LONG2BE(MAKE_ID('L','U','N','0')); + cuc->cuc_Length = AROS_LONG2BE(sizeof(struct ClsUnitCfg)-8); + cuc->cuc_AutoMountFAT = TRUE; + strcpy(cuc->cuc_FATDOSName, "UMSD"); + cuc->cuc_FATBuffers = 100; + cuc->cuc_AutoMountRDB = TRUE; + cuc->cuc_BootRDB = TRUE; + cuc->cuc_DefaultUnit = 0; + cuc->cuc_AutoUnmount = TRUE; + cuc->cuc_MountAllFAT = TRUE; + cuc->cuc_AutoMountCD = TRUE; + + ncm->ncm_UsingDefaultCfg = TRUE; + /* try to load default config */ + pic = psdGetClsCfg(libname); + if(pic) + { + cdc = psdGetCfgChunk(pic, ncm->ncm_CDC->cdc_ChunkID); + if(cdc) + { + CopyMem(((UBYTE *) cdc) + 8, ((UBYTE *) ncm->ncm_CDC) + 8, min(AROS_LONG2BE(cdc->cdc_Length), AROS_LONG2BE(ncm->ncm_CDC->cdc_Length))); + psdFreeVec(cdc); + ncm->ncm_UsingDefaultCfg = FALSE; + } + cuc = psdGetCfgChunk(pic, ncm->ncm_CUC->cuc_ChunkID); + if(cuc) + { + CopyMem(((UBYTE *) cuc) + 8, ((UBYTE *) ncm->ncm_CUC) + 8, min(AROS_LONG2BE(cuc->cuc_Length), AROS_LONG2BE(ncm->ncm_CUC->cuc_Length))); + psdFreeVec(cuc); + ncm->ncm_UsingDefaultCfg = FALSE; + } + } + Permit(); + CloseLibrary(ps); + return(FALSE); +} +/* \\\ */ + +/* /// "nLoadBindingConfig()" */ +BOOL nLoadBindingConfig(struct NepClassMS *ncm) +{ + struct NepMSBase *nh = ncm->ncm_ClsBase; + struct Library *ps; + struct ClsDevCfg *cdc; + struct ClsUnitCfg *cuc; + struct PsdIFFContext *pic; + + KPRINTF(10, ("Loading Binding Config...\n")); + if(ncm->ncm_GUITask) + { + return(FALSE); + } + //nLoadClassConfig(nh); + *ncm->ncm_CDC = *nh->nh_DummyNCM.ncm_CDC; + *ncm->ncm_CUC = *nh->nh_DummyNCM.ncm_CUC; + ncm->ncm_CUC->cuc_ChunkID = AROS_LONG2BE(MAKE_ID('L','U','N','0')+ncm->ncm_UnitLUN); + ncm->ncm_UsingDefaultCfg = TRUE; + + if(!(ps = OpenLibrary("poseidon.library", 4))) + { + return(FALSE); + } + + Forbid(); + /* Load config */ + pic = psdGetUsbDevCfg(libname, ncm->ncm_DevIDString, ncm->ncm_IfIDString); + if(pic) + { + cdc = psdGetCfgChunk(pic, ncm->ncm_CDC->cdc_ChunkID); + if(cdc) + { + CopyMem(((UBYTE *) cdc) + 8, ((UBYTE *) ncm->ncm_CDC) + 8, min(AROS_LONG2BE(cdc->cdc_Length), AROS_LONG2BE(ncm->ncm_CDC->cdc_Length))); + psdFreeVec(cdc); + ncm->ncm_UsingDefaultCfg = FALSE; + } + cuc = psdGetCfgChunk(pic, ncm->ncm_CUC->cuc_ChunkID); + if(cuc) + { + CopyMem(((UBYTE *) cuc) + 8, ((UBYTE *) ncm->ncm_CUC) + 8, min(AROS_LONG2BE(cuc->cuc_Length), AROS_LONG2BE(ncm->ncm_CUC->cuc_Length))); + psdFreeVec(cuc); + ncm->ncm_UsingDefaultCfg = FALSE; + } + } + Permit(); + CloseLibrary(ps); + return(FALSE); +} +/* \\\ */ + +/* /// "nOpenBindingCfgWindow()" */ +LONG nOpenBindingCfgWindow(struct NepMSBase *nh, struct NepClassMS *ncm) +{ + struct Library *ps; + KPRINTF(10, ("Opening GUI...\n")); + if(!(ps = OpenLibrary("poseidon.library", 4))) + { + return(FALSE); + } + Forbid(); + if(!ncm->ncm_GUITask) + { + if((ncm->ncm_GUITask = psdSpawnSubTask(MOD_NAME_STRING " GUI", nGUITask, ncm))) + { + Permit(); + CloseLibrary(ps); + return(TRUE); + } + } + Permit(); + CloseLibrary(ps); + return(FALSE); +} +/* \\\ */ + +/* /// "nStartRemovableTask()" */ +BOOL nStartRemovableTask(struct Library *ps, struct NepMSBase *nh) +{ + struct Task *tmptask; + ObtainSemaphore(&nh->nh_TaskLock); + if(nh->nh_RemovableTask) + { + ReleaseSemaphore(&nh->nh_TaskLock); + return(TRUE); + } + + nh->nh_ReadySignal = SIGB_SINGLE; + nh->nh_ReadySigTask = FindTask(NULL); + SetSignal(0, SIGF_SINGLE); + if((tmptask = psdSpawnSubTask(MOD_NAME_STRING " Removable Task", nRemovableTask, nh))) + { + psdBorrowLocksWait(tmptask, 1UL<nh_ReadySignal); + } + nh->nh_ReadySigTask = NULL; + //FreeSignal(nh->nh_ReadySignal); + if(nh->nh_RemovableTask) + { + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, + "Removable Task started."); + ReleaseSemaphore(&nh->nh_TaskLock); + return(TRUE); + } + ReleaseSemaphore(&nh->nh_TaskLock); + return(FALSE); +} +/* \\\ */ + +/**************************************************************************/ + +#undef ps +#define ps ncm->ncm_Base + +const STRPTR DeviceTypeStrings[] = +{ + "Direct Access", + "Sequential Access", + "Printer", + "Processor", + "Worm", + "CD/DVD ROM", + "Scanner", + "Optical", + "Medium Changer", + "Communications", + "Arts 1", + "Arts 2", + "RAID", + "Enclosure", + "Simple Direct Access", + "Optical Card", + "Reserved", + "Object Based" +}; + +UWORD PrimeTable[] = +{ + 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, + 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, + 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, + 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, + 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, + 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, + 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, + 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, + 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, + 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, + 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, + 953, 967, 971, 977, 983, 991, 997, 1009, 1013, 1019, 1021, 1031, 1033, + 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, 1093, 1097, 1103, 1109, + 1117, 1123, 1129, 1151, 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, + 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291, + 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, 1381, 1399, + 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, 1453, 1459, 1471, 1481, + 1483, 1487, 1489, 1493, 1499, 1511, 1523, 1531, 1543, 1549, 1553, 1559, + 1567, 1571, 1579, 1583, 1597, 1601, 1607, 1609, 1613, 1619, 1621, 1627, + 1637, 1657, 1663, 1667, 1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733, + 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, 1801, 1811, 1823, 1831, + 1847, 1861, 1867, 1871, 1873, 1877, 1879, 1889, 1901, 1907, 1913, 1931, + 1933, 1949, 1951, 1973, 1979, 1987, 1993, 1997, 1999, 0 +}; + +/* /// "nHexString()" */ +void nHexString(UBYTE *src, ULONG len, UBYTE *buf) +{ + static char *hexchars = "0123456789ABCDEF"; + UWORD cnt = 0; + + while(cnt < len) + { + if(cnt++) + { + *buf++ = ' '; + } + *buf++ = hexchars[*src>>4]; + *buf++ = hexchars[*src++ & 0xf]; + } + *buf = 0; +} +/* \\\ */ + +/* /// "nMSTask()" */ +AROS_UFH0(void, nMSTask) +{ + AROS_USERFUNC_INIT + + struct NepClassMS *ncm; + + ULONG sigmask; + ULONG sigs; + LONG ioerr; + struct PsdConfig *pc; + ULONG confignum; + UWORD cnt; + + struct IOStdReq *ioreq; + struct IOStdReq *ioreq2; + + struct SCSICmd scsicmd; + UBYTE inquirydata[36]; + //UBYTE buf[256]; + UBYTE cmd6[6]; + UBYTE sensedata[18]; + + if((ncm = nAllocMS())) + { + Forbid(); + if(ncm->ncm_ReadySigTask) + { + Signal(ncm->ncm_ReadySigTask, 1L<ncm_ReadySignal); + } + Permit(); + + if(ncm->ncm_CDC->cdc_PatchFlags) + { + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, + "Postconfig patchflags 0x%04lx%s%s%s%s%s%s%s%s%s%s%s%s%s%s.", + ncm->ncm_CDC->cdc_PatchFlags, + (ncm->ncm_CDC->cdc_PatchFlags & PFF_SINGLE_LUN) ? " SingleLun" : "", + (ncm->ncm_CDC->cdc_PatchFlags & PFF_MODE_XLATE) ? " ModeXLate" : "", + (ncm->ncm_CDC->cdc_PatchFlags & PFF_EMUL_LARGE_BLK) ? " EmulLarge" : "", + (ncm->ncm_CDC->cdc_PatchFlags & PFF_REM_SUPPORT) ? " RemSupport" : "", + (ncm->ncm_CDC->cdc_PatchFlags & PFF_FIX_INQ36) ? " FixInq36" : "", + (ncm->ncm_CDC->cdc_PatchFlags & PFF_DELAY_DATA) ? " DelayData" : "", + (ncm->ncm_CDC->cdc_PatchFlags & PFF_SIMPLE_SCSI) ? " SimpleSCSI" : "", + (ncm->ncm_CDC->cdc_PatchFlags & PFF_NO_RESET) ? " NoReset" : "", + (ncm->ncm_CDC->cdc_PatchFlags & PFF_FAKE_INQUIRY) ? " FakeInq" : "", + (ncm->ncm_CDC->cdc_PatchFlags & PFF_FIX_CAPACITY) ? " FixCapacity" : "", + (ncm->ncm_CDC->cdc_PatchFlags & PFF_NO_FALLBACK) ? " NoFallback" : "", + (ncm->ncm_CDC->cdc_PatchFlags & PFF_CSS_BROKEN) ? " CSSBroken" : "", + (ncm->ncm_CDC->cdc_PatchFlags & PFF_CLEAR_EP) ? " ClearEP" : "", + (ncm->ncm_CDC->cdc_PatchFlags & PFF_DEBUG) ? " Debug" : ""); + } + psdGetAttrs(PGA_INTERFACE, ncm->ncm_Interface, IFA_Config, &pc, TAG_END); + psdGetAttrs(PGA_CONFIG, pc, CA_ConfigNum, &confignum, TAG_END); + + if(ncm->ncm_CDC->cdc_StartupDelay) + { + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, + "Delaying init sequence by %ld00ms.", + ncm->ncm_CDC->cdc_StartupDelay); + + psdDelayMS(ncm->ncm_CDC->cdc_StartupDelay*100); + } + if(!(ncm->ncm_CDC->cdc_PatchFlags & PFF_NO_RESET)) + { + nLockXFer(ncm); + if(nBulkReset(ncm)) + { + if((!(ncm->ncm_CDC->cdc_PatchFlags & PFF_NO_FALLBACK)) && (!(ncm->ncm_CDC->cdc_PatchFlags & PFF_NO_RESET))) + { + ncm->ncm_CDC->cdc_PatchFlags |= PFF_NO_RESET; + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "Fallback: Enabling No Reset."); + nStoreConfig(ncm); + } + } + nUnlockXFer(ncm); + } + + ncm->ncm_UnitReady = FALSE; + ncm->ncm_Removable = TRUE; + ncm->ncm_DenyRequests = FALSE; + + scsicmd.scsi_Data = (UWORD *) inquirydata; + scsicmd.scsi_Length = 36; + scsicmd.scsi_Command = cmd6; + scsicmd.scsi_CmdLength = 6; + scsicmd.scsi_Flags = SCSIF_READ|SCSIF_AUTOSENSE|0x80; + scsicmd.scsi_SenseData = sensedata; + scsicmd.scsi_SenseLength = 18; + cmd6[0] = SCSI_INQUIRY; + cmd6[1] = 0; + cmd6[2] = 0; + cmd6[3] = 0; + cmd6[4] = 36; + cmd6[5] = 0; + if((ioerr = nScsiDirect(ncm, &scsicmd))) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "SCSI_INQUIRY failed: %ld", + ioerr); + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "Try increasing the startup delay value or fake inquiry."); + } else { + strncpy(ncm->ncm_LUNIDStr, &inquirydata[16], 16); + // trim spaces + cnt = strlen(ncm->ncm_LUNIDStr); + while(cnt--) + { + if(ncm->ncm_LUNIDStr[cnt] == ' ') + { + ncm->ncm_LUNIDStr[cnt] = 0; + } else { + break; + } + } + + ncm->ncm_DeviceType = inquirydata[0] & PDT_MASK; + if(ncm->ncm_DeviceType > 0x11) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, "Illegal Device Type %02lx", ncm->ncm_DeviceType); + ncm->ncm_DeviceType = 0; + } else { + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, "Device '%s' is of %s type.", ncm->ncm_LUNIDStr, DeviceTypeStrings[ncm->ncm_DeviceType]); + } + if((ncm->ncm_DeviceType == PDT_WORM) || + (ncm->ncm_DeviceType == PDT_CDROM)) + { + // assume 2048 byte blocks + ncm->ncm_BlockSize = 2048; + ncm->ncm_BlockShift = 11; + if(ncm->ncm_CDC->cdc_NakTimeout == 50) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, "Silently increasing NAK Timeout value to 15 seconds for CD/DVD drives..."); + ncm->ncm_CDC->cdc_NakTimeout = 150; + nStoreConfig(ncm); + + psdSetAttrs(PGA_PIPE, ncm->ncm_EP0Pipe, + PPA_NakTimeout, TRUE, + PPA_NakTimeoutTime, (ncm->ncm_CDC->cdc_NakTimeout+1)*100, + TAG_END); + psdSetAttrs(PGA_PIPE, ncm->ncm_EPInPipe, + PPA_NakTimeout, TRUE, + PPA_NakTimeoutTime, ncm->ncm_CDC->cdc_NakTimeout*100, + TAG_END); + psdSetAttrs(PGA_PIPE, ncm->ncm_EPOutPipe, + PPA_NakTimeout, TRUE, + PPA_NakTimeoutTime, ncm->ncm_CDC->cdc_NakTimeout*100, + TAG_END); + } + else if(!ncm->ncm_CDC->cdc_NakTimeout) + { + // that's okay, nak timeout disabled + } + else if(ncm->ncm_CDC->cdc_NakTimeout < 150) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, "NAK Timeout should be at least 15 seconds for CD/DVD drives!"); + } + } + + if(!(inquirydata[1] & 0x80)) + { + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, "Device does not seem to use removable media."); + ncm->ncm_Removable = FALSE; + ncm->ncm_UnitReady = TRUE; + ncm->ncm_ChangeCount++; + } + } + + /* Main task */ + sigmask = (1L<ncm_Unit.unit_MsgPort.mp_SigBit)| + (1L<ncm_TaskMsgPort->mp_SigBit)| + SIGBREAKF_CTRL_C; + if(ncm->ncm_CSType == MS_UFI_SUBCLASS) + { + struct IOStdReq tmpio; + tmpio.io_Command = CMD_START; + nStartStop(ncm, &tmpio); + } + + // if not removable, call it once to trigger mounting... + if(!ncm->ncm_Removable) + { + ncm->ncm_ForceRTCheck = TRUE; + } + ncm->ncm_Running = TRUE; + + do + { + if(ncm->ncm_Removable || ncm->ncm_ForceRTCheck) + { + nStartRemovableTask(ps, ncm->ncm_ClsBase); + ncm->ncm_ForceRTCheck = FALSE; + } + while((ioreq = (struct IOStdReq *) GetMsg(&ncm->ncm_Unit.unit_MsgPort))) + { + KPRINTF(5, ("command ioreq: 0x%08lx cmd: %lu len: %ld\n", + ioreq, ioreq->io_Command, ioreq->io_Length)); + + switch(ioreq->io_Command) + { + case TD_GETGEOMETRY: + nGetGeometry(ncm, ioreq); + ReplyMsg((struct Message *) ioreq); + break; + + case TD_EJECT: + case CMD_START: + case CMD_STOP: + nStartStop(ncm, ioreq); + ReplyMsg((struct Message *) ioreq); + break; + + case CMD_READ: + ioreq->io_Actual = 0; + case NSCMD_TD_READ64: + case TD_READ64: + nRead64(ncm, ioreq); + ReplyMsg((struct Message *) ioreq); + break; + + case TD_SEEK: + ioreq->io_Actual = 0; + case NSCMD_TD_SEEK64: + case TD_SEEK64: + nSeek64(ncm, ioreq); + ReplyMsg((struct Message *) ioreq); + break; + + case TD_FORMAT: + case CMD_WRITE: + ioreq->io_Actual = 0; + case NSCMD_TD_FORMAT64: + case NSCMD_TD_WRITE64: + case TD_FORMAT64: + case TD_WRITE64: + nWrite64(ncm, ioreq); + ReplyMsg((struct Message *) ioreq); + break; + + case HD_SCSICMD: + ioreq->io_Error = nScsiDirect(ncm, ioreq->io_Data); + ReplyMsg((struct Message *) ioreq); + break; + + case CMD_RESET: + if((ioreq2 = ncm->ncm_XFerPending)) + { + ncm->ncm_XFerPending = NULL; + ioreq2->io_Error = IOERR_ABORTED; + ReplyMsg((struct Message *) ioreq2); + } + /* Reset does a flush too */ + case CMD_FLUSH: + ioreq2 = (struct IOStdReq *) ncm->ncm_XFerQueue.lh_Head; + while(ioreq2->io_Message.mn_Node.ln_Succ) + { + Remove((struct Node *) ioreq2); + ioreq2->io_Error = IOERR_ABORTED; + ReplyMsg((struct Message *) ioreq2); + ioreq2 = (struct IOStdReq *) ncm->ncm_XFerQueue.lh_Head; + } + ReplyMsg((struct Message *) ioreq); + break; + + default: + ioreq->io_Error = IOERR_NOCMD; + ReplyMsg((struct Message *) ioreq); + break; + } + } + sigs = Wait(sigmask); + } while(!(sigs & SIGBREAKF_CTRL_C)); + ncm->ncm_DenyRequests = TRUE; + /* Device ejected */ + ncm->ncm_UnitReady = FALSE; + ncm->ncm_ChangeCount++; + ioreq = (struct IOStdReq *) ncm->ncm_DCInts.lh_Head; + while(((struct Node *) ioreq)->ln_Succ) + { + Cause(ioreq->io_Data); + ioreq = (struct IOStdReq *) ((struct Node *) ioreq)->ln_Succ; + } + if(!ncm->ncm_Removable) + { + nStartRemovableTask(ps, ncm->ncm_ClsBase); + } + KPRINTF(20, ("Going down the river!\n")); + nFreeMS(ncm); + } + AROS_USERFUNC_EXIT +} +/* \\\ */ + +/* /// "nAllocMS()" */ +struct NepClassMS * nAllocMS(void) +{ + struct Task *thistask; + struct NepClassMS *ncm; + ULONG epnum; + + thistask = FindTask(NULL); + ncm = thistask->tc_UserData; + do + { + if(!(ncm->ncm_Base = OpenLibrary("poseidon.library", 4))) + { + Alert(AG_OpenLib); + break; + } + ncm->ncm_EPInt = psdFindEndpoint(ncm->ncm_Interface, NULL, + EA_IsIn, TRUE, + EA_TransferType, USEAF_INTERRUPT, + TAG_END); + ncm->ncm_EPIn = psdFindEndpoint(ncm->ncm_Interface, NULL, + EA_IsIn, TRUE, + EA_TransferType, USEAF_BULK, + TAG_END); + ncm->ncm_EPOut = psdFindEndpoint(ncm->ncm_Interface, NULL, + EA_IsIn, FALSE, + EA_TransferType, USEAF_BULK, + TAG_END); + if(!(ncm->ncm_EPIn && ncm->ncm_EPOut)) + { + psdAddErrorMsg(RETURN_FAIL, (STRPTR) libname, "IN or OUT endpoint missing!"); + break; + } + if((!ncm->ncm_EPInt) && (ncm->ncm_TPType == MS_PROTO_CBI)) + { + psdAddErrorMsg(RETURN_FAIL, (STRPTR) libname, "INT endpoint missing!"); + break; + } else { + psdGetAttrs(PGA_ENDPOINT, ncm->ncm_EPOut, + EA_EndpointNum, &epnum, + TAG_END); + ncm->ncm_EPIntNum = epnum; + } + psdGetAttrs(PGA_ENDPOINT, ncm->ncm_EPIn, + EA_EndpointNum, &epnum, + TAG_END); + ncm->ncm_EPInNum = epnum; + psdGetAttrs(PGA_ENDPOINT, ncm->ncm_EPOut, + EA_EndpointNum, &epnum, + TAG_END); + ncm->ncm_EPOutNum = epnum; + + ncm->ncm_BulkResetBorks = FALSE; + ncm->ncm_GeoChangeCount = 0xffffffff; + + ncm->ncm_Unit.unit_MsgPort.mp_SigBit = AllocSignal(-1); + ncm->ncm_Unit.unit_MsgPort.mp_SigTask = thistask; + ncm->ncm_Unit.unit_MsgPort.mp_Node.ln_Type = NT_MSGPORT; + ncm->ncm_Unit.unit_MsgPort.mp_Flags = PA_SIGNAL; + ncm->ncm_XFerPending = NULL; + if((ncm->ncm_TaskMsgPort = CreateMsgPort())) + { + if((ncm->ncm_EP0Pipe = psdAllocPipe(ncm->ncm_Device, ncm->ncm_TaskMsgPort, NULL))) + { + if((ncm->ncm_EPOutPipe = psdAllocPipe(ncm->ncm_Device, ncm->ncm_TaskMsgPort, ncm->ncm_EPOut))) + { + if((ncm->ncm_EPInPipe = psdAllocPipe(ncm->ncm_Device, ncm->ncm_TaskMsgPort, ncm->ncm_EPIn))) + { + if(ncm->ncm_CDC->cdc_NakTimeout) + { + psdSetAttrs(PGA_PIPE, ncm->ncm_EP0Pipe, + PPA_NakTimeout, TRUE, + PPA_NakTimeoutTime, (ncm->ncm_CDC->cdc_NakTimeout+1)*100, + TAG_END); + psdSetAttrs(PGA_PIPE, ncm->ncm_EPInPipe, + PPA_NakTimeout, TRUE, + PPA_NakTimeoutTime, ncm->ncm_CDC->cdc_NakTimeout*100, + TAG_END); + psdSetAttrs(PGA_PIPE, ncm->ncm_EPOutPipe, + PPA_NakTimeout, TRUE, + PPA_NakTimeoutTime, ncm->ncm_CDC->cdc_NakTimeout*100, + TAG_END); + } + psdSetAttrs(PGA_PIPE, ncm->ncm_EPOutPipe, + PPA_NoShortPackets, TRUE, + TAG_END); + if(ncm->ncm_EPInt) + { + if((ncm->ncm_EPIntPipe = psdAllocPipe(ncm->ncm_Device, ncm->ncm_TaskMsgPort, ncm->ncm_EPInt))) + { + if(ncm->ncm_CDC->cdc_NakTimeout) + { + psdSetAttrs(PGA_PIPE, ncm->ncm_EPIntPipe, + PPA_NakTimeout, TRUE, + PPA_NakTimeoutTime, ncm->ncm_CDC->cdc_NakTimeout*100, + TAG_END); + } + ncm->ncm_Task = thistask; + return(ncm); + } + } else { + ncm->ncm_Task = thistask; + return(ncm); + } + psdFreePipe(ncm->ncm_EPInPipe); + } + psdFreePipe(ncm->ncm_EPOutPipe); + } + psdFreePipe(ncm->ncm_EP0Pipe); + } + DeleteMsgPort(ncm->ncm_TaskMsgPort); + } + FreeSignal((LONG) ncm->ncm_Unit.unit_MsgPort.mp_SigBit); + } while(FALSE); + CloseLibrary(ncm->ncm_Base); + Forbid(); + ncm->ncm_Task = NULL; + if(ncm->ncm_ReadySigTask) + { + Signal(ncm->ncm_ReadySigTask, 1L<ncm_ReadySignal); + } + return(NULL); +} +/* \\\ */ + +/* /// "nFreeMS()" */ +void nFreeMS(struct NepClassMS *ncm) +{ + struct IOStdReq *ioreq; + /* Disable the message port, messages may still be queued */ + Forbid(); + ncm->ncm_Unit.unit_MsgPort.mp_Flags = PA_IGNORE; + ncm->ncm_Unit.unit_MsgPort.mp_SigTask = NULL; + FreeSignal((LONG) ncm->ncm_Unit.unit_MsgPort.mp_SigBit); + // get rid of all messages that still have appeared here + while((ioreq = (struct IOStdReq *) GetMsg(&ncm->ncm_Unit.unit_MsgPort))) + { + ioreq->io_Error = IOERR_ABORTED; + ReplyMsg((struct Message *) ioreq); + } + Permit(); + + psdFreePipe(ncm->ncm_EPIntPipe); + psdFreePipe(ncm->ncm_EPInPipe); + psdFreePipe(ncm->ncm_EPOutPipe); + psdFreePipe(ncm->ncm_EP0Pipe); + DeleteMsgPort(ncm->ncm_TaskMsgPort); + + psdFreeVec(ncm->ncm_OneBlock); + ncm->ncm_OneBlock = NULL; + ncm->ncm_OneBlockSize = 0; + + CloseLibrary(ncm->ncm_Base); + Forbid(); + ncm->ncm_Task = NULL; + if(ncm->ncm_ReadySigTask) + { + Signal(ncm->ncm_ReadySigTask, 1L<ncm_ReadySignal); + } +} +/* \\\ */ + +/* /// "nGetModePage()" */ +UBYTE * nGetModePage(struct NepClassMS *ncm, UBYTE page) +{ + UBYTE cmd6[6]; + struct SCSICmd scsicmd; + UBYTE sensedata[18]; + LONG ioerr; + UBYTE *res; + ULONG pf; + + KPRINTF(10, ("page %ld\n", page)); + + memset(ncm->ncm_ModePageBuf, 0x00, 255); + scsicmd.scsi_Data = (UWORD *) ncm->ncm_ModePageBuf; + scsicmd.scsi_Length = 255; + scsicmd.scsi_Command = cmd6; + scsicmd.scsi_CmdLength = 6; + scsicmd.scsi_Flags = SCSIF_READ|SCSIF_AUTOSENSE; + scsicmd.scsi_SenseData = sensedata; + scsicmd.scsi_SenseLength = 18; + cmd6[0] = SCSI_MODE_SENSE_6; + cmd6[1] = 0x00; /* no block descriptors */ + cmd6[2] = page; + cmd6[3] = 0; + cmd6[4] = 255; + cmd6[5] = 0; + if((ioerr = nScsiDirect(ncm, &scsicmd))) + { + KPRINTF(10, ("ioerr %ld\n", ioerr)); + pf = ncm->ncm_CDC->cdc_PatchFlags; + if(pf & PFF_DEBUG) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "SCSI_MODE_SENSE(0x%02lx) failed: %ld", + page, ioerr); + } + if((!(pf & PFF_NO_FALLBACK)) && (!(pf & PFF_MODE_XLATE)) && (ioerr == HFERR_Phase)) + { + ncm->ncm_CDC->cdc_PatchFlags |= PFF_MODE_XLATE; + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "Fallback: Enabling CMD6->CMD10."); + nStoreConfig(ncm); + } + else if((!(pf & PFF_NO_FALLBACK)) && (pf & PFF_MODE_XLATE) && (!(pf & PFF_SIMPLE_SCSI)) && (ioerr == HFERR_Phase)) + { + ncm->ncm_CDC->cdc_PatchFlags |= PFF_SIMPLE_SCSI; + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "Fallback: Enabling Simple SCSI."); + nStoreConfig(ncm); + } + return(NULL); + } + pf = ncm->ncm_CDC->cdc_PatchFlags; + res = ncm->ncm_ModePageBuf; + if((scsicmd.scsi_Actual < 6) || (scsicmd.scsi_Actual < res[3]+6)) + { + if(pf & PFF_DEBUG) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "SCSI_MODE_SENSE(0x%02lx) failed: only %ld returned", + page, scsicmd.scsi_Actual); + } + return(NULL); + } + if(pf & PFF_DEBUG) + { + UBYTE hexbuf[12*3+2]; + nHexString(res, 12, hexbuf); + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, "ModePage (%ld) header: %s...", scsicmd.scsi_Actual, hexbuf); + } + if(res[3]) + { + res += res[3]; + scsicmd.scsi_Actual -= res[3]; + } + res += 4; // skip mode header */ + scsicmd.scsi_Actual -= 4; + if((*res & 0x3f) != (page & 0x3f)) + { + if(pf & PFF_DEBUG) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "SCSI_MODE_SENSE(0x%02lx) failed: wrong page 0x%02lx returned", + page, *res); + } + return(NULL); + } + if(scsicmd.scsi_Actual < res[1]) + { + if(pf & PFF_DEBUG) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "SCSI_MODE_SENSE(0x%02lx) failed: page incomplete", + page); + } + return(NULL); + } + +#if 0 + if(*res & 0x40) /* subpage mode? */ + { + res += 2; + } +#endif + return(res); +} +/* \\\ */ + +/* /// "nGetBlockSize()" */ +LONG nGetBlockSize(struct NepClassMS *ncm) +{ + UBYTE cmd10[10]; + struct SCSICmd scsicmd; + UBYTE sensedata[18]; + ULONG capacity[2]; + LONG ioerr; + + scsicmd.scsi_Data = (UWORD *) capacity; + scsicmd.scsi_Length = 8; + scsicmd.scsi_Command = cmd10; + scsicmd.scsi_CmdLength = 10; + scsicmd.scsi_Flags = SCSIF_READ|SCSIF_AUTOSENSE; + scsicmd.scsi_SenseData = sensedata; + scsicmd.scsi_SenseLength = 18; + cmd10[0] = SCSI_DA_READ_CAPACITY; + cmd10[1] = 0; + cmd10[2] = 0; + cmd10[3] = 0; + cmd10[4] = 0; + cmd10[5] = 0; + cmd10[6] = 0; + cmd10[7] = 0; + cmd10[8] = 0; + cmd10[9] = 0; + if((ioerr = nScsiDirect(ncm, &scsicmd))) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "SCSI_READ_CAPACITY failed: %ld", + ioerr); + if(!ncm->ncm_BlockSize) + { + ncm->ncm_Geometry.dg_SectorSize = ncm->ncm_BlockSize = 512; + ncm->ncm_BlockShift = 9; + } + } else { + ncm->ncm_Geometry.dg_SectorSize = ncm->ncm_BlockSize = capacity[1]; + ncm->ncm_BlockShift = 0; + while((1<ncm_BlockShift) < ncm->ncm_BlockSize) + { + ncm->ncm_BlockShift++; + } + ncm->ncm_Geometry.dg_TotalSectors = capacity[0]+1; + } + return(ioerr); +} +/* \\\ */ + +/* /// "nFakeGeometry()" */ +void nFakeGeometry(struct NepClassMS *ncm, struct DriveGeometry *tddg) +{ + UWORD cnt; + ULONG primes[32]; + UWORD count[32]; + UWORD curpos; + UWORD curprime; + ULONG curprimesq; + ULONG remblks = tddg->dg_TotalSectors; + UWORD *primetblptr = PrimeTable; + UWORD totfactors; + UWORD factor; + ULONG remfact; + UWORD tries; + BOOL taken; + + if(!ncm->ncm_Geometry.dg_TotalSectors) + { + return; + } + KPRINTF(10, ("Faking geometry for %ld sectors\n", tddg->dg_TotalSectors)); + //psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, "Prime factorisation for %ld", remblks); + tddg->dg_DeviceType = ncm->ncm_DeviceType; + tddg->dg_Flags = ncm->ncm_Removable ? DGF_REMOVABLE : 0; + tddg->dg_BufMemType = MEMF_PUBLIC; + tddg->dg_Reserved = 0; + do + { + KPRINTF(10, ("Loop\n")); + // first prime is counted manually + *primes = 2; + *count = 0; + curpos = 0; + while(!(remblks & 1)) + { + (*count)++; + remblks >>= 1; + } + if(*count) + { + curpos++; + } + + primes[curpos] = 3; + count[curpos] = 0; + primetblptr = PrimeTable; + curprime = 3; + curprimesq = 9; + // abort if no primes can be found anymore + do + { + KPRINTF(10, ("remblks = %ld, curprime=%ld\n", remblks, curprime)); + if(remblks % curprime) + { + if(remblks >= curprimesq) + { + // it's a prime! + break; + } + if(count[curpos]) // prime at least once + { + // next prime + count[++curpos] = 0; + if(curpos == 31) // end of buffer reached + { + break; + } + } + // try next "prime" + if(*primetblptr) + { + // use lookup table for the first primes to 2000 + curprime = *primetblptr++; + } else { + // do it the hard way :-( + curprime += 2; + } + primes[curpos] = curprime; + curprimesq = curprime * curprime; + } else { + // factor found + count[curpos]++; + remblks /= curprime; + } + } while((remblks > 1) && (remblks >= curprime)); + if(count[curpos]) + { + curpos++; + } + if((remblks > 1) && curpos) + { + count[curpos] = 1; + primes[curpos++] = remblks; + } + KPRINTF(10, ("Priming done, %ld different primes\n", curpos)); + if(curpos) + { + break; + } + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, "FakeGeometry: Total number of blocks is a prime number!"); + if(ncm->ncm_CDC->cdc_PatchFlags & PFF_FIX_CAPACITY) + { + if(ncm->ncm_CDC->cdc_PatchFlags & PFF_NO_FALLBACK) + { + psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname, + "This is probably due to the Fix Capacity switch being enabled incorrectly. Please check this."); + return; + } else { + ncm->ncm_CDC->cdc_PatchFlags &= ~PFF_FIX_CAPACITY; + psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname, + "Fallback: Disabling Fix Capacity."); + nStoreConfig(ncm); + remblks = ++tddg->dg_TotalSectors; + } + } else { + if(!(ncm->ncm_CDC->cdc_PatchFlags & PFF_NO_FALLBACK)) + { + ncm->ncm_CDC->cdc_PatchFlags |= PFF_FIX_CAPACITY; + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "Fallback: Enabling Fix Capacity."); + nStoreConfig(ncm); + } else { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "Assuming Fix Capacity bug (total blocks instead of last block)!"); + } + remblks = --tddg->dg_TotalSectors; + } + } while(TRUE); + + totfactors = 0; + for(cnt = 0; cnt < curpos; cnt++) + { + totfactors += count[cnt]; + } + + // Rules: + // - We want at least blocks per track * heads >= 64 + // - We want heads * heads < blocks per track + // - We want blocks per track < cylinders + // - We want heads < 8 + // - We want blocks per track < 256 + // - The rest goes into cylinders + tddg->dg_TrackSectors = 1; + tddg->dg_Heads = 1; + remfact = tddg->dg_TotalSectors; + tries = 0; + while(totfactors) + { + KPRINTF(10, ("Totfactors %ld\n", totfactors)); + cnt = 0; + while(!count[cnt]) + { + cnt++; + if(cnt >= curpos) + { + cnt = 0; + } + } + taken = TRUE; + factor = primes[cnt]; + if((tddg->dg_TrackSectors * factor < 256) && + (tddg->dg_TrackSectors * factor < remfact)) + { + tddg->dg_TrackSectors *= factor; + remfact /= factor; + } + else if((tddg->dg_Heads * factor <= 16) && + (tddg->dg_Heads * tddg->dg_Heads * factor * factor < tddg->dg_TrackSectors)) + { + tddg->dg_Heads *= factor; + remfact /= factor; + } + else if((tddg->dg_Heads * tddg->dg_TrackSectors >= 64) || + (tries > curpos)) + { + // do nothing + } else { + taken = FALSE; + } + if(taken) + { + totfactors--; + count[cnt]--; + tries = 0; + } else { + tries++; + } + KPRINTF(10, ("Factor=%ld: Cylinders = %ld, Heads=%ld, TrackSectors=%ld, Blocks=%ld\n", + factor, remfact, tddg->dg_Heads, tddg->dg_TrackSectors, + tddg->dg_TotalSectors)); + + } + KPRINTF(10, ("Final: Cylinders = %ld, Heads=%ld, TrackSectors=%ld, Blocks=%ld\n", + remfact, tddg->dg_Heads, tddg->dg_TrackSectors, + tddg->dg_TotalSectors)); + + tddg->dg_Cylinders = remfact; + tddg->dg_CylSectors = tddg->dg_TrackSectors * tddg->dg_Heads; +} +/* \\\ */ + +struct CapacityData +{ + ULONG SectorCount; + ULONG SectorSize; +}; + +#define SERVICEACTION_CAPACITY16 0x10 + +/* /// "nGetGeometry()" */ +LONG nGetGeometry(struct NepClassMS *ncm, struct IOStdReq *ioreq) +{ + struct DriveGeometry *tddg; + ULONG length; + UBYTE cmd10[10]; + struct SCSICmd scsicmd; + struct CapacityData capacitydata; + UBYTE sensedata[18]; + LONG ioerr; + ULONG tmpval; + UBYTE *mpdata; + BOOL gotblks = FALSE; + BOOL gotcyl = FALSE; + BOOL gotheads = FALSE; + BOOL gotsect = FALSE; + BOOL gotcylsect = FALSE; + KPRINTF(10, ("\n")); + + ioreq->io_Error = 0; + ioreq->io_Actual = 0; + tddg = (struct DriveGeometry *) ioreq->io_Data; + if(!tddg) + { + ioreq->io_Error = TDERR_NotSpecified; + return(ioreq->io_Error); + } + length = min(ioreq->io_Length,sizeof(struct DriveGeometry)); + if((ncm->ncm_GeoChangeCount == ncm->ncm_ChangeCount) && ncm->ncm_Geometry.dg_TotalSectors) + { + // cached + memcpy(tddg,&ncm->ncm_Geometry, (size_t) length); + ioreq->io_Actual = length; + return(0); + } + + ncm->ncm_Geometry.dg_DeviceType = ncm->ncm_DeviceType; + ncm->ncm_Geometry.dg_Flags = ncm->ncm_Removable ? DGF_REMOVABLE : 0; + + /* + * Capacity10, 32bit Sectorcount + */ + scsicmd.scsi_Data = (UWORD *) &capacitydata; + scsicmd.scsi_Length = sizeof(capacitydata); + scsicmd.scsi_Command = cmd10; + scsicmd.scsi_CmdLength = 10; + scsicmd.scsi_Flags = SCSIF_READ|SCSIF_AUTOSENSE; + scsicmd.scsi_SenseData = sensedata; + scsicmd.scsi_SenseLength = 18; + cmd10[0] = SCSI_DA_READ_CAPACITY; + cmd10[1] = 0; + cmd10[2] = 0; + cmd10[3] = 0; + cmd10[4] = 0; + cmd10[5] = 0; + cmd10[6] = 0; + cmd10[7] = 0; + cmd10[8] = 0; + cmd10[9] = 0; + + if((ioerr = nScsiDirect(ncm, &scsicmd))) + { + KPRINTF(10, ("ioerr %ld\n",ioerr)); + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "SCSI_READ_CAPACITY failed: %ld", + ioerr); + /* + * memset(tddg,0,Length); + * The error should be enough + */ + return(ioreq->io_Error = ioerr); + } else { + /* + * 32Bit Totalsectors + * R.S. + */ + ncm->ncm_BlockSize = ncm->ncm_Geometry.dg_SectorSize = capacitydata.SectorSize; + ncm->ncm_Geometry.dg_TotalSectors = capacitydata.SectorCount + 1; + if(capacitydata.SectorCount == 0xffffffff) + { + ncm->ncm_Geometry.dg_TotalSectors--; // set to maximum + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "Capacity exceeds the maximum supported for 32 bit sector counts (usually >2TB)!"); + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "I/O operations will still work, but geometry and partitioning will be unreliable!"); + } + KPRINTF(10, ("blocksize %ld totalsectors %ld\n", ncm->ncm_BlockSize, ncm->ncm_Geometry.dg_TotalSectors)); + gotblks = TRUE; + if(ncm->ncm_CDC->cdc_PatchFlags & PFF_DEBUG) + { + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, + "Capacity: %ld blocks of %ld bytes", ncm->ncm_Geometry.dg_TotalSectors, ncm->ncm_Geometry.dg_SectorSize); + } + ncm->ncm_BlockShift = 0; + while((1<ncm_BlockShift) < ncm->ncm_BlockSize) + { + ncm->ncm_BlockShift++; + } + } + KPRINTF(10, ("PatchFlags 0x%lx DeviceType %ld\n",ncm->ncm_CDC->cdc_PatchFlags,ncm->ncm_DeviceType)); + + /* + * <10000 blocks should cover all kinds of weird floppies... + * Let's hope GetModePage works with these floppy controllers + * R.S. + */ + if((ncm->ncm_CDC->cdc_PatchFlags & PFF_SIMPLE_SCSI) && (ncm->ncm_Geometry.dg_TotalSectors > 10000)) + { + /* + * Just return a LBA layout + * R.S. + */ + ncm->ncm_Geometry.dg_Cylinders = 1; + ncm->ncm_Geometry.dg_CylSectors = ncm->ncm_Geometry.dg_TotalSectors; + ncm->ncm_Geometry.dg_Heads = 1; + ncm->ncm_Geometry.dg_TrackSectors = ncm->ncm_Geometry.dg_TotalSectors; + gotcyl = gotheads = gotsect = gotcylsect = TRUE; + } else { + if(!((ncm->ncm_CDC->cdc_PatchFlags & PFF_SIMPLE_SCSI) || + (ncm->ncm_DeviceType == PDT_WORM) || + (ncm->ncm_DeviceType == PDT_CDROM))) + { + KPRINTF(10, ("SIMPLE_SCSI or PDT_WORM/CDROM\n")); + // cd roms don't have valid or sensible capacity mode pages + if((mpdata = nGetModePage(ncm, 0x03))) + { + if((tmpval = (mpdata[10]<<8)+mpdata[11])) + { + ncm->ncm_Geometry.dg_TrackSectors = tmpval; + gotsect = TRUE; + if(!ncm->ncm_Geometry.dg_Cylinders) + { + ncm->ncm_Geometry.dg_Cylinders = ncm->ncm_Geometry.dg_TotalSectors; + } + } + if(ncm->ncm_CDC->cdc_PatchFlags & PFF_DEBUG) + { + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, + "Capacity: TrackSectors=%ld", + ncm->ncm_Geometry.dg_TrackSectors); + } + } + } + /* + * Cylinder and co are only defined for old 32Bit Totalsectors. + * >2TB they have no meaning anyway, so they are calculated based + * on 32Bit INT_MAX. + */ + // recheck, could have simple scsi enabled in the meanwhile + if(!((ncm->ncm_CDC->cdc_PatchFlags & PFF_SIMPLE_SCSI) || + (ncm->ncm_DeviceType == PDT_WORM) || + (ncm->ncm_DeviceType == PDT_CDROM))) + { + KPRINTF(10, ("recheck1 SIMPLE_SCSI or PDT_WORM/CDROM\n")); + if((mpdata = nGetModePage(ncm, 0x04))) + { + if((tmpval = (mpdata[2]<<16)+(mpdata[3]<<8)+mpdata[4])) + { + ncm->ncm_Geometry.dg_Cylinders = tmpval; + ncm->ncm_Geometry.dg_Heads = mpdata[5]; + gotcyl = gotheads = TRUE; + } + if(ncm->ncm_CDC->cdc_PatchFlags & PFF_DEBUG) + { + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, + "Capacity: Cylinders=%ld, Heads=%ld", + ncm->ncm_Geometry.dg_Cylinders, ncm->ncm_Geometry.dg_Heads); + } + } + } + // recheck, could have simple scsi enabled in the meanwhile + if(!((ncm->ncm_CDC->cdc_PatchFlags & PFF_SIMPLE_SCSI) || + (ncm->ncm_DeviceType == PDT_WORM) || + (ncm->ncm_DeviceType == PDT_CDROM))) + { + KPRINTF(10, ("recheck2 SIMPLE_SCSI or PDT_WORM/CDROM\n")); + if((mpdata = nGetModePage(ncm, 0x05))) + { + if((tmpval = (mpdata[8]<<8)+mpdata[9])) + { + ncm->ncm_Geometry.dg_Cylinders = tmpval; + ncm->ncm_Geometry.dg_Heads = mpdata[4]; + ncm->ncm_Geometry.dg_TrackSectors = mpdata[5]; + + gotcyl = gotheads = gotsect = TRUE; + + if(!gotblks) + { + ncm->ncm_BlockSize = ncm->ncm_Geometry.dg_SectorSize = (mpdata[6]<<8)+mpdata[7]; + ncm->ncm_BlockShift = 0; + while((1<ncm_BlockShift) < ncm->ncm_BlockSize) + { + ncm->ncm_BlockShift++; + } + if(ncm->ncm_CDC->cdc_PatchFlags & PFF_DEBUG) + { + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, + "Capacity: %ld blocks of %ld bytes", ncm->ncm_Geometry.dg_TotalSectors, ncm->ncm_BlockSize); + } + } + else if(ncm->ncm_BlockSize != (mpdata[6]<<8)+mpdata[7]) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "Inconsistent block size information %ld != %ld!", + ncm->ncm_BlockSize, (mpdata[6]<<8)+mpdata[7]); + } + if(ncm->ncm_CDC->cdc_PatchFlags & PFF_DEBUG) + { + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, + "Capacity: Cylinders=%ld, Heads=%ld, TrackSectors=%ld", + ncm->ncm_Geometry.dg_Cylinders, ncm->ncm_Geometry.dg_Heads, ncm->ncm_Geometry.dg_TrackSectors); + } + } + } + } + } + // missing total blocks? + if((!gotblks) && gotcyl && gotheads && gotsect) + { + ncm->ncm_Geometry.dg_TotalSectors = ncm->ncm_Geometry.dg_Cylinders * ncm->ncm_Geometry.dg_Heads * ncm->ncm_Geometry.dg_TrackSectors; + gotblks = TRUE; + } + // missing cylinders? + if(gotblks && (!gotcyl) && gotheads && gotsect) + { + ncm->ncm_Geometry.dg_Cylinders = ncm->ncm_Geometry.dg_TotalSectors / (ncm->ncm_Geometry.dg_Heads * ncm->ncm_Geometry.dg_TrackSectors); + gotcyl = TRUE; + } + // missing heads? + if(gotblks && gotcyl && (!gotheads) && gotsect) + { + ncm->ncm_Geometry.dg_Heads = ncm->ncm_Geometry.dg_TotalSectors / (ncm->ncm_Geometry.dg_Cylinders * ncm->ncm_Geometry.dg_TrackSectors); + gotheads = TRUE; + } + // missing tracks per sector + if(gotblks && gotcyl && gotheads && (!gotsect)) + { + ncm->ncm_Geometry.dg_TrackSectors = ncm->ncm_Geometry.dg_TotalSectors / (ncm->ncm_Geometry.dg_Cylinders * ncm->ncm_Geometry.dg_Heads); + gotsect = TRUE; + } + + if(gotblks && gotcyl && gotheads && gotsect && + (ncm->ncm_Geometry.dg_Cylinders * ncm->ncm_Geometry.dg_TrackSectors * ncm->ncm_Geometry.dg_Heads == ncm->ncm_Geometry.dg_TotalSectors - 1) && + (!(ncm->ncm_CDC->cdc_PatchFlags & PFF_FIX_CAPACITY))) + { + if(!(ncm->ncm_CDC->cdc_PatchFlags & PFF_NO_FALLBACK)) + { + ncm->ncm_CDC->cdc_PatchFlags |= PFF_FIX_CAPACITY; + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "Fallback: Enabling Fix Capacity."); + nStoreConfig(ncm); + ncm->ncm_Geometry.dg_TotalSectors--; + } else { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "Fix Capacity is probably needed for this device. Please check this."); + } + } + else if(gotblks && gotcyl && gotheads && gotsect && + (ncm->ncm_Geometry.dg_Cylinders * ncm->ncm_Geometry.dg_TrackSectors * ncm->ncm_Geometry.dg_Heads == ncm->ncm_Geometry.dg_TotalSectors + 1) && + ncm->ncm_CDC->cdc_PatchFlags & PFF_FIX_CAPACITY) + { + if(ncm->ncm_CDC->cdc_PatchFlags & PFF_NO_FALLBACK) + { + psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname, + "Fix Capacity is probably enabled incorrectly. Please check this."); + } else { + ncm->ncm_CDC->cdc_PatchFlags &= ~PFF_FIX_CAPACITY; + psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname, + "Fallback: Disabling Fix Capacity."); + nStoreConfig(ncm); + ncm->ncm_Geometry.dg_TotalSectors++; + } + } + + // some devices report these bogus values regardless of actual device capacity, though the total number of blocks is correct. + if(((ncm->ncm_Geometry.dg_Cylinders == 500) && (ncm->ncm_Geometry.dg_TrackSectors == 32) && (ncm->ncm_Geometry.dg_Heads == 8)) || + ((ncm->ncm_Geometry.dg_Cylinders == 16383) && (ncm->ncm_Geometry.dg_TrackSectors == 63) && (ncm->ncm_Geometry.dg_Heads == 16))) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, "Firmware returns known bogus geometry, will fall back to faked geometry!"); + gotheads = gotcyl = gotsect = FALSE; + if((ncm->ncm_CDC->cdc_PatchFlags & (PFF_SIMPLE_SCSI|PFF_NO_FALLBACK)) == PFF_SIMPLE_SCSI) + { + ncm->ncm_CDC->cdc_PatchFlags |= PFF_SIMPLE_SCSI; + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "Fallback: Enabling Simple SCSI."); + nStoreConfig(ncm); + } + } + + // missing more than one? + if(gotblks && (!(gotheads && gotcyl && gotsect))) + { + nFakeGeometry(ncm, &ncm->ncm_Geometry); + } + if(!gotcylsect) + { + ncm->ncm_Geometry.dg_CylSectors = ncm->ncm_Geometry.dg_TrackSectors * ncm->ncm_Geometry.dg_Heads; + } + + if(ncm->ncm_Geometry.dg_Cylinders * ncm->ncm_Geometry.dg_CylSectors != ncm->ncm_Geometry.dg_TotalSectors) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "Estimated Geometry yields %ld less total blocks %ld: Cylinders=%ld, CylSectors=%ld, Heads=%ld, TrackSectors=%ld, Blocks=%ld", + ncm->ncm_Geometry.dg_TotalSectors - ncm->ncm_Geometry.dg_Cylinders * ncm->ncm_Geometry.dg_CylSectors, + ncm->ncm_Geometry.dg_Cylinders * ncm->ncm_Geometry.dg_CylSectors, + ncm->ncm_Geometry.dg_Cylinders, ncm->ncm_Geometry.dg_CylSectors, ncm->ncm_Geometry.dg_Heads, ncm->ncm_Geometry.dg_TrackSectors, + ncm->ncm_Geometry.dg_TotalSectors); + } + else if(ncm->ncm_CDC->cdc_PatchFlags & PFF_DEBUG) + { + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, + "Capacity: Cylinders=%ld, CylSectors=%ld, Heads=%ld, TrackSectors=%ld, Blocks=%ld, SectorSize=%ld", + ncm->ncm_Geometry.dg_Cylinders, ncm->ncm_Geometry.dg_CylSectors, ncm->ncm_Geometry.dg_Heads, ncm->ncm_Geometry.dg_TrackSectors, + ncm->ncm_Geometry.dg_TotalSectors, ncm->ncm_Geometry.dg_SectorSize); + } + + ncm->ncm_Geometry.dg_BufMemType = MEMF_PUBLIC; + ncm->ncm_Geometry.dg_Reserved = 0; + memcpy(tddg, &ncm->ncm_Geometry, (size_t) length); + ioreq->io_Actual = length; + ncm->ncm_GeoChangeCount = ncm->ncm_ChangeCount; + return(ioreq->io_Error); +} +/* \\\ */ + +/* /// "nStartStop()" */ +LONG nStartStop(struct NepClassMS *ncm, struct IOStdReq *ioreq) +{ + UBYTE cmd6[6]; + struct SCSICmd scsicmd; + UBYTE sensedata[18]; + LONG ioerr; + + if(ncm->ncm_CDC->cdc_PatchFlags & PFF_SIMPLE_SCSI) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, "Simple SCSI: Ignoring START_STOP_UNIT command"); + return(0); + } + scsicmd.scsi_Data = NULL; + scsicmd.scsi_Length = 0; + scsicmd.scsi_Command = cmd6; + scsicmd.scsi_CmdLength = 6; + scsicmd.scsi_Flags = SCSIF_AUTOSENSE|0x80; + scsicmd.scsi_SenseData = sensedata; + scsicmd.scsi_SenseLength = 18; + cmd6[0] = SCSI_DA_START_STOP_UNIT; + cmd6[1] = 0; + cmd6[2] = 0; + cmd6[3] = 0; + switch(ioreq->io_Command) + { + case CMD_START: + cmd6[4] = 0x01; + break; + + case CMD_STOP: + cmd6[4] = 0x00; + break; + + case TD_EJECT: + cmd6[4] = ioreq->io_Length ? 0x03 : 0x02; + break; + } + cmd6[5] = 0; + if((ioerr = nScsiDirect(ncm, &scsicmd))) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "START_STOP_UNIT failed: %ld", + ioerr); + ioreq->io_Error = TDERR_NotSpecified; + } + return(ioreq->io_Error); +} +/* \\\ */ + +/* /// "nRead64Emul()" */ +LONG nRead64Emul(struct NepClassMS *ncm, struct IOStdReq *ioreq) +{ + UBYTE cmd10[10]; + UBYTE sensedata[18]; + ULONG dataoffset = 0; + ULONG dataremain = ioreq->io_Length; + ULONG datalen; + ULONG startblock; + ULONG maxtrans = 1UL<<(ncm->ncm_CDC->cdc_MaxTransfer+16); + ULONG insideblockoffset; + struct SCSICmd scsicmd; + + if(dataremain & 511) + { + psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname, + "Attempt to read partial block (%ld %% %ld != 0)!", + dataremain, ncm->ncm_BlockSize); + ioreq->io_Actual = 0; + return(ioreq->io_Error = IOERR_BADLENGTH); + } + if(ioreq->io_Offset & 511) + { + psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname, + "Attempt to read unaligned block (%ld %% %ld != 0)!", + ioreq->io_Offset, ncm->ncm_BlockSize); + ioreq->io_Actual = 0; + return(ioreq->io_Error = IOERR_BADADDRESS); + } + + if(!ncm->ncm_OneBlock || (ncm->ncm_OneBlockSize < ncm->ncm_BlockSize)) + { + psdFreeVec(ncm->ncm_OneBlock); + if(!(ncm->ncm_OneBlock = psdAllocVec(ncm->ncm_BlockSize))) + { + return(IOERR_BADADDRESS); + } + ncm->ncm_OneBlockSize = ncm->ncm_BlockSize; + } + + startblock = (ioreq->io_Offset>>ncm->ncm_BlockShift)|(ioreq->io_Actual<<(32-ncm->ncm_BlockShift)); + insideblockoffset = (ioreq->io_Offset & ((1<ncm_BlockShift)-1)); + while(dataremain) + { + KPRINTF(10, ("Reading from block %ld, %ld bytes left...\n", startblock, dataremain)); + datalen = dataremain; + if(datalen > maxtrans) + { + datalen = maxtrans; + } + if(insideblockoffset || (datalen < ncm->ncm_BlockSize)) + { + if(datalen > ncm->ncm_BlockSize-insideblockoffset) + { + datalen = ncm->ncm_BlockSize-insideblockoffset; + } + scsicmd.scsi_Data = (UWORD *) ncm->ncm_OneBlock; + scsicmd.scsi_Length = ncm->ncm_BlockSize; + scsicmd.scsi_Command = cmd10; + scsicmd.scsi_CmdLength = 10; + scsicmd.scsi_Flags = SCSIF_READ|SCSIF_AUTOSENSE|0x80; + scsicmd.scsi_SenseData = sensedata; + scsicmd.scsi_SenseLength = 18; + cmd10[0] = SCSI_DA_READ_10; + cmd10[1] = 0; + *((ULONG *) (&cmd10[2])) = startblock; + cmd10[6] = 0; + cmd10[7] = 0; + cmd10[8] = 1; + cmd10[9] = 0; + if((ioreq->io_Error = nScsiDirect(ncm, &scsicmd))) + { + KPRINTF(10, ("Read error!\n")); + break; + } + CopyMemQuick(&ncm->ncm_OneBlock[insideblockoffset], &(((UBYTE *) ioreq->io_Data)[dataoffset]), datalen); + insideblockoffset = 0; + startblock++; + } else { + scsicmd.scsi_Data = (UWORD *) &(((UBYTE *) ioreq->io_Data)[dataoffset]); + scsicmd.scsi_Length = datalen; + scsicmd.scsi_Command = cmd10; + scsicmd.scsi_CmdLength = 10; + scsicmd.scsi_Flags = SCSIF_READ|SCSIF_AUTOSENSE|0x80; + scsicmd.scsi_SenseData = sensedata; + scsicmd.scsi_SenseLength = 18; + cmd10[0] = SCSI_DA_READ_10; + cmd10[1] = 0; + *((ULONG *) (&cmd10[2])) = startblock; + cmd10[6] = 0; + cmd10[7] = datalen>>(ncm->ncm_BlockShift+8); + cmd10[8] = datalen>>ncm->ncm_BlockShift; + cmd10[9] = 0; + if((ioreq->io_Error = nScsiDirect(ncm, &scsicmd))) + { + KPRINTF(10, ("Read error!\n")); + break; + } + startblock += (insideblockoffset+datalen)>>ncm->ncm_BlockShift; + } + dataoffset += datalen; + dataremain -= datalen; + } + ioreq->io_Actual = dataoffset; + return(ioreq->io_Error); +} +/* \\\ */ + +/* /// "nWrite64Emul()" */ +LONG nWrite64Emul(struct NepClassMS *ncm, struct IOStdReq *ioreq) +{ + UBYTE cmd10[10]; + UBYTE sensedata[18]; + ULONG dataoffset = 0; + ULONG dataremain = ioreq->io_Length; + ULONG datalen; + ULONG startblock; + ULONG maxtrans = 1UL<<(ncm->ncm_CDC->cdc_MaxTransfer+16); + ULONG insideblockoffset; + struct SCSICmd scsicmd; + + if(dataremain & 511) + { + psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname, + "Attempt to write partial block (%ld %% %ld != 0)!", + dataremain, ncm->ncm_BlockSize); + ioreq->io_Actual = 0; + return(ioreq->io_Error = IOERR_BADLENGTH); + } + if(ioreq->io_Offset & 511) + { + psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname, + "Attempt to write unaligned block (%ld %% %ld != 0)!", + ioreq->io_Offset, ncm->ncm_BlockSize); + ioreq->io_Actual = 0; + return(ioreq->io_Error = IOERR_BADADDRESS); + } + + if(!ncm->ncm_OneBlock || (ncm->ncm_OneBlockSize < ncm->ncm_BlockSize)) + { + psdFreeVec(ncm->ncm_OneBlock); + if(!(ncm->ncm_OneBlock = psdAllocVec(ncm->ncm_BlockSize))) + { + return(IOERR_BADADDRESS); + } + ncm->ncm_OneBlockSize = ncm->ncm_BlockSize; + } + + startblock = (ioreq->io_Offset>>ncm->ncm_BlockShift)|(ioreq->io_Actual<<(32-ncm->ncm_BlockShift)); + insideblockoffset = (ioreq->io_Offset & ((1<ncm_BlockShift)-1)); + while(dataremain) + { + KPRINTF(10, ("Writing from block %ld, %ld bytes left...\n", startblock, dataremain)); + datalen = dataremain; + if(datalen > maxtrans) + { + datalen = maxtrans; + } + if(insideblockoffset || (datalen < ncm->ncm_BlockSize)) + { + if(datalen > ncm->ncm_BlockSize-insideblockoffset) + { + datalen = ncm->ncm_BlockSize-insideblockoffset; + } + scsicmd.scsi_Data = (UWORD *) ncm->ncm_OneBlock; + scsicmd.scsi_Length = ncm->ncm_BlockSize; + scsicmd.scsi_Command = cmd10; + scsicmd.scsi_CmdLength = 10; + scsicmd.scsi_Flags = SCSIF_READ|SCSIF_AUTOSENSE|0x80; + scsicmd.scsi_SenseData = sensedata; + scsicmd.scsi_SenseLength = 18; + cmd10[0] = SCSI_DA_READ_10; + cmd10[1] = 0; + *((ULONG *) (&cmd10[2])) = startblock; + cmd10[6] = 0; + cmd10[7] = 0; + cmd10[8] = 1; + cmd10[9] = 0; + if((ioreq->io_Error = nScsiDirect(ncm, &scsicmd))) + { + KPRINTF(10, ("Read error!\n")); + break; + } + CopyMemQuick(&(((UBYTE *) ioreq->io_Data)[dataoffset]), &ncm->ncm_OneBlock[insideblockoffset], datalen); + + //scsicmd.scsi_Data = (UWORD *) ncm->ncm_OneBlock; + //scsicmd.scsi_Length = ncm->ncm_BlockSize; + //scsicmd.scsi_Command = cmd10; + //scsicmd.scsi_CmdLength = 10; + scsicmd.scsi_Flags = SCSIF_WRITE|SCSIF_AUTOSENSE|0x80; + //scsicmd.scsi_SenseData = sensedata; + //scsicmd.scsi_SenseLength = 18; + cmd10[0] = SCSI_DA_WRITE_10; + //cmd10[1] = 0; + //*((ULONG *) (&cmd10[2])) = startblock; + //cmd10[6] = 0; + //cmd10[7] = 0; + //cmd10[8] = 1; + //cmd10[9] = 0; + if((ioreq->io_Error = nScsiDirect(ncm, &scsicmd))) + { + KPRINTF(10, ("Write error!\n")); + break; + } + insideblockoffset = 0; + startblock++; + } else { + scsicmd.scsi_Data = (UWORD *) &(((UBYTE *) ioreq->io_Data)[dataoffset]); + scsicmd.scsi_Length = datalen; + scsicmd.scsi_Command = cmd10; + scsicmd.scsi_CmdLength = 10; + scsicmd.scsi_Flags = SCSIF_WRITE|SCSIF_AUTOSENSE|0x80; + scsicmd.scsi_SenseData = sensedata; + scsicmd.scsi_SenseLength = 18; + cmd10[0] = SCSI_DA_WRITE_10; + cmd10[1] = 0; + *((ULONG *) (&cmd10[2])) = startblock; + cmd10[6] = 0; + cmd10[7] = datalen>>(ncm->ncm_BlockShift+8); + cmd10[8] = datalen>>ncm->ncm_BlockShift; + cmd10[9] = 0; + if((ioreq->io_Error = nScsiDirect(ncm, &scsicmd))) + { + KPRINTF(10, ("Write error!\n")); + break; + } + startblock += (insideblockoffset+datalen)>>ncm->ncm_BlockShift; + } + dataoffset += datalen; + dataremain -= datalen; + } + ioreq->io_Actual = dataoffset; + return(ioreq->io_Error); +} +/* \\\ */ + +/* /// "nRead64()" */ +LONG nRead64(struct NepClassMS *ncm, struct IOStdReq *ioreq) +{ + UBYTE cmd10[10]; + UBYTE cmd16[16]; + UBYTE sensedata[18]; + ULONG dataoffset = 0; + ULONG dataremain = ioreq->io_Length; + ULONG datalen; + ULONG startblockhigh; + ULONG startblock; + ULONG oldstartblock; + ULONG maxtrans = 1UL<<(ncm->ncm_CDC->cdc_MaxTransfer+16); + struct SCSICmd scsicmd; + + if(!ncm->ncm_BlockSize) + { + nGetBlockSize(ncm); + } + if(((dataremain >> ncm->ncm_BlockShift)<ncm_BlockShift != dataremain) || + ((ioreq->io_Offset >> ncm->ncm_BlockShift)<ncm_BlockShift != ioreq->io_Offset)) + { + if((!(ncm->ncm_CDC->cdc_PatchFlags & PFF_EMUL_LARGE_BLK)) && (!(ncm->ncm_CDC->cdc_PatchFlags & PFF_NO_FALLBACK))) + { + ncm->ncm_CDC->cdc_PatchFlags |= PFF_EMUL_LARGE_BLK; + psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname, + "Fallback: Enabling emulation for large block devices."); + nStoreConfig(ncm); + } + if(ncm->ncm_CDC->cdc_PatchFlags & PFF_EMUL_LARGE_BLK) + { + return(nRead64Emul(ncm, ioreq)); + } + if((dataremain >> ncm->ncm_BlockShift)<ncm_BlockShift != dataremain) + { + psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname, + "Attempt to read partial block (%ld %% %ld != 0)!", + dataremain, ncm->ncm_BlockSize); + ioreq->io_Error = IOERR_BADLENGTH; + } else { + psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname, + "Attempt to read unaligned block (%ld %% %ld != 0)!", + ioreq->io_Offset, ncm->ncm_BlockSize); + ioreq->io_Error = IOERR_BADADDRESS; + } + if(ncm->ncm_BlockSize != 512) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "The used FileSystem or other software must support %ld byte blocks!", + ncm->ncm_BlockSize); + } + ioreq->io_Actual = 0; + return(ioreq->io_Error); + } + + startblockhigh = ioreq->io_Actual>>ncm->ncm_BlockShift; + startblock = (ioreq->io_Offset>>ncm->ncm_BlockShift)|(ioreq->io_Actual<<(32-ncm->ncm_BlockShift)); + while(dataremain) + { + KPRINTF(10, ("Reading from block %ld, %ld bytes left...\n", startblock, dataremain)); + datalen = dataremain; + if(datalen > maxtrans) + { + datalen = maxtrans; + } + scsicmd.scsi_Data = (UWORD *) &(((UBYTE *) ioreq->io_Data)[dataoffset]); + scsicmd.scsi_Length = datalen; + scsicmd.scsi_Flags = SCSIF_READ|SCSIF_AUTOSENSE|0x80; + scsicmd.scsi_SenseData = sensedata; + scsicmd.scsi_SenseLength = 18; + if(startblockhigh) + { + // Arithmetics for >2 TB needed + scsicmd.scsi_Command = cmd16; + scsicmd.scsi_CmdLength = 16; + cmd16[0] = SCSI_DA_READ_16; + cmd16[1] = 0; + *((ULONG *) (&cmd16[2])) = startblockhigh; + *((ULONG *) (&cmd16[6])) = startblock; + cmd16[10] = datalen>>(ncm->ncm_BlockShift+24); + cmd16[11] = datalen>>(ncm->ncm_BlockShift+16); + cmd16[12] = datalen>>(ncm->ncm_BlockShift+8); + cmd16[13] = datalen>>ncm->ncm_BlockShift; + cmd16[14] = 0; + cmd16[15] = 0; + } else { + scsicmd.scsi_Command = cmd10; + scsicmd.scsi_CmdLength = 10; + cmd10[0] = SCSI_DA_READ_10; + cmd10[1] = 0; + *((ULONG *) (&cmd10[2])) = startblock; + cmd10[6] = 0; + cmd10[7] = datalen>>(ncm->ncm_BlockShift+8); + cmd10[8] = datalen>>ncm->ncm_BlockShift; + cmd10[9] = 0; + } + if((ioreq->io_Error = nScsiDirect(ncm, &scsicmd))) + { + KPRINTF(10, ("Read error!\n")); + break; + } + dataoffset += datalen; + dataremain -= datalen; + oldstartblock = startblock; + startblock += datalen>>ncm->ncm_BlockShift; + if(startblock < oldstartblock) + { + // wrap around occurred + startblockhigh++; + } + } + ioreq->io_Actual = dataoffset; + return(ioreq->io_Error); +} +/* \\\ */ + +/* /// "nSeek64()" */ +LONG nSeek64(struct NepClassMS *ncm, struct IOStdReq *ioreq) +{ + UBYTE cmd10[10]; + UBYTE sensedata[18]; + struct SCSICmd scsicmd; + + if(!ncm->ncm_BlockSize) + { + nGetBlockSize(ncm); + } + if((ioreq->io_Offset >> ncm->ncm_BlockShift)<ncm_BlockShift != ioreq->io_Offset) + { + psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname, + "Attempt to to seek to unaligned block (%ld %% %ld != 0)!", + ioreq->io_Offset, ncm->ncm_BlockSize); + if(ncm->ncm_BlockSize != 512) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "The used FileSystem or other software must support %ld byte blocks!", + ncm->ncm_BlockSize); + } + ioreq->io_Actual = 0; + return(ioreq->io_Error = IOERR_BADADDRESS); + } + + scsicmd.scsi_Data = NULL; + scsicmd.scsi_Length = 0; + scsicmd.scsi_CmdLength = 10; + scsicmd.scsi_Flags = SCSIF_READ|SCSIF_AUTOSENSE|0x80; + scsicmd.scsi_SenseData = sensedata; + scsicmd.scsi_SenseLength = 18; + cmd10[0] = SCSI_DA_SEEK_10; + cmd10[1] = 0; + *((ULONG *) (&cmd10[2])) = (ioreq->io_Offset>>ncm->ncm_BlockShift)|(ioreq->io_Actual<<(32-ncm->ncm_BlockShift)); + cmd10[6] = 0; + cmd10[7] = 0; + cmd10[8] = 0; + cmd10[9] = 0; + if((ioreq->io_Error = nScsiDirect(ncm, &scsicmd))) + { + KPRINTF(10, ("Seek error!\n")); + } + ioreq->io_Actual = 0; + return(ioreq->io_Error); +} +/* \\\ */ + +/* /// "nWrite64()" */ +LONG nWrite64(struct NepClassMS *ncm, struct IOStdReq *ioreq) +{ + UBYTE cmd10[10]; + UBYTE cmd16[16]; + UBYTE sensedata[18]; + ULONG dataoffset = 0; + ULONG dataremain = ioreq->io_Length; + ULONG datalen; + ULONG startblockhigh; + ULONG startblock; + ULONG oldstartblock; + ULONG maxtrans = 1UL<<(ncm->ncm_CDC->cdc_MaxTransfer+16); + struct SCSICmd scsicmd; + + if(!ncm->ncm_BlockSize) + { + nGetBlockSize(ncm); + } + if(((dataremain >> ncm->ncm_BlockShift)<ncm_BlockShift != dataremain) || + ((ioreq->io_Offset >> ncm->ncm_BlockShift)<ncm_BlockShift != ioreq->io_Offset)) + { + if((!(ncm->ncm_CDC->cdc_PatchFlags & PFF_EMUL_LARGE_BLK)) && (!(ncm->ncm_CDC->cdc_PatchFlags & PFF_NO_FALLBACK))) + { + ncm->ncm_CDC->cdc_PatchFlags |= PFF_EMUL_LARGE_BLK; + psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname, + "Fallback: Enabling emulation for large block devices."); + nStoreConfig(ncm); + } + if(ncm->ncm_CDC->cdc_PatchFlags & PFF_EMUL_LARGE_BLK) + { + return(nWrite64Emul(ncm, ioreq)); + } + if((dataremain >> ncm->ncm_BlockShift)<ncm_BlockShift != dataremain) + { + psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname, + "Attempt to write partial block (%ld %% %ld != 0)!", + dataremain, ncm->ncm_BlockSize); + ioreq->io_Error = IOERR_BADLENGTH; + } else { + psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname, + "Attempt to write unaligned block (%ld %% %ld != 0)!", + ioreq->io_Offset, ncm->ncm_BlockSize); + ioreq->io_Error = IOERR_BADADDRESS; + } + if(ncm->ncm_BlockSize != 512) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "The used FileSystem or other software must support %ld byte blocks!", + ncm->ncm_BlockSize); + } + ioreq->io_Actual = 0; + return(ioreq->io_Error); + } + + startblockhigh = ioreq->io_Actual>>ncm->ncm_BlockShift; + startblock = (ioreq->io_Offset>>ncm->ncm_BlockShift)|(ioreq->io_Actual<<(32-ncm->ncm_BlockShift)); + while(dataremain) + { + datalen = dataremain; + if(datalen > maxtrans) + { + datalen = maxtrans; + } + scsicmd.scsi_Data = (UWORD *) &(((UBYTE *) ioreq->io_Data)[dataoffset]); + scsicmd.scsi_Length = datalen; + scsicmd.scsi_Flags = SCSIF_WRITE|SCSIF_AUTOSENSE|0x80; + scsicmd.scsi_SenseData = sensedata; + scsicmd.scsi_SenseLength = 18; + if(startblockhigh) + { + // Arithmetics for >2 TB needed + scsicmd.scsi_Command = cmd16; + scsicmd.scsi_CmdLength = 16; + cmd16[0] = SCSI_DA_WRITE_16; + cmd16[1] = 0; + *((ULONG *) (&cmd16[2])) = startblockhigh; + *((ULONG *) (&cmd16[6])) = startblock; + cmd16[10] = datalen>>(ncm->ncm_BlockShift+24); + cmd16[11] = datalen>>(ncm->ncm_BlockShift+16); + cmd16[12] = datalen>>(ncm->ncm_BlockShift+8); + cmd16[13] = datalen>>ncm->ncm_BlockShift; + cmd16[14] = 0; + cmd16[15] = 0; + } else { + scsicmd.scsi_Command = cmd10; + scsicmd.scsi_CmdLength = 10; + cmd10[0] = SCSI_DA_WRITE_10; + cmd10[1] = 0; + *((ULONG *) (&cmd10[2])) = startblock; + cmd10[6] = 0; + cmd10[7] = datalen>>(ncm->ncm_BlockShift+8); + cmd10[8] = datalen>>ncm->ncm_BlockShift; + cmd10[9] = 0; + } + if((ioreq->io_Error = nScsiDirect(ncm, &scsicmd))) + { + break; + } + dataoffset += datalen; + dataremain -= datalen; + oldstartblock = startblock; + startblock += datalen>>ncm->ncm_BlockShift; + if(startblock < oldstartblock) + { + // wrap around occurred + startblockhigh++; + } + } + ioreq->io_Actual = dataoffset; + return(ioreq->io_Error); +} +/* \\\ */ + +/* /// "nCBIRequestSense()" */ +LONG nCBIRequestSense(struct NepClassMS *ncm, UBYTE *senseptr, ULONG datalen) +{ + LONG ioerr; + UBYTE sensecmd[12]; + LONG actual = 0; + struct UsbMSCBIStatusWrapper umscsw; + + memset(sensecmd, 0, 12); + senseptr[2] = SK_ILLEGAL_REQUEST; + sensecmd[0] = SCSI_REQUEST_SENSE; + sensecmd[1] = 0x00; + sensecmd[2] = 0x00; + sensecmd[3] = 0x00; + sensecmd[4] = datalen; + sensecmd[5] = 0; + KPRINTF(2, ("sense command block phase...\n")); + + /*psdPipeSetup(ncm->ncm_EP0Pipe, URTF_STANDARD|URTF_ENDPOINT, + USR_CLEAR_FEATURE, UFS_ENDPOINT_HALT, (ULONG) ncm->ncm_EPInNum|URTF_IN); + ioerr = psdDoPipe(ncm->ncm_EP0Pipe, NULL, 0);*/ + psdPipeSetup(ncm->ncm_EP0Pipe, URTF_CLASS|URTF_INTERFACE, + UMSR_ADSC, 0, (ULONG) ncm->ncm_UnitIfNum); + ioerr = psdDoPipe(ncm->ncm_EP0Pipe, sensecmd, ((ncm->ncm_CSType == MS_ATAPI_SUBCLASS) || + (ncm->ncm_CSType == MS_FDDATAPI_SUBCLASS) || + (ncm->ncm_CSType == MS_UFI_SUBCLASS)) ? (ULONG) 12 : (ULONG) 6); + if(!ioerr) + { + if(ncm->ncm_CDC->cdc_PatchFlags & PFF_CLEAR_EP) + { + psdPipeSetup(ncm->ncm_EP0Pipe, URTF_STANDARD|URTF_ENDPOINT, + USR_CLEAR_FEATURE, UFS_ENDPOINT_HALT, (ULONG) ncm->ncm_EPInNum|URTF_IN); + ioerr = psdDoPipe(ncm->ncm_EP0Pipe, NULL, 0); + } + + KPRINTF(2, ("sense data phase %ld bytes...\n", datalen)); + ioerr = psdDoPipe(ncm->ncm_EPInPipe, senseptr, datalen); + actual = psdGetPipeActual(ncm->ncm_EPInPipe); + if(ioerr == UHIOERR_STALL) + { + psdPipeSetup(ncm->ncm_EP0Pipe, URTF_STANDARD|URTF_ENDPOINT, + USR_CLEAR_FEATURE, UFS_ENDPOINT_HALT, (ULONG) ncm->ncm_EPInNum|URTF_IN); + psdDoPipe(ncm->ncm_EP0Pipe, NULL, 0); + } + if((!ioerr) || (ioerr == UHIOERR_RUNTPACKET)) + { + KPRINTF(2, ("sense command status phase...\n")); + if(ncm->ncm_TPType == MS_PROTO_CBI) + { + umscsw.bType = 0; + umscsw.bValue = USMF_CSW_PHASEERR; + ioerr = psdDoPipe(ncm->ncm_EPIntPipe, &umscsw, sizeof(struct UsbMSCBIStatusWrapper)); + if(ioerr && (ioerr != UHIOERR_RUNTPACKET)) + { + psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname, + "Status interrupt failed: %s (%ld)", + psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + return(0); + } + umscsw.bValue &= USMF_CSW_PERSIST; /* mask out other bits */ + } else { + umscsw.bType = 0; + umscsw.bValue = USMF_CSW_PASS; + ioerr = 0; + } + if((!ioerr) || (ioerr == UHIOERR_RUNTPACKET)) + { + KPRINTF(2, ("sense Status:\n" + " Status : %02lx\n", + umscsw.bValue)); + if(umscsw.bValue) + { + /*psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "Sense failed: %ld", + umscsw.bValue);*/ + if(umscsw.bValue == USMF_CSW_PHASEERR) + { + return(0); + } + } else { + switch(senseptr[2] & SK_MASK) + { + case SK_UNIT_ATTENTION: + if((senseptr[12] == 0x28) || + (senseptr[12] == 0x3A)) + { + ncm->ncm_ChangeCount++; + } + break; + } + + if((ncm->ncm_CDC->cdc_PatchFlags & PFF_DEBUG) && (senseptr[2] & SK_MASK)) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "Request Sense Key %lx/%02lx/%02lx", + senseptr[2] & SK_MASK, + senseptr[12], + senseptr[13]); + } + } + } else { + psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname, + "Sense status failed: %s (%ld)", + psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + } + } else { + psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname, + "Sense data failed: %s (%ld)", + psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + } + } else { + psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname, + "Sense block failed: %s (%ld)", + psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + } + return(actual); +} +/* \\\ */ + +/* /// "nBulkReset()" */ +LONG nBulkReset(struct NepClassMS *ncm) +{ + LONG ioerr; + LONG ioerr2 = 0; + static UBYTE cbiresetcmd12[12] = { 0x1D, 0x04, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + //struct UsbMSCBIStatusWrapper umscsw; + //UBYTE sensedata[18]; + if(ncm->ncm_DenyRequests) + { + return UHIOERR_TIMEOUT; + } + KPRINTF(1, ("Bulk Reset\n")); + //psdAddErrorMsg(RETURN_OK, (STRPTR) libname, "Bulk Reset..."); + switch(ncm->ncm_TPType) + { + case MS_PROTO_BULK: + if(!ncm->ncm_BulkResetBorks) + { + psdPipeSetup(ncm->ncm_EP0Pipe, URTF_CLASS|URTF_INTERFACE, + UMSR_BULK_ONLY_RESET, 0, (ULONG) ncm->ncm_UnitIfNum); + ioerr2 = psdDoPipe(ncm->ncm_EP0Pipe, NULL, 0); + if(ioerr2 == UHIOERR_TIMEOUT) + { + return(ioerr2); + } + if(ioerr2) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "BULK_ONLY_RESET failed: %s (%ld)", + psdNumToStr(NTS_IOERR, ioerr2, "unknown"), ioerr2); + ncm->ncm_BulkResetBorks = TRUE; + } + if(ncm->ncm_DenyRequests) + { + return ioerr2; + } + } + psdPipeSetup(ncm->ncm_EP0Pipe, URTF_STANDARD|URTF_ENDPOINT, + USR_CLEAR_FEATURE, UFS_ENDPOINT_HALT, (ULONG) ncm->ncm_EPInNum|URTF_IN); + ioerr = psdDoPipe(ncm->ncm_EP0Pipe, NULL, 0); + if(ioerr) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "CLEAR_ENDPOINT_HALT %ld failed: %s (%ld)", + ncm->ncm_EPInNum, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + } + if(ncm->ncm_DenyRequests) + { + return ioerr; + } + psdPipeSetup(ncm->ncm_EP0Pipe, URTF_STANDARD|URTF_ENDPOINT, + USR_CLEAR_FEATURE, UFS_ENDPOINT_HALT, (ULONG) ncm->ncm_EPOutNum); + ioerr = psdDoPipe(ncm->ncm_EP0Pipe, NULL, 0); + if(ioerr) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "CLEAR_ENDPOINT_HALT %ld failed: %s (%ld)", + ncm->ncm_EPOutNum, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + } + return(ioerr2 ? ioerr2 : ioerr); + + case MS_PROTO_CBI: + case MS_PROTO_CB: + psdPipeSetup(ncm->ncm_EP0Pipe, URTF_CLASS|URTF_INTERFACE, + UMSR_ADSC, 0, (ULONG) ncm->ncm_UnitIfNum); + ioerr = psdDoPipe(ncm->ncm_EP0Pipe, cbiresetcmd12, 12); + if(ioerr) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "CBI_RESET failed: %s (%ld)", + psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + } + if(ncm->ncm_DenyRequests) + { + return ioerr; + } + psdPipeSetup(ncm->ncm_EP0Pipe, URTF_STANDARD|URTF_ENDPOINT, + USR_CLEAR_FEATURE, UFS_ENDPOINT_HALT, (ULONG) ncm->ncm_EPInNum|URTF_IN); + ioerr = psdDoPipe(ncm->ncm_EP0Pipe, NULL, 0); + if(ioerr) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "CLEAR_ENDPOINT_HALT %ld failed: %s (%ld)", + ncm->ncm_EPInNum, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + } + if(ncm->ncm_DenyRequests) + { + return ioerr; + } + psdPipeSetup(ncm->ncm_EP0Pipe, URTF_STANDARD|URTF_ENDPOINT, + USR_CLEAR_FEATURE, UFS_ENDPOINT_HALT, (ULONG) ncm->ncm_EPOutNum); + ioerr = psdDoPipe(ncm->ncm_EP0Pipe, NULL, 0); + if(ioerr) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "CLEAR_ENDPOINT_HALT %ld failed: %s (%ld)", + ncm->ncm_EPOutNum, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + } + //nCBIRequestSense(ncm, sensedata, 18); + return(ioerr); + } + return(0); +} +/* \\\ */ + +/* /// "nBulkClear()" */ +LONG nBulkClear(struct NepClassMS *ncm) +{ + LONG ioerr; + if(ncm->ncm_DenyRequests) + { + return UHIOERR_TIMEOUT; + } + KPRINTF(1, ("Bulk Clear\n")); + //psdAddErrorMsg(RETURN_OK, (STRPTR) libname, "Bulk Clear..."); + psdPipeSetup(ncm->ncm_EP0Pipe, URTF_STANDARD|URTF_ENDPOINT, + USR_CLEAR_FEATURE, UFS_ENDPOINT_HALT, (ULONG) ncm->ncm_EPInNum|URTF_IN); + ioerr = psdDoPipe(ncm->ncm_EP0Pipe, NULL, 0); + if(ioerr == UHIOERR_TIMEOUT) + { + return(ioerr); + } + if(ioerr) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "CLEAR_ENDPOINT_HALT %ld failed: %s (%ld)", + ncm->ncm_EPInNum, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + } + if(ncm->ncm_DenyRequests) + { + return ioerr; + } + psdPipeSetup(ncm->ncm_EP0Pipe, URTF_STANDARD|URTF_ENDPOINT, + USR_CLEAR_FEATURE, UFS_ENDPOINT_HALT, (ULONG) ncm->ncm_EPOutNum); + ioerr = psdDoPipe(ncm->ncm_EP0Pipe, NULL, 0); + if(ioerr) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "CLEAR_ENDPOINT_HALT %ld failed: %s (%ld)", + ncm->ncm_EPOutNum, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + } + return(ioerr); +} +/* \\\ */ + +/* /// "nScsiDirect()" */ +LONG nScsiDirect(struct NepClassMS *ncm, struct SCSICmd *scsicmd) +{ + STRPTR prodname; + STRPTR vendname; + UBYTE cmd12[12]; + struct SCSICmd scsicmd10; + BOOL usecmd10 = FALSE; + LONG res; + UBYTE *sensedata = NULL; + UBYTE *buf; + BOOL xlate = FALSE; + ULONG pf = ncm->ncm_CDC->cdc_PatchFlags; + + scsicmd->scsi_Actual = 0; + scsicmd->scsi_CmdActual = 0; + scsicmd->scsi_SenseActual = 0; + + if(((pf & PFF_MODE_XLATE) && (scsicmd->scsi_CmdLength == 6)) || + (ncm->ncm_CSType == MS_FDDATAPI_SUBCLASS) || + (ncm->ncm_CSType == MS_ATAPI_SUBCLASS) || + (ncm->ncm_CSType == MS_UFI_SUBCLASS)) + { + xlate = TRUE; + } + + if(pf & PFF_SIMPLE_SCSI) + { + if(scsicmd->scsi_Flags & SCSIF_AUTOSENSE) + { + if(scsicmd->scsi_SenseLength > 18) + { + KPRINTF(10, ("Fixing Sense Length to 18!\n")); + scsicmd->scsi_SenseLength = 18; + } + } + switch(scsicmd->scsi_Command[0]) + { + case SCSI_TEST_UNIT_READY: + case SCSI_INQUIRY: + //case SCSI_LOG_SELECT: + //case SCSI_LOG_SENSE: + case SCSI_REQUEST_SENSE: + //case SCSI_MODE_SELECT_6: + //case SCSI_MODE_SELECT_10: + //case SCSI_MODE_SENSE_6: + //case SCSI_MODE_SENSE_10: + case SCSI_DA_READ_6: + case SCSI_DA_READ_10: + case SCSI_DA_READ_CAPACITY: + case SCSI_DA_SEEK_6: + case SCSI_DA_SEEK_10: + case SCSI_DA_WRITE_6: + case SCSI_DA_WRITE_10: + break; + + case SCSI_MODE_SENSE_6: + { + UWORD modepage = scsicmd->scsi_Command[2] & 0x3f; + UBYTE *data = (UBYTE *) scsicmd->scsi_Data; + if((modepage == 0x3f) || + (modepage == 0x03) || + (modepage == 0x04) || + (modepage == 0x05)) + { + if(!(ncm->ncm_BlockSize && ncm->ncm_Geometry.dg_TotalSectors)) + { + nGetBlockSize(ncm); + } + if(ncm->ncm_Geometry.dg_TotalSectors) + { + nFakeGeometry(ncm, &ncm->ncm_Geometry); + ncm->ncm_GeoChangeCount = ncm->ncm_ChangeCount; + } + memset(data, 0, (size_t) scsicmd->scsi_Length); + scsicmd->scsi_Status = SCSI_GOOD; + } + if(modepage == 0x3f) // all available mode pages + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, "Simple SCSI: Faking All Mode Pages 0x03-0x05"); + data[0] = 3+2+22+2+22+2+30; + data += 4; + scsicmd->scsi_Actual = 4; + if(scsicmd->scsi_Length >= 4+2+22) + { + data[0] = 0x03; // mode page + data[1] = 22; // page length + data[10] = ncm->ncm_Geometry.dg_TrackSectors>>8; + data[11] = ncm->ncm_Geometry.dg_TrackSectors; + data[12] = ncm->ncm_Geometry.dg_SectorSize>>8; + data[13] = ncm->ncm_Geometry.dg_SectorSize; + data += 2+22; + scsicmd->scsi_Actual += 2+22; + } + if(scsicmd->scsi_Length >= 4+2+22+2+22) + { + data[0] = 0x04; // mode page + data[1] = 22; // page length + data[2] = ncm->ncm_Geometry.dg_Cylinders>>16; + data[3] = ncm->ncm_Geometry.dg_Cylinders>>8; + data[4] = ncm->ncm_Geometry.dg_Cylinders; + data[5] = ncm->ncm_Geometry.dg_Heads; + data += 2+22; + scsicmd->scsi_Actual += 2+22; + } + if(scsicmd->scsi_Length >= 4+2+22+2+22+2+30) + { + data[0] = 0x05; // mode page + data[1] = 30; // page length + data[4] = ncm->ncm_Geometry.dg_Heads; + data[5] = ncm->ncm_Geometry.dg_TrackSectors; + data[6] = ncm->ncm_Geometry.dg_SectorSize>>8; + data[7] = ncm->ncm_Geometry.dg_SectorSize; + data[8] = ncm->ncm_Geometry.dg_Cylinders>>8; + data[9] = ncm->ncm_Geometry.dg_Cylinders; + //data += 2+30; + scsicmd->scsi_Actual += 2+30; + } + return(0); + } + else if((modepage == 0x03) && (scsicmd->scsi_Length >= 6+22)) // Format Device mode page + { + // fake geometry request + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, "Simple SCSI: Faking Mode Page 0x03 (Format Device)"); + + data[0] = 5+22; // length + data += 4; + data[0] = 0x03; // mode page + data[1] = 22; // page length + data[10] = ncm->ncm_Geometry.dg_TrackSectors>>8; + data[11] = ncm->ncm_Geometry.dg_TrackSectors; + data[12] = ncm->ncm_Geometry.dg_SectorSize>>8; + data[13] = ncm->ncm_Geometry.dg_SectorSize; + scsicmd->scsi_Actual = 6+22; + return(0); + } + else if((modepage == 0x04) && (scsicmd->scsi_Length >= 6+22)) // Rigid Disk Geometry mode page + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, "Simple SCSI: Faking Mode Page 0x04 (Rigid Disk Geometry)"); + data[0] = 5+22; // length + data += 4; + data[0] = 0x04; // mode page + data[1] = 22; // page length + data[2] = ncm->ncm_Geometry.dg_Cylinders>>16; + data[3] = ncm->ncm_Geometry.dg_Cylinders>>8; + data[4] = ncm->ncm_Geometry.dg_Cylinders; + data[5] = ncm->ncm_Geometry.dg_Heads; + scsicmd->scsi_Actual = 6+22; + return(0); + } + else if((modepage == 0x05) && (scsicmd->scsi_Length >= 6+30)) // Flexible Disk mode page + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, "Simple SCSI: Faking Mode Page 0x05 (Flexible Disk)"); + data[0] = 5+30; // length + data += 4; + data[0] = 0x05; // mode page + data[1] = 30; // page length + data[4] = ncm->ncm_Geometry.dg_Heads; + data[5] = ncm->ncm_Geometry.dg_TrackSectors; + data[6] = ncm->ncm_Geometry.dg_SectorSize>>8; + data[7] = ncm->ncm_Geometry.dg_SectorSize; + data[8] = ncm->ncm_Geometry.dg_Cylinders>>8; + data[9] = ncm->ncm_Geometry.dg_Cylinders; + scsicmd->scsi_Actual = 6+30; + return(0); + } + // fall through + } + + case 0x51: // drive ready + case SCSI_CD_READ_TOC: + case SCSI_CD_PAUSE_RESUME: + case SCSI_CD_PLAY_AUDIO_10: + case SCSI_CD_PLAY_AUDIO_12: + case SCSI_CD_PLAY_AUDIO_MSF: + case SCSI_CD_PLAY_AUDIO_TRACK_INDEX: + case SCSI_CD_PLAY_TRACK_RELATIVE_10: + case SCSI_CD_PLAY_TRACK_RELATIVE_12: + case SCSI_CD_BLANK: + case SCSI_CD_CLOSE_TRACK: + case SCSI_CD_GET_CONFIGURATION: + case SCSI_CD_GET_EVENT_STATUS_NOTIFICATION: + case SCSI_CD_GET_PERFORMANCE: + case SCSI_CD_LOAD_UNLOAD_MEDIUM: + case SCSI_CD_MECHANISM_STATUS: + case SCSI_CD_PRE_FETCH: + case SCSI_CD_PREVENT_ALLOW_MEDIUM_REMOVAL: + case SCSI_CD_READ_HEADER: + case SCSI_CD_READ_SUB_CHANNEL: + if((scsicmd->scsi_Command[0] != SCSI_MODE_SENSE_6) && + ((ncm->ncm_DeviceType == PDT_WORM) || (ncm->ncm_DeviceType == PDT_CDROM))) + { + // allows these CD rom commands even with SimpleSCSI enabled. + break; + } + + default: + { + UBYTE cmdstrbuf[16*3+2]; + + nHexString(scsicmd->scsi_Command, (ULONG) (scsicmd->scsi_CmdLength < 16 ? scsicmd->scsi_CmdLength : 16), cmdstrbuf); + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, "Simple SCSI: Filtering SCSI command %s", cmdstrbuf); + + scsicmd->scsi_Status = SCSI_CHECK_CONDITION; + scsicmd->scsi_SenseActual = 0; + if(scsicmd->scsi_Flags & SCSIF_AUTOSENSE) + { + if(scsicmd->scsi_SenseLength >= 18) + { + memset(scsicmd->scsi_SenseData, 0x00, 18); + scsicmd->scsi_SenseData[0] = 0x80|0x70; + scsicmd->scsi_SenseData[2] = SK_ILLEGAL_REQUEST; + scsicmd->scsi_SenseData[12] = 0x20; // unsupported command + scsicmd->scsi_SenseActual = 18; + } + } + return(-1); + } + } + } + + if((scsicmd->scsi_Command[0] == SCSI_TEST_UNIT_READY) && scsicmd->scsi_Length) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, "Bogus TEST_UNIT_READY data length set to 0."); + scsicmd->scsi_Length = 0; + } + + if(pf & PFF_FAKE_INQUIRY) + { + if(scsicmd->scsi_Command[0] == SCSI_INQUIRY) + { + if(scsicmd->scsi_Length >= 36) + { + UBYTE *data = (UBYTE *) scsicmd->scsi_Data; + if(pf & PFF_DEBUG) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, "Faking Inquiry."); + } + KPRINTF(10, ("Faking INQUIRY!\n")); + psdGetAttrs(PGA_DEVICE, ncm->ncm_Device, + DA_ProductName, &prodname, + DA_Manufacturer, &vendname, + TAG_END); + memset(data, 0x00, (size_t) scsicmd->scsi_Length); + data[1] = 0x80; // removable media + data[2] = 0x02; // 0x03 would be ANSI X3.301:1997 (SPC). + data[3] = 0x02; // Response data format = 2 + data[4] = 32; // additional length n-4 + CopyMem(vendname, &data[8], (ULONG) ((strlen(vendname) < 8) ? strlen(vendname) : 8)); + CopyMem(prodname, &data[16], (ULONG) ((strlen(prodname) < 16) ? strlen(prodname) : 16)); + scsicmd->scsi_CmdActual = scsicmd->scsi_CmdLength; + scsicmd->scsi_Status = SCSI_GOOD; + scsicmd->scsi_SenseActual = 0; + return(0); + } + return(-1); + } + } + + if(pf & PFF_FIX_INQ36) + { + if((scsicmd->scsi_Command)[0] == SCSI_INQUIRY) + { + if(scsicmd->scsi_Length > 36) + { + if(pf & PFF_DEBUG) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, "Fixing Inquiry."); + } + + KPRINTF(10, ("Fixing INQUIRY!\n")); + scsicmd->scsi_Length = 36; + } + else if(scsicmd->scsi_Length < 36) + { + if(pf & PFF_DEBUG) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "Couldn't fix Inquiry < %ld.", + scsicmd->scsi_Length); + } + KPRINTF(10, ("Couldn't fix INQUIRY!\n")); + } + } + } + + if(xlate) + { + scsicmd10 = *scsicmd; + scsicmd10.scsi_Command = cmd12; + scsicmd10.scsi_CmdLength = 10; + memset(cmd12, 0x00, 12); + switch(scsicmd->scsi_Command[0]) + { + case SCSI_DA_READ_6: + case SCSI_DA_WRITE_6: + case SCSI_DA_SEEK_6: + cmd12[0] = scsicmd->scsi_Command[0] | 0x20; + cmd12[1] = scsicmd->scsi_Command[1] & 0xe0; + cmd12[3] = scsicmd->scsi_Command[1] & 0x1f; + cmd12[4] = scsicmd->scsi_Command[2]; + cmd12[5] = scsicmd->scsi_Command[3]; + cmd12[8] = scsicmd->scsi_Command[4]; + cmd12[9] = scsicmd->scsi_Command[5]; + usecmd10 = TRUE; + break; + + case SCSI_MODE_SELECT_6: + cmd12[0] = SCSI_MODE_SELECT_10; + cmd12[1] = scsicmd->scsi_Command[1]; + //cmd12[2] = scsicmd->scsi_Command[2]; // reserved + //cmd12[3] = scsicmd->scsi_Command[3]; // reserved + cmd12[7] = (scsicmd->scsi_Command[4]+4)>>8; + cmd12[8] = scsicmd->scsi_Command[4]+4; + cmd12[9] = scsicmd->scsi_Command[5]; + + sensedata = psdAllocVec(scsicmd->scsi_Length+4); + if(sensedata && (scsicmd->scsi_Length >= 4)) + { + buf = (UBYTE *) scsicmd->scsi_Data; + sensedata[1] = *buf++; + sensedata[2] = *buf++; + sensedata[3] = *buf++; + sensedata[7] = *buf++; + + scsicmd10.scsi_Length = scsicmd->scsi_Length+4; + scsicmd10.scsi_Data = (UWORD *) sensedata; + + CopyMem(buf, &sensedata[8], scsicmd->scsi_Length-4); + } + usecmd10 = TRUE; + break; + + case SCSI_MODE_SENSE_6: + cmd12[0] = SCSI_MODE_SENSE_10; + cmd12[1] = scsicmd->scsi_Command[1] & 0xf7; + cmd12[2] = scsicmd->scsi_Command[2]; + cmd12[3] = scsicmd->scsi_Command[3]; + // Workaround: Some devices are seriously broken and do not interprete + // the upper byte of the allocation length field. + // Hence they return 3 bytes instead of 259 bytes. For this special case, + // we will simple truncate the size by four, to get back to a 255 bytes + // buffer. + if((scsicmd->scsi_Command[4] > 251) && (scsicmd->scsi_Length == scsicmd->scsi_Command[4])) + { + scsicmd->scsi_Command[4] -= 4; + scsicmd->scsi_Length -= 4; + } + cmd12[7] = (scsicmd->scsi_Command[4]+4)>>8; + cmd12[8] = scsicmd->scsi_Command[4]+4; + cmd12[9] = scsicmd->scsi_Command[5]; + sensedata = psdAllocVec(scsicmd->scsi_Length+4); + if(sensedata) + { + scsicmd10.scsi_Length = scsicmd->scsi_Length+4; + scsicmd10.scsi_Data = (UWORD *) sensedata; + } + usecmd10 = TRUE; + break; + } + } + + if((ncm->ncm_CSType == MS_ATAPI_SUBCLASS) || + (ncm->ncm_CSType == MS_FDDATAPI_SUBCLASS) || + (ncm->ncm_CSType == MS_UFI_SUBCLASS)) + { + if(!usecmd10) + { + scsicmd10 = *scsicmd; + scsicmd10.scsi_Command = cmd12; + memset(cmd12, 0x00, 12); + CopyMem(scsicmd->scsi_Command, cmd12, (ULONG) scsicmd->scsi_CmdLength); + usecmd10 = TRUE; + } + scsicmd10.scsi_CmdLength = 12; + if(ncm->ncm_CSType == MS_UFI_SUBCLASS) + { + switch(cmd12[0]) + { + case SCSI_REQUEST_SENSE: + cmd12[4] = 18; /* restrict UFI response to 18 bytes */ + scsicmd10.scsi_Flags &= ~SCSIF_AUTOSENSE; + break; + + case SCSI_INQUIRY: + KPRINTF(10, ("Disabling autosense for UFI!\n")); + cmd12[4] = 36; /* restrict UFI response to 36 bytes */ + scsicmd10.scsi_Flags &= ~SCSIF_AUTOSENSE; + break; + + case SCSI_MODE_SELECT_10: + cmd12[7] = 0; + cmd12[8] = 8; + break; + + } + } + } + + if(usecmd10) + { + if(pf & PFF_DEBUG) + { + UBYTE cmd1strbuf[16*3+2]; + UBYTE cmd2strbuf[16*3+2]; + + nHexString(scsicmd->scsi_Command, (ULONG) (scsicmd->scsi_CmdLength < 16 ? scsicmd->scsi_CmdLength : 16), cmd1strbuf); + nHexString(scsicmd10.scsi_Command, (ULONG) (scsicmd10.scsi_CmdLength < 16 ? scsicmd10.scsi_CmdLength : 16), cmd2strbuf); + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "Mode XLATE for %s -> %s", cmd1strbuf, cmd2strbuf); + if(scsicmd->scsi_Length && (scsicmd10.scsi_Command[0] == SCSI_MODE_SELECT_10)) + { + nHexString((UBYTE *) scsicmd->scsi_Data, (ULONG) (scsicmd->scsi_Length < 16 ? scsicmd->scsi_Length : 16), cmd1strbuf); + nHexString((UBYTE *) scsicmd10.scsi_Data, (ULONG) (scsicmd10.scsi_Length < 16 ? scsicmd10.scsi_Length : 16), cmd2strbuf); + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "Request: %s (%ld) -> %s (%ld)", + cmd1strbuf, scsicmd->scsi_Length, + cmd2strbuf, scsicmd10.scsi_Length); + } + } + KPRINTF(20, ("Mode XLATE for cmd %lx\n", scsicmd->scsi_Command[0])); + } + + switch(ncm->ncm_TPType) + { + case MS_PROTO_BULK: + res = nScsiDirectBulk(ncm, usecmd10 ? &scsicmd10 : scsicmd); + break; + + case MS_PROTO_CB: + case MS_PROTO_CBI: + res = nScsiDirectCBI(ncm, usecmd10 ? &scsicmd10 : scsicmd); + break; + + default: + return(-1); + } + KPRINTF(20, ("Cmd done %ld\n", res)); + if(usecmd10) + { + if(sensedata) + { + scsicmd->scsi_Actual = 0; + if(scsicmd10.scsi_Command[0] == SCSI_MODE_SENSE_10) + { + UBYTE cmd1strbuf[16*3+2]; + UBYTE cmd2strbuf[16*3+2]; + + if(scsicmd10.scsi_Actual >= 8) + { + scsicmd->scsi_Actual = scsicmd10.scsi_Actual - 4; + buf = (UBYTE *) scsicmd->scsi_Data; + *buf++ = sensedata[1]; + *buf++ = sensedata[2]; + *buf++ = sensedata[3]; + *buf++ = sensedata[7]; + CopyMem(&sensedata[8], buf, (ULONG) scsicmd10.scsi_Actual - 8); + if(pf & PFF_DEBUG) + { + nHexString((UBYTE *) scsicmd10.scsi_Data, scsicmd10.scsi_Actual < 16 ? scsicmd10.scsi_Actual : 16, cmd1strbuf); + nHexString((UBYTE *) scsicmd->scsi_Data, scsicmd->scsi_Actual < 16 ? scsicmd->scsi_Actual : 16, cmd2strbuf); + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "Response: %s (%ld) -> %s (%ld)", + cmd1strbuf, scsicmd10.scsi_Actual, + cmd2strbuf, scsicmd->scsi_Actual); + } + } + } + psdFreeVec(sensedata); + } else { + scsicmd->scsi_Actual = scsicmd10.scsi_Actual; + } + scsicmd->scsi_CmdActual = scsicmd10.scsi_CmdActual; + scsicmd->scsi_Status = scsicmd10.scsi_Status; + scsicmd->scsi_SenseActual = scsicmd10.scsi_SenseActual; + } + + pf = ncm->ncm_CDC->cdc_PatchFlags; + if((res == HFERR_Phase) && (!(pf & PFF_NO_FALLBACK)) && (!(pf & PFF_SIMPLE_SCSI))) + { + switch(scsicmd->scsi_Command[0]) + { + case SCSI_TEST_UNIT_READY: + case SCSI_INQUIRY: + //case SCSI_LOG_SELECT: + //case SCSI_LOG_SENSE: + case SCSI_REQUEST_SENSE: + //case SCSI_MODE_SELECT_6: + //case SCSI_MODE_SELECT_10: + //case SCSI_MODE_SENSE_6: + //case SCSI_MODE_SENSE_10: + case SCSI_DA_READ_6: + case SCSI_DA_READ_10: + case SCSI_DA_READ_CAPACITY: + case SCSI_DA_SEEK_6: + case SCSI_DA_SEEK_10: + case SCSI_DA_WRITE_6: + case SCSI_DA_WRITE_10: + break; + + default: + ncm->ncm_CDC->cdc_PatchFlags |= PFF_SIMPLE_SCSI; + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "Fallback: Enabling Simple SCSI."); + nStoreConfig(ncm); + break; + } + } + + if((!res) && ((scsicmd->scsi_Command)[0] == SCSI_DA_READ_CAPACITY) && (pf & PFF_FIX_CAPACITY) && (scsicmd->scsi_Length >= 8)) + { + ULONG *capacity = ((ULONG *) scsicmd->scsi_Data); + (*capacity)--; + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "Fix Capacity: Correcting number of blocks."); + } + + if(res && (scsicmd->scsi_Command[0] == SCSI_INQUIRY)) + { + if((!(ncm->ncm_CDC->cdc_PatchFlags & PFF_NO_FALLBACK)) && (!(ncm->ncm_CDC->cdc_PatchFlags & PFF_FIX_INQ36))) + { + ncm->ncm_CDC->cdc_PatchFlags |= PFF_FIX_INQ36; + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "Fallback: Enabling Trim Inquiry."); + nStoreConfig(ncm); + } + else if((!(ncm->ncm_CDC->cdc_PatchFlags & PFF_NO_FALLBACK)) && (!(ncm->ncm_CDC->cdc_PatchFlags & PFF_FAKE_INQUIRY))) + { + ncm->ncm_CDC->cdc_PatchFlags |= PFF_FAKE_INQUIRY; + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "Fallback: Enabling Fake Inquiry."); + nStoreConfig(ncm); + } + } + + if((ncm->ncm_DeviceType == PDT_WORM) || + (ncm->ncm_DeviceType == PDT_CDROM)) + { + // cd roms are always write protected + ncm->ncm_WriteProtect = TRUE; + return(res); + } + // don't try to obtain write protection, when there's no media inserted. + if(!ncm->ncm_UnitReady) + { + return(res); + } + if((!res) && (scsicmd->scsi_Command[0] == SCSI_MODE_SENSE_6)) + { + if(((UBYTE *) scsicmd->scsi_Data)[2] & 0x80) + { + if(!ncm->ncm_WriteProtect) + { + if(pf & PFF_REM_SUPPORT) + { + ncm->ncm_ChangeCount++; + if(ncm->ncm_CDC->cdc_PatchFlags & PFF_DEBUG) + { + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, + "Diskchange: Sense6WriteProtect On (count = %ld)", + ncm->ncm_ChangeCount); + } + } + ncm->ncm_WriteProtect = TRUE; + } + } else { + if(ncm->ncm_WriteProtect) + { + if(pf & PFF_REM_SUPPORT) + { + ncm->ncm_ChangeCount++; + if(ncm->ncm_CDC->cdc_PatchFlags & PFF_DEBUG) + { + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, + "Diskchange: Sense6WriteProtect Off (count = %ld)", + ncm->ncm_ChangeCount); + } + } + ncm->ncm_WriteProtect = FALSE; + } + } + } + if((!res) && (scsicmd->scsi_Command[0] == SCSI_MODE_SENSE_10)) + { + if(((UBYTE *) scsicmd->scsi_Data)[3] & 0x80) + { + if(!ncm->ncm_WriteProtect) + { + if(pf & PFF_REM_SUPPORT) + { + ncm->ncm_ChangeCount++; + if(ncm->ncm_CDC->cdc_PatchFlags & PFF_DEBUG) + { + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, + "Diskchange: Sense10WriteProtect On (count = %ld)", + ncm->ncm_ChangeCount); + } + } + ncm->ncm_WriteProtect = TRUE; + } + } else { + if(ncm->ncm_WriteProtect) + { + if(pf & PFF_REM_SUPPORT) + { + ncm->ncm_ChangeCount++; + if(ncm->ncm_CDC->cdc_PatchFlags & PFF_DEBUG) + { + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, + "Diskchange: Sense10WriteProtect Off (count = %ld)", + ncm->ncm_ChangeCount); + } + } + ncm->ncm_WriteProtect = FALSE; + } + } + } + return(res); +} +/* \\\ */ + +/* /// "nScsiDirectBulk()" */ +LONG nScsiDirectBulk(struct NepClassMS *ncm, struct SCSICmd *scsicmd) +{ + LONG ioerr; + struct PsdPipe *pp; + struct UsbMSCmdBlkWrapper umscbw; + struct UsbMSCmdStatusWrapper umscsw; + ULONG datalen; + LONG rioerr; + UWORD retrycnt = 0; + UBYTE cmdstrbuf[16*3+2]; + + KPRINTF(10, ("\n")); + + nHexString(scsicmd->scsi_Command, (ULONG) (scsicmd->scsi_CmdLength < 16 ? scsicmd->scsi_CmdLength : 16), cmdstrbuf); + + if(scsicmd->scsi_Flags & 0x80) /* Autoretry */ + { + retrycnt = 1; + } + umscbw.dCBWSignature = AROS_LONG2LE(0x43425355); + scsicmd->scsi_Status = SCSI_GOOD; + nLockXFer(ncm); + do + { + KPRINTF(10, ("retrycnt %ld\n",retrycnt)); + if(ncm->ncm_DenyRequests) + { + rioerr = HFERR_Phase; + break; + } + /*nBulkReset(ncm);*/ + + rioerr = 0; + + /*psdPipeSetup(ncm->ncm_EP0Pipe, URTF_STANDARD|URTF_ENDPOINT, + USR_CLEAR_FEATURE, UFS_ENDPOINT_HALT, (ULONG) ncm->ncm_EPInNum|URTF_IN); + ioerr = psdDoPipe(ncm->ncm_EP0Pipe, NULL, 0);*/ + + if(ncm->ncm_CDC->cdc_PatchFlags & PFF_DELAY_DATA) + { + psdDelayMS(1); + } + + datalen = scsicmd->scsi_Length; + umscbw.dCBWTag = (ULONG) scsicmd + ++ncm->ncm_TagCount; + umscbw.dCBWDataTransferLength = AROS_LONG2LE(datalen); + umscbw.bmCBWFlags = scsicmd->scsi_Flags & SCSIF_READ ? 0x80 : 0x00; + umscbw.bCBWLUN = ncm->ncm_UnitLUN; + if((scsicmd->scsi_CmdLength) >= 16) + { + CopyMemQuick(scsicmd->scsi_Command, umscbw.CBWCB, 16); + umscbw.bCBWCBLength = scsicmd->scsi_CmdActual = 16; + } else { + memset(umscbw.CBWCB, 0, 16); + CopyMem(scsicmd->scsi_Command, umscbw.CBWCB, (ULONG) scsicmd->scsi_CmdLength); + umscbw.bCBWCBLength = scsicmd->scsi_CmdActual = scsicmd->scsi_CmdLength; + } + //psdAddErrorMsg(RETURN_OK, (STRPTR) libname, "Issueing command %s Dlen=%ld", cmdstrbuf, datalen); + + XPRINTF(2, ("command block phase, tag %08lx, len %ld, flags %02lx...\n", + umscbw.dCBWTag, scsicmd->scsi_CmdLength, scsicmd->scsi_Flags)); + XPRINTF(2, ("command: %s\n", cmdstrbuf)); + ioerr = psdDoPipe(ncm->ncm_EPOutPipe, &umscbw, UMSCBW_SIZEOF); + if(ioerr == UHIOERR_STALL) /* Retry on stall */ + { + XPRINTF(2, ("stall...\n")); + nBulkClear(ncm); + ioerr = psdDoPipe(ncm->ncm_EPOutPipe, &umscbw, UMSCBW_SIZEOF); + } + if(ncm->ncm_DenyRequests) + { + rioerr = HFERR_Phase; + break; + } + if(!ioerr) + { + if(datalen) + { + XPRINTF(2, ("data phase %ld bytes...\n", datalen)); + if(ncm->ncm_CDC->cdc_PatchFlags & PFF_DELAY_DATA) + { + psdDelayMS(1); + } + pp = (scsicmd->scsi_Flags & SCSIF_READ) ? ncm->ncm_EPInPipe : ncm->ncm_EPOutPipe; + ioerr = psdDoPipe(pp, scsicmd->scsi_Data, datalen); + scsicmd->scsi_Actual = psdGetPipeActual(pp); + if(ioerr == UHIOERR_OVERFLOW) + { + XPRINTF(10, ("Extra Data received, but ignored!\n")); + ioerr = 0; + } + else if(ioerr == UHIOERR_STALL) /* Accept on stall */ + { + XPRINTF(2, ("stall...\n")); + psdPipeSetup(ncm->ncm_EP0Pipe, URTF_STANDARD|URTF_ENDPOINT, + USR_CLEAR_FEATURE, UFS_ENDPOINT_HALT, + (ULONG) ((scsicmd->scsi_Flags & SCSIF_READ) ? ncm->ncm_EPInNum|URTF_IN : ncm->ncm_EPOutNum)); + ioerr = psdDoPipe(ncm->ncm_EP0Pipe, NULL, 0); + } + else if(ioerr == UHIOERR_RUNTPACKET) + { + XPRINTF(10, ("Runt packet ignored...\n")); + ioerr = 0; + /*psdPipeSetup(ncm->ncm_EP0Pipe, URTF_STANDARD|URTF_ENDPOINT, + USR_CLEAR_FEATURE, UFS_ENDPOINT_HALT, + (ULONG) ncm->ncm_EPInNum|URTF_IN); + ioerr = psdDoPipe(ncm->ncm_EP0Pipe, NULL, 0);*/ + } + } else { + ioerr = 0; + scsicmd->scsi_Actual = 0; + } + if(!ioerr) + { + XPRINTF(2, ("command status phase...\n")); + ioerr = psdDoPipe(ncm->ncm_EPInPipe, &umscsw, UMSCSW_SIZEOF); + if(ioerr == UHIOERR_STALL) /* Retry on stall */ + { + XPRINTF(2, ("stall...\n")); + psdPipeSetup(ncm->ncm_EP0Pipe, URTF_STANDARD|URTF_ENDPOINT, + USR_CLEAR_FEATURE, UFS_ENDPOINT_HALT, (ULONG) ncm->ncm_EPInNum|URTF_IN); + ioerr = psdDoPipe(ncm->ncm_EP0Pipe, NULL, 0); + /*nBulkClear(ncm);*/ + ioerr = psdDoPipe(ncm->ncm_EPInPipe, &umscsw, UMSCSW_SIZEOF); + } + if(ioerr == UHIOERR_RUNTPACKET) + { + // well, retry then + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "Command status block truncated (%ld bytes), retrying...", + psdGetPipeActual(ncm->ncm_EPInPipe)); + ioerr = psdDoPipe(ncm->ncm_EPInPipe, &umscsw, UMSCSW_SIZEOF); + } + if(ioerr == UHIOERR_OVERFLOW) + { + XPRINTF(10, ("Extra Status received, but ignored!\n")); + ioerr = 0; + } + if(ncm->ncm_DenyRequests) + { + rioerr = HFERR_Phase; + break; + } + if(!ioerr) + { + XPRINTF(2, ("Status:\n" + " Signature: %08lx\n" + " Tag : %08lx\n" + " Residue : %08lx\n" + " Status : %02lx\n", + umscsw.dCSWSignature, + umscsw.dCSWTag, + umscsw.dCSWDataResidue, + umscsw.bCSWStatus)); + if(((umscsw.dCSWSignature != AROS_LONG2LE(0x53425355)) && (!(ncm->ncm_CDC->cdc_PatchFlags & PFF_CSS_BROKEN))) || (umscsw.dCSWTag != umscbw.dCBWTag)) + { + psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname, "Command (%s) failed:", cmdstrbuf); + psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname, + "Illegal command status block (Sig:%08lx, Tag=%08lx/%08lx (TX/RX), Len=%ld)", + umscsw.dCSWSignature, + umscbw.dCBWTag, + umscsw.dCSWTag, + psdGetPipeActual(ncm->ncm_EPInPipe)); + scsicmd->scsi_Status = SCSI_CHECK_CONDITION; + rioerr = HFERR_Phase; + nBulkReset(ncm); + continue; + } + /* ignore this: too many firmwares report shit */ + //scsicmd->scsi_Actual = datalen - AROS_LONG2LE(umscsw.dCSWDataResidue); + if((scsicmd->scsi_Actual > 7) && ((AROS_LONG2BE(*((ULONG *) scsicmd->scsi_Data))>>8) == 0x555342) && (((ULONG *) scsicmd->scsi_Data)[1] == umscbw.dCBWTag)) + { + psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname, + "Your MSD has a very bad firmware! Havoc!"); + scsicmd->scsi_Actual = 0; + umscsw.bCSWStatus = USMF_CSW_FAIL; + } + scsicmd->scsi_Status = umscsw.bCSWStatus; + if(umscsw.bCSWStatus) + { + if(umscsw.bCSWStatus == USMF_CSW_PHASEERR) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, "Command (%s) failed: %ld", cmdstrbuf, umscsw.bCSWStatus); + nBulkReset(ncm); + } + /* Autosensing required? */ + if(scsicmd->scsi_Flags & SCSIF_AUTOSENSE) + { + /*nBulkClear(ncm);*/ + + datalen = scsicmd->scsi_SenseLength; + umscbw.dCBWTag = (ULONG) scsicmd + ++ncm->ncm_TagCount; + umscbw.dCBWDataTransferLength = AROS_LONG2LE(datalen); + umscbw.bmCBWFlags = 0x80; + /*umscbw.bCBWLUN = ncm->ncm_UnitLun;*/ + umscbw.bCBWCBLength = 6; + umscbw.CBWCB[0] = SCSI_REQUEST_SENSE; + umscbw.CBWCB[1] = 0x00; + umscbw.CBWCB[2] = 0x00; + umscbw.CBWCB[3] = 0x00; + umscbw.CBWCB[4] = datalen; + umscbw.CBWCB[5] = 0; + XPRINTF(2, ("sense command block phase...\n")); + ioerr = psdDoPipe(ncm->ncm_EPOutPipe, &umscbw, UMSCBW_SIZEOF); + if(ioerr == UHIOERR_STALL) /* Retry on stall */ + { + XPRINTF(2, ("stall...\n")); + nBulkClear(ncm); + ioerr = psdDoPipe(ncm->ncm_EPOutPipe, &umscbw, UMSCBW_SIZEOF); + } + if(!ioerr) + { + XPRINTF(2, ("sense data phase %ld bytes...\n", datalen)); + if(ncm->ncm_CDC->cdc_PatchFlags & PFF_DELAY_DATA) + { + psdDelayMS(1); + } + ioerr = psdDoPipe(ncm->ncm_EPInPipe, scsicmd->scsi_SenseData, datalen); + scsicmd->scsi_SenseActual = psdGetPipeActual(ncm->ncm_EPInPipe); + if(ioerr == UHIOERR_STALL) /* Accept on stall */ + { + psdPipeSetup(ncm->ncm_EP0Pipe, URTF_STANDARD|URTF_ENDPOINT, + USR_CLEAR_FEATURE, UFS_ENDPOINT_HALT, (ULONG) ncm->ncm_EPInNum|URTF_IN); + ioerr = psdDoPipe(ncm->ncm_EP0Pipe, NULL, 0); + } + if((ioerr == UHIOERR_RUNTPACKET) || (ioerr == UHIOERR_OVERFLOW)) + { + XPRINTF(10, ("Extra or less data received, but ignored!\n")); + ioerr = 0; + } + + if(!ioerr) + { + if(ncm->ncm_CDC->cdc_PatchFlags & PFF_DELAY_DATA) + { + psdDelayMS(1); + } + XPRINTF(2, ("sense command status phase...\n")); + ioerr = psdDoPipe(ncm->ncm_EPInPipe, &umscsw, UMSCSW_SIZEOF); + if(ioerr == UHIOERR_STALL) /* Retry on stall */ + { + XPRINTF(2, ("stall...\n")); + psdPipeSetup(ncm->ncm_EP0Pipe, URTF_STANDARD|URTF_ENDPOINT, + USR_CLEAR_FEATURE, UFS_ENDPOINT_HALT, (ULONG) ncm->ncm_EPInNum|URTF_IN); + ioerr = psdDoPipe(ncm->ncm_EP0Pipe, NULL, 0); + ioerr |= psdDoPipe(ncm->ncm_EPInPipe, &umscsw, UMSCSW_SIZEOF); + } + if(ioerr == UHIOERR_RUNTPACKET) + { + // well, retry then + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "Command (sense) status block truncated (%ld bytes), retrying...", + psdGetPipeActual(ncm->ncm_EPInPipe)); + ioerr = psdDoPipe(ncm->ncm_EPInPipe, &umscsw, UMSCSW_SIZEOF); + } + + if(ioerr == UHIOERR_OVERFLOW) + { + XPRINTF(10, ("Extra Status received, but ignored!\n")); + ioerr = 0; + } + if(!ioerr) + { + XPRINTF(2, ("sense Status:\n" + " Signature: %08lx\n" + " Tag : %08lx\n" + " Residue : %08lx\n" + " Status : %02lx\n", + umscsw.dCSWSignature, + umscsw.dCSWTag, + umscsw.dCSWDataResidue, + umscsw.bCSWStatus)); + if(((umscsw.dCSWSignature != AROS_LONG2LE(0x53425355)) && (!(ncm->ncm_CDC->cdc_PatchFlags & PFF_CSS_BROKEN))) || (umscsw.dCSWTag != umscbw.dCBWTag)) + { + psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname, + "Illegal command (sense) status block (Sig:%08lx, Tag=%08lx/%08lx (TX/RX), Len=%ld)", + umscsw.dCSWSignature, + umscbw.dCBWTag, + umscsw.dCSWTag, + psdGetPipeActual(ncm->ncm_EPInPipe)); + scsicmd->scsi_Status = SCSI_CHECK_CONDITION; + rioerr = HFERR_Phase; + nBulkReset(ncm); + continue; + } + /* ignore this: too many firmwares report shit */ + //scsicmd->scsi_SenseActual = datalen - AROS_LONG2LE(umscsw.dCSWDataResidue); + if((scsicmd->scsi_SenseActual > 7) && ((*((ULONG *) scsicmd->scsi_SenseData)>>8) == 0x555342) && (((ULONG *) scsicmd->scsi_SenseData)[1] == umscbw.dCBWTag)) + { + psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname, + "Your MSD has a very bad firmware! Havoc!"); + scsicmd->scsi_Actual = 0; + umscsw.bCSWStatus = USMF_CSW_FAIL; + } + + if(umscsw.bCSWStatus) + { + /*psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "Sense failed: %ld", + umscsw.bCSWStatus);*/ + if(umscsw.bCSWStatus == USMF_CSW_PHASEERR) + { + nBulkReset(ncm); + } + } else { + switch(scsicmd->scsi_SenseData[2] & SK_MASK) + { + case SK_ILLEGAL_REQUEST: + case SK_NOT_READY: + retrycnt = 0; + break; + case SK_DATA_PROTECT: + if(!ncm->ncm_WriteProtect) + { + ncm->ncm_WriteProtect = TRUE; + if(ncm->ncm_CDC->cdc_PatchFlags & PFF_DEBUG) + { + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, + "WriteProtect On: Sense Data Protect"); + } + } + break; + + case SK_UNIT_ATTENTION: + if((ncm->ncm_CDC->cdc_PatchFlags & PFF_REM_SUPPORT) && + ((scsicmd->scsi_SenseData[12] == 0x28) || + (scsicmd->scsi_SenseData[12] == 0x3A))) + { + ncm->ncm_ChangeCount++; + if(ncm->ncm_CDC->cdc_PatchFlags & PFF_DEBUG) + { + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, + "Diskchange: Unit Attention (count = %ld)", + ncm->ncm_ChangeCount); + } + } + break; + } + XPRINTF(10, ("Sense Key: %lx/%02lx/%02lx\n", + scsicmd->scsi_SenseData[2] & SK_MASK, + scsicmd->scsi_SenseData[12], + scsicmd->scsi_SenseData[13])); + if(ncm->ncm_CDC->cdc_PatchFlags & PFF_DEBUG) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "Cmd %s: Sense Key %lx/%02lx/%02lx", + cmdstrbuf, + scsicmd->scsi_SenseData[2] & SK_MASK, + scsicmd->scsi_SenseData[12], + scsicmd->scsi_SenseData[13]); + } + } + } else { + XPRINTF(10, ("Sense status failed: %s (%ld)\n", psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr)); + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, "Command (%s) okay, but:", cmdstrbuf); + psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname, + "Sense status failed: %s (%ld)", + psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + nBulkReset(ncm); + } + } else { + XPRINTF(10, ("Sense data failed: %s (%ld)\n", psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr)); + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, "Command (%s) okay, but:", cmdstrbuf); + psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname, + "Sense data failed: %s (%ld)", + psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + nBulkReset(ncm); + } + } else { + XPRINTF(10, ("Sense block failed: %s (%ld)\n", psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr)); + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, "Command (%s) okay, but:", cmdstrbuf); + psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname, + "Sense block failed: %s (%ld)", + psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + /*nBulkReset(ncm);*/ + } + } + rioerr = HFERR_BadStatus; + } + } else { + XPRINTF(10, ("Command status failed: %s (%ld)\n", psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr)); + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, "Command (%s) failed:", cmdstrbuf); + psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname, + "Command status failed: %s (%ld)", + psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + scsicmd->scsi_Status = SCSI_CHECK_CONDITION; + rioerr = HFERR_Phase; + nBulkReset(ncm); + } + } else { + XPRINTF(10, ("Data phase failed: %s (%ld)\n", psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr)); + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, "Command (%s) failed:", cmdstrbuf); + psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname, + "Data phase failed: %s (%ld)", + psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + scsicmd->scsi_Status = SCSI_CHECK_CONDITION; + rioerr = HFERR_Phase; + nBulkReset(ncm); + } + } else { + XPRINTF(10, ("Command block failed: %s (%ld)\n", psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr)); + scsicmd->scsi_Status = SCSI_CHECK_CONDITION; + rioerr = HFERR_Phase; + if(ioerr == UHIOERR_TIMEOUT) + { + break; + } + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, "Command (%s) failed:", cmdstrbuf); + psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname, + "Command block failed: %s (%ld)", + psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + nBulkReset(ncm); + } + if(!rioerr) + { + break; + } + XPRINTF(1, ("Retrying...\n")); + } while(retrycnt--); + nUnlockXFer(ncm); + return(rioerr); +} +/* \\\ */ + +/* /// "nScsiDirectCBI()" */ +LONG nScsiDirectCBI(struct NepClassMS *ncm, struct SCSICmd *scsicmd) +{ + LONG ioerr; + struct PsdPipe *pp; + struct PsdPipe *backpp; + struct UsbMSCBIStatusWrapper umscsw; + ULONG datalen; + LONG rioerr; + UWORD retrycnt = 0; + UBYTE sensedata[18]; + UBYTE *senseptr; + UBYTE asc, ascq; + BOOL datadone; + BOOL statusdone; + BOOL ufisense; + UBYTE cmdstrbuf[16*3+2]; + + nHexString(scsicmd->scsi_Command, (ULONG) (scsicmd->scsi_CmdLength < 16 ? scsicmd->scsi_CmdLength : 16), cmdstrbuf); + + if(scsicmd->scsi_Flags & 0x80) /* Autoretry */ + { + retrycnt = 1; + } + scsicmd->scsi_Status = SCSI_GOOD; + nLockXFer(ncm); + do + { + if(ncm->ncm_DenyRequests) + { + rioerr = HFERR_Phase; + break; + } + rioerr = 0; + datalen = scsicmd->scsi_Length; + + KPRINTF(2, ("command block phase, tag %08lx, len %ld, flags %02lx...\n", + scsicmd, scsicmd->scsi_CmdLength, scsicmd->scsi_Flags)); + + KPRINTF(2, ("command: %s\n", cmdstrbuf)); + + //nBulkClear(ncm); + scsicmd->scsi_CmdActual = scsicmd->scsi_CmdLength; + /*if(datalen) + { + psdPipeSetup(ncm->ncm_EP0Pipe, URTF_STANDARD|URTF_ENDPOINT, + USR_CLEAR_FEATURE, UFS_ENDPOINT_HALT, + (ULONG) ((scsicmd->scsi_Flags & SCSIF_READ) ? ncm->ncm_EPInNum|URTF_IN : ncm->ncm_EPOutNum)); + ioerr = psdDoPipe(ncm->ncm_EP0Pipe, NULL, 0); + }*/ + psdPipeSetup(ncm->ncm_EP0Pipe, URTF_CLASS|URTF_INTERFACE, + UMSR_ADSC, 0, (ULONG) ncm->ncm_UnitIfNum); + ioerr = psdDoPipe(ncm->ncm_EP0Pipe, scsicmd->scsi_Command, (ULONG) scsicmd->scsi_CmdLength); + + if(ncm->ncm_DenyRequests) + { + rioerr = HFERR_Phase; + break; + } + if(!ioerr) + { + datadone = statusdone = FALSE; + if(datalen) + { + if(ncm->ncm_CDC->cdc_PatchFlags & PFF_CLEAR_EP) + { + psdPipeSetup(ncm->ncm_EP0Pipe, URTF_STANDARD|URTF_ENDPOINT, + USR_CLEAR_FEATURE, UFS_ENDPOINT_HALT, + (ULONG) ((scsicmd->scsi_Flags & SCSIF_READ) ? ncm->ncm_EPInNum|URTF_IN : ncm->ncm_EPOutNum)); + ioerr = psdDoPipe(ncm->ncm_EP0Pipe, NULL, 0); + } + + KPRINTF(2, ("data phase %ld bytes...\n", datalen)); + pp = (scsicmd->scsi_Flags & SCSIF_READ) ? ncm->ncm_EPInPipe : ncm->ncm_EPOutPipe; + + if(ncm->ncm_TPType == MS_PROTO_CBI) + { + /* okay, this is a major pain in the arse. + we have to do this asynchroneously */ + umscsw.bType = 0; + umscsw.bValue = USMF_CSW_PHASEERR; + psdSendPipe(ncm->ncm_EPIntPipe, &umscsw, sizeof(struct UsbMSCBIStatusWrapper)); + psdSendPipe(pp, scsicmd->scsi_Data, datalen); + do + { + WaitPort(ncm->ncm_TaskMsgPort); + while((backpp = (struct PsdPipe *) GetMsg(ncm->ncm_TaskMsgPort))) + { + if(backpp == pp) + { + /* data transfer finished */ + datadone = TRUE; + } + else if(backpp == ncm->ncm_EPIntPipe) + { + /* status returned */ + statusdone = TRUE; + } + } + } while(!statusdone); + if(!datadone) + { + psdAbortPipe(pp); + psdWaitPipe(pp); + ioerr = 0; + } else { + ioerr = psdGetPipeError(pp); + } + + } else { + ioerr = psdDoPipe(pp, scsicmd->scsi_Data, datalen); + } + + scsicmd->scsi_Actual = psdGetPipeActual(pp); + if(ioerr == UHIOERR_OVERFLOW) + { + KPRINTF(10, ("Extra Data received, but ignored!\n")); + ioerr = 0; + } + if(ioerr == UHIOERR_STALL) /* Accept on stall */ + { + KPRINTF(2, ("stall...\n")); + //nBulkClear(ncm); + psdPipeSetup(ncm->ncm_EP0Pipe, URTF_STANDARD|URTF_ENDPOINT, + USR_CLEAR_FEATURE, UFS_ENDPOINT_HALT, + (ULONG) ((scsicmd->scsi_Flags & SCSIF_READ) ? ncm->ncm_EPInNum|URTF_IN : ncm->ncm_EPOutNum)); + psdDoPipe(ncm->ncm_EP0Pipe, NULL, 0); + ioerr = 0; + } + } else { + ioerr = 0; + scsicmd->scsi_Actual = 0; + } + ufisense = FALSE; + if((!ioerr) || (ioerr == UHIOERR_RUNTPACKET)) + { + KPRINTF(2, ("command status phase...\n")); + if(ncm->ncm_TPType == MS_PROTO_CBI) + { + if(!statusdone) + { + if(ncm->ncm_CSType == MS_UFI_SUBCLASS) + { + umscsw.bType = 0x04; + umscsw.bValue = 0; + } else { + umscsw.bType = 0; + umscsw.bValue = USMF_CSW_PHASEERR; + } + ioerr = psdDoPipe(ncm->ncm_EPIntPipe, &umscsw, sizeof(struct UsbMSCBIStatusWrapper)); + } else { + ioerr = psdGetPipeError(ncm->ncm_EPIntPipe); + } + umscsw.bValue &= 0x0f; /* mask out upper nibble */ + if(ioerr) + { + psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname, + "Status interrupt failed: %s (%ld)", + psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + nBulkReset(ncm); + } + if(ncm->ncm_CSType == MS_UFI_SUBCLASS) + { + asc = umscsw.bType; + ascq = umscsw.bValue; + if((scsicmd->scsi_Command[0] == SCSI_REQUEST_SENSE) || + (scsicmd->scsi_Command[0] == SCSI_INQUIRY)) + { + umscsw.bType = 0; + umscsw.bValue = USMF_CSW_PASS; + } else { + umscsw.bType = 0; + umscsw.bValue = asc ? USMF_CSW_FAIL : USMF_CSW_PASS; + if(umscsw.bValue) + { + rioerr = HFERR_BadStatus; + } + } + } else { + umscsw.bValue &= USMF_CSW_PERSIST; /* mask out other bits */ + } + } else { + umscsw.bType = 0; + umscsw.bValue = USMF_CSW_PASS; + ioerr = 0; + } + if(ncm->ncm_DenyRequests) + { + rioerr = HFERR_Phase; + break; + } + if((!ioerr) || (ioerr == UHIOERR_RUNTPACKET)) + { + scsicmd->scsi_Status = umscsw.bValue; + if(umscsw.bValue == USMF_CSW_PHASEERR) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "Command (%s) phase error: %ld", + cmdstrbuf, + umscsw.bValue); + nBulkReset(ncm); + } + else if(umscsw.bValue == USMF_CSW_PERSIST) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "Command (%s) persistant error: %ld", + cmdstrbuf, + umscsw.bValue); + nBulkReset(ncm); + } + + /* Autosensing required? */ + if(((umscsw.bValue && (scsicmd->scsi_Flags & SCSIF_AUTOSENSE))) || + (ncm->ncm_TPType == MS_PROTO_CB) || (ncm->ncm_TPType == MS_PROTO_CBI)) + { + if(scsicmd->scsi_Flags & SCSIF_AUTOSENSE) + { + datalen = scsicmd->scsi_SenseLength; + senseptr = scsicmd->scsi_SenseData; + } else { + datalen = 18; + senseptr = sensedata; + } + if(!(scsicmd->scsi_SenseActual = nCBIRequestSense(ncm, senseptr, datalen))) + { + nBulkReset(ncm); + } + if(senseptr[2] & SK_MASK) + { + rioerr = HFERR_BadStatus; + scsicmd->scsi_Status = SCSI_CHECK_CONDITION; + } + } + } else { + psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname, + "Command status failed: %s (%ld)", + psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + scsicmd->scsi_Status = SCSI_CHECK_CONDITION; + rioerr = HFERR_Phase; + nBulkReset(ncm); + } + } else { + psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname, + "Data phase failed: %s (%ld)", + psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + scsicmd->scsi_Status = SCSI_CHECK_CONDITION; + rioerr = HFERR_Phase; + nBulkClear(ncm); + } + } else { + scsicmd->scsi_Status = SCSI_CHECK_CONDITION; + rioerr = HFERR_Phase; + if(ioerr == UHIOERR_TIMEOUT) + { + break; + } + if(ncm->ncm_CDC->cdc_PatchFlags & PFF_DEBUG) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, "Command (%s) failed:", cmdstrbuf); + psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname, + "Command block failed: %s (%ld)", + psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + } + if(scsicmd->scsi_Flags & SCSIF_AUTOSENSE) + { + datalen = scsicmd->scsi_SenseLength; + senseptr = scsicmd->scsi_SenseData; + } else { + datalen = 18; + senseptr = sensedata; + } + if(!(scsicmd->scsi_SenseActual = nCBIRequestSense(ncm, senseptr, datalen))) + { + nBulkReset(ncm); + retrycnt = 0; + } else { + if(senseptr[2] & SK_MASK) + { + rioerr = HFERR_BadStatus; + if((senseptr[2] & SK_MASK) == SK_NOT_READY) + { + retrycnt = 0; + } + } + } + } + if(!rioerr) + { + break; + } + KPRINTF(1, ("Retrying...\n")); + } while(retrycnt--); + nUnlockXFer(ncm); + return(rioerr); +} +/* \\\ */ + +/* /// "nLockXFer()" */ +void nLockXFer(struct NepClassMS *ncm) +{ + if(ncm->ncm_MaxLUN) + { + KPRINTF(1, ("PING(lock)\n")); + ObtainSemaphore(&ncm->ncm_UnitLUN0->ncm_XFerLock); + KPRINTF(1, ("PONG(lock)\n")); + } +} +/* \\\ */ + +/* /// "nUnlockXFer()" */ +void nUnlockXFer(struct NepClassMS *ncm) +{ + if(ncm->ncm_MaxLUN) + { + KPRINTF(1, ("PING(unlock)\n")); + ReleaseSemaphore(&ncm->ncm_UnitLUN0->ncm_XFerLock); + KPRINTF(1, ("PONG(unlock)\n")); + } +} +/* \\\ */ + +/* /// "nStoreConfig()" */ +BOOL nStoreConfig(struct NepClassMS *ncm) +{ + APTR pic; + struct NepClassMS *cncm; + if(ncm->ncm_Interface) + { + pic = psdGetUsbDevCfg(libname, ncm->ncm_DevIDString, ncm->ncm_IfIDString); + if(!pic) + { + psdSetUsbDevCfg(libname, ncm->ncm_DevIDString, ncm->ncm_IfIDString, NULL); + pic = psdGetUsbDevCfg(libname, ncm->ncm_DevIDString, ncm->ncm_IfIDString); + } + if(pic) + { + psdAddCfgEntry(pic, ncm->ncm_CDC); + cncm = ncm; + while(((struct Node *) cncm)->ln_Succ) + { + if(cncm->ncm_UnitLUN0 != ncm) + { + break; + } + psdAddCfgEntry(pic, cncm->ncm_CUC); + cncm = (struct NepClassMS *) ((struct Node *) cncm)->ln_Succ; + } + return(TRUE); + } + } else { + return(TRUE); + } + return(FALSE); +} +/* \\\ */ + +/* ********************************************************************* */ + +/* /// "BSTR Macros" */ +#define b2cstr(bstr, cstr) { ULONG i; for (i = 0; i < bstr[0]; i++) cstr[i] = bstr[i + 1]; cstr[i] = 0x00; } +#define i2a(x) ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24)) +#define c2bstr(cstr, bstr)\ + do\ + {\ + int i = 0;\ + UBYTE c;\ + STRPTR cp = (STRPTR) (cstr);\ + STRPTR bp = (STRPTR) (bstr);\ + while(c = cp[i])\ + {\ + bp[++i] = c;\ + }\ + bp[0] = i;\ + } while(0) +/* \\\ */ + +#undef ps +#define ps nh->nh_PsdBase + +/* /// "nRemovableTask()" */ +AROS_UFH0(void, nRemovableTask) +{ + AROS_USERFUNC_INIT + + struct NepMSBase *nh; + struct NepClassMS *ncm; + ULONG sigmask; + ULONG sigs; + LONG ioerr; + struct SCSICmd scsicmd; + UBYTE cmd6[6]; + UBYTE sensedata[18]; + struct IOStdReq *ioreq; + BOOL dontquit = TRUE; + + if((nh = nAllocRT())) + { + Forbid(); + if(nh->nh_ReadySigTask) + { + Signal(nh->nh_ReadySigTask, 1L<nh_ReadySignal); + } + Permit(); + /* Main task */ + sigmask = (1L<nh_TimerMsgPort->mp_SigBit)| + SIGBREAKF_CTRL_C; + do + { + while((ioreq = (struct IOStdReq *) GetMsg(nh->nh_TimerMsgPort))) + { + dontquit = FALSE; + KPRINTF(2, ("Timer interrupt\n")); + ncm = (struct NepClassMS *) nh->nh_Units.lh_Head; + while(ncm->ncm_Unit.unit_MsgPort.mp_Node.ln_Succ) + { + if(ncm->ncm_Task && (!ncm->ncm_DenyRequests)) + { + dontquit = TRUE; + + if(ncm->ncm_Removable && ncm->ncm_Running) + { + scsicmd.scsi_Data = NULL; + scsicmd.scsi_Length = 0; + scsicmd.scsi_Command = cmd6; + scsicmd.scsi_CmdLength = 6; + scsicmd.scsi_Flags = SCSIF_READ|SCSIF_AUTOSENSE|0x80; + scsicmd.scsi_SenseData = sensedata; + scsicmd.scsi_SenseLength = 18; + cmd6[0] = SCSI_TEST_UNIT_READY; + cmd6[1] = 0; + cmd6[2] = 0; + cmd6[3] = 0; + cmd6[4] = 0; + cmd6[5] = 0; + if((ioerr = nScsiDirectTunnel(ncm, &scsicmd))) + { + KPRINTF(1, ("Test unit ready yielded: %ld/%ld\n", sensedata[2], sensedata[12])); + /*psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "SCSI_TEST_UNIT_READY failed: %ld", + ioerr);*/ + /* Check for MEDIUM NOT PRESENT */ + if(((sensedata[2] & SK_MASK) == SK_NOT_READY) && + ((sensedata[12] == 0x3a) || (sensedata[12] == 0x04))) + { + if(ncm->ncm_UnitReady) + { + ncm->ncm_UnitReady = FALSE; + ncm->ncm_ChangeCount++; + KPRINTF(10, ("Diskchange: Medium removed (count = %ld)!\n", ncm->ncm_ChangeCount)); + if(ncm->ncm_CDC->cdc_PatchFlags & PFF_DEBUG) + { + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, + "Diskchange: Medium removed (count = %ld)", + ncm->ncm_ChangeCount); + } + } + } + } else { + if(!ncm->ncm_UnitReady) + { + ncm->ncm_UnitReady = TRUE; + ncm->ncm_ChangeCount++; + KPRINTF(10, ("Diskchange: Medium inserted (count = %ld)!\n", ncm->ncm_ChangeCount)); + if(ncm->ncm_CDC->cdc_PatchFlags & PFF_DEBUG) + { + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, + "Diskchange: Medium inserted (count = %ld)", + ncm->ncm_ChangeCount); + } + if(ncm->ncm_CSType == MS_UFI_SUBCLASS) + { + nh->nh_IOReq.io_Command = CMD_START; + nIOCmdTunnel(ncm, &nh->nh_IOReq); + } + } else { + if(ncm->ncm_CDC->cdc_PatchFlags & PFF_REM_SUPPORT) + { + nGetWriteProtect(ncm); + } + } + } + } + if(ncm->ncm_LastChange != ncm->ncm_ChangeCount) + { + if(ncm->ncm_UnitReady) + { + nGetWriteProtect(ncm); + if(ncm->ncm_CDC->cdc_PatchFlags & PFF_REM_SUPPORT) + { + nh->nh_IOReq.io_Command = TD_GETGEOMETRY; + nh->nh_IOReq.io_Data = &ncm->ncm_Geometry; + nh->nh_IOReq.io_Length = sizeof(ncm->ncm_Geometry); + nIOCmdTunnel(ncm, &nh->nh_IOReq); + } + } + ioreq = (struct IOStdReq *) ncm->ncm_DCInts.lh_Head; + while(((struct Node *) ioreq)->ln_Succ) + { + Cause(ioreq->io_Data); + ioreq = (struct IOStdReq *) ((struct Node *) ioreq)->ln_Succ; + } + if(ncm->ncm_UnitReady) + { + // obtain blocksize first + if(!ncm->ncm_BlockSize) + { + nh->nh_IOReq.io_Command = TD_GETGEOMETRY; + nh->nh_IOReq.io_Data = &ncm->ncm_Geometry; + nh->nh_IOReq.io_Length = sizeof(ncm->ncm_Geometry); + nIOCmdTunnel(ncm, &nh->nh_IOReq); + } + ncm->ncm_HasMounted = TRUE; + + if(ncm->ncm_BlockSize && ncm->ncm_CUC->cuc_AutoMountRDB) + { + ProcessRDB(ncm); + } + if(ncm->ncm_CUC->cuc_AutoMountFAT) + { + CheckFATPartition(ncm, 0); + } + if((ncm->ncm_BlockSize == 2048) && + ((ncm->ncm_DeviceType == PDT_WORM) || (ncm->ncm_DeviceType == PDT_CDROM))) + { + if(ncm->ncm_CUC->cuc_AutoMountCD) + { + CheckISO9660(ncm); + } + } + } + ncm->ncm_LastChange = ncm->ncm_ChangeCount; + } + } else { + if(ncm->ncm_DenyRequests && ncm->ncm_CUC->cuc_AutoUnmount && ncm->ncm_HasMounted) + { + nUnmountPartition(ncm); + ncm->ncm_HasMounted = FALSE; + } + } + ncm = (struct NepClassMS *) ncm->ncm_Unit.unit_MsgPort.mp_Node.ln_Succ; + } + nh->nh_TimerIOReq->tr_time.tv_secs = 3; + nh->nh_TimerIOReq->tr_time.tv_micro = 0; + SendIO((struct IORequest *) nh->nh_TimerIOReq); + } + + if(nh->nh_RemovableTask->tc_Node.ln_Type == NT_TASK) + { + APTR doslib; + if((doslib = OpenLibrary("dos.library", 39))) + { + CloseLibrary(doslib); + // increase disk change count to force mounting + ncm = (struct NepClassMS *) nh->nh_Units.lh_Head; + while(ncm->ncm_Unit.unit_MsgPort.mp_Node.ln_Succ) + { + ncm->ncm_ChangeCount++; + ncm->ncm_ForceRTCheck = TRUE; + ncm = (struct NepClassMS *) ncm->ncm_Unit.unit_MsgPort.mp_Node.ln_Succ; + } + + /* restart task */ + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, + "DOS found, stopping removable task..."); + nh->nh_RestartIt = TRUE; + break; + } + // don't quit task, otherwise nobody will be there to restart it and retry mounting stuff + dontquit = TRUE; + } + + if(!dontquit) + { + break; + } + sigs = Wait(sigmask); + } while(!(sigs & SIGBREAKF_CTRL_C)); + ncm = (struct NepClassMS *) nh->nh_Units.lh_Head; + while(ncm->ncm_Unit.unit_MsgPort.mp_Node.ln_Succ) + { + if(ncm->ncm_DenyRequests && ncm->ncm_CUC->cuc_AutoUnmount && ncm->ncm_HasMounted) + { + nUnmountPartition(ncm); + ncm->ncm_HasMounted = FALSE; + } + ncm = (struct NepClassMS *) ncm->ncm_Unit.unit_MsgPort.mp_Node.ln_Succ; + } + KPRINTF(20, ("Going down the river!\n")); + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, "Removable Task stopped."); + nFreeRT(nh); + } + AROS_USERFUNC_EXIT +} +/* \\\ */ + +/* /// "nAllocRT()" */ +struct NepMSBase * nAllocRT(void) +{ + struct Task *thistask; + struct NepMSBase *nh; + + thistask = FindTask(NULL); + nh = thistask->tc_UserData; +#undef ExpansionBase +#define ExpansionBase nh->nh_ExpansionBase + do + { + if(!(ExpansionBase = OpenLibrary("expansion.library", 37))) + { + Alert(AG_OpenLib); + break; + } + if(!(ps = OpenLibrary("poseidon.library", 4))) + { + Alert(AG_OpenLib); + break; + } + if(!(nh->nh_IOMsgPort = CreateMsgPort())) + { + break; + } + nh->nh_IOReq.io_Message.mn_ReplyPort = nh->nh_IOMsgPort; + if(!(nh->nh_TimerMsgPort = CreateMsgPort())) + { + break; + } + if(!(nh->nh_TimerIOReq = (struct timerequest *) CreateIORequest(nh->nh_TimerMsgPort, sizeof(struct timerequest)))) + { + break; + } + if(OpenDevice("timer.device", UNIT_VBLANK, (struct IORequest *) nh->nh_TimerIOReq, 0)) + { + break; + } + /* Start removable interrupt */ + nh->nh_TimerIOReq->tr_node.io_Command = TR_ADDREQUEST; + nh->nh_TimerIOReq->tr_time.tv_secs = 0; + nh->nh_TimerIOReq->tr_time.tv_micro = 50; + SendIO((struct IORequest *) nh->nh_TimerIOReq); + nh->nh_RemovableTask = thistask; + return(nh); + } while(FALSE); + if(ExpansionBase) + { + CloseLibrary(ExpansionBase); + ExpansionBase = NULL; + } + if(ps) + { + CloseLibrary(ps); + ps = NULL; + } + + if(nh->nh_TimerIOReq) + { + if(nh->nh_TimerIOReq->tr_node.io_Device) + { + CloseDevice((struct IORequest *) nh->nh_TimerIOReq); + } + DeleteIORequest((struct IORequest *) nh->nh_TimerIOReq); + nh->nh_TimerIOReq = NULL; + } + if(nh->nh_TimerMsgPort) + { + DeleteMsgPort(nh->nh_TimerMsgPort); + nh->nh_TimerMsgPort = NULL; + } + if(nh->nh_IOMsgPort) + { + DeleteMsgPort(nh->nh_IOMsgPort); + nh->nh_IOMsgPort = NULL; + } + Forbid(); + nh->nh_RemovableTask = NULL; + if(nh->nh_ReadySigTask) + { + Signal(nh->nh_ReadySigTask, 1L<nh_ReadySignal); + } + return(NULL); +} +/* \\\ */ + +/* /// "nFreeRT()" */ +void nFreeRT(struct NepMSBase *nh) +{ + + psdFreeVec(nh->nh_OneBlock); + nh->nh_OneBlock = NULL; + nh->nh_OneBlockSize = 0; + + if(nh->nh_DOSBase) + { + CloseLibrary(nh->nh_DOSBase); + nh->nh_DOSBase = NULL; + } + CloseLibrary(ExpansionBase); + ExpansionBase = NULL; + CloseLibrary(ps); + ps = NULL; + + AbortIO((struct IORequest *) nh->nh_TimerIOReq); + WaitIO((struct IORequest *) nh->nh_TimerIOReq); + CloseDevice((struct IORequest *) nh->nh_TimerIOReq); + DeleteIORequest((struct IORequest *) nh->nh_TimerIOReq); + DeleteMsgPort(nh->nh_TimerMsgPort); + nh->nh_TimerMsgPort = NULL; + nh->nh_TimerIOReq = NULL; + + Forbid(); + nh->nh_RemovableTask = NULL; + if(nh->nh_ReadySigTask) + { + Signal(nh->nh_ReadySigTask, 1L<nh_ReadySignal); + } + if(nh->nh_RestartIt) + { + // wake up every task to relaunch removable task + struct NepClassMS *ncm; + ncm = (struct NepClassMS *) nh->nh_Units.lh_Head; + while(ncm->ncm_Unit.unit_MsgPort.mp_Node.ln_Succ) + { + if(ncm->ncm_Task) + { + Signal(ncm->ncm_Task, 1L<ncm_TaskMsgPort->mp_SigBit); + } + ncm = (struct NepClassMS *) ncm->ncm_Unit.unit_MsgPort.mp_Node.ln_Succ; + } + nh->nh_RestartIt = FALSE; + } +} +/* \\\ */ + +/* /// "nOpenDOS()" */ +BOOL nOpenDOS(struct NepMSBase *nh) +{ + if(nh->nh_DOSBase) + { + return(TRUE); + } + if(nh->nh_RemovableTask->tc_Node.ln_Type != NT_PROCESS) + { + return(FALSE); + } + if((nh->nh_DOSBase = OpenLibrary("dos.library", 39))) + { + KPRINTF(10, ("Opened dos.library!\n")); + return(TRUE); + } + return(FALSE); +} +/* \\\ */ + +#undef DOSBase +#define DOSBase nh->nh_DOSBase + +/* /// "nUnmountPartition()" */ +void nUnmountPartition(struct NepClassMS *ncm) +{ + // FIXME AROS devs, you need to add the actual mounting code +} +/* \\\ */ + +/* /// "nIOCmdTunnel()" */ +LONG nIOCmdTunnel(struct NepClassMS *ncm, struct IOStdReq *ioreq) +{ + struct NepMSBase *nh = ncm->ncm_ClsBase; + Forbid(); + if(ncm->ncm_DenyRequests) + { + Permit(); + return(ioreq->io_Error = IOERR_ABORTED); + } + PutMsg(&ncm->ncm_Unit.unit_MsgPort, (struct Message *) ioreq); + Permit(); + while(!GetMsg(nh->nh_IOMsgPort)) + { + WaitPort(nh->nh_IOMsgPort); + } + return(ioreq->io_Error); +} +/* \\\ */ + +/* /// "nScsiDirectTunnel()" */ +LONG nScsiDirectTunnel(struct NepClassMS *ncm, struct SCSICmd *scsicmd) +{ + struct NepMSBase *nh = ncm->ncm_ClsBase; + struct IOStdReq *ioreq = &nh->nh_IOReq; + ioreq->io_Command = HD_SCSICMD; + ioreq->io_Data = scsicmd; + ioreq->io_Length = sizeof(*scsicmd); + return(nIOCmdTunnel(ncm, ioreq)); +} +/* \\\ */ + +/* /// "nGetWriteProtect()" */ +LONG nGetWriteProtect(struct NepClassMS *ncm) +{ + struct NepMSBase *nh = ncm->ncm_ClsBase; + UBYTE cmd10[10]; + struct SCSICmd scsicmd; + UBYTE inquirydata[256]; + UBYTE sensedata[18]; + LONG ioerr; + + if((ncm->ncm_DeviceType == PDT_WORM) || + (ncm->ncm_DeviceType == PDT_CDROM)) + { + // cd roms are always write protected + return(ncm->ncm_WriteProtect = TRUE); + } + if(ncm->ncm_CDC->cdc_PatchFlags & PFF_SIMPLE_SCSI) + { + return(ncm->ncm_WriteProtect = FALSE); + } + scsicmd.scsi_Data = (UWORD *) inquirydata; + scsicmd.scsi_Length = 8; + scsicmd.scsi_Command = cmd10; + scsicmd.scsi_CmdLength = 10; + scsicmd.scsi_Flags = SCSIF_READ|SCSIF_AUTOSENSE|0x80; + scsicmd.scsi_SenseData = sensedata; + scsicmd.scsi_SenseLength = 18; + cmd10[0] = SCSI_MODE_SENSE_10; + cmd10[1] = 0x00; /* no block descriptors */ + cmd10[2] = 0x3f; /* no page, only header */ + cmd10[3] = 0; + cmd10[4] = 0; + cmd10[5] = 0; + cmd10[6] = 0; + cmd10[7] = 0; + cmd10[8] = 8; + cmd10[9] = 0; + if((ioerr = nScsiDirectTunnel(ncm, &scsicmd))) + { + cmd10[2] = 0x00; /* try again with vendor page, only header */ + if((ioerr = nScsiDirectTunnel(ncm, &scsicmd))) + { + cmd10[2] = 0x3f; /* try again with 255 length */ + cmd10[8] = 0xff; + if((ioerr = nScsiDirectTunnel(ncm, &scsicmd))) + { + if(ncm->ncm_CDC->cdc_PatchFlags & PFF_DEBUG) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "Failed to get write protection state: %ld", + ioerr); + } + if(!(ncm->ncm_CDC->cdc_PatchFlags & PFF_NO_FALLBACK)) + { + ncm->ncm_CDC->cdc_PatchFlags |= PFF_SIMPLE_SCSI; + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "Fallback: Enabling Simple SCSI."); + } + nStoreConfig(ncm); + return(0); + } + } + } + if(inquirydata[3] & 0x80) + { + if(!ncm->ncm_WriteProtect) + { + if(ncm->ncm_CDC->cdc_PatchFlags & PFF_REM_SUPPORT) + { + ncm->ncm_ChangeCount++; + if(ncm->ncm_CDC->cdc_PatchFlags & PFF_DEBUG) + { + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, + "Diskchange: GetWriteProtect On (count = %ld)", + ncm->ncm_ChangeCount); + } + } + ncm->ncm_WriteProtect = TRUE; + } + } else { + if(ncm->ncm_WriteProtect) + { + if(ncm->ncm_CDC->cdc_PatchFlags & PFF_REM_SUPPORT) + { + ncm->ncm_ChangeCount++; + if(ncm->ncm_CDC->cdc_PatchFlags & PFF_DEBUG) + { + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, + "Diskchange: GetWriteProtect Off (count = %ld)", + ncm->ncm_ChangeCount); + } + } + ncm->ncm_WriteProtect = FALSE; + } + } + return(ncm->ncm_WriteProtect); +} +/* \\\ */ + +/* /// "ProcessRDB()" */ +void ProcessRDB(struct NepClassMS *ncm) +{ + // FIXME AROS devs, you need to add the actual mounting code +} +/* \\\ */ + +/* /// "CheckFATPartition()" */ +void CheckFATPartition(struct NepClassMS *ncm, ULONG startblock) +{ + // FIXME AROS devs, you need to add the actual mounting code +} +/* \\\ */ + +/* /// "CheckISO9660()" */ +void CheckISO9660(struct NepClassMS *ncm) +{ + struct NepMSBase *nh = ncm->ncm_ClsBase; + UBYTE *blockbuf; + struct IOStdReq *stdIO = &nh->nh_IOReq; + + blockbuf = (UBYTE *) psdAllocVec(ncm->ncm_BlockSize); + if(!blockbuf) + { + return; + } + stdIO->io_Command = TD_READ64; + stdIO->io_Offset = 0x8000; + stdIO->io_Actual = 0; + stdIO->io_Length = ncm->ncm_BlockSize; + stdIO->io_Data = blockbuf; + if(!nIOCmdTunnel(ncm, stdIO)) + { + if((((ULONG *) blockbuf)[0] == AROS_LONG2BE(0x01434430)) && (((ULONG *) blockbuf)[1] == AROS_LONG2BE(0x30310100))) + { + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, "Media is ISO9660."); + // FIXME AROS devs, you need to add the actual mounting code + //AutoMountCD(ncm); + } + } else { + KPRINTF(10, ("failed to read ISO sector\n")); + if(ncm->ncm_CDC->cdc_PatchFlags & PFF_DEBUG) + { + psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname, + "Failed to read block 16 for CDFS AutoMounting."); + } + } + psdFreeVec(blockbuf); +} +/* \\\ */ + +/**************************************************************************/ + +static const char *MaxTransferStrings[] = +{ + " 64 KB", + "128 KB", + "256 KB", + "512 KB", + " 1 MB", + " 2 MB", + NULL +}; + +static char *MainGUIPages[] = { "Device Settings", "LUN Settings", NULL }; +static char *MainGUIPagesDefault[] = { "Device Defaults", "LUN Defaults", NULL }; + +/* /// "nGetDosType()" */ +ULONG nGetDosType(STRPTR tmpstr) +{ + ULONG dostype = 0; + UBYTE ch; + + while((ch = *tmpstr++)) + { + dostype <<= 4; + if((ch >= '0') && (ch <= '9')) + { + dostype += ch - '0'; + } + else if((ch >= 'a') && (ch <= 'f')) + { + dostype += ch - 'a' + 10; + } + else if((ch >= 'A') && (ch <= 'F')) + { + dostype += ch - 'A' + 10; + } + } + return(dostype); +} +/* \\\ */ + +/* /// "nGUITask()" */ +AROS_UFH0(void, nGUITask) +{ + AROS_USERFUNC_INIT + + struct Task *thistask; + struct NepMSBase *nh; + struct NepClassMS *ncm; + struct NepClassMS *cncm; + struct NepClassMS *curncm = NULL; + APTR pic; + char dostypebuf[10]; + char cddostypebuf[10]; + char ntfsdostypebuf[10]; + char bar[] = "BAR,"; + + thistask = FindTask(NULL); +#undef ps +#define ps ncm->ncm_PsdBase +#undef IntuitionBase +#define IntuitionBase ncm->ncm_IntBase +#undef MUIMasterBase +#define MUIMasterBase ncm->ncm_MUIBase + + ncm = thistask->tc_UserData; + nh = ncm->ncm_ClsBase; + + ++nh->nh_Library.lib_OpenCnt; + if(!(MUIMasterBase = OpenLibrary(MUIMASTER_NAME, MUIMASTER_VMIN))) + { + KPRINTF(10, ("Couldn't open muimaster.library.\n")); + nGUITaskCleanup(ncm); + return; + } + + if(!(IntuitionBase = OpenLibrary("intuition.library", 39))) + { + KPRINTF(10, ("Couldn't open intuition.library.\n")); + nGUITaskCleanup(ncm); + return; + } + if(!(ps = OpenLibrary("poseidon.library", 4))) + { + KPRINTF(10, ("Couldn't open poseidon.library.\n")); + nGUITaskCleanup(ncm); + return; + } + + ncm->ncm_LUNListDisplayHook.h_Data = NULL; + ncm->ncm_LUNListDisplayHook.h_Entry = (APTR) LUNListDisplayHook; + + psdSafeRawDoFmt(dostypebuf, 10, "%08lx", ncm->ncm_CDC->cdc_FATDosType); + psdSafeRawDoFmt(ntfsdostypebuf, 10, "%08lx", ncm->ncm_CDC->cdc_NTFSDosType); + psdSafeRawDoFmt(cddostypebuf, 10, "%08lx", ncm->ncm_CDC->cdc_CDDosType); + + ncm->ncm_App = ApplicationObject, + MUIA_Application_Title , libname, + MUIA_Application_Version , VERSION_STRING, + MUIA_Application_Copyright , "©2002-2009 Chris Hodges", + MUIA_Application_Author , "Chris Hodges ", + MUIA_Application_Description, "Settings for the massstorage.class", + MUIA_Application_Base , "MASSSTORAGE", + MUIA_Application_HelpFile , "HELP:Poseidon.guide", + MUIA_Application_Menustrip , MenustripObject, + Child, MenuObjectT("Project"), + Child, ncm->ncm_AboutMI = MenuitemObject, + MUIA_Menuitem_Title, "About...", + MUIA_Menuitem_Shortcut, "?", + End, + End, + Child, MenuObjectT("Settings"), + Child, ncm->ncm_UseMI = MenuitemObject, + MUIA_Menuitem_Title, "Save", + MUIA_Menuitem_Shortcut, "S", + End, + Child, ncm->ncm_SetDefaultMI = MenuitemObject, + MUIA_Menuitem_Title, "Save as Default", + MUIA_Menuitem_Shortcut, "D", + End, + Child, MenuitemObject, + MUIA_Menuitem_Title, NM_BARLABEL, + End, + Child, ncm->ncm_MUIPrefsMI = MenuitemObject, + MUIA_Menuitem_Title, "MUI Settings", + MUIA_Menuitem_Shortcut, "M", + End, + End, + End, + + SubWindow, ncm->ncm_MainWindow = WindowObject, + MUIA_Window_ID , MAKE_ID('M','A','I','N'), + MUIA_Window_Title, libname, + MUIA_HelpNode, libname, + + WindowContents, VGroup, + Child, RegisterGroup(ncm->ncm_Interface ? MainGUIPages : MainGUIPagesDefault), + MUIA_CycleChain, 1, + MUIA_Register_Frame, TRUE, + Child, VGroup, + Child, VSpace(0), + Child, ColGroup(2), + Child, Label((IPTR) "NAK Timeout:"), + Child, ncm->ncm_NakTimeoutObj = SliderObject, SliderFrame, + MUIA_CycleChain, 1, + MUIA_Numeric_Min, 0, + MUIA_Numeric_Max, 600, + MUIA_Numeric_Value, ncm->ncm_CDC->cdc_NakTimeout, + MUIA_Numeric_Format, "%ld00ms", + End, + Child, Label((IPTR) "Startup delay:"), + Child, ncm->ncm_StartupDelayObj = SliderObject, SliderFrame, + MUIA_CycleChain, 1, + MUIA_Numeric_Min, 0, + MUIA_Numeric_Max, 100, + MUIA_Numeric_Value, ncm->ncm_CDC->cdc_StartupDelay, + MUIA_Numeric_Format, "%ld00ms", + End, + Child, Label((IPTR) "Single LUN:"), + Child, HGroup, + Child, ncm->ncm_SingleLunObj = ImageObject, ImageButtonFrame, + MUIA_Background, MUII_ButtonBack, + MUIA_CycleChain, 1, + MUIA_InputMode, MUIV_InputMode_Toggle, + MUIA_Image_Spec, MUII_CheckMark, + MUIA_Image_FreeVert, TRUE, + MUIA_Selected, ncm->ncm_CDC->cdc_PatchFlags & PFF_SINGLE_LUN, + MUIA_ShowSelState, FALSE, + End, + Child, HSpace(0), + Child, Label((IPTR) "No Initial Reset:"), + Child, ncm->ncm_InitialResetObj = ImageObject, ImageButtonFrame, + MUIA_Background, MUII_ButtonBack, + MUIA_CycleChain, 1, + MUIA_InputMode, MUIV_InputMode_Toggle, + MUIA_Image_Spec, MUII_CheckMark, + MUIA_Image_FreeVert, TRUE, + MUIA_Selected, ncm->ncm_CDC->cdc_PatchFlags & PFF_NO_RESET, + MUIA_ShowSelState, FALSE, + End, + End, + Child, Label((IPTR) "Simple SCSI:"), + Child, HGroup, + Child, ncm->ncm_SimpleSCSIObj = ImageObject, ImageButtonFrame, + MUIA_Background, MUII_ButtonBack, + MUIA_CycleChain, 1, + MUIA_InputMode, MUIV_InputMode_Toggle, + MUIA_Image_Spec, MUII_CheckMark, + MUIA_Image_FreeVert, TRUE, + MUIA_Selected, ncm->ncm_CDC->cdc_PatchFlags & PFF_SIMPLE_SCSI, + MUIA_ShowSelState, FALSE, + End, + Child, HSpace(0), + Child, Label((IPTR) "Translate CMD6->CMD10:"), + Child, ncm->ncm_XLate610Obj = ImageObject, ImageButtonFrame, + MUIA_Background, MUII_ButtonBack, + MUIA_CycleChain, 1, + MUIA_InputMode, MUIV_InputMode_Toggle, + MUIA_Image_Spec, MUII_CheckMark, + MUIA_Image_FreeVert, TRUE, + MUIA_Selected, ncm->ncm_CDC->cdc_PatchFlags & PFF_MODE_XLATE, + MUIA_ShowSelState, FALSE, + End, + End, + Child, Label((IPTR) "Fake Inquiry:"), + Child, HGroup, + Child, ncm->ncm_FakeInquiryObj = ImageObject, ImageButtonFrame, + MUIA_Background, MUII_ButtonBack, + MUIA_CycleChain, 1, + MUIA_InputMode, MUIV_InputMode_Toggle, + MUIA_Image_Spec, MUII_CheckMark, + MUIA_Image_FreeVert, TRUE, + MUIA_Selected, ncm->ncm_CDC->cdc_PatchFlags & PFF_FAKE_INQUIRY, + MUIA_ShowSelState, FALSE, + End, + Child, HSpace(0), + Child, Label((IPTR) "Better Removable Support:"), + Child, ncm->ncm_RemSupportObj = ImageObject, ImageButtonFrame, + MUIA_Background, MUII_ButtonBack, + MUIA_CycleChain, 1, + MUIA_InputMode, MUIV_InputMode_Toggle, + MUIA_Image_Spec, MUII_CheckMark, + MUIA_Image_FreeVert, TRUE, + MUIA_Selected, ncm->ncm_CDC->cdc_PatchFlags & PFF_REM_SUPPORT, + MUIA_ShowSelState, FALSE, + End, + End, + Child, Label((IPTR) "Trim Inquiry:"), + Child, HGroup, + Child, ncm->ncm_FixInquiryObj = ImageObject, ImageButtonFrame, + MUIA_Background, MUII_ButtonBack, + MUIA_CycleChain, 1, + MUIA_InputMode, MUIV_InputMode_Toggle, + MUIA_Image_Spec, MUII_CheckMark, + MUIA_Image_FreeVert, TRUE, + MUIA_Selected, ncm->ncm_CDC->cdc_PatchFlags & PFF_FIX_INQ36, + MUIA_ShowSelState, FALSE, + End, + Child, HSpace(0), + Child, Label((IPTR) "Ignore broken CSS-ID:"), + Child, ncm->ncm_CSSBrokenObj = ImageObject, ImageButtonFrame, + MUIA_Background, MUII_ButtonBack, + MUIA_CycleChain, 1, + MUIA_InputMode, MUIV_InputMode_Toggle, + MUIA_Image_Spec, MUII_CheckMark, + MUIA_Image_FreeVert, TRUE, + MUIA_Selected, ncm->ncm_CDC->cdc_PatchFlags & PFF_CSS_BROKEN, + MUIA_ShowSelState, FALSE, + End, + End, + Child, Label((IPTR) "Fix Capacity:"), + Child, HGroup, + Child, ncm->ncm_FixCapacityObj = ImageObject, ImageButtonFrame, + MUIA_Background, MUII_ButtonBack, + MUIA_CycleChain, 1, + MUIA_InputMode, MUIV_InputMode_Toggle, + MUIA_Image_Spec, MUII_CheckMark, + MUIA_Image_FreeVert, TRUE, + MUIA_Selected, ncm->ncm_CDC->cdc_PatchFlags & PFF_FIX_CAPACITY, + MUIA_ShowSelState, FALSE, + End, + Child, HSpace(0), + Child, Label((IPTR) "Emulate on larger block sizes:"), + Child, ncm->ncm_EmulLargeBlkObj = ImageObject, ImageButtonFrame, + MUIA_Background, MUII_ButtonBack, + MUIA_CycleChain, 1, + MUIA_InputMode, MUIV_InputMode_Toggle, + MUIA_Image_Spec, MUII_CheckMark, + MUIA_Image_FreeVert, TRUE, + MUIA_Selected, ncm->ncm_CDC->cdc_PatchFlags & PFF_EMUL_LARGE_BLK, + MUIA_ShowSelState, FALSE, + End, + End, + Child, Label((IPTR) "No Fallback:"), + Child, HGroup, + Child, ncm->ncm_NoFallbackObj = ImageObject, ImageButtonFrame, + MUIA_Background, MUII_ButtonBack, + MUIA_CycleChain, 1, + MUIA_InputMode, MUIV_InputMode_Toggle, + MUIA_Image_Spec, MUII_CheckMark, + MUIA_Image_FreeVert, TRUE, + MUIA_Selected, ncm->ncm_CDC->cdc_PatchFlags & PFF_NO_FALLBACK, + MUIA_ShowSelState, FALSE, + End, + Child, HSpace(0), + Child, Label((IPTR) "Debug:"), + Child, ncm->ncm_DebugObj = ImageObject, ImageButtonFrame, + MUIA_Background, MUII_ButtonBack, + MUIA_CycleChain, 1, + MUIA_InputMode, MUIV_InputMode_Toggle, + MUIA_Image_Spec, MUII_CheckMark, + MUIA_Image_FreeVert, TRUE, + MUIA_Selected, ncm->ncm_CDC->cdc_PatchFlags & PFF_DEBUG, + MUIA_ShowSelState, FALSE, + End, + End, + Child, Label((IPTR) "Max Transfer:"), + Child, HGroup, + Child, ncm->ncm_MaxTransferObj = CycleObject, + MUIA_Cycle_Entries, MaxTransferStrings, + MUIA_Cycle_Active, ncm->ncm_CDC->cdc_MaxTransfer, + End, + //Child, HSpace(0), + Child, ncm->ncm_AutoDtxMaxTransObj = TextObject, ButtonFrame, + MUIA_Disabled, !ncm->ncm_Interface, + MUIA_Background, MUII_ButtonBack, + MUIA_CycleChain, 1, + MUIA_InputMode, MUIV_InputMode_RelVerify, + MUIA_Text_Contents, "\33c Auto-detect ", + End, + End, + End, + Child, VSpace(0), + + Child, ColGroup(6), + Child, Label((IPTR) "FAT:"), + Child, PopaslObject, + MUIA_Popstring_String, ncm->ncm_FatFSObj = StringObject, + StringFrame, + MUIA_CycleChain, 1, + MUIA_String_AdvanceOnCR, TRUE, + MUIA_String_Contents, ncm->ncm_CDC->cdc_FATFSName, + MUIA_String_MaxLen, 63, + End, + MUIA_Popstring_Button, PopButton(MUII_PopFile), + ASLFR_TitleText, "Select filesystem to use with FAT partitions...", + End, + Child, Label((IPTR) "DosType:"), + Child, ncm->ncm_FatDosTypeObj = StringObject, + StringFrame, + MUIA_HorizWeight, 50, + MUIA_CycleChain, 1, + MUIA_String_AdvanceOnCR, TRUE, + MUIA_String_Contents, dostypebuf, + MUIA_String_Accept, "0123456789abcdefABCDEF", + MUIA_String_MaxLen, 9, + End, + Child, Label((IPTR) "Ctrl:"), + Child, ncm->ncm_FatControlObj = StringObject, + StringFrame, + MUIA_HorizWeight, 50, + MUIA_CycleChain, 1, + MUIA_String_AdvanceOnCR, TRUE, + MUIA_String_Contents, ncm->ncm_CDC->cdc_FATControl, + MUIA_String_MaxLen, 63, + End, + Child, Label((IPTR) "NTFS:"), + Child, PopaslObject, + MUIA_Popstring_String, ncm->ncm_NTFSObj = StringObject, + StringFrame, + MUIA_CycleChain, 1, + MUIA_String_AdvanceOnCR, TRUE, + MUIA_String_Contents, ncm->ncm_CDC->cdc_NTFSName, + MUIA_String_MaxLen, 63, + End, + MUIA_Popstring_Button, PopButton(MUII_PopFile), + ASLFR_TitleText, "Select filesystem to use with NTFS partitions...", + End, + Child, Label((IPTR) "DosType:"), + Child, ncm->ncm_NTFSDosTypeObj = StringObject, + StringFrame, + MUIA_HorizWeight, 50, + MUIA_CycleChain, 1, + MUIA_String_AdvanceOnCR, TRUE, + MUIA_String_Contents, ntfsdostypebuf, + MUIA_String_Accept, "0123456789abcdefABCDEF", + MUIA_String_MaxLen, 9, + End, + Child, Label((IPTR) "Ctrl:"), + Child, ncm->ncm_NTFSControlObj = StringObject, + StringFrame, + MUIA_HorizWeight, 50, + MUIA_CycleChain, 1, + MUIA_String_AdvanceOnCR, TRUE, + MUIA_String_Contents, ncm->ncm_CDC->cdc_NTFSControl, + MUIA_String_MaxLen, 63, + End, + Child, Label((IPTR) "CD/DVD:"), + Child, PopaslObject, + MUIA_Popstring_String, ncm->ncm_CDFSObj = StringObject, + StringFrame, + MUIA_CycleChain, 1, + MUIA_String_AdvanceOnCR, TRUE, + MUIA_String_Contents, ncm->ncm_CDC->cdc_CDFSName, + MUIA_String_MaxLen, 63, + End, + MUIA_Popstring_Button, PopButton(MUII_PopFile), + ASLFR_TitleText, "Select filesystem to use with CD/DVD partitions...", + End, + Child, Label((IPTR) "DosType:"), + Child, ncm->ncm_CDDosTypeObj = StringObject, + StringFrame, + MUIA_HorizWeight, 50, + MUIA_CycleChain, 1, + MUIA_String_AdvanceOnCR, TRUE, + MUIA_String_Contents, cddostypebuf, + MUIA_String_Accept, "0123456789abcdefABCDEF", + MUIA_String_MaxLen, 9, + End, + Child, Label((IPTR) "Ctrl:"), + Child, ncm->ncm_CDControlObj = StringObject, + StringFrame, + MUIA_HorizWeight, 50, + MUIA_CycleChain, 1, + MUIA_String_AdvanceOnCR, TRUE, + MUIA_String_Contents, ncm->ncm_CDC->cdc_CDControl, + MUIA_String_MaxLen, 63, + End, + End, + Child, VSpace(0), + End, + Child, VGroup, + Child, ListviewObject, + MUIA_CycleChain, 1, + MUIA_Listview_List, ncm->ncm_LunLVObj = ListObject, + ReadListFrame, + MUIA_List_Format, bar, + MUIA_List_Title, TRUE, + MUIA_List_DisplayHook, &ncm->ncm_LUNListDisplayHook, + End, + End, + Child, ncm->ncm_LunGroupObj = VGroup, + MUIA_Disabled, TRUE, + Child, VSpace(0), + Child, HGroup, + Child, ncm->ncm_AutoMountRDBObj = ImageObject, ImageButtonFrame, + MUIA_Background, MUII_ButtonBack, + MUIA_CycleChain, 1, + MUIA_InputMode, MUIV_InputMode_Toggle, + MUIA_Image_Spec, MUII_CheckMark, + MUIA_Image_FreeVert, TRUE, + MUIA_Selected, TRUE, + MUIA_ShowSelState, FALSE, + End, + Child, Label((IPTR) "AutoMount RDB partitions"), + Child, HSpace(0), + End, + Child, HGroup, + Child, ncm->ncm_BootRDBObj = ImageObject, ImageButtonFrame, + MUIA_Background, MUII_ButtonBack, + MUIA_CycleChain, 1, + MUIA_InputMode, MUIV_InputMode_Toggle, + MUIA_Image_Spec, MUII_CheckMark, + MUIA_Image_FreeVert, TRUE, + MUIA_Selected, FALSE, + MUIA_ShowSelState, FALSE, + End, + Child, Label((IPTR) "Boot from RDB partitions"), + Child, HSpace(0), + End, + Child, VSpace(0), + Child, HGroup, + Child, ncm->ncm_AutoMountFATObj = ImageObject, ImageButtonFrame, + MUIA_Background, MUII_ButtonBack, + MUIA_CycleChain, 1, + MUIA_InputMode, MUIV_InputMode_Toggle, + MUIA_Image_Spec, MUII_CheckMark, + MUIA_Image_FreeVert, TRUE, + MUIA_Selected, TRUE, + MUIA_ShowSelState, FALSE, + End, + Child, Label((IPTR) "AutoMount FAT/NTFS partitions"), + Child, HSpace(0), + End, + Child, HGroup, + Child, ncm->ncm_MountAllFATObj = ImageObject, ImageButtonFrame, + MUIA_Background, MUII_ButtonBack, + MUIA_CycleChain, 1, + MUIA_InputMode, MUIV_InputMode_Toggle, + MUIA_Image_Spec, MUII_CheckMark, + MUIA_Image_FreeVert, TRUE, + MUIA_Selected, TRUE, + MUIA_ShowSelState, FALSE, + End, + Child, Label((IPTR) "Mount all FAT partitions"), + Child, HSpace(0), + End, + Child, VSpace(0), + Child, HGroup, + Child, ncm->ncm_AutoMountCDObj = ImageObject, ImageButtonFrame, + MUIA_Background, MUII_ButtonBack, + MUIA_CycleChain, 1, + MUIA_InputMode, MUIV_InputMode_Toggle, + MUIA_Image_Spec, MUII_CheckMark, + MUIA_Image_FreeVert, TRUE, + MUIA_Selected, TRUE, + MUIA_ShowSelState, FALSE, + End, + Child, Label((IPTR) "AutoMount CD/DVD"), + Child, HSpace(0), + End, + Child, VSpace(0), + Child, HGroup, + Child, ncm->ncm_UnmountObj = ImageObject, ImageButtonFrame, + MUIA_Background, MUII_ButtonBack, + MUIA_CycleChain, 1, + MUIA_InputMode, MUIV_InputMode_Toggle, + MUIA_Image_Spec, MUII_CheckMark, + MUIA_Image_FreeVert, TRUE, + MUIA_Selected, FALSE, + MUIA_ShowSelState, FALSE, + End, + Child, HGroup, + Child, Label((IPTR) "Unmount partitions after removal"), + Child, HSpace(0), + End, + End, + Child, VSpace(0), + Child, HGroup, + Child, Label((IPTR) "DOSName:"), + Child, ncm->ncm_FatDOSNameObj = StringObject, + StringFrame, + MUIA_CycleChain, 1, + MUIA_String_AdvanceOnCR, TRUE, + MUIA_String_Contents, "UMSD", + MUIA_String_Reject, "/ :?#*", + MUIA_String_MaxLen, 31, + End, + Child, Label((IPTR) "Buffers:"), + Child, ncm->ncm_FatBuffersObj = StringObject, + StringFrame, + MUIA_CycleChain, 1, + MUIA_String_AdvanceOnCR, TRUE, + MUIA_String_Integer, 100, + MUIA_String_Accept, "0123456789", + End, + End, + Child, VSpace(0), + Child, HGroup, + Child, Label((IPTR) "Default " DEVNAME " unit:"), + Child, ncm->ncm_UnitObj = StringObject, + StringFrame, + MUIA_CycleChain, 1, + MUIA_String_AdvanceOnCR, TRUE, + MUIA_String_Integer, 0, + MUIA_String_Accept, "0123456789", + End, + End, + End, + End, + End, + Child, HGroup, + MUIA_Group_SameWidth, TRUE, + Child, ncm->ncm_UseObj = TextObject, ButtonFrame, + MUIA_ShowMe, ncm->ncm_Interface, + MUIA_Background, MUII_ButtonBack, + MUIA_CycleChain, 1, + MUIA_InputMode, MUIV_InputMode_RelVerify, + MUIA_Text_Contents, "\33c Save ", + End, + Child, ncm->ncm_SetDefaultObj = TextObject, ButtonFrame, + MUIA_Background, MUII_ButtonBack, + MUIA_CycleChain, 1, + MUIA_InputMode, MUIV_InputMode_RelVerify, + MUIA_Text_Contents, ncm->ncm_Interface ? "\33c Save as Default " : "\33c Save Defaults ", + End, + Child, ncm->ncm_CloseObj = TextObject, ButtonFrame, + MUIA_Background, MUII_ButtonBack, + MUIA_CycleChain, 1, + MUIA_InputMode, MUIV_InputMode_RelVerify, + MUIA_Text_Contents, "\33c Use ", + End, + End, + End, + End, + End; + + if(!ncm->ncm_App) + { + KPRINTF(10, ("Couldn't create application\n")); + nGUITaskCleanup(ncm); + return; + } + + if(ncm->ncm_Interface) + { + cncm = ncm; + while(((struct Node *) cncm)->ln_Succ) + { + if(cncm->ncm_UnitLUN0 != ncm) + { + break; + } + DoMethod(ncm->ncm_LunLVObj, MUIM_List_InsertSingle, cncm, MUIV_List_Insert_Bottom); + cncm = (struct NepClassMS *) ((struct Node *) cncm)->ln_Succ; + } + } else { + DoMethod(ncm->ncm_LunLVObj, MUIM_List_InsertSingle, ncm, MUIV_List_Insert_Bottom); + } + DoMethod(ncm->ncm_MainWindow, MUIM_Notify, MUIA_Window_CloseRequest, TRUE, + ncm->ncm_App, 2, MUIM_Application_ReturnID, MUIV_Application_ReturnID_Quit); + DoMethod(ncm->ncm_UseObj, MUIM_Notify, MUIA_Pressed, FALSE, + ncm->ncm_App, 2, MUIM_Application_ReturnID, ID_STORE_CONFIG); + DoMethod(ncm->ncm_SetDefaultObj, MUIM_Notify, MUIA_Pressed, FALSE, + ncm->ncm_App, 2, MUIM_Application_ReturnID, ID_DEF_CONFIG); + DoMethod(ncm->ncm_CloseObj, MUIM_Notify, MUIA_Pressed, FALSE, + ncm->ncm_App, 2, MUIM_Application_ReturnID, MUIV_Application_ReturnID_Quit); + + DoMethod(ncm->ncm_AutoDtxMaxTransObj, MUIM_Notify, MUIA_Pressed, FALSE, + ncm->ncm_App, 2, MUIM_Application_ReturnID, ID_AUTODTXMAXTX); + DoMethod(ncm->ncm_LunLVObj, MUIM_Notify, MUIA_List_Active, MUIV_EveryTime, + ncm->ncm_App, 2, MUIM_Application_ReturnID, ID_SELECT_LUN); + + DoMethod(ncm->ncm_AboutMI, MUIM_Notify, MUIA_Menuitem_Trigger, MUIV_EveryTime, + ncm->ncm_App, 2, MUIM_Application_ReturnID, ID_ABOUT); + DoMethod(ncm->ncm_UseMI, MUIM_Notify, MUIA_Menuitem_Trigger, MUIV_EveryTime, + ncm->ncm_App, 2, MUIM_Application_ReturnID, ID_STORE_CONFIG); + DoMethod(ncm->ncm_SetDefaultMI, MUIM_Notify, MUIA_Menuitem_Trigger, MUIV_EveryTime, + ncm->ncm_App, 2, MUIM_Application_ReturnID, ID_DEF_CONFIG); + DoMethod(ncm->ncm_MUIPrefsMI, MUIM_Notify, MUIA_Menuitem_Trigger, MUIV_EveryTime, + ncm->ncm_App, 2, MUIM_Application_OpenConfigWindow, 0); + + set(ncm->ncm_LunLVObj, MUIA_List_Active, MUIV_List_Active_Top); + { + ULONG isopen; + ULONG iconify; + ULONG sigs; + ULONG sigmask; + LONG retid; + + get(ncm->ncm_App, MUIA_Application_Iconified, &iconify); + set(ncm->ncm_MainWindow, MUIA_Window_Open, TRUE); + get(ncm->ncm_MainWindow, MUIA_Window_Open, &isopen); + if(!(isopen || iconify)) + { + nGUITaskCleanup(ncm); + return; + } + sigmask = 0; + do + { + retid = DoMethod(ncm->ncm_App, MUIM_Application_NewInput, &sigs); + switch(retid) + { + case ID_DEF_CONFIG: + case ID_STORE_CONFIG: + case MUIV_Application_ReturnID_Quit: + { + ULONG tmpflags; + ULONG patchflags; + STRPTR tmpstr; + + get(ncm->ncm_NakTimeoutObj, MUIA_Numeric_Value, &ncm->ncm_CDC->cdc_NakTimeout); + get(ncm->ncm_StartupDelayObj, MUIA_Numeric_Value, &ncm->ncm_CDC->cdc_StartupDelay); + patchflags = ncm->ncm_CDC->cdc_PatchFlags & ~(PFF_SINGLE_LUN|PFF_FAKE_INQUIRY|PFF_SIMPLE_SCSI|PFF_NO_RESET|PFF_MODE_XLATE|PFF_DEBUG|PFF_NO_FALLBACK|PFF_REM_SUPPORT|PFF_FIX_INQ36|PFF_CSS_BROKEN|PFF_FIX_CAPACITY|PFF_EMUL_LARGE_BLK); + get(ncm->ncm_SingleLunObj, MUIA_Selected, &tmpflags); + if(tmpflags) patchflags |= PFF_SINGLE_LUN; + get(ncm->ncm_FakeInquiryObj, MUIA_Selected, &tmpflags); + if(tmpflags) patchflags |= PFF_FAKE_INQUIRY; + get(ncm->ncm_SimpleSCSIObj, MUIA_Selected, &tmpflags); + if(tmpflags) patchflags |= PFF_SIMPLE_SCSI; + get(ncm->ncm_InitialResetObj, MUIA_Selected, &tmpflags); + if(tmpflags) patchflags |= PFF_NO_RESET; + get(ncm->ncm_XLate610Obj, MUIA_Selected, &tmpflags); + if(tmpflags) patchflags |= PFF_MODE_XLATE; + get(ncm->ncm_RemSupportObj, MUIA_Selected, &tmpflags); + if(tmpflags) patchflags |= PFF_REM_SUPPORT; + get(ncm->ncm_FixInquiryObj, MUIA_Selected, &tmpflags); + if(tmpflags) patchflags |= PFF_FIX_INQ36; + get(ncm->ncm_CSSBrokenObj, MUIA_Selected, &tmpflags); + if(tmpflags) patchflags |= PFF_CSS_BROKEN; + get(ncm->ncm_FixCapacityObj, MUIA_Selected, &tmpflags); + if(tmpflags) patchflags |= PFF_FIX_CAPACITY; + get(ncm->ncm_EmulLargeBlkObj, MUIA_Selected, &tmpflags); + if(tmpflags) patchflags |= PFF_EMUL_LARGE_BLK; + get(ncm->ncm_NoFallbackObj, MUIA_Selected, &tmpflags); + if(tmpflags) patchflags |= PFF_NO_FALLBACK; + get(ncm->ncm_DebugObj, MUIA_Selected, &tmpflags); + if(tmpflags) patchflags |= PFF_DEBUG; + ncm->ncm_CDC->cdc_PatchFlags = patchflags; + + get(ncm->ncm_MaxTransferObj, MUIA_Cycle_Active, &ncm->ncm_CDC->cdc_MaxTransfer); + + get(ncm->ncm_FatFSObj, MUIA_String_Contents, &tmpstr); + strncpy(ncm->ncm_CDC->cdc_FATFSName, tmpstr, 63); + get(ncm->ncm_FatControlObj, MUIA_String_Contents, &tmpstr); + strncpy(ncm->ncm_CDC->cdc_FATControl, tmpstr, 63); + get(ncm->ncm_FatDosTypeObj, MUIA_String_Contents, &tmpstr); + ncm->ncm_CDC->cdc_FATDosType = nGetDosType(tmpstr); + + get(ncm->ncm_NTFSObj, MUIA_String_Contents, &tmpstr); + strncpy(ncm->ncm_CDC->cdc_NTFSName, tmpstr, 63); + get(ncm->ncm_NTFSControlObj, MUIA_String_Contents, &tmpstr); + strncpy(ncm->ncm_CDC->cdc_NTFSControl, tmpstr, 63); + get(ncm->ncm_NTFSDosTypeObj, MUIA_String_Contents, &tmpstr); + ncm->ncm_CDC->cdc_NTFSDosType = nGetDosType(tmpstr); + + get(ncm->ncm_CDFSObj, MUIA_String_Contents, &tmpstr); + strncpy(ncm->ncm_CDC->cdc_CDFSName, tmpstr, 63); + get(ncm->ncm_CDControlObj, MUIA_String_Contents, &tmpstr); + strncpy(ncm->ncm_CDC->cdc_CDControl, tmpstr, 63); + get(ncm->ncm_CDDosTypeObj, MUIA_String_Contents, &tmpstr); + ncm->ncm_CDC->cdc_CDDosType = nGetDosType(tmpstr); + + if(ncm->ncm_Interface) + { + /* copy device config to all luns */ + cncm = (struct NepClassMS *) ((struct Node *) ncm)->ln_Succ; + while(((struct Node *) cncm)->ln_Succ) + { + if(cncm->ncm_UnitLUN0 != ncm) + { + break; + } + *(cncm->ncm_CDC) = *(ncm->ncm_CDC); + cncm = (struct NepClassMS *) ((struct Node *) cncm)->ln_Succ; + } + } + if(curncm) + { + get(ncm->ncm_AutoMountFATObj, MUIA_Selected, &curncm->ncm_CUC->cuc_AutoMountFAT); + get(ncm->ncm_MountAllFATObj, MUIA_Selected, &curncm->ncm_CUC->cuc_MountAllFAT); + get(ncm->ncm_AutoMountCDObj, MUIA_Selected, &curncm->ncm_CUC->cuc_AutoMountCD); + get(ncm->ncm_FatDOSNameObj, MUIA_String_Contents, &tmpstr); + strncpy(curncm->ncm_CUC->cuc_FATDOSName, tmpstr, 31); + get(ncm->ncm_FatBuffersObj, MUIA_String_Integer, &curncm->ncm_CUC->cuc_FATBuffers); + get(ncm->ncm_AutoMountRDBObj, MUIA_Selected, &curncm->ncm_CUC->cuc_AutoMountRDB); + get(ncm->ncm_BootRDBObj, MUIA_Selected, &curncm->ncm_CUC->cuc_BootRDB); + get(ncm->ncm_UnitObj, MUIA_String_Integer, &curncm->ncm_CUC->cuc_DefaultUnit); + get(ncm->ncm_UnmountObj, MUIA_Selected, &curncm->ncm_CUC->cuc_AutoUnmount); + } + + if(retid == ID_DEF_CONFIG) + { + pic = psdGetClsCfg(libname); + if(!pic) + { + psdSetClsCfg(libname, NULL); + pic = psdGetClsCfg(libname); + } + if(pic) + { + psdAddCfgEntry(pic, ncm->ncm_CDC); + psdAddCfgEntry(pic, ncm->ncm_CUC); + psdSaveCfgToDisk(NULL, FALSE); + } + } + if(nStoreConfig(ncm)) + { + if(retid != MUIV_Application_ReturnID_Quit) + { + psdSaveCfgToDisk(NULL, FALSE); + } + retid = MUIV_Application_ReturnID_Quit; + } + break; + } + + case ID_SELECT_LUN: + { + STRPTR tmpstr; + DoMethod(ncm->ncm_LunLVObj, MUIM_List_GetEntry, MUIV_List_GetEntry_Active, &cncm); + if(curncm != cncm) + { + if(curncm) + { + get(ncm->ncm_AutoMountFATObj, MUIA_Selected, &curncm->ncm_CUC->cuc_AutoMountFAT); + get(ncm->ncm_MountAllFATObj, MUIA_Selected, &curncm->ncm_CUC->cuc_MountAllFAT); + get(ncm->ncm_AutoMountCDObj, MUIA_Selected, &curncm->ncm_CUC->cuc_AutoMountCD); + get(ncm->ncm_FatDOSNameObj, MUIA_String_Contents, &tmpstr); + strncpy(curncm->ncm_CUC->cuc_FATDOSName, tmpstr, 31); + get(ncm->ncm_FatBuffersObj, MUIA_String_Integer, &curncm->ncm_CUC->cuc_FATBuffers); + get(ncm->ncm_AutoMountRDBObj, MUIA_Selected, &curncm->ncm_CUC->cuc_AutoMountRDB); + get(ncm->ncm_BootRDBObj, MUIA_Selected, &curncm->ncm_CUC->cuc_BootRDB); + get(ncm->ncm_UnitObj, MUIA_String_Integer, &curncm->ncm_CUC->cuc_DefaultUnit); + get(ncm->ncm_UnmountObj, MUIA_Selected, &curncm->ncm_CUC->cuc_AutoUnmount); + } + } + if((curncm = cncm)) + { + set(ncm->ncm_AutoMountFATObj, MUIA_Selected, curncm->ncm_CUC->cuc_AutoMountFAT); + set(ncm->ncm_MountAllFATObj, MUIA_Selected, curncm->ncm_CUC->cuc_MountAllFAT); + set(ncm->ncm_AutoMountCDObj, MUIA_Selected, curncm->ncm_CUC->cuc_AutoMountCD); + set(ncm->ncm_FatDOSNameObj, MUIA_String_Contents, curncm->ncm_CUC->cuc_FATDOSName); + set(ncm->ncm_FatBuffersObj, MUIA_String_Integer, curncm->ncm_CUC->cuc_FATBuffers); + set(ncm->ncm_AutoMountRDBObj, MUIA_Selected, curncm->ncm_CUC->cuc_AutoMountRDB); + set(ncm->ncm_BootRDBObj, MUIA_Selected, curncm->ncm_CUC->cuc_BootRDB); + set(ncm->ncm_UnitObj, MUIA_String_Integer, curncm->ncm_CUC->cuc_DefaultUnit); + set(ncm->ncm_UnmountObj, MUIA_Selected, curncm->ncm_CUC->cuc_AutoUnmount); + set(ncm->ncm_LunGroupObj, MUIA_Disabled, FALSE); + } else { + set(ncm->ncm_LunGroupObj, MUIA_Disabled, TRUE); + } + break; + } + case ID_AUTODTXMAXTX: + { + DoMethod(ncm->ncm_LunLVObj, MUIM_List_GetEntry, MUIV_List_GetEntry_Active, &cncm); + set(ncm->ncm_App, MUIA_Application_Sleep, TRUE); + AutoDetectMaxTransfer(cncm); + set(ncm->ncm_App, MUIA_Application_Sleep, FALSE); + set(ncm->ncm_MaxTransferObj, MUIA_Cycle_Active, ncm->ncm_CDC->cdc_MaxTransfer); + break; + } + + case ID_ABOUT: + MUI_RequestA(ncm->ncm_App, ncm->ncm_MainWindow, 0, NULL, "Blimey!", VERSION_STRING, NULL); + break; + } + if(retid == MUIV_Application_ReturnID_Quit) + { + break; + } + if(sigs) + { + sigs = Wait(sigs | sigmask | SIGBREAKF_CTRL_C); + if(sigs & SIGBREAKF_CTRL_C) + { + break; + } + } + } while(TRUE); + set(ncm->ncm_MainWindow, MUIA_Window_Open, FALSE); + } + nGUITaskCleanup(ncm); + + AROS_USERFUNC_EXIT +} +/* \\\ */ + +/* /// "AutoDetectMaxTransfer()" */ +void AutoDetectMaxTransfer(struct NepClassMS *cncm) +{ + LONG res; + UBYTE *memory; + UBYTE *orgbuffer; + UBYTE *cmpbuffer; + ULONG *lbufptr; + struct MsgPort *mp; + struct IOStdReq *ioreq; + struct NepClassMS *ncm = cncm->ncm_UnitLUN0; + ULONG numblocks; + ULONG memsize = 4<<20; + ULONG block; + ULONG maxtrans; + LONG ioerr; + BOOL bail = FALSE; + ULONG cnt; + + res = MUI_RequestA(ncm->ncm_App, ncm->ncm_MainWindow, 0, NULL, "Continue|Cancel", + "Auto-detection of the maximum transfer rate\n" + "will need some media inserted in the selected\n" + "LUN of the drive. Moreover, the contents of the\n" + "media may not be empty.\n" + "The test will need about 4 MB of temporary memory!\n" + "No data is written to the disk!", NULL); + if(!res) + { + return; + } + if(!cncm->ncm_UnitReady) + { + MUI_RequestA(ncm->ncm_App, ncm->ncm_MainWindow, 0, NULL, "Argh!", "No disk/media in drive!", NULL); + return; + } + memory = (UBYTE *) AllocVec(memsize, MEMF_CLEAR); + if(!memory) + { + MUI_RequestA(ncm->ncm_App, ncm->ncm_MainWindow, 0, NULL, "Argh!", "Sorry, out of memory!", NULL); + return; + } + mp = CreateMsgPort(); + if(mp) + { + ioreq = (struct IOStdReq *) CreateIORequest(mp, sizeof(struct IOStdReq)); + if(ioreq) + { + if(!OpenDevice(DEVNAME, cncm->ncm_UnitNo, (struct IORequest *) ioreq, 0)) + { + ncm->ncm_CDC->cdc_MaxTransfer = 0; + if(!cncm->ncm_BlockSize) + { + ioreq->io_Command = TD_GETGEOMETRY; + ioreq->io_Data = &cncm->ncm_Geometry; + ioreq->io_Length = sizeof(cncm->ncm_Geometry); + DoIO((struct IORequest *) ioreq); + } + + numblocks = (memsize>>1) / cncm->ncm_BlockSize; + orgbuffer = memory; + cmpbuffer = &memory[memsize>>1]; + + do + { + for(block = 0; block < numblocks; block++) + { + ioreq->io_Command = TD_READ64; + ioreq->io_Actual = 0; + ioreq->io_Offset = block*cncm->ncm_BlockSize; + ioreq->io_Length = cncm->ncm_BlockSize; + ioreq->io_Data = &orgbuffer[ioreq->io_Offset]; + ioerr = DoIO((struct IORequest *) ioreq); + if(ioerr) + { + MUI_Request(ncm->ncm_App, ncm->ncm_MainWindow, 0, NULL, ">:-{", "Error %ld while reading block %ld!\nAborting process...", ioerr, block); + bail = TRUE; + break; + } + } + if(bail) break; + + do + { + maxtrans = (1UL<<(ncm->ncm_CDC->cdc_MaxTransfer+16)); + // do a quick check on block contents + numblocks = (memsize>>1) / maxtrans; + if(numblocks) + { + for(block = 0; block < numblocks-1; block++) + { + if(!memcmp(&orgbuffer[block * maxtrans], &orgbuffer[(block + 1) * maxtrans], (size_t) maxtrans)) + { + res = MUI_RequestA(ncm->ncm_App, ncm->ncm_MainWindow, 0, NULL, "Continue|Abort", "Sorry, media contents do not\nseem to be diversive enough!\nResults might be wrong!", NULL); + if(!res) + { + bail = TRUE; + } + break; + } + } + } + if(bail) break; + + // fill compare buffer with garbage + cnt = (memsize>>3); + lbufptr = (ULONG *) cmpbuffer; + do + { + *lbufptr = (ULONG) lbufptr; + lbufptr++; + } + while(--cnt); + + // start reading the chunks + numblocks = (memsize>>1) / maxtrans; + for(block = 0; block < numblocks; block++) + { + ioreq->io_Command = TD_READ64; + ioreq->io_Actual = 0; + ioreq->io_Offset = block*maxtrans; + ioreq->io_Length = maxtrans; + ioreq->io_Data = &cmpbuffer[ioreq->io_Offset]; + ioerr = DoIO((struct IORequest *) ioreq); + if(ioerr) + { + MUI_Request(ncm->ncm_App, ncm->ncm_MainWindow, 0, NULL, ">:-{", "Error %ld while reading at offset %ld!\nAborting process...", ioerr, &ioreq->io_Offset); + bail = TRUE; + break; + } + if(memcmp(&orgbuffer[ioreq->io_Offset], &cmpbuffer[ioreq->io_Offset], (size_t) maxtrans)) + { + MUI_Request(ncm->ncm_App, ncm->ncm_MainWindow, 0, NULL, "Hmpf!", "Reading failed at MaxTrans = %08lx", maxtrans-1); + if(ncm->ncm_CDC->cdc_MaxTransfer) + { + ncm->ncm_CDC->cdc_MaxTransfer--; + } + bail = TRUE; + break; + } + } + if(bail) break; + //MUI_Request(ncm->ncm_App, ncm->ncm_MainWindow, 0, NULL, "Wow!", "Test with %ld (%ld) succeeded!", maxtrans, numblocks); + if(ncm->ncm_CDC->cdc_MaxTransfer < 5) + { + ncm->ncm_CDC->cdc_MaxTransfer++; + } else { + break; + } + } while(TRUE); + if(!bail) + { + MUI_RequestA(ncm->ncm_App, ncm->ncm_MainWindow, 0, NULL, "Wow!", "Test succeeded, setting MaxTrans to maximum value!", NULL); + } + } while(FALSE); + CloseDevice((struct IORequest *) ioreq); + } else { + MUI_RequestA(ncm->ncm_App, ncm->ncm_MainWindow, 0, NULL, "Argh!", "Couldn't open device!", NULL); + } + DeleteIORequest((struct IORequest *) ioreq); + } else { + MUI_RequestA(ncm->ncm_App, ncm->ncm_MainWindow, 0, NULL, "Argh!", "No IOReq!", NULL); + } + DeleteMsgPort(mp); + } else { + MUI_RequestA(ncm->ncm_App, ncm->ncm_MainWindow, 0, NULL, "Argh!", "No MsgPort!", NULL); + } + FreeVec(memory); +} +/* \\\ */ + +/* /// "nGUITaskCleanup()" */ +void nGUITaskCleanup(struct NepClassMS *ncm) +{ + if(ncm->ncm_App) + { + MUI_DisposeObject(ncm->ncm_App); + ncm->ncm_App = NULL; + } + if(MUIMasterBase) + { + CloseLibrary(MUIMasterBase); + MUIMasterBase = NULL; + } + if(IntuitionBase) + { + CloseLibrary(IntuitionBase); + IntuitionBase = NULL; + } + if(ps) + { + CloseLibrary(ps); + ps = NULL; + } + Forbid(); + ncm->ncm_GUIBinding = NULL; + ncm->ncm_GUITask = NULL; + --ncm->ncm_ClsBase->nh_Library.lib_OpenCnt; +} +/* \\\ */ + +/* /// "LUNListDisplayHook()" */ +AROS_UFH3(LONG, LUNListDisplayHook, + AROS_UFHA(struct Hook *, hook, A0), + AROS_UFHA(char **, strarr, A2), + AROS_UFHA(struct NepClassMS *, ncm, A1)) +{ + AROS_USERFUNC_INIT + + //struct NepMSBase *nh = ncm->ncm_ClsBase; + if(ncm) + { + *strarr++ = ncm->ncm_LUNNumStr; + *strarr = ncm->ncm_LUNIDStr; + } else { + *strarr++ = "\33l\33uLUN"; + *strarr = "\33l\33uID"; + } + return(0); + + AROS_USERFUNC_EXIT +} +/* \\\ */ + diff --git a/rom/usb/classes/massstorage/massstorage.class.h b/rom/usb/classes/massstorage/massstorage.class.h new file mode 100644 index 000000000..937289aa7 --- /dev/null +++ b/rom/usb/classes/massstorage/massstorage.class.h @@ -0,0 +1,102 @@ +#ifndef MASSSTORAGE_CLASS_H +#define MASSSTORAGE_CLASS_H + +/* + *---------------------------------------------------------------------------- + * Includes for MS class + *---------------------------------------------------------------------------- + * By Chris Hodges + */ + +#include "common.h" + +#include + +#include "massstorage.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include "dev.h" + +#ifndef TD_READ64 +#define TD_READ64 24 +#define TD_WRITE64 25 +#define TD_SEEK64 26 +#define TD_FORMAT64 27 +#endif + +/* Protos */ + +struct NepClassMS * usbAttemptInterfaceBinding(struct NepMSBase *nh, struct PsdInterface *pif); +struct NepClassMS * usbForceInterfaceBinding(struct NepMSBase *nh, struct PsdInterface *pif); +void usbReleaseInterfaceBinding(struct NepMSBase *nh, struct NepClassMS *ncm); + +struct NepClassMS * nAllocMS(void); +void nFreeMS(struct NepClassMS *ncm); + +BOOL nLoadClassConfig(struct NepMSBase *nh); +BOOL nLoadBindingConfig(struct NepClassMS *ncm); +LONG nOpenBindingCfgWindow(struct NepMSBase *nh, struct NepClassMS *ncm); + +void nGUITaskCleanup(struct NepClassMS *ncm); +BOOL nStoreConfig(struct NepClassMS *ncm); + +LONG nScsiDirect(struct NepClassMS *ncm, struct SCSICmd *scsicmd); +LONG nScsiDirectBulk(struct NepClassMS *ncm, struct SCSICmd *scsicmd); +LONG nScsiDirectCBI(struct NepClassMS *ncm, struct SCSICmd *scsicmd); +LONG nBulkReset(struct NepClassMS *ncm); +void nLockXFer(struct NepClassMS *ncm); +void nUnlockXFer(struct NepClassMS *ncm); +LONG nRead64(struct NepClassMS *ncm, struct IOStdReq *ioreq); +LONG nWrite64(struct NepClassMS *ncm, struct IOStdReq *ioreq); +LONG nFormat64(struct NepClassMS *ncm, struct IOStdReq *ioreq); +LONG nSeek64(struct NepClassMS *ncm, struct IOStdReq *ioreq); +LONG nGetGeometry(struct NepClassMS *ncm, struct IOStdReq *ioreq); +LONG nGetWriteProtect(struct NepClassMS *ncm); +LONG nStartStop(struct NepClassMS *ncm, struct IOStdReq *ioreq); + +BOOL nStartRemovableTask(struct Library *ps, struct NepMSBase *nh); +struct NepMSBase * nAllocRT(void); +void nFreeRT(struct NepMSBase *nh); +void nUnmountPartition(struct NepClassMS *ncm); +LONG nIOCmdTunnel(struct NepClassMS *ncm, struct IOStdReq *ioreq); +LONG nScsiDirectTunnel(struct NepClassMS *ncm, struct SCSICmd *scsicmd); + +BPTR CreateSegment(struct NepClassMS *ncm, const ULONG *MyData); +struct DeviceNode * FindMatchingDevice(struct NepClassMS *ncm, struct DosEnvec *envec); +void CheckFATPartition(struct NepClassMS *ncm, ULONG startblock); +void ProcessRDB(struct NepClassMS *ncm); +void AutoMountCD(struct NepClassMS *ncm); +void CheckISO9660(struct NepClassMS *ncm); + +void AutoDetectMaxTransfer(struct NepClassMS *ncm); + +AROS_UFP0(void, nMSTask); +AROS_UFP0(void, nRemovableTask); +AROS_UFP0(void, nGUITask); + +AROS_UFP3(LONG, LUNListDisplayHook, + AROS_UFPA(struct Hook *, hook, A0), + AROS_UFPA(char **, strarr, A2), + AROS_UFPA(struct NepClassMS *, ncm, A1)); + +#endif /* MASSSTORAGE_CLASS_H */ diff --git a/rom/usb/classes/massstorage/massstorage.conf b/rom/usb/classes/massstorage/massstorage.conf new file mode 100644 index 000000000..1595e416c --- /dev/null +++ b/rom/usb/classes/massstorage/massstorage.conf @@ -0,0 +1,19 @@ +##begin config +version 4.3 +libbase nh +libbasetype struct NepMSBase +libbasetypeextern struct Library +residentpri 39 +basename nep +##end config + +##begin cdef +#include +#include "massstorage.h" +##end cdef + +##begin functionlist +LONG usbGetAttrsA(ULONG type, APTR usbstruct, struct TagItem *taglist) (D0,A0,A1) +LONG usbSetAttrsA(ULONG type, APTR usbstruct, struct TagItem *taglist) (D0,A0,A1) +IPTR usbDoMethodA(ULONG methodid, IPTR *methoddata) (D0,A1) +##end functionlist diff --git a/rom/usb/classes/massstorage/massstorage.h b/rom/usb/classes/massstorage/massstorage.h new file mode 100644 index 000000000..87f19cd2b --- /dev/null +++ b/rom/usb/classes/massstorage/massstorage.h @@ -0,0 +1,305 @@ +#ifndef MASSSTORAGE_H +#define MASSSTORAGE_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#define NIL_PTR 0xffffffff + +#if defined(__GNUC__) +# pragma pack(2) +#endif + +#define ID_ABOUT 0x55555555 +#define ID_STORE_CONFIG 0xaaaaaaaa +#define ID_DEF_CONFIG 0xaaaaaaab +#define ID_SELECT_LUN 0x22222222 +#define ID_AUTODTXMAXTX 0x11111111 + +struct ClsDevCfg +{ + ULONG cdc_ChunkID; + ULONG cdc_Length; + IPTR cdc_NakTimeout; + IPTR cdc_PatchFlags; + char cdc_FATFSName[64]; + ULONG cdc_FATDosType; + IPTR cdc_StartupDelay; + char cdc_FATControl[64]; + ULONG cdc_MaxTransfer; + char cdc_CDFSName[64]; + ULONG cdc_CDDosType; + char cdc_CDControl[64]; + char cdc_NTFSName[64]; + ULONG cdc_NTFSDosType; + char cdc_NTFSControl[64]; +}; + +struct ClsUnitCfg +{ + ULONG cuc_ChunkID; + ULONG cuc_Length; + IPTR cuc_AutoMountFAT; + char cuc_FATDOSName[32]; + IPTR cuc_FATBuffers; + IPTR cuc_AutoMountRDB; + IPTR cuc_BootRDB; + IPTR cuc_DefaultUnit; + IPTR cuc_AutoUnmount; + IPTR cuc_MountAllFAT; + IPTR cuc_AutoMountCD; +}; + +#if 0 +struct PartitionEntry +{ + UBYTE pe_Flags; /* Offset 0 */ + UBYTE pe_StartCHS[3]; /* Offset 1 */ + UBYTE pe_Type; /* Offset 4 */ + UBYTE pe_EndCHS[3]; /* Offset 5 */ + ULONG pe_StartLBA; /* Offset 8 */ + ULONG pe_SectorCount; /* Offset 12 */ +}; + +#define PE_FLAGB_ACTIVE 7 +#define PE_FLAGF_ACTIVE (1 << PE_FLAGB_ACTIVE) + +struct MasterBootRecord { + UBYTE mbr_pad0[446]; + struct PartitionEntry mbr_Partition[4]; + UBYTE mbr_Signature[2]; +}; + +#define MBR_SIGNATURE 0x55aa + +struct FATSuperBlock +{ + UBYTE fsb_Jump[3]; // 0000 + UBYTE fsb_Vendor[8]; // 0003 + UBYTE fsb_BytesPerSector[2]; // 000B + UBYTE fsb_SectorsPerCluster; // 000D + UBYTE fsb_ReservedSectors[2]; // 000E + UBYTE fsb_NumberFATs; // 0010 + UBYTE fsb_NumberRootEntries[2]; // 0011 + UBYTE fsb_SectorsPerVolume[2]; // 0013 + UBYTE fsb_MediaDescriptor; // 0015 + UBYTE fsb_SectorsPerFAT[2]; // 0016 + UBYTE fsb_SectorsPerTrack[2]; // 0018 + UBYTE fsb_Heads[2]; // 001A + UBYTE fsb_FirstVolumeSector[2]; // 001C + UBYTE fsb_pad0[13]; // 001E + UBYTE fsb_Label[11]; // 002B + UBYTE fsb_FileSystem[8]; // 0036 + UBYTE fsb_pad1[9]; // 003E + UBYTE fsb_Label2[11]; // 0047 + UBYTE fsb_FileSystem2[8]; // 0052 + UBYTE fsb_BootCode[512 - 90]; // 005A +}; +#endif + +#if defined(__GNUC__) +# pragma pack() +#endif + +#if 0 +struct RigidDisk +{ + struct RigidDiskBlock rdsk_RDB; + struct PartitionBlock rdsk_PART; + struct FileSysHeaderBlock rdsk_FSHD; +}; +#endif + +#define PFF_SINGLE_LUN 0x000001 /* allow access only to LUN 0 */ +#define PFF_MODE_XLATE 0x000002 /* translate 6 byte commands to 10 byte commands */ +#define PFF_EMUL_LARGE_BLK 0x000004 /* Emulate access on larger block sizes */ +#define PFF_REM_SUPPORT 0x000010 /* extended removable support */ +#define PFF_FIX_INQ36 0x000040 /* inquiry request needs fixing */ +#define PFF_DELAY_DATA 0x000080 /* delay data phase */ +#define PFF_SIMPLE_SCSI 0x000100 /* kill all complicated SCSI commands that might crash firmware */ +#define PFF_NO_RESET 0x000200 /* do not perform initial bulk reset */ +#define PFF_FAKE_INQUIRY 0x000400 /* filter inquiry and fake it */ +#define PFF_FIX_CAPACITY 0x000800 /* fix capacity by one */ +#define PFF_NO_FALLBACK 0x001000 /* don't fall back automatically */ +#define PFF_CSS_BROKEN 0x002000 /* olympus command status signature fix */ +#define PFF_CLEAR_EP 0x004000 /* clear endpoint halt */ +#define PFF_DEBUG 0x008000 /* more debug output */ + +struct NepClassMS +{ + struct Unit ncm_Unit; /* Unit structure */ + struct NepClassMS *ncm_UnitLUN0; /* Head of list */ + ULONG ncm_UnitNo; /* Unit number */ + struct NepMSBase *ncm_ClsBase; /* Up linkage */ + struct NepMSDevBase *ncm_DevBase; /* Device base */ + struct Library *ncm_Base; /* Poseidon base */ + struct PsdDevice *ncm_Device; /* Up linkage */ + struct PsdConfig *ncm_Config; /* Up linkage */ + struct PsdInterface *ncm_Interface; /* Up linkage */ + struct Task *ncm_ReadySigTask; /* Task to send ready signal to */ + LONG ncm_ReadySignal; /* Signal to send when ready */ + struct Task *ncm_Task; /* Subtask */ + struct MsgPort *ncm_TaskMsgPort; /* Message Port of Subtask */ + struct SignalSemaphore ncm_XFerLock; /* LUN allowed to talk to the device */ + struct PsdPipe *ncm_EP0Pipe; /* Endpoint 0 pipe */ + struct PsdEndpoint *ncm_EPOut; /* Endpoint OUT */ + struct PsdPipe *ncm_EPOutPipe; /* Endpoint OUT pipe */ + struct PsdEndpoint *ncm_EPIn; /* Endpoint IN */ + struct PsdPipe *ncm_EPInPipe; /* Endpoint IN pipe */ + struct PsdEndpoint *ncm_EPInt; /* Optional Endpoint INT */ + struct PsdPipe *ncm_EPIntPipe; /* Optional Endpoint INT pipe */ + UWORD ncm_EPOutNum; /* Endpoint OUT number */ + UWORD ncm_EPInNum; /* Endpoint IN number */ + UWORD ncm_EPIntNum; /* Endpoint INT number */ + struct MsgPort *ncm_DevMsgPort; /* Message Port for IOParReq */ + UWORD ncm_UnitProdID; /* ProductID of unit */ + UWORD ncm_UnitVendorID; /* VendorID of unit */ + UWORD ncm_UnitCfgNum; /* Config of unit */ + UWORD ncm_UnitIfNum; /* Interface number */ + UWORD ncm_UnitLUN; /* LUN */ + UWORD ncm_MaxLUN; /* Number of LUNs */ + BOOL ncm_DenyRequests; /* Device is gone! */ + BOOL ncm_HasMounted; /* Has mounted some partitions */ + BOOL ncm_UnitReady; /* Unit is ready */ + ULONG ncm_ChangeCount; /* Number of disk changes */ + ULONG ncm_LastChange; /* Change number last interrupt created */ + struct List ncm_DCInts; /* DiskChange Interrupt IORequests */ + ULONG ncm_BlockSize; /* BlockSize = 512 */ + ULONG ncm_BlockShift; /* Log2 BlockSize */ + BOOL ncm_WriteProtect; /* Is Disk write protected? */ + BOOL ncm_Removable; /* Is disk removable? */ + BOOL ncm_ForceRTCheck; /* Force removable task to be restarted */ + UWORD ncm_DeviceType; /* Peripheral Device Type (from Inquiry data) */ + UWORD ncm_TPType; /* Transport type */ + UWORD ncm_CSType; /* SCSI Commandset type */ + ULONG ncm_TagCount; /* Tag for CBW */ + struct DriveGeometry ncm_Geometry; /* Drive Geometry */ + ULONG ncm_GeoChangeCount; /* when did we last obtained the geometry for caching */ + BOOL ncm_BulkResetBorks; /* Bulk Reset is broken, don't try to use it */ + + UBYTE *ncm_OneBlock; /* buffer for one block */ + ULONG ncm_OneBlockSize; /* size of one block buffer */ + + STRPTR ncm_DevIDString; /* Device ID String */ + STRPTR ncm_IfIDString; /* Interface ID String */ + + struct IOStdReq *ncm_XFerPending; /* XFer IORequest pending */ + struct List ncm_XFerQueue; /* List of xfer requests */ + + char ncm_LUNIDStr[18]; + char ncm_LUNNumStr[4]; + UBYTE ncm_ModePageBuf[256]; + UBYTE ncm_FATControlBSTR[68]; + + BOOL ncm_UsingDefaultCfg; + + BOOL ncm_IOStarted; /* IO Running */ + BOOL ncm_Running; /* Not suspended */ + + struct ClsDevCfg *ncm_CDC; + struct ClsUnitCfg *ncm_CUC; + + struct Library *ncm_MUIBase; /* MUI master base */ + struct Library *ncm_PsdBase; /* Poseidon base */ + struct Library *ncm_IntBase; /* Intuition base */ + struct Task *ncm_GUITask; /* GUI Task */ + struct NepClassMS *ncm_GUIBinding; /* Window of binding that's open */ + + Object *ncm_App; + Object *ncm_MainWindow; + Object *ncm_NakTimeoutObj; + Object *ncm_SingleLunObj; + Object *ncm_FixInquiryObj; + Object *ncm_FakeInquiryObj; + Object *ncm_SimpleSCSIObj; + Object *ncm_XLate610Obj; + Object *ncm_CSSBrokenObj; + Object *ncm_EmulLargeBlkObj; + Object *ncm_FixCapacityObj; + Object *ncm_DebugObj; + Object *ncm_RemSupportObj; + Object *ncm_NoFallbackObj; + Object *ncm_MaxTransferObj; + Object *ncm_AutoDtxMaxTransObj; + Object *ncm_FatFSObj; + Object *ncm_FatDosTypeObj; + Object *ncm_FatControlObj; + Object *ncm_NTFSObj; + Object *ncm_NTFSDosTypeObj; + Object *ncm_NTFSControlObj; + Object *ncm_CDFSObj; + Object *ncm_CDDosTypeObj; + Object *ncm_CDControlObj; + Object *ncm_StartupDelayObj; + Object *ncm_InitialResetObj; + + Object *ncm_LunGroupObj; + Object *ncm_LunLVObj; + Object *ncm_UnitObj; + Object *ncm_AutoMountFATObj; + Object *ncm_AutoMountCDObj; + Object *ncm_FatDOSNameObj; + Object *ncm_FatBuffersObj; + Object *ncm_MountAllFATObj; + Object *ncm_AutoMountRDBObj; + Object *ncm_BootRDBObj; + Object *ncm_UnmountObj; + + Object *ncm_UseObj; + Object *ncm_SetDefaultObj; + Object *ncm_CloseObj; + + Object *ncm_AboutMI; + Object *ncm_UseMI; + Object *ncm_SetDefaultMI; + Object *ncm_MUIPrefsMI; + + struct Hook ncm_LUNListDisplayHook; +}; + +struct NepMSBase +{ + struct Library nh_Library; /* standard */ + UWORD nh_Flags; /* various flags */ + + struct Library *nh_UtilityBase; /* Utility base */ + + struct NepMSDevBase *nh_DevBase; /* base of device created */ + struct List nh_Units; /* List of units available */ + struct NepClassMS nh_DummyNCM; /* Dummy NCM for default config */ + + struct SignalSemaphore nh_TaskLock; /* single task monitor */ + struct Task *nh_ReadySigTask; /* Task to send ready signal to */ + LONG nh_ReadySignal; /* Signal to send when ready */ + struct Task *nh_RemovableTask; /* Task for removable control */ + struct MsgPort *nh_IOMsgPort; /* Port for local IO */ + struct IOStdReq nh_IOReq; /* Fake IOReq */ + struct Library *nh_ExpansionBase; /* ExpansionBase */ + struct Library *nh_PsdBase; /* PsdBase */ + struct Library *nh_DOSBase; /* DOS base */ + struct MsgPort *nh_TimerMsgPort; /* Port for timer.device */ + struct timerequest *nh_TimerIOReq; /* Timer IO Request */ + BOOL nh_RestartIt; /* Restart removable task? */ + //struct RigidDisk nh_RDsk; /* RigidDisk */ + UBYTE *nh_OneBlock; /* buffer for one block */ + ULONG nh_OneBlockSize; /* size of one block buffer */ + +}; + +struct NepMSDevBase +{ + struct Library np_Library; /* standard */ + UWORD np_Flags; /* various flags */ + + BPTR np_SegList; /* device seglist */ + struct NepMSBase *np_ClsBase; /* pointer to class base */ + struct Library *np_UtilityBase; /* cached utilitybase */ +}; + +#endif /* MASSSTORAGE_H */ diff --git a/rom/usb/classes/massstorage/mmakefile.src b/rom/usb/classes/massstorage/mmakefile.src new file mode 100644 index 000000000..d619ca3a8 --- /dev/null +++ b/rom/usb/classes/massstorage/mmakefile.src @@ -0,0 +1,13 @@ +# $Id: mmakefile.src $ +include $(TOP)/config/make.cfg + +FILES := massstorage.class dev debug + +#MM- rom-usb-classes-massstorage : rom-usb-usbclass rom-usb-poseidon + +%build_module mmake=rom-usb-classes-massstorage \ + modname=massstorage modtype=usbclass modsuffix="class" \ + files="$(FILES)" \ + uselibs="amiga rom mui" + +%common diff --git a/rom/usb/classes/mmakefile b/rom/usb/classes/mmakefile new file mode 100644 index 000000000..5dcc900c8 --- /dev/null +++ b/rom/usb/classes/mmakefile @@ -0,0 +1,353 @@ +# $Id: mmakefile.src $ +include $(TOP)/config/make.cfg + +#MM rom-usb-usbclass-includes : \ +#MM rom-usb-poseidon-includes \ +#MM includes-copy +#MM- rom-usb-usbclass : linklibs + + +# Define metamake targets and their dependencies +#MM- includes-all : rom-usb-usbclass-includes +#MM rom-usb-usbclass : rom-usb-usbclass-includes core-linklibs +#MM rom-usb-usbclass-kobj : rom-usb-usbclass-includes core-linklibs +#MM rom-usb-usbclass-linklib : rom-usb-usbclass-includes +#MM rom-usb-usbclass-quick : rom-usb-usbclass-includes-quick +#MM rom-usb-usbclass-includes : rom-usb-usbclass-makefile rom-usb-usbclass-includes-dirs \ +#MM includes-generate-deps +#MM rom-usb-usbclass-includes-quick +#MM rom-usb-usbclass-includes-dirs +#MM rom-usb-usbclass-makefile +#MM rom-usb-usbclass-funclist +#MM rom-usb-usbclass-clean + +# All MetaMake targets defined by this macro +BD_ALLTARGETS := rom-usb-usbclass rom-usb-usbclass-quick rom-usb-usbclass-includes \ + rom-usb-usbclass-includes-quick rom-usb-usbclass-includes-dirs rom-usb-usbclass-clean \ + rom-usb-usbclass-kobj rom-usb-usbclass-funclist + +.PHONY : $(BD_ALLTARGETS) rom-usb-usbclass-makefile + +ifeq (usbclass,) +$(error using %build_module_skeleton: modname may not be empty) +endif +ifeq (library,) +$(error using %build_module_skeleton: $(MODTYPE) has to be defined with the type of the module) +endif + +# Default values for variables and arguments +BD_DEFLINKLIBNAME := usbclass +BD_DEFREFFILE := $(OBJDIR)/usbclass_ALL.ref +BD_DEFDFLAGS := %(cflags) +OBJDIR ?= $(GENDIR)/$(CURDIR) + +## Create genmodule include Makefile for the module +## +rom-usb-usbclass-makefile : $(OBJDIR)/Makefile.usbclass + + +TMP_TARGET := Makefile.usbclass +TMP_DEPS := $(GENMODULE) +TMP_OPTS := +ifneq (,) + TMP_OPTS += -c $(SRCDIR)/$(CURDIR)/ + TMP_DEPS += $(SRCDIR)/$(CURDIR)/ +else + TMP_OPTS += -c $(SRCDIR)/$(CURDIR)/usbclass.conf + TMP_DEPS += $(SRCDIR)/$(CURDIR)/usbclass.conf +endif +ifneq (,) + TMP_OPTS += -s +endif +ifneq ($(OBJDIR),) + TMP_OPTS += -d $(OBJDIR) + TMP_TARGET := $(OBJDIR)/$(TMP_TARGET) +endif + +$(TMP_TARGET) : OPTS := $(TMP_OPTS) +$(TMP_TARGET) : MODNAME := usbclass +$(TMP_TARGET) : MODTYPE := library +$(TMP_TARGET) : $(TMP_DEPS) + @$(GENMODULE) $(OPTS) writemakefile $(MODNAME) $(MODTYPE) + +$(OBJDIR)/Makefile.usbclass : | $(OBJDIR) + +GLOB_MKDIRS += $(OBJDIR) + +# Do not parse these statements if metatarget is not appropriate +ifneq ($(filter $(TARGET),$(BD_ALLTARGETS)),) + +include $(OBJDIR)/Makefile.usbclass + +BD_DEFMODDIR := $(usbclass_MODDIR) + + +## include files generation +## +BD_INCDIR := $(AROSDIR)/$(AROS_DIR_INCLUDE) +BD_LIBDEFSINC := $(OBJDIR)/include/usbclass_libdefs.h +BD_DEFLIBDEFSINC := $(OBJDIR)/include/usbclass_deflibdefs.h + +rom-usb-usbclass-includes-quick : rom-usb-usbclass-includes +rom-usb-usbclass-includes : $(addprefix $(GENINCDIR)/,$(usbclass_INCLUDES)) \ + $(addprefix $(BD_INCDIR)/,$(usbclass_INCLUDES)) \ + $(BD_LIBDEFSINC) $(BD_DEFLIBDEFSINC) + +ifneq ($(usbclass_INCLUDES),) + + +ifneq ($(usbclass_INCLUDES),) +TMP_TARGETS := $(usbclass_INCLUDES) + +TMP_DEPS := $(GENMODULE) +ifeq ($(usbclass_NEEDREF), yes) + ifeq ($(BD_DEFREFFILE),) + $(error reffile needed in rule_genmodule_files but none specified) + endif + TMP_OPTS := -r $(BD_DEFREFFILE) + TMP_DEPS += $(BD_DEFREFFILE) +else + TMP_OPTS := +endif +ifneq (,) + TMP_OPTS += -c $(SRCDIR)/$(CURDIR)/ + TMP_DEPS += $(SRCDIR)/$(CURDIR)/ +else + TMP_OPTS += -c $(SRCDIR)/$(CURDIR)/usbclass.conf + TMP_DEPS += $(SRCDIR)/$(CURDIR)/usbclass.conf +endif +ifneq (,) + TMP_OPTS += -s +endif +ifneq ($(OBJDIR)/include,) + TMP_OPTS += -d $(OBJDIR)/include + TMP_TARGETS := $(addprefix $(OBJDIR)/include/,$(TMP_TARGETS)) +endif + +$(TMP_TARGETS) : OPTS := $(TMP_OPTS) +$(TMP_TARGETS) : MODNAME := usbclass +$(TMP_TARGETS) : MODTYPE := library +$(TMP_TARGETS) : $(TMP_DEPS) + @$(ECHO) "Generating include files" + @$(GENMODULE) $(OPTS) writeincludes $(MODNAME) $(MODTYPE) +endif + + +TMP_SRCDIR := $(OBJDIR)/include + +$(addprefix $(GENINCDIR)/,$(usbclass_INCLUDES)) : | $(OBJDIR)/usbclass_geninc + +$(OBJDIR)/usbclass_geninc : COPYSRCDIR := $(OBJDIR)/include +$(OBJDIR)/usbclass_geninc : TGTDIR := $(GENINCDIR) +$(OBJDIR)/usbclass_geninc : FILES := $(usbclass_INCLUDES) +$(OBJDIR)/usbclass_geninc : $(addprefix $(OBJDIR)/include/,$(usbclass_INCLUDES)) + @for f in $(FILES); do \ + $(IF) ! $(CMP) -s $(COPYSRCDIR)/$$f $(TGTDIR)/$$f ; then \ + $(CP) $(COPYSRCDIR)/$$f $(TGTDIR)/$$f ; \ + fi ; \ + done + @$(TOUCH) $@ + + +TMP_SRCDIR := $(OBJDIR)/include + +$(addprefix $(BD_INCDIR)/,$(usbclass_INCLUDES)) : | $(OBJDIR)/usbclass_incs + +$(OBJDIR)/usbclass_incs : COPYSRCDIR := $(OBJDIR)/include +$(OBJDIR)/usbclass_incs : TGTDIR := $(BD_INCDIR) +$(OBJDIR)/usbclass_incs : FILES := $(usbclass_INCLUDES) +$(OBJDIR)/usbclass_incs : $(addprefix $(OBJDIR)/include/,$(usbclass_INCLUDES)) + @for f in $(FILES); do \ + $(IF) ! $(CMP) -s $(COPYSRCDIR)/$$f $(TGTDIR)/$$f ; then \ + $(CP) $(COPYSRCDIR)/$$f $(TGTDIR)/$$f ; \ + fi ; \ + done + @$(TOUCH) $@ + + +ifneq ($(usbclass_INCLUDES),) +TMP_TARGETS := $(usbclass_INCLUDES) + +TMP_DEPS := $(GENMODULE) +TMP_OPTS := +ifneq (,) + TMP_OPTS += -c $(SRCDIR)/$(CURDIR)/ + TMP_DEPS += $(SRCDIR)/$(CURDIR)/ +else + TMP_OPTS += -c $(SRCDIR)/$(CURDIR)/usbclass.conf + TMP_DEPS += $(SRCDIR)/$(CURDIR)/usbclass.conf +endif +ifneq (,) + TMP_OPTS += -s +endif +ifneq ($(OBJDIR)/dummyinc,) + TMP_OPTS += -d $(OBJDIR)/dummyinc + TMP_TARGETS := $(addprefix $(OBJDIR)/dummyinc/,$(TMP_TARGETS)) +endif + +$(TMP_TARGETS) : OPTS := $(TMP_OPTS) +$(TMP_TARGETS) : MODNAME := usbclass +$(TMP_TARGETS) : MODTYPE := library +$(TMP_TARGETS) : $(TMP_DEPS) + @$(ECHO) "Generating dummy include files" + @$(GENMODULE) $(OPTS) writedummy $(MODNAME) $(MODTYPE) +endif + +BD_INCDIRS := $(filter-out ./,$(sort $(dir $(usbclass_INCLUDES)))) + +TMPusbclass_INCDIRS := \ + $(OBJDIR)/include $(addprefix $(OBJDIR)/include/,$(BD_INCDIRS)) \ + $(GENINCDIR) $(addprefix $(GENINCDIR)/,$(BD_INCDIRS)) \ + $(BD_INCDIR) $(addprefix $(BD_INCDIR)/,$(BD_INCDIRS)) + +rom-usb-usbclass-includes-dirs :: $(TMPusbclass_INCDIRS) + +GLOB_MKDIRS += $(TMPusbclass_INCDIRS) + + +$(addprefix $(OBJDIR)/dummyinc/,$(usbclass_INCLUDES)) : | $(OBJDIR)/dummyinc $(addprefix $(OBJDIR)/dummyinc/,$(BD_INCDIRS)) +GLOB_MKDIRS += $(OBJDIR)/dummyinc $(addprefix $(OBJDIR)/dummyinc/,$(BD_INCDIRS)) + +endif + + +TMP_TARGET := usbclass_libdefs.h +TMP_DEPS := $(GENMODULE) +TMP_OPTS := +ifneq (,) + TMP_OPTS += -c $(SRCDIR)/$(CURDIR)/ + TMP_DEPS += $(SRCDIR)/$(CURDIR)/ +else + TMP_OPTS += -c $(SRCDIR)/$(CURDIR)/usbclass.conf + TMP_DEPS += $(SRCDIR)/$(CURDIR)/usbclass.conf +endif +ifneq (,) + TMP_OPTS += -s +endif +ifneq ($(OBJDIR)/include,) + TMP_OPTS += -d $(OBJDIR)/include + TMP_TARGET := $(OBJDIR)/include/$(TMP_TARGET) +endif + +$(TMP_TARGET) : OPTS := $(TMP_OPTS) +$(TMP_TARGET) : MODNAME := usbclass +$(TMP_TARGET) : MODTYPE := library +$(TMP_TARGET) : $(TMP_DEPS) + @$(ECHO) "Generating $(notdir $@)" + @$(GENMODULE) $(OPTS) writelibdefs $(MODNAME) $(MODTYPE) + +$(BD_DEFLIBDEFSINC) : FILENAME := $(BD_LIBDEFSINC) +$(BD_DEFLIBDEFSINC) : + @$(ECHO) "generating $@" + @$(ECHO) "#define LC_LIBDEFS_FILE \"$(FILENAME)\"" >$@ + +$(BD_LIBDEFSINC) $(BD_DEFLIBDEFSINC) : | $(OBJDIR)/include +GLOB_MKDIRS += $(OBJDIR)/include + +## Generation of the funclist file +## +rom-usb-usbclass-funclist : usbclass.funclist + + +TMP_TARGET := usbclass.funclist +TMP_DEPS := $(GENMODULE) +TMP_OPTS := +ifeq ($(BD_DEFREFFILE),) + $(error reffile needed in rule_genmodule_funclist but none specified) +endif +TMP_OPTS := -r $(BD_DEFREFFILE) +TMP_DEPS += $(BD_DEFREFFILE) +ifneq (,) + TMP_OPTS += -c $(SRCDIR)/$(CURDIR)/ + TMP_DEPS += $(SRCDIR)/$(CURDIR)/ +else + TMP_OPTS += -c $(SRCDIR)/$(CURDIR)/usbclass.conf + TMP_DEPS += $(SRCDIR)/$(CURDIR)/usbclass.conf +endif +ifneq (,) + TMP_OPTS += -s +endif +ifneq (,) + TMP_OPTS += -d + TMP_TARGET := /$(TMP_TARGET) +endif + +$(TMP_TARGET) : OPTS := $(TMP_OPTS) +$(TMP_TARGET) : MODNAME := usbclass +$(TMP_TARGET) : MODTYPE := library +$(TMP_TARGET) : $(TMP_DEPS) + @$(ECHO) "Generating $(notdir $@)" + @$(GENMODULE) $(OPTS) writefunclist $(MODNAME) $(MODTYPE) + + +## Extra genmodule src files generation +## + +TMP_TARGETS := $(usbclass_STARTFILES) $(usbclass_ENDFILES) \ + $(usbclass_LINKLIBFILES) +TMP_TARGETS := $(addsuffix .c,$(TMP_TARGETS)) $(addsuffix .S, $(usbclass_LINKLIBAFILES)) + +TMP_DEPS := $(GENMODULE) +ifeq ($(usbclass_NEEDREF), yes) + ifeq ($(BD_DEFREFFILE),) + $(error reffile needed in rule_genmodule_files but none specified) + endif + TMP_OPTS := -r $(BD_DEFREFFILE) + TMP_DEPS += $(BD_DEFREFFILE) +else + TMP_OPTS := +endif +ifneq (,) + TMP_OPTS += -c $(SRCDIR)/$(CURDIR)/ + TMP_DEPS += $(SRCDIR)/$(CURDIR)/ +else + TMP_OPTS += -c $(SRCDIR)/$(CURDIR)/usbclass.conf + TMP_DEPS += $(SRCDIR)/$(CURDIR)/usbclass.conf +endif +ifneq (,) + TMP_OPTS += -s +endif +ifneq ($(OBJDIR),) + TMP_OPTS += -d $(OBJDIR) + TMP_TARGETS := $(addprefix $(OBJDIR)/,$(TMP_TARGETS)) +endif + +$(TMP_TARGETS) : OPTS := $(TMP_OPTS) +$(TMP_TARGETS) : MODNAME := usbclass +$(TMP_TARGETS) : MODTYPE := library +$(TMP_TARGETS) : $(TMP_DEPS) + @$(ECHO) "Generating functable and support files for module $(MODNAME$(BDID))" +ifneq (,lib.conf) + @$(IF) $(TEST) -f lib.conf; then \ + $(ECHO) "WARNING !!! $(CURDIR)/lib.conf may probably be removed"; \ + fi +endif + @$(IF) $(TEST) -f libdefs.h; then \ + $(ECHO) "WARNING !!! $(CURDIR)/libdefs.h may probably be removed"; \ + fi + @$(GENMODULE) $(OPTS) writefiles $(MODNAME) $(MODTYPE) + +BD_TOCLEAN := $(BD_OBJS) $(BD_DEPS) $(BD_DEFREFFILE) \ + $(BD_REFS) $(BD_MODULE) $(BD_LINKLIB) $(BD_KOBJ) \ + $(OBJDIR)/Makefile.usbclass \ + $(addprefix $(OBJDIR)/include/,$(usbclass_INCLUDES)) \ + $(addprefix $(GENINCDIR)/,$(usbclass_INCLUDES)) \ + $(addprefix $(BD_INCDIR)/,$(usbclass_INCLUDES)) \ + $(OBJDIR)/usbclass_geninc $(OBJDIR)/usbclass_incs \ + $(addsuffix .c,$(BD_LINKLIBFILES)) $(BD_LINKLIBOBJS) $(BD_LIBDEFSINC) \ + $(BD_DEFLIBDEFSINC) +rom-usb-usbclass-clean : FILES := $(BD_TOCLEAN) +rom-usb-usbclass-clean :: + @$(ECHO) "Cleaning up for module usbclass" + @$(RM) $(FILES) + +endif # $(TARGET) in $(BD_ALLTARGETS) + +# Delete generated makefiles +#MM +clean :: + @$(RM) $(TOP)/$(CURDIR)/mmakefile $(TOP)/$(CURDIR)/mmakefile.bak + +include $(SRCDIR)/config/make.tail + +BDID := $(BDTARGETID) diff --git a/rom/usb/classes/mmakefile.src b/rom/usb/classes/mmakefile.src new file mode 100644 index 000000000..8e39724f6 --- /dev/null +++ b/rom/usb/classes/mmakefile.src @@ -0,0 +1,12 @@ +# $Id: mmakefile.src $ +include $(TOP)/config/make.cfg + +#MM rom-usb-usbclass-includes : \ +#MM rom-usb-poseidon-includes \ +#MM includes-copy +#MM- rom-usb-usbclass : linklibs + +%build_module_skeleton mmake=rom-usb-usbclass \ + modname=usbclass modtype=library + +%common diff --git a/rom/usb/classes/usbclass.conf b/rom/usb/classes/usbclass.conf new file mode 100644 index 000000000..5b0b59a48 --- /dev/null +++ b/rom/usb/classes/usbclass.conf @@ -0,0 +1,26 @@ +##begin config +version 1.1 +libbase UsbClsBase +libbasetype struct Library +libbasetypeextern struct Library +residentpri 48 +##end config + +##begin cdef +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +##end cdef + +##begin functionlist +LONG usbGetAttrsA(ULONG type, APTR usbstruct, struct TagItem *taglist) (D0,A0,A1) +LONG usbSetAttrsA(ULONG type, APTR usbstruct, struct TagItem *taglist) (D0,A0,A1) +LONG usbDoMethodA(ULONG methodid, IPTR *methoddata) (D0,A1) +##end functionlist diff --git a/rom/usb/classes/usbclass.doc b/rom/usb/classes/usbclass.doc new file mode 100644 index 000000000..ef8dda5db --- /dev/null +++ b/rom/usb/classes/usbclass.doc @@ -0,0 +1,607 @@ +TABLE OF CONTENTS + +usbclass/--background-- +usbclass/usbAttemptDeviceBinding +usbclass/usbAttemptInterfaceBinding +usbclass/usbDoMethod +usbclass/usbForceDeviceBinding +usbclass/usbForceInterfaceBinding +usbclass/usbGetAttrs +usbclass/usbReleaseDeviceBinding +usbclass/usbReleaseInterfaceBinding +usbclass/usbSetAttrs + + + usbclass/--background-- usbclass/--background-- + + PURPOSE + USB classes in the sense of the Poseidon stack environment, are + libraries that provide functionality for USB devices. They interface + to the poseidon.library via its function vectors and are called + whenever a new device is found. + + This document is dated to 11-May-03 19:24:05. + + OVERVIEW + Each class will be offered the interface or device descriptor of every + device not yet having a binding. If the class 'knows' the type of the + device and is able to communicate with it, it tells back the Poseidon + stack that it wants to use it. There are two types of bindings: device + bindings, that take over control of the whole device, and interface + bindings, that only use the endpoints of a particular interface, + sharing the (compound) device with other classes that bind to other + interfaces. + + Bindings are exclusive. No class can bind to an interface already + claimed by someone else. Also, no device binding will be allowed, if + there are interface bindings to that device and vice versa. A class + normally only needs to implement either interface or device bindings. + + A class may only claim bindings it is SURE to understand. Otherwise + another class will not be able to add its functionality. + + There is an option for the user to force a binding to a device or + interface. This makes sense, if it is a vendor specific driver and + likely to by supported by some yet unknown device which a similar + chipset. Support for forced bindings is optional -- a class driver + may still refuse to bind to the device or interface, if it is not + compatible. + + The device or interface structure, as well as any other structures of + the Poseidon stack are private, except for they all contain a Node + structure for linking. Do NOT assume any data layout as it might + change. To get or set attributes, use the psdGetAttrs() and + psdSetAttrs() function of the poseidon.library. + + A class driver should spawn a subtask for each instance of the + functionality added. For example, as there can be as many mice on the + USB as the users connects, there will be multiple instances of the + bootmouse.class tasks running. + + Whenever the device gets removed, the poseidon.library will ask you + to remove your binding to it and you will properly behave and release + the binding. Note that your library does not need to free all your + resources on this operation. This allows you suspend your + functionality and return it, when the device gets plugged in again. + For example, the printer.class keeps the information about every + printer connected and maps it back to the same unit number whenever it + is reconnected. The data is only freed on the expunge of the class. + + Classes communicate with the USB devices via pipes. Have a look at the + poseidon.library AutoDocs. + + It is a preferred method only to open the poseidon.library when + required (i.e. inside the attempt/release binding vectors, or inside + the subtask). This allows the stack to expunge itself when it is no + longer needed, taking down the class libraries aswell. + + With some newer releases of Poseidon, some functionality has been + added. This includes the usbSetAttrs() and usbGetAttrs() function, + aswell as the usbDoMethod() call. These allow some querying of classes + and their state as well as easier extension without breaking + compatibility with newer versions of the main library. + + All class drivers can have their own global configuration and/or + interface or device preferences. It is recommended that if such prefs + exist, a nice GUI should be available to the end user. If interface + or device prefs exist, the ability to change default prefs for these + should be available through the global configuration. Common prefs + handling is supported by the poseidon.library. + + Class drivers should be stored in SYS:Classes/USB. + + WARNING + The class library interface is PRELIMINARY! It WILL be expanded and + more features WILL be added. If you write your class libraries, be + sure to use version 1. Newer versions of poseidon then will probably + ask for version 2 or higher class library versions, if the interface + is not compatible anymore (or more functions are required). + + If you have good ideas on expanding the API, please let me know. + + + usbclass/usbAttemptDeviceBinding usbclass/usbAttemptDeviceBinding + + NAME + usbAttemptDeviceBinding -- establish device binding if possible + + SYNOPSIS + udb = usbAttemptDeviceBinding(pd); + D0 A0 + + APTR usbAttemptDeviceBinding(APTR); + + FUNCTION + The class gets a device structure from the Poseidon stack. It may + then examine it further (using psdGetAttrs()) to decide, if it wants + to use it. In this case, this function returns the pointer to a + private context structure which will not be touched by Poseidon, but + used for the usbReleaseDeviceBinding() call whenever the stack + wants go get rid of the instance. + + You can go down the device, traverse its configurations, interfaces + and endpoints by hand. Just read out the structure data using + psdGetAttrs(). + + NOTE + When establishing a device binding, you are allowed to do anything + you like with the device, including switching configurations and + changing to alternative settings on the interfaces. + + However, if it is possible for that kind of device to have multiple + interfaces of which you will not use, but some other class could, + do not use device bindings, but interface bindings. + + INPUTS + pd - pointer to a Poseidon device structure (private). + + RESULT + udb - private pointer of the binding context or NULL, if no binding + could be established. + + SEE ALSO + usbReleaseDeviceBinding(), usbForceDeviceBinding() + + + usbclass/usbAttemptInterfaceBinding usbclass/usbAttemptInterfaceBinding + + NAME + usbAttemptInterfaceBinding -- establish interface binding if possible + + SYNOPSIS + uifb = usbAttemptInterfaceBinding(pif); + D0 A0 + + APTR usbAttemptInterfaceBinding(APTR); + + FUNCTION + The class gets an interface structure from the Poseidon stack. It may + then examine it further (using psdGetAttrs()) to decide, if it wants + to use it. In this case, this function returns the pointer to a + private context structure which will not be touched by Poseidon, but + used for the usbReleaseInterfaceBinding() call whenever the stack + wants go get rid of the instance. + + Note that all structures have uplinking data, i.e. you can climb up + to the device structure via the interface IFA_Config and then + CA_Device tag to get the ProductID and other information available. + + NOTE + When establishing an interface binding, you are allowed to check for + alternate settings. If you decide to use some other setting, use + the psdSetAltInterface() call. + + You may not change the configuration number using + psdSetDeviceConfig() as you only own the given interface and not the + whole device. + + INPUTS + pif - pointer to a Poseidon interface structure (private). + + RESULT + uifb - private pointer of the binding context or NULL, if no binding + could be established. + + SEE ALSO + usbReleaseInterfaceBinding(), usbForceInterfaceBinding() + + + usbclass/usbDoMethod usbclass/usbDoMethod + + NAME + usbDoMethodA -- perform a class function + usbDoMethod -- varargs stub for usbDoMethodA + + SYNOPSIS + result = usbDoMethodA(methodid, methodddata); + D0 D0 A1 + + LONG usbDoMethodA(ULONG, APTR); + + result = usbDoMethod(methodid, ...); + + LONG usbDoMethod(ULONG, ...); + + FUNCTION + Similar to the DoMethod() function of amiga.lib. Performs a class + function and returns its results. + + METHODS + UCM_AttemptInterfaceBinding + + APTR uifb = usbDoMethod(UCM_AttemptInterfaceBinding, APTR pif); + + Does the same as the old vector usbAttemptInterfaceBinding(). + For compatibility, both should be implemented. The first and only + parameter contains the interface pointer. The result is the + private binding pointer or NULL, if no binding could be + established. + + UCM_ForceInterfaceBinding + + APTR uifb = usbDoMethod(UCM_ForceInterfaceBinding, APTR pif); + + Does the same as the old vector usbForceInterfaceBinding(). + For compatibility, both should be implemented. The first and only + parameter contains the interface pointer. The result is the + private binding pointer or NULL, if no binding could be + established. + + UCM_ReleaseInterfaceBinding + + void usbDoMethod(UCM_ReleaseInterfaceBinding, APTR uifb); + + Does the same as the old vector usbReleaseInterfaceBinding(). + For compatibility, both should be implemented. The first and only + parameter contains the private binding pointer returned by + UCM_AttemptInterfaceBinding or UCM_ForceInterfaceBinding. + + UCM_AttemptDeviceBinding + + APTR udb = usbDoMethod(UCM_AttemptDeviceBinding, APTR pd); + + Does the same as the old vector usbAttemptDeviceBinding(). + For compatibility, both should be implemented. The first and only + parameter contains the device pointer. The result is the class + private pointer to the device binding or NULL, if no binding could + be established. + + UCM_ForceDeviceBinding + + APTR udb = usbDoMethod(UCM_ForceDeviceBinding, APTR pd); + + Does the same as the old vector usbForceDeviceBinding(). + For compatibility, both should be implemented. The first and only + parameter contains the device pointer. The result is the class + private pointer to the device binding or NULL, if no binding could + be established. + + UCM_ReleaseDeviceBinding + + void usbDoMethod(UCM_ReleaseDeviceBinding, APTR udb); + + Does the same as the old vector usbReleaseDeviceBinding(). + For compatibility, both should be implemented. The first and only + parameter contains the private binding pointer returned by + UCM_AttemptDeviceBinding or UCM_ForceDeviceBinding. + + UCM_OpenCfgWindow + + BOOL good = usbDoMethod(UCM_OpenCfgWindow); + + If the class has a global configuration GUI, it should be opened + by a call to UCM_OpenCfgWindow. There are no parameters. + + If your class does not provide a global GUI, return FALSE. + Otherwise, return TRUE. + + Take care that the GUI window has to be started asynchroneously + and may not block. Also, ensure that your window does not get + opened twice, if it is already open. Please be so nice and allow + the window to be closed at any time -- either by the user or + by UCM_CloseCfgWindow. If your global prefs relies on existing + bindings, make sure that it copes with them going away at any + time (through the known release calls). + + It is recommended that you inject the prefs to the main Poseidon + prefs structure at the closure of the window. + + UCM_CloseCfgWindow + + void usbDoMethod(UCM_CloseCfgWindow); + + This method requests the GUI to be closed. The class may or may + not obey to this. + + UCM_OpenBindingCfgWindow + + BOOL good = usbDoMethod(UCM_OpenBindingCfgWindow, APTR ub); + + If the class has a binding configuration GUI, it should be opened + by a call to UCM_OpenBindingCfgWindow. The parameter specifies, + which binding should be used and is a the private pointer to the + binding structure the class uses itself. This may either be a + device or interface binding structure. + + If your class does not provide a binding configuration GUI, + return FALSE. Otherwise, return TRUE. + + Take care that the GUI window has to be started asynchroneously + and may not block. Also, ensure that your window does not get + opened twice, if it is already open. Please be so nice and allow + the window to be closed at any time -- either by the user or + by UCM_CloseBindingCfgWindow. If there are default settings and + no binding config has been generated yet, it should initially use + the default settings for the binding prefs. Make sure that the + prefs task copes the binding going away at any time (through the + known release calls). + + Please remember that multiple windows for seperate binding prefs + should be supported. + + UCM_CloseBindingCfgWindow + + void usbDoMethod(UCM_CloseBindingCfgWindow); + + This method requests the GUI window for the binding settings to + be closed. The class may or may not obey to this. + + NOTE + The list of methods may grow in future. + + INPUTS + methodid - numeric method id a specific in libraries/usbclass.h + methoddata - the message packet to send according to the method id + + RESULT + result - result of the method called. + + SEE ALSO + usbGetAttrs(), usbSetAttrs() + + + usbclass/usbForceDeviceBinding usbclass/usbForceDeviceBinding + + NAME + usbForceDeviceBinding -- force device binding if possible + + SYNOPSIS + udb = usbForceDeviceBinding(pd); + D0 A0 + + APTR usbForceDeviceBinding(APTR); + + FUNCTION + This call is very similar to usbAttemptDeviceBinding(), except that it + should do a best attempt to build up a binding, even if it does not + know, if the device is compatible or supported. This allows expert + users to try to get devices to work that normally would not bind + automatically, because the class does not know about it. + + Still, even usbForceDeviceBinding() may fail, e.g. if the device does + not meet the requirements (interfaces, endpoints) or does not respond + properly to the expected protocol. + + See usbAttemptDeviceBinding() for details. + + NOTE + It is recommended that usbAttemptDeviceBinding() only does some + pre-checking and then calls usbForceDeviceBinding() internally. + + INPUTS + pd - pointer to a Poseidon device structure (private). + + RESULT + udb - private pointer of the binding context or NULL, if no binding + could be established. + + SEE ALSO + usbAttemptDeviceBinding(), usbReleaseDeviceBinding() + + + usbclass/usbForceInterfaceBinding usbclass/usbForceInterfaceBinding + + NAME + usbForceInterfaceBinding -- force interface binding if possible + + SYNOPSIS + uifb = usbForceInterfaceBinding(pif); + D0 A0 + + APTR usbForceInterfaceBinding(APTR); + + FUNCTION + This call is very similar to usbAttemptInterfaceBinding(), except that + it should do a best attempt to build up a binding, even if it does not + know, if the device is compatible or supported. This allows expert + users to try to get interfaces to work that normally would not bind + automatically, because the class does not know about it. + + Still, even usbForceInterfaceBinding() may fail, e.g. if the device + does not meet the requirements (e.g. endpoints) or does not respond + properly to the expected protocol. + + See usbAttemptInterfaceBinding() for details. + + NOTE + It is recommended that usbAttemptInterfaceBinding() only does some + pre-checking and then calls usbForceInterfaceBinding() internally. + + INPUTS + pif - pointer to a Poseidon interface structure (private). + + RESULT + uifb - private pointer of the binding context or NULL, if no binding + could be established. + + SEE ALSO + usbAttemptInterfaceBinding(), usbReleaseInterfaceBinding() + + + usbclass/usbGetAttrs usbclass/usbGetAttrs + + NAME + usbGetAttrsA -- get information from an internal class structure + usbGetAttrs -- varargs stub for usbGetAttrsA() + + SYNOPSIS + num = usbGetAttrsA(type, usbstruct, taglist); + D0 D0 A0 A1 + + LONG usbGetAttrsA(ULONG, APTR, struct TagList *); + + num = usbGetAttrs(type, usbstruct, tag1, ...); + + LONG usbGetAttrs(ULONG, APTR, Tag, ...); + + FUNCTION + Acquires attribute information from an internal class structure, + according to the attributes chosen in the tag list. For each entry in + the tag list, ti_Tag identifies the attribute and ti_Data is a pointer + to the long variable where you wish the result to be stored. + + There are currently a number of thee different system structures which + can be accessed in this way. To avoid adding multiple functions with + the same semantics, usbGetAttrs() requires the type of the structure + passed. + + INPUTS + type - describes the type of the structure passed. + See libraries/usbclass.h for details. + usbstruct - pointer to the system structure on which information + should be gathered. Can be NULL only for UGA_CLASS. + taglist - pointer to TagItem list, terminated by TAG_END. + + TAGS + All tags are read-only, except stated otherwise. + + UGA_CLASS: (read-only) + UCCA_Priority (LONG) - Priority for the class scan. Valid inputs are + between -128 and 127. The higher the priority, the earlier the + class gets to attempt a binding. This is important if different + classes lock to the same interfaces or devices, but have varying + degree of functionality and availability (e.g. hid.class versus + bootmouse.class or bootkeyboard.class). + UCCA_Description (STRPTR) - String to display in Trident, describing + the basic features and intention of the class. + UCCA_HasClassCfgGUI (BOOL) - Returns TRUE, if the class has a global + prefs window, or FALSE otherwise. + UCCA_HasBindingCfgGUI (BOOL) - Returns TRUE, if the class implements + a GUI for seperate bindings. If it does not have this feature, + it retuns FALSE. + UCCA_AfterDOSRestart (BOOL) - Returns TRUE, if the class needs to + be restarted (i.e. all bindings closed and reopened), after DOS + has been available. This only applies to classes that are + available while booting and don't need the dos.library, but would + benefit from its existance later on. + + UCBA_BINDING: + no tags yet defined + + UCFA_CONFIG: + no tags yet defined + + RESULT + num - number of tags actually read or -1, if the request was not + supported somehow. + + SEE ALSO + psdSetAttrs(), psdNumToStr() + + + usbclass/usbReleaseDeviceBinding usbclass/usbReleaseDeviceBinding + + NAME + usbReleaseDeviceBinding -- release a previously bound device + + SYNOPSIS + usbReleaseDeviceBinding(udb); + A0 + + void usbReleaseDeviceBinding(APTR); + + FUNCTION + If this function is called, Poseidon wants to release an established + device binding. The class MUST release the device and stop all further + transactions to it. After you've returned from this call, the whole + device you were talking to might be gone. + + WARNING + Read the last sentence: Everything you ever owned of the device, is + not available anymore after you have returned from that call. Do NOT + attempt to read out structures you might have got before. Do NOT + try to send pipe transfers anymore. + + Normally, this call terminates the subtask created and frees the + context allocated for the instance. This call should not take too + long to terminate, especially, it MAY NOT WAIT for certain + application level action (like closing of a device in use). + + INPUTS + udb - private pointer of the binding context. + + SEE ALSO + usbAttemptDeviceBinding() + + + usbclass/usbReleaseInterfaceBinding usbclass/usbReleaseInterfaceBinding + + NAME + usbReleaseInterfaceBinding -- release a previously bound interface + + SYNOPSIS + usbReleaseInterfaceBinding(uifb); + A0 + + void usbReleaseInterfaceBinding(APTR); + + FUNCTION + If this function is called, Poseidon wants to release an established + binding. The class MUST release the interface and stop all further + transactions to it. After you've returned from this call, the + interface and possibly the whole device you were talking to might be + gone. + + WARNING + Read the last sentence: Everything you ever owned of the device, is + not available anymore after you have returned from that call. Do NOT + attempt to read out structures you might have got before. Do NOT + try to send pipe transfers anymore. + + Normally, this call terminates the subtask created and frees the + context allocated for the instance. This call should not take too + long to terminate, especially, it MAY NOT WAIT for certain + application level action (like closing of a device in use). + + INPUTS + uifb - private pointer of the binding context. + + SEE ALSO + usbAttemptInterfaceBinding() + + + usbclass/usbSetAttrs usbclass/usbSetAttrs + + NAME + usbSetAttrsA -- change fields of an internal class structure + usbSetAttrs -- varargs stub for usbSetAttrsA() + + SYNOPSIS + num = usbSetAttrsA(type, usbstruct, taglist); + D0 D0 A0 A1 + + LONG usbSetAttrsA(ULONG, APTR, struct TagList *); + + num = usbSetAttrs(type, usbstruct, tag1, ...); + + LONG usbSetAttrs(ULONG, APTR, Tag, ...); + + FUNCTION + Changes the fields allowed to be written of an internal class + structure according to the attributes chosen in the tag list. For + each entry in the tag list, ti_Tag identifies the attribute and + ti_Data is the long data you wish to change the value to. + + There are currently a number of three different system structures + which can be accessed in this way. To avoid adding multiple functions + with the same semantics, usbSetAttrs() requires the type of the + structure passed. + + INPUTS + type - describes the type of the structure passed. + See libraries/usbclass.h for details. + usbstruct - pointer to the system structure on which information + should be changed. Can be NULL only for UGA_CLASS. + taglist - pointer to TagItem list, terminated by TAG_END. + + TAGS + See usbGetAttrs() for the tags which can be changed. + + RESULT + num - number of tags actually read or -1, if the request was not + supported somehow. + + SEE ALSO + usbGetAttrs() + + diff --git a/rom/usb/pciusb/debug.c b/rom/usb/pciusb/debug.c new file mode 100644 index 000000000..f29021b6b --- /dev/null +++ b/rom/usb/pciusb/debug.c @@ -0,0 +1,38 @@ +#include "debug.h" + +#ifdef DEBUG +void dumpmem(void *mem, unsigned long int len) +{ + unsigned char *p; + + if (!mem || !len) { return; } + + p = (unsigned char *) mem; + + bug("\n"); + + do + { + unsigned char b, c, str[17]; + + for (b = 0; b < 16; b++) + { + c = *p++; + str[b] = ((c >= ' ') && (c <= 'z')) ? c : '.'; + str[b + 1] = 0; + bug("%02lx ", c); + if (--len == 0) break; + } + + while (++b < 16) + { + bug(" "); + } + + bug(" %s\n", str); + } while (len); + + bug("\n\n"); +} + +#endif /* DEBUG */ diff --git a/rom/usb/pciusb/debug.h b/rom/usb/pciusb/debug.h new file mode 100644 index 000000000..6d5cb840e --- /dev/null +++ b/rom/usb/pciusb/debug.h @@ -0,0 +1,22 @@ +#ifndef __DEBUG_H__ +#define __DEBUG_H__ + +#define DB_LEVEL 1 + +#define DEBUG 1 + +#include + +#ifdef DEBUG +#define KPRINTF(l, x) do { if ((l) >= DB_LEVEL) \ + { bug("%s:%s/%lu: ", __FILE__, __FUNCTION__, __LINE__); bug x;} } while (0) +#define DB(x) x + void dumpmem(void *mem, unsigned long int len); +#else /* !DEBUG */ + +#define KPRINTF(l, x) ((void) 0) +#define DB(x) + +#endif /* DEBUG */ + +#endif /* __DEBUG_H__ */ diff --git a/rom/usb/pciusb/dev.c b/rom/usb/pciusb/dev.c new file mode 100644 index 000000000..8063a47d1 --- /dev/null +++ b/rom/usb/pciusb/dev.c @@ -0,0 +1,262 @@ +/* dev.c - pciusb.device by Chris Hodges +*/ + +#include "debug.h" + +#include +#include + +#include "uhwcmd.h" + +#define DEVNAME "pciusb.device" + +#define NewList NEWLIST + +const char devname[] = MOD_NAME_STRING; + +static int devInit(LIBBASETYPEPTR base) +{ + KPRINTF(10, ("devInit base: 0x%08lx SysBase: 0x%08lx\n", + base, SysBase)); + + base->hd_UtilityBase = (struct UtilityBase *) OpenLibrary("utility.library", 39); + +#define UtilityBase base->hd_UtilityBase + + if(UtilityBase) + { + base->hd_MemPool = CreatePool(MEMF_PUBLIC | MEMF_CLEAR | MEMF_SEM_PROTECTED, + 16384, 4096); + if(base->hd_MemPool) + { + NewList(&base->hd_Units); + + KPRINTF(10, ("devInit: Ok\n")); + } else { + KPRINTF(10, ("devInit: CreatePool() failed!\n")); + CloseLibrary((struct Library *) UtilityBase); + base = NULL; + } + } else { + KPRINTF(10, ("devInit: OpenLibrary(\"utility.library\", 39) failed!\n")); + base = NULL; + } + + KPRINTF(10, ("devInit: openCnt = %ld\n", base->hd_Library.lib_OpenCnt)); + + return base ? TRUE : FALSE; +} + +/* + *=========================================================== + * devOpen(ioreq, unit, flags, base) + *=========================================================== + * + * This is the the DEV_OPEN function. + * + */ +static int devOpen(LIBBASETYPEPTR base, struct IOUsbHWReq *ioreq, ULONG unit, ULONG flags) +{ + KPRINTF(10, ("devOpen ioreq: 0x%08lx unit: %ld flags: 0x%08lx base: 0x%08lx\n", + ioreq, unit, flags, base)); + + KPRINTF(10, ("devOpen: openCnt = %ld\n", base->hd_Library.lib_OpenCnt)); + + if(ioreq->iouh_Req.io_Message.mn_Length < sizeof(struct IOUsbHWReq)) + { + KPRINTF(20, ("devOpen: invalid MN_LENGTH!\n")); + + ioreq->iouh_Req.io_Error = IOERR_BADLENGTH; + } else { + /* Default to open failure. */ + ioreq->iouh_Req.io_Error = IOERR_OPENFAIL; + + ioreq->iouh_Req.io_Unit = Open_Unit(ioreq, unit, base); + if(!ioreq->iouh_Req.io_Unit) + { + KPRINTF(20, ("devOpen: could not open unit!\n")); + } else { + /* Opended ok! */ + ioreq->iouh_Req.io_Message.mn_Node.ln_Type = NT_REPLYMSG; + ioreq->iouh_Req.io_Error = 0; + + return TRUE; + } + } + + return FALSE; +} + + +/* + *=========================================================== + * devClose(ioreq, base) + *=========================================================== + * + * This is the the DEV_EXPUNGE function. + * + */ + +static int devClose(LIBBASETYPEPTR base, struct IOUsbHWReq *ioreq) +{ + KPRINTF(10, ("devClose ioreq: 0x%08lx base: 0x%08lx\n", ioreq, base)); + + Close_Unit(base, (struct PCIUnit *) ioreq->iouh_Req.io_Unit, ioreq); + + ioreq->iouh_Req.io_Unit = (APTR) -1; + ioreq->iouh_Req.io_Device = (APTR) -1; + return TRUE; +} + + +static int devExpunge(LIBBASETYPEPTR base) +{ + pciExpunge(base); + + DeletePool(base->hd_MemPool); + + KPRINTF(5, ("devExpunge: closelibrary utilitybase 0x%08lx\n", + UtilityBase)); + CloseLibrary((struct Library *) UtilityBase); + return TRUE; +} + +ADD2INITLIB(devInit, 0) +ADD2OPENDEV(devOpen, 0) +ADD2CLOSEDEV(devClose, 0) +ADD2EXPUNGELIB(devExpunge, 0) + +/* + *=========================================================== + * devBeginIO(ioreq, base) + *=========================================================== + * + * This is the DEV_BEGINIO vector of the device. + * + */ +AROS_LH1(void, devBeginIO, + AROS_LHA(struct IOUsbHWReq *, ioreq, A1), + LIBBASETYPEPTR, base, 5, pciusb) +{ + AROS_LIBFUNC_INIT + + struct PCIUnit *unit = (struct PCIUnit *) ioreq->iouh_Req.io_Unit; + WORD ret; + + //KPRINTF(1, ("devBeginIO ioreq: 0x%08lx base: 0x%08lx cmd: %lu\n", ioreq, base, ioreq->iouh_Req.io_Command)); + + ioreq->iouh_Req.io_Message.mn_Node.ln_Type = NT_MESSAGE; + ioreq->iouh_Req.io_Error = UHIOERR_NO_ERROR; + + if (ioreq->iouh_Req.io_Command < NSCMD_DEVICEQUERY) + { + switch (ioreq->iouh_Req.io_Command) + { + case CMD_RESET: + ret = cmdReset(ioreq, unit, base); + break; + + case CMD_FLUSH: + ret = cmdFlush(ioreq, unit, base); + break; + + case UHCMD_QUERYDEVICE: + ret = cmdQueryDevice(ioreq, unit, base); + break; + + case UHCMD_USBRESET: + ret = cmdUsbReset(ioreq, unit, base); + break; + + case UHCMD_USBRESUME: + ret = cmdUsbResume(ioreq, unit, base); + break; + + case UHCMD_USBSUSPEND: + ret = cmdUsbSuspend(ioreq, unit, base); + break; + + case UHCMD_USBOPER: + ret = cmdUsbOper(ioreq, unit, base); + break; + + case UHCMD_CONTROLXFER: + ret = cmdControlXFer(ioreq, unit, base); + break; + + case UHCMD_BULKXFER: + ret = cmdBulkXFer(ioreq, unit, base); + break; + + case UHCMD_INTXFER: + ret = cmdIntXFer(ioreq, unit, base); + break; + + case UHCMD_ISOXFER: + ret = cmdIsoXFer(ioreq, unit, base); + break; + + default: + ret = IOERR_NOCMD; + break; + } + } else { + switch(ioreq->iouh_Req.io_Command) + { + case NSCMD_DEVICEQUERY: + ret = cmdNSDeviceQuery((struct IOStdReq *) ioreq, unit, base); + break; + + default: + ret = IOERR_NOCMD; + break; + } + } + + if(ret != RC_DONTREPLY) + { + KPRINTF(1, ("TermIO\n")); + if (ret != RC_OK) + { + /* Set error codes */ + ioreq->iouh_Req.io_Error = ret & 0xff; + } + /* Terminate the iorequest */ + TermIO(ioreq, base); + } + + AROS_LIBFUNC_EXIT +} + +/* + *=========================================================== + * devAbortIO(ioreq, base) + *=========================================================== + * + * This is the DEV_ABORTIO vector of the device. It abort + * the given iorequest, and set + * + */ +AROS_LH1(LONG, devAbortIO, + AROS_LHA(struct IOUsbHWReq *, ioreq, A1), + LIBBASETYPEPTR, base, 5, pciusb) +{ + AROS_LIBFUNC_INIT + + KPRINTF(1, ("devAbortIO ioreq: 0x%08lx\n", ioreq)); + + /* Is it pending? */ + if(ioreq->iouh_Req.io_Message.mn_Node.ln_Type == NT_MESSAGE) + { + if(cmdAbortIO(ioreq, base)) + { + ioreq->iouh_Req.io_Error = IOERR_ABORTED; + TermIO(ioreq, base); + return(0); + } + } + return(-1); + + AROS_LIBFUNC_EXIT +} + diff --git a/rom/usb/pciusb/ehcichip.h b/rom/usb/pciusb/ehcichip.h new file mode 100644 index 000000000..6c2a702b3 --- /dev/null +++ b/rom/usb/pciusb/ehcichip.h @@ -0,0 +1,315 @@ +#ifndef EHCICHIP_H +#define EHCICHIP_H + +/* + *---------------------------------------------------------------------------- + * Includes for EHCI USB Controller + *---------------------------------------------------------------------------- + * By Chris Hodges + */ + +#include +#include "hccommon.h" + +/* + * --------------------- EHCI registers ------------------------ + * Warning: These are BYTE offsets! + */ + +#define EHCI_CAPLENGTH 0x000 /* Offset for operational registers */ +#define EHCI_HCIVERSION 0x002 /* HC Version Number */ +#define EHCI_HCSPARAMS 0x004 /* HC Structural Parameters */ +#define EHCI_HCCPARAMS 0x008 /* HC Capability Parameters */ +#define EHCI_HCSPPORTROUTE 0x00c /* HC Companion Port Route Description */ + +/* EHCI_HCSPARAMS defines */ +#define EHSB_PORTPOWERCTRL 4 /* Support for Port Power Control */ +#define EHSB_EXTPORTROUTING 7 /* Routing to companion ports via HCSSPORTROUTE array */ +#define EHSB_PORTINDICATORS 16 /* Support for Port Indicators */ + +#define EHSS_NUM_PORTS 0 /* Number of ports */ +#define EHSS_PORTS_PER_COMP 8 /* Ports per companion controller */ +#define EHSS_NUM_COMPANIONS 12 /* Number of companion controllers */ + +#define EHSF_PORTPOWERCTRL (1UL< + * + */ + +/* Macros to swap bit defines, constants & variables */ +#define SWB(x) ((x+16) & 31) +#define SWC(x) ((x>>16)|((x & 0xffff)<<16)) +#define SWW(x) ((x>>16)|(x<<16)) +#define L2U(x) (x<<16) +#define U2L(x) (x>>16) + +#define PID_IN 0x69 +#define PID_OUT 0xe1 +#define PID_SETUP 0x2d + +#endif /* HCCOMMON_H */ diff --git a/rom/usb/pciusb/mmakefile.src b/rom/usb/pciusb/mmakefile.src new file mode 100644 index 000000000..6634e9a66 --- /dev/null +++ b/rom/usb/pciusb/mmakefile.src @@ -0,0 +1,11 @@ +# $Id: mmakefile.src $ +include $(TOP)/config/make.cfg + +FILES := pci_aros dev uhwcmd debug + +%build_module mmake=rom-usb-pciusb \ + modname=pciusb modtype=device \ + files="$(FILES)" \ + uselibs="amiga rom oop hiddstubs" + +%common diff --git a/rom/usb/pciusb/ohcichip.h b/rom/usb/pciusb/ohcichip.h new file mode 100644 index 000000000..edde9fa19 --- /dev/null +++ b/rom/usb/pciusb/ohcichip.h @@ -0,0 +1,324 @@ +#ifndef OHCICHIP_H +#define OHCICHIP_H + +/* + *---------------------------------------------------------------------------- + * Includes for OHCI USB Controller + *---------------------------------------------------------------------------- + * By Chris Hodges + */ + +#include +#include "hccommon.h" + +/* PCI Class: PCI_CLASS_SERIAL_USB */ + +/* Framelist stuff + + - Framelist contains all the same entries pointing to ISO-TD + - ISO-TD: is inactive by default. Links to Control-QH + - Control-QH: - Head links to Int-Queue + - Element: Links to dummy-TD if empty (inactive) + - Element: otherwise links to QH for control transfer + - Int-Queue : - Head links to Bulk-Queue + + +*/ + +/* + * --------------------- OHCI registers ------------------------ + * Warning: These are BYTE offsets! + */ + +/* operational registers */ +#define OHCI_REVISION 0x000 /* Host Controller Revision (r) */ +#define OHCI_CONTROL 0x004 /* Control register (r/w) */ +#define OHCI_CMDSTATUS 0x008 /* Command and Status */ +#define OHCI_INTSTATUS 0x00c /* Interrupt Status (r/wc) */ +#define OHCI_INTEN 0x010 /* Interrupt Enable (r/ws) */ +#define OHCI_INTDIS 0x014 /* Interrupt Disable (r/wc) */ +#define OHCI_HCCA 0x018 /* Pointer to HCCA */ +#define OHCI_PERIODIC_ED 0x01c /* Current periodic ED */ +#define OHCI_CTRL_HEAD_ED 0x020 /* Control Head ED */ +#define OHCI_CTRL_ED 0x024 /* Current control ED */ +#define OHCI_BULK_HEAD_ED 0x028 /* Bulk Head ED */ +#define OHCI_BULK_ED 0x02c /* Current bulk ED */ +#define OHCI_DONEHEAD 0x030 /* Done head pointer */ +#define OHCI_FRAMEINTERVAL 0x034 /* Frame interval */ +#define OHCI_FRAMEREMAINING 0x038 /* Frame remaining time */ +#define OHCI_FRAMECOUNT 0x03c /* Frame number */ +#define OHCI_PERIODICSTART 0x040 /* Periodic start (usually 10% of 12000 == 0x3e67) */ +#define OHCI_LSTHRESHOLD 0x044 /* Lowspeed threshold (usually 0x0628) */ +#define OHCI_HUBDESCA 0x048 /* Root Hub Descriptor A */ +#define OHCI_HUBDESCB 0x04c /* Root Hub Descriptor B */ +#define OHCI_HUBSTATUS 0x050 /* Root Hub Status */ +#define OHCI_PORTSTATUS 0x054 /* Port Status */ + +/* OHCI_CONTROL defines */ +#define OCLS_CBSR 0 /* Control Bulk Service Ratio */ +#define OCLB_PERIODICENABLE 2 /* Periodic Enable */ +#define OCLB_ISOENABLE 3 /* Isochronous Enable */ +#define OCLB_CTRLENABLE 4 /* Control List enable */ +#define OCLB_BULKENABLE 5 /* Bulk List enable */ +#define OCLS_USBSTATE 6 /* Host controller functional state */ +#define OCLB_SMIINT 8 /* SMI Interrupt routing */ +#define OCLB_REMOTEWAKEUP 10 /* Remote wakeup enabled */ + +#define OCLF_PERIODICENABLE (1UL< + +#include + +#include +#include + +#include + +#include +#include +#include + +#include + +#include +#include +#include + +#define NewList NEWLIST + +#undef HiddPCIDeviceAttrBase +#undef HiddUSBDeviceAttrBase +#undef HiddUSBHubAttrBase +#undef HiddUSBDrvAttrBase +#undef HiddAttrBase + +#define HiddPCIDeviceAttrBase (hd->hd_HiddPCIDeviceAB) +#define HiddUSBDeviceAttrBase (hd->hd_HiddUSBDeviceAB) +#define HiddUSBHubAttrBase (hd->hd_HiddUSBHubAB) +#define HiddUSBDrvAttrBase (hd->hd_HiddUSBDrvAB) +#define HiddAttrBase (hd->hd_HiddAB) + +AROS_UFH3(void, pciEnumerator, + AROS_UFHA(struct Hook *, hook, A0), + AROS_UFHA(OOP_Object *, pciDevice, A2), + AROS_UFHA(APTR, message, A1)) +{ + AROS_USERFUNC_INIT + + struct PCIDevice *hd = (struct PCIDevice *) hook->h_Data; + struct PCIController *hc; + IPTR hcitype; + IPTR dev; + IPTR bus; + IPTR intline; + ULONG devid; + + OOP_GetAttr(pciDevice, aHidd_PCIDevice_Interface, &hcitype); + OOP_GetAttr(pciDevice, aHidd_PCIDevice_Bus, &bus); + OOP_GetAttr(pciDevice, aHidd_PCIDevice_Dev, &dev); + OOP_GetAttr(pciDevice, aHidd_PCIDevice_INTLine, &intline); + + devid = (bus<<16)|dev; + + if((hcitype == HCITYPE_UHCI) || (hcitype == HCITYPE_OHCI) || (hcitype == HCITYPE_EHCI)) + { + KPRINTF(10, ("Found PCI device 0x%lx of type %ld\n", devid, hcitype)); + + hc = AllocPooled(hd->hd_MemPool, sizeof(struct PCIController)); + if(hc) + { + hc->hc_Device = hd; + hc->hc_DevID = devid; + hc->hc_HCIType = hcitype; + hc->hc_PCIDeviceObject = pciDevice; + hc->hc_PCIIntLine = intline; + NewList(&hc->hc_CtrlXFerQueue); + NewList(&hc->hc_IntXFerQueue); + NewList(&hc->hc_IsoXFerQueue); + NewList(&hc->hc_BulkXFerQueue); + NewList(&hc->hc_TDQueue); + NewList(&hc->hc_PeriodicTDQueue); + NewList(&hc->hc_OhciRetireQueue); + AddTail(&hd->hd_TempHCIList, &hc->hc_Node); + } + } +#if 0 + OOP_GetAttr(pciDevice, aHidd_PCIDevice_Base4, &LIBBASE->sd.iobase[counter]); + OOP_GetAttr(pciDevice, aHidd_PCIDevice_Driver, (APTR)&LIBBASE->sd.uhciPCIDriver[counter]); + LIBBASE->sd.uhciDevice[counter] = pciDevice; + + D(bug("[UHCI] Device %d @ %08x with IO @ %08x\n", counter, pciDevice, LIBBASE->sd.iobase[counter])); + + struct pHidd_PCIDevice_WriteConfigWord wcw = { + OOP_GetMethodID(CLID_Hidd_PCIDevice, moHidd_PCIDevice_WriteConfigWord), PCI_LEGSUP, 0x8f00 + }; + + D(bug("[UHCI] Performing full reset. Hopefull legacy USB will do it'S handoff at this time.\n")); + OOP_DoMethod(pciDevice, &wcw.mID); + + outw(UHCI_CMD_HCRESET, LIBBASE->sd.iobase[counter] + UHCI_CMD); + struct timerequest *tr = USBCreateTimer(); + USBDelay(tr, 10); + USBDeleteTimer(tr); + if (inw(LIBBASE->sd.iobase[counter] + UHCI_CMD) & UHCI_CMD_HCRESET) + D(bug("[UHCI] Wrrr. Reset not yet completed\n")); + + outw(0, LIBBASE->sd.iobase[counter] + UHCI_INTR); + outw(0, LIBBASE->sd.iobase[counter] + UHCI_CMD); + + + D({ + struct pHidd_PCIDevice_ReadConfigWord __msg = { + OOP_GetMethodID(CLID_Hidd_PCIDevice, moHidd_PCIDevice_ReadConfigWord), 0xc0 + }, *msg = &__msg; + + bug("[UHCI] 0xc0: %04x\n", OOP_DoMethod(pciDevice, msg)); + }); + + LIBBASE->sd.num_devices = ++counter; +#endif + + AROS_USERFUNC_EXIT +} + + +/* /// "pciInit()" */ +BOOL pciInit(struct PCIDevice *hd) +{ + struct PCIController *hc; + struct PCIController *nexthc; + struct PCIUnit *hu; + ULONG unitno = 0; + struct List hcilist; + UWORD ohcicnt; + UWORD uhcicnt; + + KPRINTF(10, ("*** pciInit(%08lx) ***\n", hd)); + NewList(&hd->hd_TempHCIList); + + if(!(hd->hd_IRQHidd = OOP_NewObject(NULL, (STRPTR) CLID_Hidd_IRQ, NULL))) + { + KPRINTF(20, ("Unable to create IRQHidd object!\n")); + return FALSE; + } + + if((hd->hd_PCIHidd = OOP_NewObject(NULL, (STRPTR) CLID_Hidd_PCI, NULL))) + { + struct TagItem tags[] = + { + { tHidd_PCI_Class, (PCI_CLASS_SERIAL_USB>>8) & 0xff }, + { tHidd_PCI_SubClass, (PCI_CLASS_SERIAL_USB & 0xff) }, + //{ tHidd_PCI_Interface, PCI_INTERFACE_UHCI }, + { TAG_DONE, 0UL } + }; + + struct OOP_ABDescr attrbases[] = + { + { (STRPTR) IID_Hidd, &hd->hd_HiddAB }, + { (STRPTR) IID_Hidd_PCIDevice, &hd->hd_HiddPCIDeviceAB }, + { (STRPTR) IID_Hidd_USBDevice, &hd->hd_HiddUSBDeviceAB }, + { (STRPTR) IID_Hidd_USBHub, &hd->hd_HiddUSBHubAB }, + { (STRPTR) IID_Hidd_USBDrv, &hd->hd_HiddUSBDrvAB }, + { NULL, NULL } + }; + + struct Hook findHook = + { + h_Entry: (IPTR (*)()) pciEnumerator, + h_Data: hd, + }; + + OOP_ObtainAttrBases(attrbases); + + KPRINTF(20, ("Searching for xHCI devices...\n")); + + HIDD_PCI_EnumDevices(hd->hd_PCIHidd, &findHook, (struct TagItem *) &tags); + } else { + KPRINTF(20, ("Unable to create PCIHidd object!\n")); + OOP_DisposeObject(hd->hd_IRQHidd); + return FALSE; + } + + while(hd->hd_TempHCIList.lh_Head->ln_Succ) + { + hu = AllocPooled(hd->hd_MemPool, sizeof(struct PCIUnit)); + if(!hu) + { + // actually, we should get rid of the allocated memory first, but I don't care as DeletePool() will take care of this eventually + return FALSE; + } + hu->hu_Device = hd; + hu->hu_UnitNo = unitno; + hu->hu_DevID = ((struct PCIController *) hcilist.lh_Head)->hc_DevID; + + NewList(&hu->hu_Controllers); + NewList(&hu->hu_RHIOQueue); + ohcicnt = 0; + uhcicnt = 0; + // find all belonging host controllers + hc = (struct PCIController *) hcilist.lh_Head; + while((nexthc = (struct PCIController *) hc->hc_Node.ln_Succ)) + { + if(hc->hc_DevID == hu->hu_DevID) + { + Remove(&hc->hc_Node); + hc->hc_Unit = hu; + if(hc->hc_HCIType == HCITYPE_UHCI) + { + hc->hc_FunctionNum = uhcicnt++; + } + else if(hc->hc_HCIType == HCITYPE_OHCI) + { + hc->hc_FunctionNum = ohcicnt++; + } else { + hc->hc_FunctionNum = 0; + } + AddTail(&hu->hu_Controllers, &hc->hc_Node); + } + hc = nexthc; + } + AddTail(&hd->hd_Units, (struct Node *) hu); + unitno++; + } + return TRUE; +} +/* \\\ */ + +/* /// "PCIXReadConfigByte()" */ +UBYTE PCIXReadConfigByte(struct PCIController *hc, UBYTE offset) +{ + struct pHidd_PCIDevice_ReadConfigByte msg; + + msg.mID = OOP_GetMethodID(CLID_Hidd_PCIDevice, moHidd_PCIDevice_ReadConfigByte); + msg.reg = offset; + + return OOP_DoMethod(hc->hc_PCIDeviceObject, (OOP_Msg) &msg); +} +/* \\\ */ + +/* /// "PCIXWriteConfigByte()" */ +void PCIXWriteConfigByte(struct PCIController *hc, ULONG offset, UBYTE value) +{ + struct pHidd_PCIDevice_WriteConfigByte msg; + + msg.mID = OOP_GetMethodID(CLID_Hidd_PCIDevice, moHidd_PCIDevice_WriteConfigByte); + msg.reg = offset; + msg.val = value; + + OOP_DoMethod(hc->hc_PCIDeviceObject, (OOP_Msg) &msg); +} +/* \\\ */ + +/* /// "pciAllocUnit()" */ +BOOL pciAllocUnit(struct PCIUnit *hu) +{ + struct PCIDevice *hd = hu->hu_Device; + struct PCIController *hc; + struct PCIController *usb20hc = NULL; + BOOL allocgood = TRUE; + ULONG usb11ports; + ULONG usb20ports; + ULONG cnt; + BOOL complexrouting = FALSE; + ULONG portroute = 0; + + struct TagItem pciActivateMem[] = + { + { aHidd_PCIDevice_isIO, TRUE }, + { aHidd_PCIDevice_isMEM, TRUE }, + { aHidd_PCIDevice_isMaster, FALSE }, + { TAG_DONE, 0UL }, + }; + + struct TagItem pciActivateBusmaster[] = + { + { aHidd_PCIDevice_isIO, TRUE }, + { aHidd_PCIDevice_isMEM, TRUE }, + { aHidd_PCIDevice_isMaster, TRUE }, + { TAG_DONE, 0UL }, + }; + + KPRINTF(10, ("*** pciAllocUnit(%08lx) ***\n", hu)); + hc = (struct PCIController *) hu->hu_Controllers.lh_Head; + while(hc->hc_Node.ln_Succ) + { +#if 0 + PCIXObtainBoard(hc->hc_BoardObject); + hc->hc_BoardAllocated = PCIXSetBoardAttr(hc->hc_BoardObject, PCIXTAG_OWNER, (ULONG) hd->hd_Library.lib_Node.ln_Name); + allocgood &= hc->hc_BoardAllocated; + if(!hc->hc_BoardAllocated) + { + KPRINTF(20, ("Couldn't allocate board, already allocated by %s\n", PCIXGetBoardAttr(hc->hc_BoardObject, PCIXTAG_OWNER))); + } + PCIXReleaseBoard(hc->hc_BoardObject); +#endif + + hc = (struct PCIController *) hc->hc_Node.ln_Succ; + } + + if(allocgood) + { + // allocate necessary memory + hc = (struct PCIController *) hu->hu_Controllers.lh_Head; + while(hc->hc_Node.ln_Succ) + { + switch(hc->hc_HCIType) + { + case HCITYPE_UHCI: + { + struct UhciQH *uqh; + struct UhciQH *preduqh; + struct UhciTD *utd; + ULONG *tabptr; + UBYTE *memptr; + ULONG bitcnt; + + hc->hc_NumPorts = 2; // UHCI always uses 2 ports per controller + KPRINTF(20, ("Found UHCI Controller %08lx FuncNum=%ld with %ld ports\n", hc->hc_PCIDeviceObject, hc->hc_FunctionNum, hc->hc_NumPorts)); + hc->hc_CompleteInt.is_Node.ln_Type = NT_INTERRUPT; + hc->hc_CompleteInt.is_Node.ln_Name = "UHCI CompleteInt"; + hc->hc_CompleteInt.is_Node.ln_Pri = 0; + hc->hc_CompleteInt.is_Data = hc; + hc->hc_CompleteInt.is_Code = (void (*)(void)) &uhciCompleteInt; + + hc->hc_PCIMemSize = sizeof(ULONG) * UHCI_FRAMELIST_SIZE + UHCI_FRAMELIST_ALIGNMENT + 1; + hc->hc_PCIMemSize += sizeof(struct UhciQH) * UHCI_QH_POOLSIZE; + hc->hc_PCIMemSize += sizeof(struct UhciTD) * UHCI_TD_POOLSIZE; + memptr = HIDD_PCIDriver_AllocPCIMem(hc->hc_PCIDeviceObject, hc->hc_PCIMemSize); + if(!memptr) + { + allocgood = FALSE; + break; + } + hc->hc_PCIMem = (APTR) memptr; + // PhysicalAddress - VirtualAdjust = VirtualAddress + // VirtualAddress + VirtualAdjust = PhysicalAddress + hc->hc_PCIVirtualAdjust = ((ULONG) pciGetPhysical(hc, memptr)) - ((ULONG) memptr); + KPRINTF(10, ("VirtualAdjust 0x%08lx\n", hc->hc_PCIVirtualAdjust)); + + // align memory + memptr = (UBYTE *) ((((ULONG) hc->hc_PCIMem) + UHCI_FRAMELIST_ALIGNMENT) & (~UHCI_FRAMELIST_ALIGNMENT)); + hc->hc_UhciFrameList = (ULONG *) memptr; + KPRINTF(10, ("FrameListBase 0x%08lx\n", hc->hc_UhciFrameList)); + memptr += sizeof(APTR) * UHCI_FRAMELIST_SIZE; + + // build up QH pool + uqh = (struct UhciQH *) memptr; + hc->hc_UhciQHPool = uqh; + cnt = UHCI_QH_POOLSIZE - 1; + do + { + // minimal initalization + uqh->uqh_Succ = (struct UhciXX *) (uqh + 1); + WRITEMEM32_LE(&uqh->uqh_Self, (ULONG) (&uqh->uqh_Link) + hc->hc_PCIVirtualAdjust + UHCI_QHSELECT); + uqh++; + } while(--cnt); + uqh->uqh_Succ = NULL; + memptr += sizeof(struct UhciQH) * UHCI_QH_POOLSIZE; + + // build up TD pool + utd = (struct UhciTD *) memptr; + hc->hc_UhciTDPool = utd; + cnt = UHCI_TD_POOLSIZE - 1; + do + { + utd->utd_Succ = (struct UhciXX *) (utd + 1); + WRITEMEM32_LE(&utd->utd_Self, (ULONG) (&utd->utd_Link) + hc->hc_PCIVirtualAdjust + UHCI_TDSELECT); + utd++; + } while(--cnt); + utd->utd_Succ = NULL; + memptr += sizeof(struct UhciTD) * UHCI_TD_POOLSIZE; + + // terminating QH + hc->hc_UhciTermQH = preduqh = uqh = uhciAllocQH(hc); + uqh->uqh_Succ = NULL; + CONSTWRITEMEM32_LE(&uqh->uqh_Link, UHCI_TERMINATE); + CONSTWRITEMEM32_LE(&uqh->uqh_Element, UHCI_TERMINATE); + + // dummy Bulk QH + hc->hc_UhciBulkQH = uqh = uhciAllocQH(hc); + uqh->uqh_Succ = (struct UhciXX *) preduqh; + preduqh->uqh_Pred = (struct UhciXX *) uqh; + uqh->uqh_Link = preduqh->uqh_Self; // link to terminating QH + CONSTWRITEMEM32_LE(&uqh->uqh_Element, UHCI_TERMINATE); + preduqh = uqh; + + // dummy Ctrl QH + hc->hc_UhciCtrlQH = uqh = uhciAllocQH(hc); + uqh->uqh_Succ = (struct UhciXX *) preduqh; + preduqh->uqh_Pred = (struct UhciXX *) uqh; + uqh->uqh_Link = preduqh->uqh_Self; // link to Bulk QH + CONSTWRITEMEM32_LE(&uqh->uqh_Element, UHCI_TERMINATE); + + // dummy ISO TD + hc->hc_UhciIsoTD = utd = uhciAllocTD(hc); + utd->utd_Succ = (struct UhciXX *) uqh; + //utd->utd_Pred = NULL; // no certain linkage above this level + uqh->uqh_Pred = (struct UhciXX *) utd; + utd->utd_Link = uqh->uqh_Self; // link to Ctrl QH + + CONSTWRITEMEM32_LE(&utd->utd_CtrlStatus, 0); + + // 1 ms INT QH + hc->hc_UhciIntQH[0] = uqh = uhciAllocQH(hc); + uqh->uqh_Succ = (struct UhciXX *) utd; + uqh->uqh_Pred = NULL; // who knows... + //uqh->uqh_Link = utd->utd_Self; // link to ISO + CONSTWRITEMEM32_LE(&uqh->uqh_Element, UHCI_TERMINATE); + preduqh = uqh; + + // make 9 levels of QH interrupts + for(cnt = 1; cnt < 9; cnt++) + { + hc->hc_UhciIntQH[cnt] = uqh = uhciAllocQH(hc); + uqh->uqh_Succ = (struct UhciXX *) preduqh; + uqh->uqh_Pred = NULL; // who knows... + //uqh->uqh_Link = preduqh->uqh_Self; // link to previous int level + CONSTWRITEMEM32_LE(&uqh->uqh_Element, UHCI_TERMINATE); + preduqh = uqh; + } + + uhciUpdateIntTree(hc); + + // fill in framelist with IntQH entry points based on interval + tabptr = hc->hc_UhciFrameList; + for(cnt = 0; cnt < UHCI_FRAMELIST_SIZE; cnt++) + { + uqh = hc->hc_UhciIntQH[8]; + bitcnt = 0; + do + { + if(cnt & (1UL<hc_UhciIntQH[bitcnt]; + break; + } + } while(++bitcnt < 9); + *tabptr++ = uqh->uqh_Self; + } + + // this will cause more PCI memory access, but faster USB transfers aswell + //WRITEMEM32_LE(&hc->hc_UhciTermQH->uqh_Link, AROS_LONG2LE(hc->hc_UhciBulkQH->uqh_Self)); + + // time to initialize hardware... + OOP_GetAttr(hc->hc_PCIDeviceObject, aHidd_PCIDevice_Base4, (IPTR *) &hc->hc_RegBase); + hc->hc_RegBase = (APTR) (((IPTR) hc->hc_RegBase) & (~0xf)); + KPRINTF(10, ("RegBase = 0x%08lx\n", hc->hc_RegBase)); + OOP_SetAttrs(hc->hc_PCIDeviceObject, (struct TagItem *) pciActivateMem); // no busmaster yet + SYNC; + EIEIO; + + KPRINTF(10, ("Resetting UHCI HC\n")); + CONSTWRITEREG16_LE(hc->hc_RegBase, UHCI_USBCMD, UHCF_HCRESET|UHCF_GLOBALRESET); + uhwDelayMS(10, hu, hd); + CONSTWRITEREG16_LE(hc->hc_RegBase, UHCI_USBCMD, UHCF_HCRESET); + cnt = 100; + do + { + uhwDelayMS(10, hu, hd); + if(!(READREG16_LE(hc->hc_RegBase, UHCI_USBCMD) & UHCF_HCRESET)) + { + break; + } + } while(--cnt); + + if(cnt == 0) + { + KPRINTF(20, ("Reset Timeout!\n")); + } else { + KPRINTF(20, ("Reset finished after %ld ticks\n", 100-cnt)); + } + OOP_SetAttrs(hc->hc_PCIDeviceObject, (struct TagItem *) pciActivateBusmaster); // enable busmaster + // I've got no idea, why cyfm overwrites the status register with these values, but if it helps... + //PCIXWriteConfigLong(hc->hc_BoardObject, PCIXCONFIG_COMMAND, 0x80900007); + SYNC; + EIEIO; + + // Fix for VIA Babble problem + cnt = PCIXReadConfigByte(hc, 0x40); + if(!(cnt & 0x40)) + { + KPRINTF(20, ("Applying VIA Babble workaround\n")); + PCIXWriteConfigByte(hc, 0x40, cnt|0x40); + } + + CONSTWRITEREG16_LE(hc->hc_RegBase, UHCI_USBCMD, UHCF_MAXPACKET64|UHCF_CONFIGURE); + + CONSTWRITEREG16_LE(hc->hc_RegBase, UHCI_FRAMECOUNT, 0); + + WRITEREG32_LE(hc->hc_RegBase, UHCI_FRAMELISTADDR, (ULONG) pciGetPhysical(hc, hc->hc_UhciFrameList)); + + CONSTWRITEREG16_LE(hc->hc_RegBase, UHCI_USBSTATUS, UHIF_TIMEOUTCRC|UHIF_INTONCOMPLETE|UHIF_SHORTPACKET); + CONSTWRITEREG16_LE(hc->hc_RegBase, UHCI_USBINTEN, UHIF_TIMEOUTCRC|UHIF_INTONCOMPLETE|UHIF_SHORTPACKET); + + // add interrupt + hc->hc_PCIIntHandler.h_Node.ln_Name = "UHCI PCI (pciusb.device)"; + hc->hc_PCIIntHandler.h_Node.ln_Pri = 5; + hc->hc_PCIIntHandler.h_Code = uhciIntCode; + hc->hc_PCIIntHandler.h_Data = hc; + HIDD_IRQ_AddHandler(hd->hd_IRQHidd, &hc->hc_PCIIntHandler, hc->hc_PCIIntLine); + + CONSTWRITEREG16_LE(hc->hc_RegBase, UHCI_USBCMD, UHCF_MAXPACKET64|UHCF_CONFIGURE|UHCF_RUNSTOP); + SYNC; + EIEIO; + KPRINTF(20, ("HW Init done\n")); + + KPRINTF(10, ("HW Regs USBCMD/STS=%08lx\n", READREG32_LE(hc->hc_RegBase, UHCI_USBCMD))); + KPRINTF(10, ("HW Regs USBCMD=%04lx\n", READREG16_LE(hc->hc_RegBase, UHCI_USBCMD))); + KPRINTF(10, ("HW Regs USBSTS=%04lx\n", READREG16_LE(hc->hc_RegBase, UHCI_USBSTATUS))); + KPRINTF(10, ("HW Regs FRAMECOUNT=%04lx\n", READREG16_LE(hc->hc_RegBase, UHCI_FRAMECOUNT))); + break; + } + + case HCITYPE_OHCI: + { + struct OhciED *oed; + struct OhciED *predoed; + struct OhciTD *otd; + ULONG *tabptr; + UBYTE *memptr; + ULONG bitcnt; + ULONG hubdesca; + ULONG frameival; + + hc->hc_CompleteInt.is_Node.ln_Type = NT_INTERRUPT; + hc->hc_CompleteInt.is_Node.ln_Name = "OHCI CompleteInt"; + hc->hc_CompleteInt.is_Node.ln_Pri = 0; + hc->hc_CompleteInt.is_Data = hc; + hc->hc_CompleteInt.is_Code = (void (*)(void)) &ohciCompleteInt; + + hc->hc_PCIMemSize = OHCI_HCCA_SIZE + OHCI_HCCA_ALIGNMENT + 1; + hc->hc_PCIMemSize += sizeof(struct OhciED) * OHCI_ED_POOLSIZE; + hc->hc_PCIMemSize += sizeof(struct OhciTD) * OHCI_TD_POOLSIZE; + memptr = HIDD_PCIDriver_AllocPCIMem(hc->hc_PCIDeviceObject, hc->hc_PCIMemSize); + if(!memptr) + { + allocgood = FALSE; + break; + } + hc->hc_PCIMem = (APTR) memptr; + // PhysicalAddress - VirtualAdjust = VirtualAddress + // VirtualAddress + VirtualAdjust = PhysicalAddress + hc->hc_PCIVirtualAdjust = ((ULONG) pciGetPhysical(hc, memptr)) - ((ULONG) memptr); + KPRINTF(10, ("VirtualAdjust 0x%08lx\n", hc->hc_PCIVirtualAdjust)); + + // align memory + memptr = (UBYTE *) ((((ULONG) hc->hc_PCIMem) + OHCI_HCCA_ALIGNMENT) & (~OHCI_HCCA_ALIGNMENT)); + hc->hc_OhciHCCA = (struct OhciHCCA *) memptr; + KPRINTF(10, ("HCCA 0x%08lx\n", hc->hc_OhciHCCA)); + memptr += OHCI_HCCA_SIZE; + + // build up ED pool + oed = (struct OhciED *) memptr; + hc->hc_OhciEDPool = oed; + cnt = OHCI_ED_POOLSIZE - 1; + do + { + // minimal initalization + oed->oed_Succ = (oed + 1); + WRITEMEM32_LE(&oed->oed_Self, (ULONG) (&oed->oed_EPCaps) + hc->hc_PCIVirtualAdjust); + oed++; + } while(--cnt); + oed->oed_Succ = NULL; + memptr += sizeof(struct OhciED) * OHCI_ED_POOLSIZE; + + // build up TD pool + otd = (struct OhciTD *) memptr; + hc->hc_OhciTDPool = otd; + cnt = OHCI_TD_POOLSIZE - 1; + do + { + otd->otd_Succ = (otd + 1); + WRITEMEM32_LE(&otd->otd_Self, (ULONG) (&otd->otd_Ctrl) + hc->hc_PCIVirtualAdjust); + otd++; + } while(--cnt); + otd->otd_Succ = NULL; + memptr += sizeof(struct OhciTD) * OHCI_TD_POOLSIZE; + + // terminating ED + hc->hc_OhciTermED = oed = ohciAllocED(hc); + oed->oed_Succ = NULL; + oed->oed_Pred = NULL; + CONSTWRITEMEM32_LE(&oed->oed_EPCaps, OECF_SKIP); + oed->oed_NextED = 0; + + // terminating TD + hc->hc_OhciTermTD = otd = ohciAllocTD(hc); + otd->otd_Succ = NULL; + otd->otd_NextTD = 0; + + // dummy head & tail Ctrl ED + hc->hc_OhciCtrlHeadED = predoed = ohciAllocED(hc); + hc->hc_OhciCtrlTailED = oed = ohciAllocED(hc); + CONSTWRITEMEM32_LE(&predoed->oed_EPCaps, OECF_SKIP); + CONSTWRITEMEM32_LE(&oed->oed_EPCaps, OECF_SKIP); + predoed->oed_Succ = oed; + predoed->oed_Pred = NULL; + predoed->oed_NextED = oed->oed_Self; + oed->oed_Succ = NULL; + oed->oed_Pred = predoed; + oed->oed_NextED = 0; + + // dummy head & tail Bulk ED + hc->hc_OhciBulkHeadED = predoed = ohciAllocED(hc); + hc->hc_OhciBulkTailED = oed = ohciAllocED(hc); + CONSTWRITEMEM32_LE(&predoed->oed_EPCaps, OECF_SKIP); + CONSTWRITEMEM32_LE(&oed->oed_EPCaps, OECF_SKIP); + predoed->oed_Succ = oed; + predoed->oed_Pred = NULL; + predoed->oed_NextED = oed->oed_Self; + oed->oed_Succ = NULL; + oed->oed_Pred = predoed; + oed->oed_NextED = 0; + + // 1 ms INT QH + hc->hc_OhciIntED[0] = oed = ohciAllocED(hc); + oed->oed_Succ = hc->hc_OhciTermED; + oed->oed_Pred = NULL; // who knows... + CONSTWRITEMEM32_LE(&oed->oed_EPCaps, OECF_SKIP); + oed->oed_NextED = hc->hc_OhciTermED->oed_Self; + predoed = oed; + + // make 5 levels of QH interrupts + for(cnt = 1; cnt < 5; cnt++) + { + hc->hc_OhciIntED[cnt] = oed = ohciAllocED(hc); + oed->oed_Succ = predoed; + oed->oed_Pred = NULL; // who knows... + CONSTWRITEMEM32_LE(&oed->oed_EPCaps, OECF_SKIP); + oed->oed_NextED = hc->hc_OhciTermED->oed_Self; + predoed = oed; + } + + ohciUpdateIntTree(hc); + + // fill in framelist with IntED entry points based on interval + tabptr = hc->hc_OhciHCCA->oha_IntEDs; + for(cnt = 0; cnt < 32; cnt++) + { + oed = hc->hc_OhciIntED[4]; + bitcnt = 0; + do + { + if(cnt & (1UL<hc_OhciIntED[bitcnt]; + break; + } + } while(++bitcnt < 5); + *tabptr++ = oed->oed_Self; + } + + // time to initialize hardware... + OOP_GetAttr(hc->hc_PCIDeviceObject, aHidd_PCIDevice_Base4, (IPTR *) &hc->hc_RegBase); + hc->hc_RegBase = (APTR) (((IPTR) hc->hc_RegBase) & (~0xf)); + KPRINTF(10, ("RegBase = 0x%08lx\n", hc->hc_RegBase)); + OOP_SetAttrs(hc->hc_PCIDeviceObject, (struct TagItem *) pciActivateMem); // no busmaster yet + SYNC; + EIEIO; + + hubdesca = READREG32_LE(hc->hc_RegBase, OHCI_HUBDESCA); + hc->hc_NumPorts = (hubdesca & OHAM_NUMPORTS)>>OHAS_NUMPORTS; + KPRINTF(20, ("Found OHCI Controller %08lx FuncNum = %ld, Rev %02lx, with %ld ports\n", + hc->hc_PCIDeviceObject, hc->hc_FunctionNum, + READREG32_LE(hc->hc_RegBase, OHCI_REVISION), + hc->hc_NumPorts)); + + KPRINTF(20, ("Powerswitching: %s %s\n", + hubdesca & OHAF_NOPOWERSWITCH ? "available" : "always on", + hubdesca & OHAF_INDIVIDUALPS ? "per port" : "global")); + + KPRINTF(10, ("Resetting OHCI HC\n")); + CONSTWRITEREG32_LE(hc->hc_RegBase, OHCI_CMDSTATUS, OCSF_HCRESET); + cnt = 100; + do + { + if(!(READREG32_LE(hc->hc_RegBase, OHCI_CMDSTATUS) & OCSF_HCRESET)) + { + break; + } + uhwDelayMS(1, hu, hd); + } while(--cnt); + + if(cnt == 0) + { + KPRINTF(20, ("Reset Timeout!\n")); + } else { + KPRINTF(20, ("Reset finished after %ld ticks\n", 100-cnt)); + } + + OOP_SetAttrs(hc->hc_PCIDeviceObject, (struct TagItem *) pciActivateBusmaster); // enable busmaster + SYNC; + EIEIO; + + CONSTWRITEREG32_LE(hc->hc_RegBase, OHCI_FRAMECOUNT, 0); + CONSTWRITEREG32_LE(hc->hc_RegBase, OHCI_PERIODICSTART, 10800); // 10% of 12000 + frameival = READREG32_LE(hc->hc_RegBase, OHCI_FRAMEINTERVAL); + KPRINTF(10, ("FrameInterval=%08lx\n", frameival)); + frameival &= ~OIVM_BITSPERFRAME; + frameival |= OHCI_DEF_BITSPERFRAME<hc_RegBase, OHCI_FRAMEINTERVAL, frameival); + + // make sure nothing is running + CONSTWRITEREG32_LE(hc->hc_RegBase, OHCI_PERIODIC_ED, 0); + CONSTWRITEREG32_LE(hc->hc_RegBase, OHCI_CTRL_HEAD_ED, AROS_LONG2LE(hc->hc_OhciCtrlHeadED->oed_Self)); + CONSTWRITEREG32_LE(hc->hc_RegBase, OHCI_CTRL_ED, 0); + CONSTWRITEREG32_LE(hc->hc_RegBase, OHCI_BULK_HEAD_ED, AROS_LONG2LE(hc->hc_OhciBulkHeadED->oed_Self)); + CONSTWRITEREG32_LE(hc->hc_RegBase, OHCI_BULK_ED, 0); + CONSTWRITEREG32_LE(hc->hc_RegBase, OHCI_DONEHEAD, 0); + + WRITEREG32_LE(hc->hc_RegBase, OHCI_HCCA, (ULONG) pciGetPhysical(hc, hc->hc_OhciHCCA)); + + CONSTWRITEREG32_LE(hc->hc_RegBase, OHCI_INTSTATUS, OISF_ALL_INTS); + CONSTWRITEREG32_LE(hc->hc_RegBase, OHCI_INTDIS, OISF_ALL_INTS); + SYNC; + EIEIO; + + // add interrupt + hc->hc_PCIIntHandler.h_Node.ln_Name = "OHCI PCI (pciusb.device)"; + hc->hc_PCIIntHandler.h_Node.ln_Pri = 5; + hc->hc_PCIIntHandler.h_Code = ohciIntCode; + hc->hc_PCIIntHandler.h_Data = hc; + HIDD_IRQ_AddHandler(hd->hd_IRQHidd, &hc->hc_PCIIntHandler, hc->hc_PCIIntLine); + + hc->hc_PCIIntEnMask = OISF_SCHEDOVERRUN|OISF_DONEHEAD|OISF_RESUMEDTX|OISF_HOSTERROR|OISF_FRAMECOUNTOVER|OISF_HUBCHANGE; + + CONSTWRITEREG32_LE(hc->hc_RegBase, OHCI_INTEN, OISF_SCHEDOVERRUN|OISF_DONEHEAD|OISF_RESUMEDTX|OISF_HOSTERROR|OISF_FRAMECOUNTOVER|OISF_HUBCHANGE|OISF_MASTERENABLE); + + CONSTWRITEREG32_LE(hc->hc_RegBase, OHCI_CONTROL, OCLF_PERIODICENABLE|OCLF_CTRLENABLE|OCLF_BULKENABLE|OCLF_USBRESET); + SYNC; + EIEIO; + + if(!(hubdesca & OHAF_INDIVIDUALPS)) + { + KPRINTF(20, ("Individual power switching not available, turning on all ports!\n")); + WRITEREG32_LE(hc->hc_RegBase, OHCI_HUBDESCB, 0); + WRITEREG32_LE(hc->hc_RegBase, OHCI_HUBSTATUS, OHSF_POWERHUB); + } else { + KPRINTF(20, ("Enabling individual power switching\n")); + WRITEREG32_LE(hc->hc_RegBase, OHCI_HUBDESCB, ((2<hc_NumPorts)-2)<hc_RegBase, OHCI_HUBSTATUS, OHSF_POWERHUB); + } + + uhwDelayMS(50, hu, hd); + CONSTWRITEREG32_LE(hc->hc_RegBase, OHCI_CONTROL, OCLF_PERIODICENABLE|OCLF_CTRLENABLE|OCLF_BULKENABLE|OCLF_USBOPER); + SYNC; + EIEIO; + + KPRINTF(20, ("HW Init done\n")); + break; + } + + case HCITYPE_EHCI: + { + struct EhciQH *eqh; + struct EhciQH *predeqh; + struct EhciTD *etd; + ULONG *tabptr; + UBYTE *memptr; + ULONG bitcnt; + ULONG hcsparams; + ULONG hccparams; + volatile APTR pciregbase; + + usb20hc = hc; + + hc->hc_CompleteInt.is_Node.ln_Type = NT_INTERRUPT; + hc->hc_CompleteInt.is_Node.ln_Name = "EHCI CompleteInt"; + hc->hc_CompleteInt.is_Node.ln_Pri = 0; + hc->hc_CompleteInt.is_Data = hc; + hc->hc_CompleteInt.is_Code = (void (*)(void)) &ehciCompleteInt; + + hc->hc_PCIMemSize = sizeof(ULONG) * EHCI_FRAMELIST_SIZE + EHCI_FRAMELIST_ALIGNMENT + 1; + hc->hc_PCIMemSize += sizeof(struct EhciQH) * EHCI_QH_POOLSIZE; + hc->hc_PCIMemSize += sizeof(struct EhciTD) * EHCI_TD_POOLSIZE; + memptr = HIDD_PCIDriver_AllocPCIMem(hc->hc_PCIDeviceObject, hc->hc_PCIMemSize); + if(!memptr) + { + allocgood = FALSE; + break; + } + hc->hc_PCIMem = (APTR) memptr; + // PhysicalAddress - VirtualAdjust = VirtualAddress + // VirtualAddress + VirtualAdjust = PhysicalAddress + hc->hc_PCIVirtualAdjust = ((ULONG) pciGetPhysical(hc, memptr)) - ((ULONG) memptr); + KPRINTF(10, ("VirtualAdjust 0x%08lx\n", hc->hc_PCIVirtualAdjust)); + + // align memory + memptr = (UBYTE *) ((((ULONG) hc->hc_PCIMem) + EHCI_FRAMELIST_ALIGNMENT) & (~EHCI_FRAMELIST_ALIGNMENT)); + hc->hc_EhciFrameList = (ULONG *) memptr; + KPRINTF(10, ("FrameListBase 0x%08lx\n", hc->hc_EhciFrameList)); + memptr += sizeof(APTR) * EHCI_FRAMELIST_SIZE; + + // build up QH pool + eqh = (struct EhciQH *) memptr; + hc->hc_EhciQHPool = eqh; + cnt = EHCI_QH_POOLSIZE - 1; + do + { + // minimal initalization + eqh->eqh_Succ = (eqh + 1); + WRITEMEM32_LE(&eqh->eqh_Self, (ULONG) (&eqh->eqh_NextQH) + hc->hc_PCIVirtualAdjust + EHCI_QUEUEHEAD); + CONSTWRITEMEM32_LE(&eqh->eqh_NextTD, EHCI_TERMINATE); + CONSTWRITEMEM32_LE(&eqh->eqh_AltNextTD, EHCI_TERMINATE); + eqh++; + } while(--cnt); + eqh->eqh_Succ = NULL; + memptr += sizeof(struct EhciQH) * EHCI_QH_POOLSIZE; + + // build up TD pool + etd = (struct EhciTD *) memptr; + hc->hc_EhciTDPool = etd; + cnt = EHCI_TD_POOLSIZE - 1; + do + { + etd->etd_Succ = (etd + 1); + WRITEMEM32_LE(&etd->etd_Self, (ULONG) (&etd->etd_NextTD) + hc->hc_PCIVirtualAdjust); + etd++; + } while(--cnt); + etd->etd_Succ = NULL; + memptr += sizeof(struct EhciTD) * EHCI_TD_POOLSIZE; + + // empty async queue head + hc->hc_EhciAsyncFreeQH = NULL; + hc->hc_EhciAsyncQH = eqh = ehciAllocQH(hc); + eqh->eqh_Succ = eqh; + eqh->eqh_Pred = eqh; + CONSTWRITEMEM32_LE(&eqh->eqh_EPCaps, EQEF_RECLAMHEAD); + eqh->eqh_NextQH = eqh->eqh_Self; + + // empty terminating queue head + hc->hc_EhciTermQH = eqh = ehciAllocQH(hc); + eqh->eqh_Succ = NULL; + CONSTWRITEMEM32_LE(&eqh->eqh_NextQH, EHCI_TERMINATE); + predeqh = eqh; + + // 1 ms INT QH + hc->hc_EhciIntQH[0] = eqh = ehciAllocQH(hc); + eqh->eqh_Succ = predeqh; + predeqh->eqh_Pred = eqh; + eqh->eqh_Pred = NULL; // who knows... + //eqh->eqh_NextQH = predeqh->eqh_Self; + predeqh = eqh; + + // make 11 levels of QH interrupts + for(cnt = 1; cnt < 11; cnt++) + { + hc->hc_EhciIntQH[cnt] = eqh = ehciAllocQH(hc); + eqh->eqh_Succ = predeqh; + eqh->eqh_Pred = NULL; // who knows... + //eqh->eqh_NextQH = predeqh->eqh_Self; // link to previous int level + predeqh = eqh; + } + + ehciUpdateIntTree(hc); + + // fill in framelist with IntQH entry points based on interval + tabptr = hc->hc_EhciFrameList; + for(cnt = 0; cnt < EHCI_FRAMELIST_SIZE; cnt++) + { + eqh = hc->hc_EhciIntQH[10]; + bitcnt = 0; + do + { + if(cnt & (1UL<hc_EhciIntQH[bitcnt]; + break; + } + } while(++bitcnt < 11); + *tabptr++ = eqh->eqh_Self; + } + + etd = hc->hc_ShortPktEndTD = ehciAllocTD(hc); + etd->etd_Succ = NULL; + CONSTWRITEMEM32_LE(&etd->etd_NextTD, EHCI_TERMINATE); + CONSTWRITEMEM32_LE(&etd->etd_AltNextTD, EHCI_TERMINATE); + CONSTWRITEMEM32_LE(&etd->etd_CtrlStatus, 0); + + // time to initialize hardware... + OOP_GetAttr(hc->hc_PCIDeviceObject, aHidd_PCIDevice_Base4, (IPTR *) &pciregbase); + pciregbase = (APTR) (((IPTR) pciregbase) & (~0xf)); + OOP_SetAttrs(hc->hc_PCIDeviceObject, (struct TagItem *) pciActivateMem); // no busmaster yet + SYNC; + EIEIO; + + // we use the operational registers as RegBase. + hc->hc_RegBase = (APTR) ((ULONG) pciregbase + READREG16_LE(pciregbase, EHCI_CAPLENGTH)); + KPRINTF(10, ("RegBase = 0x%08lx\n", hc->hc_RegBase)); + + KPRINTF(10, ("Resetting EHCI HC\n")); + CONSTWRITEREG32_LE(hc->hc_RegBase, EHCI_USBCMD, EHUF_HCRESET|(1UL<hc_RegBase, EHCI_USBCMD) & EHUF_HCRESET)) + { + break; + } + } while(--cnt); + + if(cnt == 0) + { + KPRINTF(20, ("Reset Timeout!\n")); + } else { + KPRINTF(20, ("Reset finished after %ld ticks\n", 100-cnt)); + } + OOP_SetAttrs(hc->hc_PCIDeviceObject, (struct TagItem *) pciActivateBusmaster); // enable busmaster + SYNC; + EIEIO; + + // Read HCSPARAMS register to obtain number of downstream ports + hcsparams = READREG32_LE(pciregbase, EHCI_HCSPARAMS); + hccparams = READREG32_LE(pciregbase, EHCI_HCCPARAMS); + + hc->hc_NumPorts = (hcsparams & EHSM_NUM_PORTS)>>EHSS_NUM_PORTS; + KPRINTF(20, ("Found EHCI Controller %08lx with %ld ports (%ld companions with %ld ports each)\n", + hc->hc_PCIDeviceObject, hc->hc_NumPorts, + (hcsparams & EHSM_NUM_COMPANIONS)>>EHSS_NUM_COMPANIONS, + (hcsparams & EHSM_PORTS_PER_COMP)>>EHSS_PORTS_PER_COMP)); + if(hcsparams & EHSF_EXTPORTROUTING) + { + complexrouting = TRUE; + portroute = READREG32_LE(pciregbase, EHCI_HCSPPORTROUTE); +#ifdef DEBUG + for(cnt = 0; cnt < hc->hc_NumPorts; cnt++) + { + KPRINTF(100, ("Port %ld maps to controller %ld\n", cnt, ((portroute >> (cnt<<2)) & 0xf))); + } +#endif + } + KPRINTF(20, ("HCCParams: 64 Bit=%s, ProgFrameList=%s, AsyncSchedPark=%s\n", + (hccparams & EHCF_64BITS) ? "Yes" : "No", + (hccparams & EHCF_PROGFRAMELIST) ? "Yes" : "No", + (hccparams & EHCF_ASYNCSCHEDPARK) ? "Yes" : "No")); + hc->hc_EhciUsbCmd = (1UL<hc_EhciUsbCmd |= EHUF_ASYNCSCHEDPARK|(3<hc_RegBase, EHCI_USBCMD, hc->hc_EhciUsbCmd); + + CONSTWRITEREG32_LE(hc->hc_RegBase, EHCI_FRAMECOUNT, 0); + + WRITEREG32_LE(hc->hc_RegBase, EHCI_PERIODICLIST, (ULONG) pciGetPhysical(hc, hc->hc_EhciFrameList)); + WRITEREG32_LE(hc->hc_RegBase, EHCI_ASYNCADDR, AROS_LONG2LE(hc->hc_EhciAsyncQH->eqh_Self)); + + CONSTWRITEREG32_LE(hc->hc_RegBase, EHCI_USBSTATUS, EHSF_ALL_INTS); + CONSTWRITEREG32_LE(hc->hc_RegBase, EHCI_USBINTEN, EHSF_ALL_INTS); + hc->hc_PCIIntEnMask = EHSF_ALL_INTS; + + // add interrupt + hc->hc_PCIIntHandler.h_Node.ln_Name = "EHCI PCI (pciusb.device)"; + hc->hc_PCIIntHandler.h_Node.ln_Pri = 5; + hc->hc_PCIIntHandler.h_Code = ehciIntCode; + hc->hc_PCIIntHandler.h_Data = hc; + HIDD_IRQ_AddHandler(hd->hd_IRQHidd, &hc->hc_PCIIntHandler, hc->hc_PCIIntLine); + + CONSTWRITEREG32_LE(hc->hc_RegBase, EHCI_CONFIGFLAG, EHCF_CONFIGURED); + hc->hc_EhciUsbCmd |= EHUF_RUNSTOP|EHUF_PERIODICENABLE|EHUF_ASYNCENABLE; + WRITEREG32_LE(hc->hc_RegBase, EHCI_USBCMD, hc->hc_EhciUsbCmd); + SYNC; + EIEIO; + KPRINTF(20, ("HW Init done\n")); + + KPRINTF(10, ("HW Regs USBCMD=%04lx\n", READREG32_LE(hc->hc_RegBase, EHCI_USBCMD))); + KPRINTF(10, ("HW Regs USBSTS=%04lx\n", READREG32_LE(hc->hc_RegBase, EHCI_USBSTATUS))); + KPRINTF(10, ("HW Regs FRAMECOUNT=%04lx\n", READREG32_LE(hc->hc_RegBase, EHCI_FRAMECOUNT))); + break; + } + } + hc = (struct PCIController *) hc->hc_Node.ln_Succ; + } + } + + if(!allocgood) + { + // free previously allocated boards + hc = (struct PCIController *) hu->hu_Controllers.lh_Head; + while(hc->hc_Node.ln_Succ) + { +#if 0 + PCIXObtainBoard(hc->hc_BoardObject); + if(hc->hc_BoardAllocated) + { + hc->hc_BoardAllocated = FALSE; + PCIXSetBoardAttr(hc->hc_BoardObject, PCIXTAG_OWNER, 0); + } + PCIXReleaseBoard(hc->hc_BoardObject); +#endif + hc = (struct PCIController *) hc->hc_Node.ln_Succ; + } + return FALSE; + } + + // find all belonging host controllers + usb11ports = 0; + usb20ports = 0; + hc = (struct PCIController *) hu->hu_Controllers.lh_Head; + while(hc->hc_Node.ln_Succ) + { + if(hc->hc_HCIType == HCITYPE_EHCI) + { + if(usb20ports) + { + KPRINTF(200, ("WARNING: Two EHCI controllers per Board?!?\n")); + } + usb20ports = hc->hc_NumPorts; + for(cnt = 0; cnt < usb20ports; cnt++) + { + hu->hu_PortMap20[cnt] = hc; + hc->hc_PortNum20[cnt] = cnt; + } + } + hc = (struct PCIController *) hc->hc_Node.ln_Succ; + } + + hc = (struct PCIController *) hu->hu_Controllers.lh_Head; + while(hc->hc_Node.ln_Succ) + { + if((hc->hc_HCIType == HCITYPE_UHCI) || (hc->hc_HCIType == HCITYPE_OHCI)) + { + if(complexrouting) + { + ULONG locport = 0; + for(cnt = 0; cnt < usb20ports; cnt++) + { + if(((portroute >> (cnt<<2)) & 0xf) == hc->hc_FunctionNum) + { + KPRINTF(10, ("CHC %ld Port %ld assigned to global Port %ld\n", hc->hc_FunctionNum, locport, cnt)); + hu->hu_PortMap11[cnt] = hc; + hu->hu_PortNum11[cnt] = locport; + hc->hc_PortNum20[locport] = cnt; + locport++; + } + } + } else { + for(cnt = usb11ports; cnt < usb11ports + hc->hc_NumPorts; cnt++) + { + hu->hu_PortMap11[cnt] = hc; + hu->hu_PortNum11[cnt] = cnt - usb11ports; + hc->hc_PortNum20[cnt - usb11ports] = cnt; + } + } + usb11ports += hc->hc_NumPorts; + } + hc = (struct PCIController *) hc->hc_Node.ln_Succ; + } + if((usb11ports != usb20ports) && usb20ports) + { + KPRINTF(20, ("Warning! #EHCI Ports (%ld) does not match USB 1.1 Ports (%ld)!\n", usb20ports, usb11ports)); + } + hu->hu_RootHub11Ports = usb11ports; + hu->hu_RootHub20Ports = usb20ports; + hu->hu_RootHubPorts = (usb11ports > usb20ports) ? usb11ports : usb20ports; + + for(cnt = 0; cnt < hu->hu_RootHubPorts; cnt++) + { + hu->hu_EhciOwned[cnt] = hu->hu_PortMap20[cnt] ? TRUE : FALSE; + } + + KPRINTF(10, ("Unit %ld: USB Board %08lx has %ld USB1.1 and %ld USB2.0 ports!\n", hu->hu_UnitNo, hu->hu_DevID, hu->hu_RootHub11Ports, hu->hu_RootHub20Ports)); + + hu->hu_FrameCounter = 1; + hu->hu_RootHubAddr = 0; + + // put em online + hc = (struct PCIController *) hu->hu_Controllers.lh_Head; + while(hc->hc_Node.ln_Succ) + { + hc->hc_Online = TRUE; + hc = (struct PCIController *) hc->hc_Node.ln_Succ; + } + + KPRINTF(10, ("Unit allocated!\n", hd)); + + return TRUE; +} +/* \\\ */ + +/* /// "pciFreeUnit()" */ +void pciFreeUnit(struct PCIUnit *hu) +{ + struct PCIDevice *hd = hu->hu_Device; + struct PCIController *hc; + + struct TagItem pciDeactivate[] = + { + { aHidd_PCIDevice_isIO, FALSE }, + { aHidd_PCIDevice_isMEM, FALSE }, + { aHidd_PCIDevice_isMaster, FALSE }, + { TAG_DONE, 0UL }, + }; + + KPRINTF(10, ("*** pciFreeUnit(%08lx) ***\n", hu)); + + // put em offline + hc = (struct PCIController *) hu->hu_Controllers.lh_Head; + while(hc->hc_Node.ln_Succ) + { + hc->hc_Online = FALSE; + hc = (struct PCIController *) hc->hc_Node.ln_Succ; + } + + // doing this in three steps to avoid these damn host errors + hc = (struct PCIController *) hu->hu_Controllers.lh_Head; + while(hc->hc_Node.ln_Succ) + { + switch(hc->hc_HCIType) + { + case HCITYPE_EHCI: + { + UWORD portreg; + UWORD hciport; + KPRINTF(20, ("Shutting down EHCI %08lx\n", hc)); + CONSTWRITEREG32_LE(hc->hc_RegBase, EHCI_USBINTEN, 0); + // disable all ports + for(hciport = 0; hciport < hc->hc_NumPorts; hciport++) + { + portreg = EHCI_PORTSC1 + (hciport<<2); + WRITEREG32_LE(hc->hc_RegBase, portreg, 0); + } + CONSTWRITEREG32_LE(hc->hc_RegBase, EHCI_USBCMD, 1UL<hc_RegBase, EHCI_CONFIGFLAG, 0); + CONSTWRITEREG32_LE(hc->hc_RegBase, EHCI_USBCMD, EHUF_HCRESET|(1UL<hc_RegBase, EHCI_USBCMD, 1UL<hc_Node.ln_Succ; + } + + hc = (struct PCIController *) hu->hu_Controllers.lh_Head; + while(hc->hc_Node.ln_Succ) + { + switch(hc->hc_HCIType) + { + case HCITYPE_UHCI: + KPRINTF(20, ("Shutting down UHCI %08lx\n", hc)); + CONSTWRITEREG16_LE(hc->hc_RegBase, UHCI_USBINTEN, 0); + // disable all ports + CONSTWRITEREG16_LE(hc->hc_RegBase, UHCI_PORT1STSCTRL, 0x0000); + CONSTWRITEREG16_LE(hc->hc_RegBase, UHCI_PORT2STSCTRL, 0x0000); + uhwDelayMS(50, hu, hd); + //CONSTWRITEREG16_LE(hc->hc_RegBase, UHCI_USBCMD, UHCF_MAXPACKET64|UHCF_CONFIGURE); + //uhwDelayMS(50, hu, hd); + KPRINTF(20, ("Stopping UHCI %08lx\n", hc)); + CONSTWRITEREG16_LE(hc->hc_RegBase, UHCI_USBCMD, 0); + SYNC; + EIEIO; + //KPRINTF(20, ("Reset done UHCI %08lx\n", hc)); + uhwDelayMS(10, hu, hd); + KPRINTF(20, ("Resetting UHCI %08lx\n", hc)); + CONSTWRITEREG16_LE(hc->hc_RegBase, UHCI_USBCMD, UHCF_HCRESET|UHCF_GLOBALRESET); + SYNC; + EIEIO; + uhwDelayMS(50, hu, hd); + + KPRINTF(20, ("Shutting down UHCI done.\n")); + break; + + case HCITYPE_OHCI: + KPRINTF(20, ("Shutting down OHCI %08lx\n", hc)); + CONSTWRITEREG32_LE(hc->hc_RegBase, OHCI_INTDIS, OISF_ALL_INTS); + CONSTWRITEREG32_LE(hc->hc_RegBase, OHCI_INTSTATUS, OISF_ALL_INTS); + + // disable all ports + WRITEREG32_LE(hc->hc_RegBase, OHCI_HUBDESCB, 0); + WRITEREG32_LE(hc->hc_RegBase, OHCI_HUBSTATUS, OHSF_UNPOWERHUB); + + uhwDelayMS(50, hu, hd); + KPRINTF(20, ("Stopping OHCI %08lx\n", hc)); + CONSTWRITEREG32_LE(hc->hc_RegBase, OHCI_CONTROL, 0); + CONSTWRITEREG32_LE(hc->hc_RegBase, OHCI_CMDSTATUS, 0); + SYNC; + EIEIO; + //KPRINTF(20, ("Reset done UHCI %08lx\n", hc)); + uhwDelayMS(10, hu, hd); + KPRINTF(20, ("Resetting OHCI %08lx\n", hc)); + CONSTWRITEREG32_LE(hc->hc_RegBase, OHCI_CMDSTATUS, OCSF_HCRESET); + SYNC; + EIEIO; + uhwDelayMS(50, hu, hd); + + KPRINTF(20, ("Shutting down OHCI done.\n")); + break; + } + + if(hc->hc_PCIMem) + { + HIDD_PCIDriver_FreePCIMem(hc->hc_PCIDeviceObject, hc->hc_PCIMem); + hc->hc_PCIMem = NULL; + } + hc = (struct PCIController *) hc->hc_Node.ln_Succ; + } + + // disable and free board + hc = (struct PCIController *) hu->hu_Controllers.lh_Head; + while(hc->hc_Node.ln_Succ) + { + OOP_SetAttrs(hc->hc_PCIDeviceObject, (struct TagItem *) pciDeactivate); // deactivate busmaster and IO/Mem + if(hc->hc_PCIIntHandler.h_Node.ln_Name) + { + HIDD_IRQ_RemHandler(hd->hd_IRQHidd, &hc->hc_PCIIntHandler); + hc->hc_PCIIntHandler.h_Node.ln_Name = NULL; + } +#if 0 + + PCIXObtainBoard(hc->hc_BoardObject); + hc->hc_BoardAllocated = FALSE; + PCIXSetBoardAttr(hc->hc_BoardObject, PCIXTAG_OWNER, 0); + PCIXReleaseBoard(hc->hc_BoardObject); +#endif + hc = (struct PCIController *) hc->hc_Node.ln_Succ; + } +} +/* \\\ */ + +/* /// "pciExpunge()" */ +void pciExpunge(struct PCIDevice *hd) +{ + struct PCIController *hc; + struct PCIUnit *hu; + + KPRINTF(10, ("*** pciExpunge(%08lx) ***\n", hd)); + + hu = (struct PCIUnit *) hd->hd_Units.lh_Head; + while(((struct Node *) hu)->ln_Succ) + { + Remove((struct Node *) hu); + hc = (struct PCIController *) hu->hu_Controllers.lh_Head; + while(hc->hc_Node.ln_Succ) + { + Remove(&hc->hc_Node); + FreePooled(hd->hd_MemPool, hc, sizeof(struct PCIController)); + hc = (struct PCIController *) hu->hu_Controllers.lh_Head; + } + FreePooled(hd->hd_MemPool, hu, sizeof(struct PCIUnit)); + hu = (struct PCIUnit *) hd->hd_Units.lh_Head; + } + if(hd->hd_PCIHidd) + { + struct OOP_ABDescr attrbases[] = + { + { (STRPTR) IID_Hidd, &hd->hd_HiddAB }, + { (STRPTR) IID_Hidd_PCIDevice, &hd->hd_HiddPCIDeviceAB }, + { (STRPTR) IID_Hidd_USBDevice, &hd->hd_HiddUSBDeviceAB }, + { (STRPTR) IID_Hidd_USBHub, &hd->hd_HiddUSBHubAB }, + { (STRPTR) IID_Hidd_USBDrv, &hd->hd_HiddUSBDrvAB }, + { NULL, NULL } + }; + + OOP_ReleaseAttrBases(attrbases); + + OOP_DisposeObject(hd->hd_PCIHidd); + } + if(hd->hd_IRQHidd) + { + OOP_DisposeObject(hd->hd_IRQHidd); + } +} +/* \\\ */ + +/* /// "pciGetPhysical()" */ +APTR pciGetPhysical(struct PCIController *hc, APTR virtaddr) +{ + //struct PCIDevice *hd = hc->hc_Device; + return(HIDD_PCIDriver_CPUtoPCI(hc->hc_PCIDeviceObject, virtaddr)); +} +/* \\\ */ diff --git a/rom/usb/pciusb/pci_aros.h b/rom/usb/pciusb/pci_aros.h new file mode 100644 index 000000000..bb87783a7 --- /dev/null +++ b/rom/usb/pciusb/pci_aros.h @@ -0,0 +1,50 @@ +#ifndef PCI_AROS_H +#define PCI_AROS_H + +/* + *---------------------------------------------------------------------------- + * Includes for AROS PCI handling + *---------------------------------------------------------------------------- + * By Chris Hodges + + * + */ + +// hmmm, these were PPC specific barriers +#define SYNC +#define EIEIO + +#if 1 + +#define READMEM16_LE(rb) AROS_WORD2LE(*((UWORD *) (rb))) +#define READMEM32_LE(rb) AROS_LONG2LE(*((ULONG *) (rb))) +#define WRITEMEM32_LE(adr, value) *((ULONG *) (adr)) = AROS_LONG2LE(value) +#define CONSTWRITEMEM32_LE(adr, value) *((ULONG *) (adr)) = AROS_LONG2LE(value) + +#define CONSTWRITEREG16_LE(rb, offset, value) *((volatile UWORD *) (((UBYTE *) (rb)) + ((ULONG) (offset)))) = AROS_WORD2LE(value) +#define CONSTWRITEREG32_LE(rb, offset, value) *((volatile ULONG *) (((UBYTE *) (rb)) + ((ULONG) (offset)))) = AROS_LONG2LE(value) +#define WRITEREG16_LE(rb, offset, value) *((volatile UWORD *) (((UBYTE *) (rb)) + ((ULONG) (offset)))) = AROS_WORD2LE(value) +#define WRITEREG32_LE(rb, offset, value) *((volatile ULONG *) (((UBYTE *) (rb)) + ((ULONG) (offset)))) = AROS_LONG2LE(value) + +#define READREG16_LE(rb, offset) AROS_WORD2LE(*((volatile UWORD *) (((UBYTE *) (rb)) + ((ULONG) (offset))))) +#define READREG32_LE(rb, offset) AROS_LONG2LE(*((volatile ULONG *) (((UBYTE *) (rb)) + ((ULONG) (offset))))) + +#else + +#define READMEM16_LE(rb) inw(rb) +#define READMEM32_LE(rb) inl(rb) + +#define WRITEMEM32_LE(adr, value) outl(value, adr) +#define CONSTWRITEMEM32_LE(adr, value) outl(value, adr) + +#define CONSTWRITEREG16_LE(rb, offset, value) outw(value, (((UBYTE *) (rb)) + ((ULONG) (offset)))) +#define CONSTWRITEREG32_LE(rb, offset, value) outl(value, (((UBYTE *) (rb)) + ((ULONG) (offset)))) +#define WRITEREG16_LE(rb, offset, value) outw(value, (((UBYTE *) (rb)) + ((ULONG) (offset)))) +#define WRITEREG32_LE(rb, offset, value) outl(value, (((UBYTE *) (rb)) + ((ULONG) (offset)))) + +#define READREG16_LE(rb, offset) inw(((UBYTE *) (rb)) + ((ULONG) (offset)))) +#define READREG32_LE(rb, offset) inl((((UBYTE *) (rb)) + ((ULONG) (offset)))) + +#endif + +#endif // PCI_AROS_H diff --git a/rom/usb/pciusb/pciusb.conf b/rom/usb/pciusb/pciusb.conf new file mode 100644 index 000000000..3eafb4c72 --- /dev/null +++ b/rom/usb/pciusb/pciusb.conf @@ -0,0 +1,16 @@ +##begin config +version 1.3 +libbase base +libbasetype struct PCIDevice +libbasetypeextern struct Device +residentpri 48 +basename pciusb +beginio_func devBeginIO +abortio_func devAbortIO +##end config +##begin cdef +#include +##end cdef +##begin cdefprivate +#include "uhwcmd.h" +##end cdefprivate diff --git a/rom/usb/pciusb/pciusb.h b/rom/usb/pciusb/pciusb.h new file mode 100644 index 000000000..214228808 --- /dev/null +++ b/rom/usb/pciusb/pciusb.h @@ -0,0 +1,196 @@ +#ifndef PCIUSB_H +#define PCIUSB_H + +/* + *---------------------------------------------------------------------------- + * Includes for pciusb.device + *---------------------------------------------------------------------------- + * By Chris Hodges + */ + +#include LC_LIBDEFS_FILE + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#include "debug.h" + +/* Reply the iorequest with success */ +#define RC_OK 0 + +/* Magic cookie, don't set error fields & don't reply the ioreq */ +#define RC_DONTREPLY -1 + +#define MAX_ROOT_PORTS 16 + +#define PCI_CLASS_SERIAL_USB 0x0c03 + +/* The unit node - private */ +struct PCIUnit +{ + struct Unit hu_Unit; + LONG hu_UnitNo; + + struct PCIDevice *hu_Device; /* Uplink */ + struct MsgPort *hu_MsgPort; + struct timerequest *hu_TimerReq; /* Timer I/O Request */ + struct timerequest hu_LateIOReq; /* Timer I/O Request */ + struct MsgPort hu_LateMsgPort; + struct timerequest hu_NakTimeoutReq; + struct MsgPort hu_NakTimeoutMsgPort; + struct Interrupt hu_NakTimeoutInt; + + BOOL hu_UnitAllocated; /* Unit opened */ + + ULONG hu_DevID; /* Device ID (BusID+DevNo) */ + struct List hu_Controllers; /* List of controllers */ + UWORD hu_RootHub11Ports; + UWORD hu_RootHub20Ports; + UWORD hu_RootHubPorts; + UWORD hu_RootHubAddr; /* Root Hub Address */ + UWORD hu_RootPortChanges; /* Merged root hub changes */ + ULONG hu_FrameCounter; /* Common frame counter */ + struct List hu_RHIOQueue; /* Root Hub Pending IO Requests */ + + struct PCIController *hu_PortMap11[MAX_ROOT_PORTS]; /* Maps from Global Port to USB 1.1 controller */ + struct PCIController *hu_PortMap20[MAX_ROOT_PORTS]; /* Maps from Global Port to USB 2.0 controller */ + UBYTE hu_PortNum11[MAX_ROOT_PORTS]; /* Maps from Global Port to USB 1.1 companion controller port */ + UBYTE hu_EhciOwned[MAX_ROOT_PORTS]; /* TRUE, if currently owned by EHCI */ + + struct PCIController *hu_DevControllers[128]; /* maps from Device address to controller */ + struct IOUsbHWReq *hu_DevBusyReq[128*16*2]; /* pointer to io assigned to the Endpoint */ + ULONG hu_NakTimeoutFrame[128*16*2]; /* Nak Timeout framenumber */ + UBYTE hu_DevDataToggle[128*16*2]; /* Data toggle bit for endpoints */ +}; + +#define HCITYPE_UHCI 0x00 +#define HCITYPE_OHCI 0x10 +#define HCITYPE_EHCI 0x20 + +struct PCIController +{ + struct Node hc_Node; + struct PCIDevice *hc_Device; /* Uplink */ + struct PCIUnit *hc_Unit; /* Uplink */ + + OOP_Object *hc_PCIDeviceObject; + ULONG hc_DevID; + UWORD hc_FunctionNum; + UWORD hc_HCIType; + UWORD hc_NumPorts; + BOOL hc_BoardAllocated; + BOOL hc_Online; + + volatile APTR hc_RegBase; + + APTR hc_PCIMem; + ULONG hc_PCIMemSize; + ULONG hc_PCIVirtualAdjust; + IPTR hc_PCIIntLine; + HIDDT_IRQ_Handler hc_PCIIntHandler; + ULONG hc_PCIIntEnMask; + + ULONG *hc_UhciFrameList; + struct UhciQH *hc_UhciQHPool; + struct UhciTD *hc_UhciTDPool; + + struct UhciQH *hc_UhciCtrlQH; + struct UhciQH *hc_UhciBulkQH; + struct UhciQH *hc_UhciIntQH[9]; + struct UhciTD *hc_UhciIsoTD; + struct UhciQH *hc_UhciTermQH; + + ULONG hc_EhciUsbCmd; + ULONG *hc_EhciFrameList; + struct EhciQH *hc_EhciQHPool; + struct EhciTD *hc_EhciTDPool; + + struct EhciQH *hc_EhciAsyncQH; + struct EhciQH *hc_EhciIntQH[11]; + struct EhciQH *hc_EhciTermQH; + volatile BOOL hc_AsyncAdvanced; + struct EhciQH *hc_EhciAsyncFreeQH; + struct EhciTD *hc_ShortPktEndTD; + + struct OhciED *hc_OhciCtrlHeadED; + struct OhciED *hc_OhciCtrlTailED; + struct OhciED *hc_OhciBulkHeadED; + struct OhciED *hc_OhciBulkTailED; + struct OhciED *hc_OhciIntED[5]; + struct OhciED *hc_OhciTermED; + struct OhciTD *hc_OhciTermTD; + struct OhciHCCA *hc_OhciHCCA; + struct OhciED *hc_OhciEDPool; + struct OhciTD *hc_OhciTDPool; + struct OhciED *hc_OhciAsyncFreeED; + ULONG hc_OhciDoneQueue; + struct List hc_OhciRetireQueue; + + ULONG hc_FrameCounter; + struct List hc_TDQueue; + struct List hc_PeriodicTDQueue; + struct List hc_CtrlXFerQueue; + struct List hc_IntXFerQueue; + struct List hc_IsoXFerQueue; + struct List hc_BulkXFerQueue; + + struct Interrupt hc_CompleteInt; + + UBYTE hc_PortNum20[MAX_ROOT_PORTS]; /* Global Port number the local controller port corresponds with */ + + UWORD hc_PortChangeMap[MAX_ROOT_PORTS]; /* Port Change Map */ +}; + + +/* The device node - private +*/ +struct PCIDevice +{ + struct Library hd_Library; /* standard */ + UWORD hd_Flags; /* various flags */ + + struct UtilityBase *hd_UtilityBase; /* for tags etc */ + + struct List hd_TempHCIList; + OOP_Object *hd_PCIHidd; + OOP_Object *hd_IRQHidd; + OOP_AttrBase hd_HiddAB; + OOP_AttrBase hd_HiddPCIDeviceAB; + OOP_AttrBase hd_HiddUSBDeviceAB; + OOP_AttrBase hd_HiddUSBHubAB; + OOP_AttrBase hd_HiddUSBDrvAB; + + BOOL hd_ScanDone; /* PCI scan done? */ + APTR hd_MemPool; /* Memory Pool */ + + struct Device *hd_TimerBase; /* timer device base */ + + struct List hd_Units; /* List of units */ +}; + +#endif /* PCIUSB_H */ diff --git a/rom/usb/pciusb/uhcichip.h b/rom/usb/pciusb/uhcichip.h new file mode 100644 index 000000000..35d5515f6 --- /dev/null +++ b/rom/usb/pciusb/uhcichip.h @@ -0,0 +1,243 @@ +#ifndef UHCICHIP_H +#define UHCICHIP_H + +/* + *---------------------------------------------------------------------------- + * Includes for UHCI USB Controller + *---------------------------------------------------------------------------- + * By Chris Hodges + */ + +#include +#include "hccommon.h" + +/* PCI Class: PCI_CLASS_SERIAL_USB */ + +/* Framelist stuff + + 1. Standard approach + - Framelist contains all the same entries pointing to ISO-TD + - ISO-TD: is inactive by default. Links to Control-QH + - Control-QH: - Head links to Int-Queue + - Element: Links to dummy-TD if empty (inactive) + - Element: otherwise links to QH for control transfer + - Int-Queue : - Head links to Bulk-Queue + 2. Not quite conform but better approach: + - Framelist contains pointers to the correct interrupt queue head, + depending on the interval (9 different QHs). The last 1ms qh points to the iso-td + - the iso-td points to the first Control-QH + - the control qh has vertical TDs for each transfer, and points to the next control qh + - the last control qh points to bulk qh. + - the bulk qh has vertical TDs for each (partial) transfer, and points to the next bulk qh + - the last bulk qh points to the terminating qh with terminating bits set. +*/ + +/* + * --------------------- UHCI registers ------------------------ + * Warning: These are BYTE offsets! + */ + +#define UHCI_USBCMD 0x000 /* USB Command (r/w) */ +#define UHCI_USBSTATUS 0x002 /* USB Status (r/wc) */ +#define UHCI_USBINTEN 0x004 /* USB Interrupt Enable (r/w) */ +#define UHCI_FRAMECOUNT 0x006 /* Frame Number (r/w) */ +#define UHCI_FRAMELISTADDR 0x008 /* Framelist Base Address (LONGWORD!), 4KB aligned! (r/w) */ +#define UHCI_SOFMOD 0x00c /* Start Of Frame Modify (upper byte?) (r/w) */ +#define UHCI_PORT1STSCTRL 0x010 /* Port 1 Status/Control (r/wc) */ +#define UHCI_PORT2STSCTRL 0x012 /* Port 2 Status/Control (r/wc) */ + +struct UHCIRegs +{ + volatile UWORD uhr_USBCmd; /* USB Command (r/w) */ + volatile UWORD uhr_USBStatus; /* USB Status (r/wc) */ + volatile UWORD uhr_USBIntEn; /* USB Interrupt Enable (r/w) */ + volatile UWORD uhr_FrameCount; /* Frame Number (r/w) */ + volatile APTR uhr_FrameListAddr; /* Framelist Base Address (LONGWORD!) (r/w) */ + volatile UBYTE uhr_SOFMod; /* Start Of Frame Modify (upper byte?) (r/w) */ + volatile UBYTE uhr_Reserved0; + volatile UWORD uhr_Reserved1; + volatile UWORD uhr_PortStsCtrl[2]; /* Port 1/2 Status/Control (r/wc) */ +}; + +/* UHCI_USBCMD defines */ +#define UHCB_RUNSTOP 0 /* 1=Run, 0=Stop */ +#define UHCB_HCRESET 1 /* Host Controller Reset */ +#define UHCB_GLOBALRESET 2 /* Reset everything */ +#define UHCB_USBSUSPEND 3 /* Send USB Suspend */ +#define UHCB_USBRESUME 4 /* Send USB Resume */ +#define UHCB_DEBUG 5 /* Software Debug */ +#define UHCB_CONFIGURE 6 /* Semaphore */ +#define UHCB_MAXPACKET64 7 /* 1=64 bytes, 0=32 bytes */ + +#define UHCF_RUNSTOP (1UL< +#include + +#include +#include + +#define NewList NEWLIST + +/* Root hub data */ +const struct UsbStdDevDesc RHDevDesc = { sizeof(struct UsbStdDevDesc), UDT_DEVICE, AROS_WORD2LE(0x0110), HUB_CLASSCODE, 0, 0, 8, AROS_WORD2LE(0x0000), AROS_WORD2LE(0x0000), AROS_WORD2LE(0x0100), 1, 2, 0, 1 }; + +const struct UsbStdCfgDesc RHCfgDesc = { 9, UDT_CONFIGURATION, AROS_WORD2LE(9+9+7), 1, 1, 3, USCAF_ONE|USCAF_SELF_POWERED, 0 }; +const struct UsbStdIfDesc RHIfDesc = { 9, UDT_INTERFACE, 0, 0, 1, HUB_CLASSCODE, 0, 0, 4 }; +const struct UsbStdEPDesc RHEPDesc = { 7, UDT_ENDPOINT, URTF_IN|1, USEAF_INTERRUPT, AROS_WORD2LE(1), 255 }; +const struct UsbHubDesc RHHubDesc = { 9, UDT_HUB, 0, AROS_WORD2LE(UHCF_INDIVID_POWER|UHCF_INDIVID_OVP), 0, 1, 1, 0 }; + +const CONST_STRPTR RHStrings[] = { "Chris Hodges", "PCI Root Hub", "Standard Config", "Hub interface" }; + +/* /// "SureCause()" */ +void SureCause(struct PCIDevice *base, struct Interrupt *interrupt) +{ + /* this is a workaround for the original Cause() function missing tailed calls */ + Disable(); + if((interrupt->is_Node.ln_Type == NT_SOFTINT) || (interrupt->is_Node.ln_Type == NT_USER)) + { + // signal tailed call + interrupt->is_Node.ln_Type = NT_USER; + } else { + do + { + interrupt->is_Node.ln_Type = NT_SOFTINT; + Enable(); + (*((void (*)(struct Interrupt *)) (interrupt->is_Code)))(interrupt->is_Data); + Disable(); + } while(interrupt->is_Node.ln_Type != NT_SOFTINT); + interrupt->is_Node.ln_Type = NT_INTERRUPT; + } + Enable(); +} +/* \\\ */ + +/* /// "uhwOpenTimer()" */ +BOOL uhwOpenTimer(struct PCIUnit *unit, struct PCIDevice *base) +{ + if((unit->hu_MsgPort = CreateMsgPort())) + { + if((unit->hu_TimerReq = (struct timerequest *) CreateIORequest(unit->hu_MsgPort, sizeof(struct timerequest)))) + { + if(!OpenDevice("timer.device", UNIT_MICROHZ, (struct IORequest *) unit->hu_TimerReq, 0)) + { + unit->hu_TimerReq->tr_node.io_Message.mn_Node.ln_Name = "PCI hardware"; + unit->hu_TimerReq->tr_node.io_Command = TR_ADDREQUEST; + KPRINTF(1, ("opened timer device\n")); + return(TRUE); + } + DeleteIORequest((struct IORequest *) unit->hu_TimerReq); + unit->hu_TimerReq = NULL; + } + DeleteMsgPort(unit->hu_MsgPort); + unit->hu_MsgPort = NULL; + } + KPRINTF(5, ("failed to open timer.device\n")); + return(FALSE); +} +/* \\\ */ + +/* /// "uhwDelayMS()" */ +void uhwDelayMS(ULONG milli, struct PCIUnit *unit, struct PCIDevice *base) +{ + unit->hu_TimerReq->tr_time.tv_secs = 0; + unit->hu_TimerReq->tr_time.tv_micro = milli * 1000; + DoIO((struct IORequest *) unit->hu_TimerReq); +} +/* \\\ */ + +/* /// "uhwCloseTimer()" */ +void uhwCloseTimer(struct PCIUnit *unit, struct PCIDevice *base) +{ + if(unit->hu_MsgPort) + { + if(unit->hu_TimerReq) + { + KPRINTF(1, ("closing timer.device\n")); + CloseDevice((APTR) unit->hu_TimerReq); + DeleteIORequest((struct IORequest *) unit->hu_TimerReq); + unit->hu_TimerReq = NULL; + } + DeleteMsgPort(unit->hu_MsgPort); + unit->hu_MsgPort = NULL; + } +} +/* \\\ */ + +/* /// "uhwHWInit()" */ +void uhwHWInit(struct PCIController *hc) +{ + KPRINTF(1, ("Reset\n")); + //unit->hu_FrameCounter = 1; + //unit->hu_RootHubAddr = 0; +} +/* \\\ */ + +/* /// "Open_Unit()" */ +struct Unit * Open_Unit(struct IOUsbHWReq *ioreq, + LONG unitnr, + struct PCIDevice *base) +{ + struct PCIUnit *unit = NULL; + + if(!base->hd_ScanDone) + { + base->hd_ScanDone = TRUE; + if(!pciInit(base)) + { + return NULL; + } + } + unit = (struct PCIUnit *) base->hd_Units.lh_Head; + while(((struct Node *) unit)->ln_Succ) + { + if(unit->hu_UnitNo == unitnr) + { + break; + } + unit = (struct PCIUnit *) ((struct Node *) unit)->ln_Succ; + } + if(!((struct Node *) unit)->ln_Succ) + { + KPRINTF(20, ("Unit %ld does not exist!\n", unitnr)); + return NULL; + } + if(unit->hu_UnitAllocated) + { + ioreq->iouh_Req.io_Error = IOERR_UNITBUSY; + KPRINTF(5, ("Unit %ld already open!\n", unitnr)); + return NULL; + } + + if(uhwOpenTimer(unit, base)) + { + + if(pciAllocUnit(unit)) // hardware self test + { + + unit->hu_NakTimeoutInt.is_Node.ln_Type = NT_INTERRUPT; + unit->hu_NakTimeoutInt.is_Node.ln_Name = "PCI NakTimeout"; + unit->hu_NakTimeoutInt.is_Node.ln_Pri = -16; + unit->hu_NakTimeoutInt.is_Data = unit; + unit->hu_NakTimeoutInt.is_Code = (void (*)(void)) &uhwNakTimeoutInt; + + CopyMem(unit->hu_TimerReq, &unit->hu_NakTimeoutReq, sizeof(struct timerequest)); + unit->hu_NakTimeoutReq.tr_node.io_Message.mn_ReplyPort = &unit->hu_NakTimeoutMsgPort; + unit->hu_NakTimeoutMsgPort.mp_Node.ln_Type = NT_MSGPORT; + unit->hu_NakTimeoutMsgPort.mp_Flags = PA_SOFTINT; + unit->hu_NakTimeoutMsgPort.mp_SigTask = &unit->hu_NakTimeoutInt; + NewList(&unit->hu_NakTimeoutMsgPort.mp_MsgList); + Cause(&unit->hu_NakTimeoutInt); + return(&unit->hu_Unit); + } else { + ioreq->iouh_Req.io_Error = IOERR_SELFTEST; + KPRINTF(20, ("Hardware allocation failure!\n")); + } + uhwCloseTimer(unit, base); + } + return(NULL); +} +/* \\\ */ + +/* /// "Close_Unit()" */ +void Close_Unit(struct PCIDevice *base, + struct PCIUnit *unit, + struct IOUsbHWReq *ioreq) +{ + /* Disable all interrupts */ + unit->hu_NakTimeoutMsgPort.mp_Flags = PA_IGNORE; + unit->hu_NakTimeoutInt.is_Node.ln_Type = NT_SOFTINT; + AbortIO((APTR) &unit->hu_NakTimeoutReq); + + pciFreeUnit(unit); + + uhwCloseTimer(unit, base); + unit->hu_UnitAllocated = FALSE; +} +/* \\\ */ + +/* /// "uhwGetUsbState()" */ +UWORD uhwGetUsbState(struct IOUsbHWReq *ioreq, + struct PCIUnit *unit, + struct PCIDevice *base) +{ + return(ioreq->iouh_State = UHSF_OPERATIONAL); +} +/* \\\ */ + +/* /// "cmdReset()" */ +/* + *====================================================================== + * cmdReset(ioreq, unit, base) + *====================================================================== + * + * This is the device CMD_RESET routine. + * + * Resets the whole USB hardware. Goes into USBOperational mode right + * after. Must NOT be called from an interrupt. + * + */ + +WORD cmdReset(struct IOUsbHWReq *ioreq, + struct PCIUnit *unit, + struct PCIDevice *base) +{ + KPRINTF(10, ("CMD_RESET ioreq: 0x%08lx\n", ioreq)); + //uhwHWInit(unit); + + uhwDelayMS(1, unit, base); + uhwGetUsbState(ioreq, unit, base); + + if(ioreq->iouh_State & UHSF_OPERATIONAL) + { + return RC_OK; + } + return UHIOERR_USBOFFLINE; +} +/* \\\ */ + +/* /// "cmdUsbReset()" */ +/* + *====================================================================== + * cmdUsbReset(ioreq, unit, base) + *====================================================================== + * + * This is the device UHCMD_USBRESET routine. + * + * Resets the USB bus. Goes into USBOperational mode right after. Must + * NOT be called from an interrupt. + * + */ + +WORD cmdUsbReset(struct IOUsbHWReq *ioreq, + struct PCIUnit *unit, + struct PCIDevice *base) +{ + KPRINTF(10, ("UHCMD_USBRESET ioreq: 0x%08lx\n", ioreq)); + + /* FIXME */ + uhwGetUsbState(ioreq, unit, base); + + unit->hu_FrameCounter = 1; + unit->hu_RootHubAddr = 0; + + if(ioreq->iouh_State & UHSF_OPERATIONAL) + { + return RC_OK; + } + return UHIOERR_USBOFFLINE; +} +/* \\\ */ + +/* /// "cmdUsbResume()" */ +/* + *====================================================================== + * cmdUsbResume(ioreq, unit, base) + *====================================================================== + * + * This is the device UHCMD_USBRESUME routine. + * + * Tries to resume from USBSuspend mode into USBOperational. + * Must NOT be called from an interrupt. + * + */ + +WORD cmdUsbResume(struct IOUsbHWReq *ioreq, + struct PCIUnit *unit, + struct PCIDevice *base) +{ + KPRINTF(10, ("UHCMD_USBRESUME ioreq: 0x%08lx\n", ioreq)); + + /* FIXME */ + uhwGetUsbState(ioreq, unit, base); + if(ioreq->iouh_State & UHSF_OPERATIONAL) + { + return RC_OK; + } + return UHIOERR_USBOFFLINE; +} +/* \\\ */ + +/* /// "cmdUsbSuspend()" */ +/* + *====================================================================== + * cmdUsbSuspend(ioreq, unit, base) + *====================================================================== + * + * This is the device UHCMD_USBSUSPEND routine. + * + * Sets the USB into USBSuspend mode. + * Must NOT be called from an interrupt. + * + */ + +WORD cmdUsbSuspend(struct IOUsbHWReq *ioreq, + struct PCIUnit *unit, + struct PCIDevice *base) +{ + KPRINTF(10, ("UHCMD_USBSUSPEND ioreq: 0x%08lx\n", ioreq)); + + /* FIXME */ + uhwGetUsbState(ioreq, unit, base); + if(ioreq->iouh_State & UHSF_SUSPENDED) + { + return RC_OK; + } + return UHIOERR_USBOFFLINE; +} +/* \\\ */ + +/* /// "cmdUsbOper()" */ +/* + *====================================================================== + * cmdUsbOper(ioreq, unit, base) + *====================================================================== + * + * This is the device UHCMD_USBOPER routine. + * + * Sets the USB into USBOperational mode. + * Must NOT be called from an interrupt. + * + */ + +WORD cmdUsbOper(struct IOUsbHWReq *ioreq, + struct PCIUnit *unit, + struct PCIDevice *base) +{ + KPRINTF(10, ("UHCMD_USBOPER ioreq: 0x%08lx\n", ioreq)); + + /* FIXME */ + uhwGetUsbState(ioreq, unit, base); + if(ioreq->iouh_State & UHSF_OPERATIONAL) + { + return RC_OK; + } + return UHIOERR_USBOFFLINE; +} +/* \\\ */ + +/* /// "cmdQueryDevice()" */ +/* + *====================================================================== + * cmdQueryDevice(ioreq, unit, base) + *====================================================================== + * + * This is the device UHCMD_QUERYDEVICE routine. + * + * Returns information about the hardware. + * + */ + +WORD cmdQueryDevice(struct IOUsbHWReq *ioreq, + struct PCIUnit *unit, + struct PCIDevice *base) +{ + struct TagItem *taglist = (struct TagItem *) ioreq->iouh_Data; + struct TagItem *tag; + ULONG count = 0; + + KPRINTF(10, ("UHCMD_QUERYDEVICE ioreq: 0x%08lx, taglist: 0x%08lx\n", ioreq, taglist)); + + if((tag = FindTagItem(UHA_State, taglist))) + { + *((ULONG *) tag->ti_Data) = (ULONG) uhwGetUsbState(ioreq, unit, base); + count++; + } + if((tag = FindTagItem(UHA_Manufacturer, taglist))) + { + *((STRPTR *) tag->ti_Data) = "Chris Hodges"; + count++; + } + if((tag = FindTagItem(UHA_ProductName, taglist))) + { + *((STRPTR *) tag->ti_Data) = "PCI UHCI/OHCI/EHCI USB Host Controller"; + count++; + } + if((tag = FindTagItem(UHA_Description, taglist))) + { + *((STRPTR *) tag->ti_Data) = "Generic adaptive host controller driver for PCI cards"; + count++; + } + if((tag = FindTagItem(UHA_Copyright, taglist))) + { + *((STRPTR *) tag->ti_Data) = "©2007-2009 Chris Hodges"; + count++; + } + if((tag = FindTagItem(UHA_Version, taglist))) + { + *((ULONG *) tag->ti_Data) = VERSION_NUMBER; + count++; + } + if((tag = FindTagItem(UHA_Revision, taglist))) + { + *((ULONG *) tag->ti_Data) = REVISION_NUMBER; + count++; + } + if((tag = FindTagItem(UHA_DriverVersion, taglist))) + { + *((ULONG *) tag->ti_Data) = 0x220; + count++; + } + if((tag = FindTagItem(UHA_Capabilities, taglist))) + { + *((ULONG *) tag->ti_Data) = UHCF_USB20; + count++; + } + ioreq->iouh_Actual = count; + return RC_OK; +} +/* \\\ */ + +/* /// "cmdControlXFerRootHub()" */ +WORD cmdControlXFerRootHub(struct IOUsbHWReq *ioreq, + struct PCIUnit *unit, + struct PCIDevice *base) +{ + struct PCIController *hc; + struct PCIController *chc; + UWORD rt = ioreq->iouh_SetupData.bmRequestType; + UWORD req = ioreq->iouh_SetupData.bRequest; + UWORD idx = AROS_WORD2LE(ioreq->iouh_SetupData.wIndex); + UWORD val = AROS_WORD2LE(ioreq->iouh_SetupData.wValue); + UWORD len = AROS_WORD2LE(ioreq->iouh_SetupData.wLength); + UWORD hciport; + ULONG numports = unit->hu_RootHubPorts; + BOOL cmdgood; + ULONG cnt; + + if(ioreq->iouh_Endpoint) + { + return(UHIOERR_STALL); + } + + if(len != ioreq->iouh_Length) + { + KPRINTF(20, ("RH: Len (%ld != %ld) mismatch!\n", len != ioreq->iouh_Length)); + return(UHIOERR_STALL); + } + switch(rt) + { + case (URTF_STANDARD|URTF_DEVICE): + switch(req) + { + case USR_SET_ADDRESS: + KPRINTF(1, ("RH: SetAddress = %ld\n", val)); + unit->hu_RootHubAddr = val; + ioreq->iouh_Actual = len; + return(0); + + case USR_SET_CONFIGURATION: + KPRINTF(1, ("RH: SetConfiguration=%ld\n", val)); + ioreq->iouh_Actual = len; + return(0); + } + break; + + case (URTF_IN|URTF_STANDARD|URTF_DEVICE): + switch(req) + { + case USR_GET_DESCRIPTOR: + switch(val>>8) + { + case UDT_DEVICE: + KPRINTF(1, ("RH: GetDeviceDescriptor (%ld)\n", len)); + ioreq->iouh_Actual = (len > sizeof(struct UsbStdDevDesc)) ? sizeof(struct UsbStdDevDesc) : len; + CopyMem((APTR) &RHDevDesc, ioreq->iouh_Data, ioreq->iouh_Actual); + if(ioreq->iouh_Length >= sizeof(struct UsbStdDevDesc)) + { + if(unit->hu_RootHub20Ports) + { + struct UsbStdDevDesc *usdd = (struct UsbStdDevDesc *) ioreq->iouh_Data; + usdd->bcdUSB = AROS_WORD2LE(0x0200); // signal a highspeed root hub + usdd->bDeviceProtocol = 1; // single TT + } + } + return(0); + + case UDT_CONFIGURATION: + { + UBYTE tmpbuf[9+9+7]; + KPRINTF(1, ("RH: GetConfigDescriptor (%ld)\n", len)); + CopyMem((APTR) &RHCfgDesc, tmpbuf, 9); + CopyMem((APTR) &RHIfDesc, &tmpbuf[9], 9); + CopyMem((APTR) &RHEPDesc, &tmpbuf[9+9], 7); + if(unit->hu_RootHub20Ports) + { + struct UsbStdEPDesc *usepd = (struct UsbStdEPDesc *) &tmpbuf[9+9]; + usepd->bInterval = 12; // 2048 µFrames + } + ioreq->iouh_Actual = (len > 9+9+7) ? 9+9+7 : len; + CopyMem(tmpbuf, ioreq->iouh_Data, ioreq->iouh_Actual); + return(0); + } + + case UDT_STRING: + if(val & 0xff) /* get lang array */ + { + CONST_STRPTR source = NULL; + UWORD *mptr = ioreq->iouh_Data; + UWORD slen = 1; + KPRINTF(1, ("RH: GetString %04lx (%ld)\n", val, len)); + if((val & 0xff) > 4) /* index too high? */ + { + return(UHIOERR_STALL); + } + source = RHStrings[(val & 0xff)-1]; + if(len > 1) + { + ioreq->iouh_Actual = 2; + while(*source++) + { + slen++; + } + source = RHStrings[(val & 0xff)-1]; + *mptr++ = (slen<<9)|UDT_STRING; + while(ioreq->iouh_Actual+1 < len) + { + *mptr++ = AROS_WORD2LE(*source); + source++; + ioreq->iouh_Actual += 2; + if(!(*source)) + { + break; + } + } + } + } else { + UWORD *mptr = ioreq->iouh_Data; + KPRINTF(1, ("RH: GetLangArray %04lx (%ld)\n", val, len)); + if(len > 1) + { + ioreq->iouh_Actual = 2; + mptr[0] = AROS_WORD2BE((4<<8)|UDT_STRING); + if(len > 3) + { + ioreq->iouh_Actual += 2; + mptr[1] = AROS_WORD2LE(0x0409); + } + } + } + return(0); + + default: + KPRINTF(1, ("RH: Unsupported Descriptor %04lx\n", idx)); + } + break; + + case USR_GET_CONFIGURATION: + if(len == 1) + { + KPRINTF(1, ("RH: GetConfiguration\n")); + ((UBYTE *) ioreq->iouh_Data)[0] = 1; + ioreq->iouh_Actual = len; + return(0); + } + break; + } + break; + + case (URTF_CLASS|URTF_OTHER): + switch(req) + { + case USR_SET_FEATURE: + if((!idx) && (idx > numports)) + { + KPRINTF(20, ("Port %ld out of range\n", idx)); + return(UHIOERR_STALL); + } + chc = unit->hu_PortMap11[idx - 1]; + if(unit->hu_EhciOwned[idx - 1]) + { + hc = unit->hu_PortMap20[idx - 1]; + hciport = idx - 1; + } else { + hc = chc; + hciport = unit->hu_PortNum11[idx - 1]; + } + cmdgood = FALSE; + switch(hc->hc_HCIType) + { + case HCITYPE_UHCI: + { + UWORD portreg = hciport ? UHCI_PORT2STSCTRL : UHCI_PORT1STSCTRL; + ULONG oldval = READREG16_LE(hc->hc_RegBase, portreg) & ~(UHPF_ENABLECHANGE|UHPF_CONNECTCHANGE); // these are clear-on-write! + ULONG newval = oldval; + switch(val) + { + /* case UFS_PORT_CONNECTION: not possible */ + case UFS_PORT_ENABLE: + KPRINTF(10, ("Enabling Port (%s)\n", newval & UHPF_PORTENABLE ? "already" : "ok")); + newval |= UHPF_PORTENABLE; + cmdgood = TRUE; + break; + + case UFS_PORT_SUSPEND: + newval |= UHPF_PORTSUSPEND; + hc->hc_PortChangeMap[hciport] |= UPSF_PORT_SUSPEND; // manually fake suspend change + cmdgood = TRUE; + break; + + /* case UFS_PORT_OVER_CURRENT: not possible */ + case UFS_PORT_RESET: + KPRINTF(10, ("Resetting Port (%s)\n", newval & UHPF_PORTRESET ? "already" : "ok")); + + // this is an ugly blocking workaround to the inability of UHCI to clear reset automatically + newval &= ~(UHPF_PORTSUSPEND|UHPF_PORTENABLE); + newval |= UHPF_PORTRESET; + WRITEREG16_LE(hc->hc_RegBase, portreg, newval); + uhwDelayMS(75, unit, base); + newval = READREG16_LE(hc->hc_RegBase, portreg) & ~(UHPF_ENABLECHANGE|UHPF_CONNECTCHANGE|UHPF_PORTSUSPEND|UHPF_PORTENABLE); + KPRINTF(10, ("Reset=%s\n", newval & UHPF_PORTRESET ? "GOOD" : "BAD!")); + newval &= ~UHPF_PORTRESET; + WRITEREG16_LE(hc->hc_RegBase, portreg, newval); + uhwDelayMS(5, unit, base); + newval = READREG16_LE(hc->hc_RegBase, portreg) & ~(UHPF_ENABLECHANGE|UHPF_CONNECTCHANGE|UHPF_PORTSUSPEND); + KPRINTF(10, ("Reset=%s\n", newval & UHPF_PORTRESET ? "BAD!" : "GOOD")); + newval &= ~UHPF_PORTRESET; + newval |= UHPF_PORTENABLE; + WRITEREG16_LE(hc->hc_RegBase, portreg, newval); + hc->hc_PortChangeMap[hciport] |= UPSF_PORT_RESET|UPSF_PORT_ENABLE; // manually fake reset change + uhwDelayMS(10, unit, base); + + cnt = 100; + do + { + uhwDelayMS(1, unit, base); + newval = READREG16_LE(hc->hc_RegBase, portreg) & ~(UHPF_ENABLECHANGE|UHPF_CONNECTCHANGE); + } while(--cnt && (!(newval & UHPF_PORTENABLE))); + if(cnt) + { + KPRINTF(10, ("Enabled after %ld ticks\n", 100-cnt)); + } else { + KPRINTF(20, ("Port refuses to be enabled!\n")); + return(UHIOERR_HOSTERROR); + } + // make enumeration possible + unit->hu_DevControllers[0] = hc; + cmdgood = TRUE; + break; + + case UFS_PORT_POWER: + KPRINTF(10, ("Powering Port\n")); + // ignore for UHCI, is always powered + cmdgood = TRUE; + break; + + /* case UFS_PORT_LOW_SPEED: not possible */ + /* case UFS_C_PORT_CONNECTION: + case UFS_C_PORT_ENABLE: + case UFS_C_PORT_SUSPEND: + case UFS_C_PORT_OVER_CURRENT: + case UFS_C_PORT_RESET: */ + } + if(cmdgood) + { + KPRINTF(5, ("Port %ld SET_FEATURE %04lx->%04lx\n", idx, oldval, newval)); + WRITEREG16_LE(hc->hc_RegBase, portreg, newval); + return(0); + } + break; + } + + case HCITYPE_OHCI: + { + UWORD portreg = OHCI_PORTSTATUS + (hciport<<2); + ULONG oldval = READREG32_LE(hc->hc_RegBase, portreg); + + switch(val) + { + /* case UFS_PORT_CONNECTION: not possible */ + case UFS_PORT_ENABLE: + KPRINTF(10, ("Enabling Port (%s)\n", oldval & OHPF_PORTENABLE ? "already" : "ok")); + WRITEREG32_LE(hc->hc_RegBase, portreg, OHPF_PORTENABLE); + cmdgood = TRUE; + break; + + case UFS_PORT_SUSPEND: + KPRINTF(10, ("Suspending Port (%s)\n", oldval & OHPF_PORTSUSPEND ? "already" : "ok")); + //hc->hc_PortChangeMap[hciport] |= UPSF_PORT_SUSPEND; // manually fake suspend change + WRITEREG32_LE(hc->hc_RegBase, portreg, OHPF_PORTSUSPEND); + cmdgood = TRUE; + break; + + /* case UFS_PORT_OVER_CURRENT: not possible */ + case UFS_PORT_RESET: + KPRINTF(10, ("Resetting Port (%s)\n", oldval & OHPF_PORTRESET ? "already" : "ok")); + WRITEREG32_LE(hc->hc_RegBase, portreg, OHPF_PORTRESET); + // make enumeration possible + unit->hu_DevControllers[0] = hc; + cmdgood = TRUE; + break; + + case UFS_PORT_POWER: + KPRINTF(10, ("Powering Port (%s)\n", oldval & OHPF_PORTPOWER ? "already" : "ok")); + WRITEREG32_LE(hc->hc_RegBase, portreg, OHPF_PORTPOWER); + cmdgood = TRUE; + break; + + /* case UFS_PORT_LOW_SPEED: not possible */ + /* case UFS_C_PORT_CONNECTION: + case UFS_C_PORT_ENABLE: + case UFS_C_PORT_SUSPEND: + case UFS_C_PORT_OVER_CURRENT: + case UFS_C_PORT_RESET: */ + } + if(cmdgood) + { + return(0); + } + break; + } + + case HCITYPE_EHCI: + { + UWORD portreg = EHCI_PORTSC1 + (hciport<<2); + ULONG oldval = READREG32_LE(hc->hc_RegBase, portreg) & ~(EHPF_OVERCURRENTCHG|EHPF_ENABLECHANGE|EHPF_CONNECTCHANGE); // these are clear-on-write! + ULONG newval = oldval; + switch(val) + { + /* case UFS_PORT_CONNECTION: not possible */ + case UFS_PORT_ENABLE: + KPRINTF(10, ("Enabling Port (%s)\n", newval & EHPF_PORTENABLE ? "already" : "ok")); + newval |= EHPF_PORTENABLE; + cmdgood = TRUE; + break; + + case UFS_PORT_SUSPEND: + newval |= EHPF_PORTSUSPEND; + hc->hc_PortChangeMap[hciport] |= UPSF_PORT_SUSPEND; // manually fake suspend change + cmdgood = TRUE; + break; + + /* case UFS_PORT_OVER_CURRENT: not possible */ + case UFS_PORT_RESET: + KPRINTF(10, ("Resetting Port (%s)\n", newval & EHPF_PORTRESET ? "already" : "ok")); + + // this is an ugly blocking workaround to the inability of UHCI to clear reset automatically + newval &= ~(EHPF_PORTSUSPEND|EHPF_PORTENABLE); + newval |= EHPF_PORTRESET; + WRITEREG32_LE(hc->hc_RegBase, portreg, newval); + uhwDelayMS(75, unit, base); + newval = READREG32_LE(hc->hc_RegBase, portreg) & ~(EHPF_OVERCURRENTCHG|EHPF_ENABLECHANGE|EHPF_CONNECTCHANGE|EHPF_PORTSUSPEND|EHPF_PORTENABLE); + KPRINTF(10, ("Reset=%s\n", newval & EHPF_PORTRESET ? "GOOD" : "BAD!")); + newval &= ~EHPF_PORTRESET; + WRITEREG32_LE(hc->hc_RegBase, portreg, newval); + uhwDelayMS(10, unit, base); + newval = READREG32_LE(hc->hc_RegBase, portreg) & ~(EHPF_OVERCURRENTCHG|EHPF_ENABLECHANGE|EHPF_CONNECTCHANGE|EHPF_PORTSUSPEND); + KPRINTF(10, ("Reset=%s\n", newval & EHPF_PORTRESET ? "BAD!" : "GOOD")); + KPRINTF(10, ("Highspeed=%s\n", newval & EHPF_PORTENABLE ? "YES!" : "NO")); + if(!(newval & EHPF_PORTENABLE)) + { + // if not highspeed, release ownership + KPRINTF(20, ("Transferring ownership to UHCI/OHCI port %ld\n", unit->hu_PortNum11[idx - 1])); + KPRINTF(10, ("Device is %s\n", newval & EHPF_LINESTATUS_DM ? "LOWSPEED" : "FULLSPEED")); + unit->hu_EhciOwned[idx - 1] = FALSE; + newval |= EHPF_NOTPORTOWNER; + WRITEREG32_LE(hc->hc_RegBase, portreg, newval); + // enable companion controller port + switch(chc->hc_HCIType) + { + case HCITYPE_UHCI: + { + UWORD uhcihciport = unit->hu_PortNum11[idx - 1]; + UWORD uhciportreg = uhcihciport ? UHCI_PORT2STSCTRL : UHCI_PORT1STSCTRL; + ULONG uhcinewval; + + uhcinewval = READREG16_LE(chc->hc_RegBase, uhciportreg) & ~(UHPF_ENABLECHANGE|UHPF_CONNECTCHANGE|UHPF_PORTSUSPEND); + KPRINTF(10, ("UHCI Reset=%s\n", uhcinewval & UHPF_PORTRESET ? "BAD!" : "GOOD")); + if((uhcinewval & UHPF_PORTRESET))//|| (newval & EHPF_LINESTATUS_DM)) + { + // this is an ugly blocking workaround to the inability of UHCI to clear reset automatically + KPRINTF(20, ("Uhm, UHCI reset was bad!\n")); + uhcinewval &= ~(UHPF_PORTSUSPEND|UHPF_PORTENABLE); + uhcinewval |= UHPF_PORTRESET; + WRITEREG16_LE(chc->hc_RegBase, uhciportreg, uhcinewval); + uhwDelayMS(75, unit, base); + uhcinewval = READREG16_LE(chc->hc_RegBase, uhciportreg) & ~(UHPF_ENABLECHANGE|UHPF_CONNECTCHANGE|UHPF_PORTSUSPEND|UHPF_PORTENABLE); + KPRINTF(10, ("ReReset=%s\n", uhcinewval & UHPF_PORTRESET ? "GOOD" : "BAD!")); + uhcinewval &= ~UHPF_PORTRESET; + WRITEREG16_LE(chc->hc_RegBase, uhciportreg, uhcinewval); + uhwDelayMS(5, unit, base); + uhcinewval = READREG16_LE(chc->hc_RegBase, uhciportreg) & ~(UHPF_ENABLECHANGE|UHPF_CONNECTCHANGE|UHPF_PORTSUSPEND); + KPRINTF(10, ("ReReset=%s\n", uhcinewval & UHPF_PORTRESET ? "STILL BAD!" : "GOOD")); + } + uhcinewval &= ~UHPF_PORTRESET; + uhcinewval |= UHPF_PORTENABLE; + WRITEREG16_LE(chc->hc_RegBase, uhciportreg, uhcinewval); + chc->hc_PortChangeMap[uhcihciport] |= UPSF_PORT_RESET|UPSF_PORT_ENABLE; // manually fake reset change + uhwDelayMS(5, unit, base); + cnt = 100; + do + { + uhwDelayMS(1, unit, base); + uhcinewval = READREG16_LE(chc->hc_RegBase, uhciportreg) & ~(UHPF_ENABLECHANGE|UHPF_CONNECTCHANGE); + } while(--cnt && (!(uhcinewval & UHPF_PORTENABLE))); + if(cnt) + { + KPRINTF(10, ("Enabled after %ld ticks\n", 100-cnt)); + } else { + KPRINTF(20, ("Port refuses to be enabled!\n")); + return(UHIOERR_HOSTERROR); + } + break; + } + + case HCITYPE_OHCI: + { + UWORD ohcihciport = unit->hu_PortNum11[idx - 1]; + UWORD ohciportreg = OHCI_PORTSTATUS + (ohcihciport<<2); + ULONG ohcioldval = READREG32_LE(hc->hc_RegBase, portreg); + KPRINTF(10, ("OHCI Resetting Port (%s)\n", ohcioldval & OHPF_PORTRESET ? "already" : "ok")); + WRITEREG32_LE(chc->hc_RegBase, ohciportreg, OHPF_PORTPOWER|OHPF_PORTRESET); + break; + } + + } + // make enumeration possible + unit->hu_DevControllers[0] = chc; + } else { + newval &= ~EHPF_PORTRESET; + newval |= EHPF_PORTENABLE; + WRITEREG16_LE(hc->hc_RegBase, portreg, newval); + hc->hc_PortChangeMap[hciport] |= UPSF_PORT_RESET; // manually fake reset change + uhwDelayMS(10, unit, base); + cnt = 100; + do + { + uhwDelayMS(1, unit, base); + newval = READREG32_LE(hc->hc_RegBase, portreg) & ~(EHPF_OVERCURRENTCHG|EHPF_ENABLECHANGE|EHPF_CONNECTCHANGE); + } while(--cnt && (!(newval & EHPF_PORTENABLE))); + if(cnt) + { + KPRINTF(10, ("Enabled after %ld ticks\n", 100-cnt)); + } else { + KPRINTF(20, ("Port refuses to be enabled!\n")); + return(UHIOERR_HOSTERROR); + } + // make enumeration possible + unit->hu_DevControllers[0] = hc; + } + cmdgood = TRUE; + break; + + case UFS_PORT_POWER: + KPRINTF(10, ("Powering Port\n")); + newval |= EHPF_PORTPOWER; + cmdgood = TRUE; + break; + + /* case UFS_PORT_LOW_SPEED: not possible */ + /* case UFS_C_PORT_CONNECTION: + case UFS_C_PORT_ENABLE: + case UFS_C_PORT_SUSPEND: + case UFS_C_PORT_OVER_CURRENT: + case UFS_C_PORT_RESET: */ + } + if(cmdgood) + { + KPRINTF(5, ("Port %ld SET_FEATURE %04lx->%04lx\n", idx, oldval, newval)); + WRITEREG32_LE(hc->hc_RegBase, portreg, newval); + return(0); + } + break; + } + } + break; + + case USR_CLEAR_FEATURE: + if((!idx) && (idx > numports)) + { + KPRINTF(20, ("Port %ld out of range\n", idx)); + return(UHIOERR_STALL); + } + if(unit->hu_EhciOwned[idx - 1]) + { + hc = unit->hu_PortMap20[idx - 1]; + hciport = idx - 1; + } else { + hc = unit->hu_PortMap11[idx - 1]; + hciport = unit->hu_PortNum11[idx - 1]; + } + KPRINTF(10, ("Clear Feature %ld maps from glob. Port %ld to local Port %ld\n", val, idx, hciport)); + cmdgood = FALSE; + switch(hc->hc_HCIType) + { + case HCITYPE_UHCI: + { + UWORD portreg = hciport ? UHCI_PORT2STSCTRL : UHCI_PORT1STSCTRL; + ULONG oldval = READREG16_LE(hc->hc_RegBase, portreg) & ~(UHPF_ENABLECHANGE|UHPF_CONNECTCHANGE); // these are clear-on-write! + ULONG newval = oldval; + switch(val) + { + case UFS_PORT_ENABLE: + KPRINTF(10, ("Disabling Port (%s)\n", newval & UHPF_PORTENABLE ? "ok" : "already")); + newval &= ~UHPF_PORTENABLE; + cmdgood = TRUE; + // disable enumeration + unit->hu_DevControllers[0] = NULL; + break; + + case UFS_PORT_SUSPEND: + newval &= ~UHPF_PORTSUSPEND; + cmdgood = TRUE; + break; + + case UFS_PORT_POWER: // ignore for UHCI, there's no power control here + KPRINTF(10, ("Disabling Power\n")); + KPRINTF(10, ("Disabling Port (%s)\n", newval & UHPF_PORTENABLE ? "ok" : "already")); + newval &= ~UHPF_PORTENABLE; + cmdgood = TRUE; + break; + + case UFS_C_PORT_CONNECTION: + newval |= UHPF_CONNECTCHANGE; // clear-on-write! + hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_CONNECTION; + cmdgood = TRUE; + break; + + case UFS_C_PORT_ENABLE: + newval |= UHPF_ENABLECHANGE; // clear-on-write! + hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_ENABLE; + cmdgood = TRUE; + break; + + case UFS_C_PORT_SUSPEND: // ignore for UHCI, there's no bit indicating this + hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_SUSPEND; // manually fake suspend change clearing + cmdgood = TRUE; + break; + + case UFS_C_PORT_OVER_CURRENT: // ignore for UHCI, there's no bit indicating this + hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_OVER_CURRENT; // manually fake over current clearing + cmdgood = TRUE; + break; + + case UFS_C_PORT_RESET: // ignore for UHCI, there's no bit indicating this + hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_RESET; // manually fake reset change clearing + cmdgood = TRUE; + break; + } + if(cmdgood) + { + KPRINTF(5, ("Port %ld CLEAR_FEATURE %04lx->%04lx\n", idx, oldval, newval)); + WRITEREG16_LE(hc->hc_RegBase, portreg, newval); + if(hc->hc_PortChangeMap[hciport]) + { + unit->hu_RootPortChanges |= 1UL<hu_RootPortChanges &= ~(1UL<hc_RegBase, portreg); + + switch(val) + { + case UFS_PORT_ENABLE: + KPRINTF(10, ("Disabling Port (%s)\n", oldval & OHPF_PORTENABLE ? "ok" : "already")); + WRITEREG32_LE(hc->hc_RegBase, portreg, OHPF_PORTDISABLE); + cmdgood = TRUE; + break; + + case UFS_PORT_SUSPEND: + KPRINTF(10, ("Resuming Port (%s)\n", oldval & OHPF_PORTSUSPEND ? "ok" : "already")); + //hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_SUSPEND; // manually fake suspend change + WRITEREG32_LE(hc->hc_RegBase, portreg, OHPF_RESUME); + cmdgood = TRUE; + break; + + case UFS_PORT_POWER: + KPRINTF(10, ("Unpowering Port (%s)\n", oldval & OHPF_PORTPOWER ? "ok" : "already")); + WRITEREG32_LE(hc->hc_RegBase, portreg, OHPF_PORTUNPOWER); + cmdgood = TRUE; + break; + + case UFS_C_PORT_CONNECTION: + WRITEREG32_LE(hc->hc_RegBase, portreg, OHPF_CONNECTCHANGE); + hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_CONNECTION; + cmdgood = TRUE; + break; + + case UFS_C_PORT_ENABLE: + WRITEREG32_LE(hc->hc_RegBase, portreg, OHPF_ENABLECHANGE); + hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_ENABLE; + cmdgood = TRUE; + break; + + case UFS_C_PORT_SUSPEND: + WRITEREG32_LE(hc->hc_RegBase, portreg, OHPF_RESUMEDTX); + hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_SUSPEND; + cmdgood = TRUE; + break; + + case UFS_C_PORT_OVER_CURRENT: + WRITEREG32_LE(hc->hc_RegBase, portreg, OHPF_OVERCURRENTCHG); + hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_OVER_CURRENT; + cmdgood = TRUE; + break; + + case UFS_C_PORT_RESET: + WRITEREG32_LE(hc->hc_RegBase, portreg, OHPF_RESETCHANGE); + hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_RESET; + cmdgood = TRUE; + break; + } + if(cmdgood) + { + return(0); + } + break; + } + + case HCITYPE_EHCI: + { + UWORD portreg = EHCI_PORTSC1 + (hciport<<2); + ULONG oldval = READREG32_LE(hc->hc_RegBase, portreg) & ~(EHPF_OVERCURRENTCHG|EHPF_ENABLECHANGE|EHPF_CONNECTCHANGE); // these are clear-on-write! + ULONG newval = oldval; + switch(val) + { + case UFS_PORT_ENABLE: + KPRINTF(10, ("Disabling Port (%s)\n", newval & EHPF_PORTENABLE ? "ok" : "already")); + newval &= ~EHPF_PORTENABLE; + cmdgood = TRUE; + // disable enumeration + unit->hu_DevControllers[0] = NULL; + break; + + case UFS_PORT_SUSPEND: + newval &= ~EHPF_PORTSUSPEND; + cmdgood = TRUE; + break; + + case UFS_PORT_POWER: // ignore for UHCI, there's no power control here + KPRINTF(10, ("Disabling Power (%s)\n", newval & EHPF_PORTPOWER ? "ok" : "already")); + KPRINTF(10, ("Disabling Port (%s)\n", newval & EHPF_PORTENABLE ? "ok" : "already")); + newval &= ~(EHPF_PORTENABLE|EHPF_PORTPOWER); + cmdgood = TRUE; + break; + + case UFS_C_PORT_CONNECTION: + newval |= EHPF_CONNECTCHANGE; // clear-on-write! + hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_CONNECTION; + cmdgood = TRUE; + break; + + case UFS_C_PORT_ENABLE: + newval |= EHPF_ENABLECHANGE; // clear-on-write! + hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_ENABLE; + cmdgood = TRUE; + break; + + case UFS_C_PORT_SUSPEND: // ignore for EHCI, there's no bit indicating this + hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_SUSPEND; // manually fake suspend change clearing + cmdgood = TRUE; + break; + + case UFS_C_PORT_OVER_CURRENT: + newval |= EHPF_OVERCURRENTCHG; // clear-on-write! + hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_OVER_CURRENT; // manually fake over current clearing + cmdgood = TRUE; + break; + + case UFS_C_PORT_RESET: // ignore for EHCI, there's no bit indicating this + hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_RESET; // manually fake reset change clearing + cmdgood = TRUE; + break; + } + if(cmdgood) + { + KPRINTF(5, ("Port %ld CLEAR_FEATURE %08lx->%08lx\n", idx, oldval, newval)); + WRITEREG32_LE(hc->hc_RegBase, portreg, newval); + if(hc->hc_PortChangeMap[hciport]) + { + unit->hu_RootPortChanges |= 1UL<hu_RootPortChanges &= ~(1UL<iouh_Data; + if(len != sizeof(struct UsbPortStatus)) + { + return(UHIOERR_STALL); + } + if((!idx) && (idx > numports)) + { + KPRINTF(20, ("Port %ld out of range\n", idx)); + return(UHIOERR_STALL); + } + if(unit->hu_EhciOwned[idx - 1]) + { + hc = unit->hu_PortMap20[idx - 1]; + hciport = idx - 1; + } else { + hc = unit->hu_PortMap11[idx - 1]; + hciport = unit->hu_PortNum11[idx - 1]; + } + switch(hc->hc_HCIType) + { + case HCITYPE_UHCI: + { + UWORD portreg = hciport ? UHCI_PORT2STSCTRL : UHCI_PORT1STSCTRL; + UWORD oldval = READREG16_LE(hc->hc_RegBase, portreg); + *mptr = UPSF_PORT_POWER; + if(oldval & UHPF_PORTCONNECTED) *mptr |= UPSF_PORT_CONNECTION; + if(oldval & UHPF_PORTENABLE) *mptr |= UPSF_PORT_ENABLE; + if(oldval & UHPF_LOWSPEED) *mptr |= UPSF_PORT_LOW_SPEED; + if(oldval & UHPF_PORTRESET) *mptr |= UPSF_PORT_RESET; + if(oldval & UHPF_PORTSUSPEND) *mptr |= UPSF_PORT_SUSPEND; + + KPRINTF(5, ("UHCI Port %ld is %s\n", idx, oldval & UHPF_LOWSPEED ? "LOWSPEED" : "FULLSPEED")); + KPRINTF(5, ("UHCI Port %ld Status %08lx\n", idx, *mptr)); + + mptr++; + if(oldval & UHPF_ENABLECHANGE) + { + hc->hc_PortChangeMap[hciport] |= UPSF_PORT_ENABLE; + } + if(oldval & UHPF_CONNECTCHANGE) + { + hc->hc_PortChangeMap[hciport] |= UPSF_PORT_CONNECTION; + } + if(oldval & UHPF_RESUMEDTX) + { + hc->hc_PortChangeMap[hciport] |= UPSF_PORT_SUSPEND|UPSF_PORT_ENABLE; + } + *mptr = hc->hc_PortChangeMap[hciport]; + WRITEREG16_LE(hc->hc_RegBase, portreg, oldval); + KPRINTF(5, ("UHCI Port %ld Change %08lx\n", idx, *mptr)); + return(0); + } + + case HCITYPE_OHCI: + { + UWORD portreg = OHCI_PORTSTATUS + (hciport<<2); + ULONG oldval = READREG32_LE(hc->hc_RegBase, portreg); + + *mptr = 0; + if(oldval & OHPF_PORTPOWER) *mptr |= UPSF_PORT_POWER; + if(oldval & OHPF_OVERCURRENT) *mptr |= UPSF_PORT_OVER_CURRENT; + if(oldval & OHPF_PORTCONNECTED) *mptr |= UPSF_PORT_CONNECTION; + if(oldval & OHPF_PORTENABLE) *mptr |= UPSF_PORT_ENABLE; + if(oldval & OHPF_LOWSPEED) *mptr |= UPSF_PORT_LOW_SPEED; + if(oldval & OHPF_PORTRESET) *mptr |= UPSF_PORT_RESET; + if(oldval & OHPF_PORTSUSPEND) *mptr |= UPSF_PORT_SUSPEND; + + KPRINTF(5, ("OHCI Port %ld (glob. %ld) is %s\n", hciport, idx, oldval & OHPF_LOWSPEED ? "LOWSPEED" : "FULLSPEED")); + KPRINTF(5, ("OHCI Port %ld Status %08lx (%08lx)\n", idx, *mptr, oldval)); + + mptr++; + if(oldval & OHPF_OVERCURRENTCHG) + { + hc->hc_PortChangeMap[hciport] |= UPSF_PORT_OVER_CURRENT; + } + if(oldval & OHPF_RESETCHANGE) + { + hc->hc_PortChangeMap[hciport] |= UPSF_PORT_RESET; + } + if(oldval & OHPF_ENABLECHANGE) + { + hc->hc_PortChangeMap[hciport] |= UPSF_PORT_ENABLE; + } + if(oldval & OHPF_CONNECTCHANGE) + { + hc->hc_PortChangeMap[hciport] |= UPSF_PORT_CONNECTION; + } + if(oldval & OHPF_RESUMEDTX) + { + hc->hc_PortChangeMap[hciport] |= UPSF_PORT_SUSPEND; + } + *mptr = hc->hc_PortChangeMap[hciport]; + KPRINTF(5, ("OHCI Port %ld Change %08lx\n", idx, *mptr)); + return(0); + } + + case HCITYPE_EHCI: + { + UWORD portreg = EHCI_PORTSC1 + (hciport<<2); + ULONG oldval = READREG32_LE(hc->hc_RegBase, portreg); + + *mptr = 0; + if(oldval & EHPF_PORTCONNECTED) *mptr |= UPSF_PORT_CONNECTION; + if(oldval & EHPF_PORTENABLE) *mptr |= UPSF_PORT_ENABLE|UPSF_PORT_HIGH_SPEED; + if((oldval & (EHPF_LINESTATUS_DM|EHPF_PORTCONNECTED|EHPF_PORTENABLE)) == + (EHPF_LINESTATUS_DM|EHPF_PORTCONNECTED)) + { + KPRINTF(10, ("EHCI Port %ld is LOWSPEED\n", idx)); + // we need to detect low speed devices prior to reset + *mptr |= UPSF_PORT_LOW_SPEED; + } + + if(oldval & EHPF_PORTRESET) *mptr |= UPSF_PORT_RESET; + if(oldval & EHPF_PORTSUSPEND) *mptr |= UPSF_PORT_SUSPEND; + if(oldval & EHPF_PORTPOWER) *mptr |= UPSF_PORT_POWER; + if(oldval & EHPM_PORTINDICATOR) *mptr |= UPSF_PORT_INDICATOR; + + KPRINTF(5, ("EHCI Port %ld Status %08lx\n", idx, *mptr)); + + mptr++; + if(oldval & EHPF_ENABLECHANGE) + { + hc->hc_PortChangeMap[hciport] |= UPSF_PORT_ENABLE; + } + if(oldval & EHPF_CONNECTCHANGE) + { + hc->hc_PortChangeMap[hciport] |= UPSF_PORT_CONNECTION; + } + if(oldval & EHPF_RESUMEDTX) + { + hc->hc_PortChangeMap[hciport] |= UPSF_PORT_SUSPEND|UPSF_PORT_ENABLE; + } + if(oldval & EHPF_OVERCURRENTCHG) + { + hc->hc_PortChangeMap[hciport] |= UPSF_PORT_OVER_CURRENT; + } + *mptr = hc->hc_PortChangeMap[hciport]; + WRITEREG32_LE(hc->hc_RegBase, portreg, oldval); + KPRINTF(5, ("EHCI Port %ld Change %08lx\n", idx, *mptr)); + return(0); + } + } + return(0); + } + + } + break; + + case (URTF_IN|URTF_CLASS|URTF_DEVICE): + switch(req) + { + case USR_GET_STATUS: + { + UWORD *mptr = ioreq->iouh_Data; + if(len < sizeof(struct UsbHubStatus)) + { + return(UHIOERR_STALL); + } + *mptr++ = 0; + *mptr++ = 0; + ioreq->iouh_Actual = 4; + return(0); + } + + case USR_GET_DESCRIPTOR: + switch(val>>8) + { + case UDT_HUB: + { + ULONG hubdesclen = 9; + ULONG powergood = 1; + struct UsbHubDesc *uhd = (struct UsbHubDesc *) ioreq->iouh_Data; + KPRINTF(1, ("RH: GetHubDescriptor (%ld)\n", len)); + if(unit->hu_RootHubPorts > 7) // needs two bytes for port masks + { + hubdesclen += 2; + } + ioreq->iouh_Actual = (len > hubdesclen) ? hubdesclen : len; + CopyMem((APTR) &RHHubDesc, ioreq->iouh_Data, ioreq->iouh_Actual); + if(ioreq->iouh_Length) + { + uhd->bLength = hubdesclen; + } + if(ioreq->iouh_Length >= 6) + { + hc = (struct PCIController *) unit->hu_Controllers.lh_Head; + while(hc->hc_Node.ln_Succ) + { + if(hc->hc_HCIType == HCITYPE_OHCI) + { + ULONG localpwgood = READREG32_LE(hc->hc_RegBase, OHCI_HUBDESCA & OHAM_POWERGOOD) >> OHAS_POWERGOOD; + if(localpwgood > powergood) + { + powergood = localpwgood; + KPRINTF(10, ("Increasing power good time to %ld\n", powergood)); + } + } + hc = (struct PCIController *) hc->hc_Node.ln_Succ; + } + + uhd->bPwrOn2PwrGood = powergood; + } + if(ioreq->iouh_Length >= hubdesclen) + { + uhd->bNbrPorts = unit->hu_RootHubPorts; + if(hubdesclen == 9) + { + uhd->DeviceRemovable = 0; + uhd->PortPwrCtrlMask = (1<<(unit->hu_RootHubPorts+2))-2; + } else { + // each field is now 16 bits wide + uhd->DeviceRemovable = 0; + uhd->PortPwrCtrlMask = 0; + ((UBYTE *) ioreq->iouh_Data)[9] = (1<<(unit->hu_RootHubPorts+2))-2; + ((UBYTE *) ioreq->iouh_Data)[10] = ((1<<(unit->hu_RootHubPorts+2))-2)>>8; + } + } + return(0); + } + + default: + KPRINTF(20, ("RH: Unsupported Descriptor %04lx\n", idx)); + } + break; + } + + } + KPRINTF(20, ("RH: Unsupported command %02lx %02lx %04lx %04lx %04lx!\n", rt, req, idx, val, len)); + return(UHIOERR_STALL); +} +/* \\\ */ + +/* /// "cmdIntXFerRootHub()" */ +WORD cmdIntXFerRootHub(struct IOUsbHWReq *ioreq, + struct PCIUnit *unit, + struct PCIDevice *base) +{ + if((ioreq->iouh_Endpoint != 1) || (!ioreq->iouh_Length)) + { + return(UHIOERR_STALL); + } + + if(unit->hu_RootPortChanges) + { + KPRINTF(1, ("Immediate Portchange map %04lx\n", unit->hu_RootPortChanges)); + + if((unit->hu_RootHubPorts < 8) || (ioreq->iouh_Length == 1)) + { + *((UBYTE *) ioreq->iouh_Data) = unit->hu_RootPortChanges; + ioreq->iouh_Actual = 1; + } else { + ((UBYTE *) ioreq->iouh_Data)[0] = unit->hu_RootPortChanges; + ((UBYTE *) ioreq->iouh_Data)[1] = unit->hu_RootPortChanges>>8; + ioreq->iouh_Actual = 2; + } + unit->hu_RootPortChanges = 0; + return(0); + } + ioreq->iouh_Req.io_Flags &= ~IOF_QUICK; + Disable(); + AddTail(&unit->hu_RHIOQueue, (struct Node *) ioreq); + Enable(); + return(RC_DONTREPLY); +} +/* \\\ */ + +/* /// "cmdControlXFer()" */ +/* + *====================================================================== + * cmdControlXFer(ioreq, unit, base) + *====================================================================== + * + * This is the device UHCMD_CONTROLXFER routine. + * + * First it check if the usb is in proper state and if user passed arguments + * are valid. If everything is ok, the request is linked to queue of + * pending transfer requests. + * + */ + +WORD cmdControlXFer(struct IOUsbHWReq *ioreq, + struct PCIUnit *unit, + struct PCIDevice *base) +{ + struct PCIController *hc; + + KPRINTF(10, ("UHCMD_CONTROLXFER ioreq: 0x%08lx\n", ioreq)); + uhwGetUsbState(ioreq, unit, base); + if(!(ioreq->iouh_State & UHSF_OPERATIONAL)) + { + return(UHIOERR_USBOFFLINE); + } + /* Root hub emulation */ + if(ioreq->iouh_DevAddr == unit->hu_RootHubAddr) + { + return(cmdControlXFerRootHub(ioreq, unit, base)); + } + + hc = unit->hu_DevControllers[ioreq->iouh_DevAddr]; + if(!hc) + { + KPRINTF(20, ("No Host controller assigned to device address %ld\n", ioreq->iouh_DevAddr)); + return(UHIOERR_HOSTERROR); + } + + ioreq->iouh_Req.io_Flags &= ~IOF_QUICK; + ioreq->iouh_Actual = 0; + + Disable(); + AddTail(&hc->hc_CtrlXFerQueue, (struct Node *) ioreq); + Enable(); + SureCause(base, &hc->hc_CompleteInt); + + KPRINTF(10, ("UHCMD_CONTROLXFER processed ioreq: 0x%08lx\n", ioreq)); + return(RC_DONTREPLY); +} +/* \\\ */ + +/* /// "cmdBulkXFer()" */ +/* + *====================================================================== + * cmdBulkXFer(ioreq, unit, base) + *====================================================================== + * + * This is the device UHCMD_BULKXFER routine. + * + * First it check if the usb is in proper state and if user passed arguments + * are valid. If everything is ok, the request is linked to queue of + * pending transfer requests. + * + */ + +WORD cmdBulkXFer(struct IOUsbHWReq *ioreq, + struct PCIUnit *unit, + struct PCIDevice *base) +{ + struct PCIController *hc; + + KPRINTF(10, ("UHCMD_BULKXFER ioreq: 0x%08lx\n", ioreq)); + uhwGetUsbState(ioreq, unit, base); + if(!(ioreq->iouh_State & UHSF_OPERATIONAL)) + { + return(UHIOERR_USBOFFLINE); + } + + if(ioreq->iouh_Flags & UHFF_LOWSPEED) + { + return(UHIOERR_BADPARAMS); + } + + hc = unit->hu_DevControllers[ioreq->iouh_DevAddr]; + if(!hc) + { + return(UHIOERR_HOSTERROR); + } + + ioreq->iouh_Req.io_Flags &= ~IOF_QUICK; + ioreq->iouh_Actual = 0; + + Disable(); + AddTail(&hc->hc_BulkXFerQueue, (struct Node *) ioreq); + Enable(); + SureCause(base, &hc->hc_CompleteInt); + + KPRINTF(10, ("UHCMD_BULKXFER processed ioreq: 0x%08lx\n", ioreq)); + return(RC_DONTREPLY); +} +/* \\\ */ + +/* /// "cmdIsoXFer()" */ +/* + *====================================================================== + * cmdIsoXFer(ioreq, unit, base) + *====================================================================== + * + * This is the device UHCMD_ISOXFER routine. + * + * First it check if the usb is in proper state and if user passed arguments + * are valid. If everything is ok, the request is linked to queue of + * pending transfer requests. + * + */ + +WORD cmdIsoXFer(struct IOUsbHWReq *ioreq, + struct PCIUnit *unit, + struct PCIDevice *base) +{ + struct PCIController *hc; + + KPRINTF(10, ("UHCMD_ISOXFER ioreq: 0x%08lx\n", ioreq)); + uhwGetUsbState(ioreq, unit, base); + if(!(ioreq->iouh_State & UHSF_OPERATIONAL)) + { + return(UHIOERR_USBOFFLINE); + } + + if(ioreq->iouh_Flags & UHFF_LOWSPEED) + { + return(UHIOERR_BADPARAMS); + } + + hc = unit->hu_DevControllers[ioreq->iouh_DevAddr]; + if(!hc) + { + return(UHIOERR_HOSTERROR); + } + + ioreq->iouh_Req.io_Flags &= ~IOF_QUICK; + ioreq->iouh_Actual = 0; + + Disable(); + AddTail(&hc->hc_IsoXFerQueue, (struct Node *) ioreq); + Enable(); + SureCause(base, &hc->hc_CompleteInt); + + KPRINTF(10, ("UHCMD_ISOXFER processed ioreq: 0x%08lx\n", ioreq)); + return(RC_DONTREPLY); +} +/* \\\ */ + +/* /// "cmdIntXFer()" */ +/* + *====================================================================== + * cmdIntXFer(ioreq, unit, base) + *====================================================================== + * + * This is the device UHCMD_INTXFER routine. + * + * First it check if the usb is in proper state and if user passed arguments + * are valid. If everything is ok, the request is linked to queue of + * pending transfer requests. + * + */ + +WORD cmdIntXFer(struct IOUsbHWReq *ioreq, + struct PCIUnit *unit, + struct PCIDevice *base) +{ + struct PCIController *hc; + + KPRINTF(10, ("UHCMD_INTXFER ioreq: 0x%08lx\n", ioreq)); + //uhwDelayMS(1000, unit, base); /* Wait 200 ms */ + uhwGetUsbState(ioreq, unit, base); + if(!(ioreq->iouh_State & UHSF_OPERATIONAL)) + { + return(UHIOERR_USBOFFLINE); + } + + /* Root Hub Emulation */ + if(ioreq->iouh_DevAddr == unit->hu_RootHubAddr) + { + return(cmdIntXFerRootHub(ioreq, unit, base)); + } + + hc = unit->hu_DevControllers[ioreq->iouh_DevAddr]; + if(!hc) + { + return(UHIOERR_HOSTERROR); + } + + ioreq->iouh_Req.io_Flags &= ~IOF_QUICK; + ioreq->iouh_Actual = 0; + + Disable(); + AddTail(&hc->hc_IntXFerQueue, (struct Node *) ioreq); + Enable(); + SureCause(base, &hc->hc_CompleteInt); + + KPRINTF(10, ("UHCMD_INTXFER processed ioreq: 0x%08lx\n", ioreq)); + return(RC_DONTREPLY); +} +/* \\\ */ + +/* /// "cmdFlush()" */ +/* + *====================================================================== + * cmdFlush(ioreq, base) + *====================================================================== + * + * This is the device CMD_FLUSH routine. + * + * This routine abort all pending transfer requests. + * + */ + +WORD cmdFlush(struct IOUsbHWReq *ioreq, + struct PCIUnit *unit, + struct PCIDevice *base) +{ + struct IOUsbHWReq *cmpioreq; + struct PCIController *hc; + UWORD devadrep; + + KPRINTF(10, ("CMD_FLUSH ioreq: 0x%08lx\n", ioreq)); + + Disable(); + cmpioreq = (struct IOUsbHWReq *) unit->hu_RHIOQueue.lh_Head; + while(((struct Node *) cmpioreq)->ln_Succ) + { + Remove(&cmpioreq->iouh_Req.io_Message.mn_Node); + cmpioreq->iouh_Req.io_Error = IOERR_ABORTED; + ReplyMsg(&cmpioreq->iouh_Req.io_Message); + cmpioreq = (struct IOUsbHWReq *) unit->hu_RHIOQueue.lh_Head; + } + hc = (struct PCIController *) unit->hu_Controllers.lh_Head; + while(hc->hc_Node.ln_Succ) + { + cmpioreq = (struct IOUsbHWReq *) hc->hc_CtrlXFerQueue.lh_Head; + while(((struct Node *) cmpioreq)->ln_Succ) + { + Remove(&cmpioreq->iouh_Req.io_Message.mn_Node); + cmpioreq->iouh_Req.io_Error = IOERR_ABORTED; + ReplyMsg(&cmpioreq->iouh_Req.io_Message); + cmpioreq = (struct IOUsbHWReq *) hc->hc_CtrlXFerQueue.lh_Head; + } + cmpioreq = (struct IOUsbHWReq *) hc->hc_IntXFerQueue.lh_Head; + while(((struct Node *) cmpioreq)->ln_Succ) + { + Remove(&cmpioreq->iouh_Req.io_Message.mn_Node); + cmpioreq->iouh_Req.io_Error = IOERR_ABORTED; + ReplyMsg(&cmpioreq->iouh_Req.io_Message); + cmpioreq = (struct IOUsbHWReq *) hc->hc_IntXFerQueue.lh_Head; + } + cmpioreq = (struct IOUsbHWReq *) hc->hc_IsoXFerQueue.lh_Head; + while(((struct Node *) cmpioreq)->ln_Succ) + { + Remove(&cmpioreq->iouh_Req.io_Message.mn_Node); + cmpioreq->iouh_Req.io_Error = IOERR_ABORTED; + ReplyMsg(&cmpioreq->iouh_Req.io_Message); + cmpioreq = (struct IOUsbHWReq *) hc->hc_IsoXFerQueue.lh_Head; + } + cmpioreq = (struct IOUsbHWReq *) hc->hc_BulkXFerQueue.lh_Head; + while(((struct Node *) cmpioreq)->ln_Succ) + { + Remove(&cmpioreq->iouh_Req.io_Message.mn_Node); + cmpioreq->iouh_Req.io_Error = IOERR_ABORTED; + ReplyMsg(&cmpioreq->iouh_Req.io_Message); + cmpioreq = (struct IOUsbHWReq *) hc->hc_BulkXFerQueue.lh_Head; + } + switch(hc->hc_HCIType) + { + case HCITYPE_UHCI: + cmpioreq = (struct IOUsbHWReq *) hc->hc_TDQueue.lh_Head; + while(((struct Node *) cmpioreq)->ln_Succ) + { + Remove(&cmpioreq->iouh_Req.io_Message.mn_Node); + devadrep = (cmpioreq->iouh_DevAddr<<5) + cmpioreq->iouh_Endpoint + ((cmpioreq->iouh_Dir == UHDIR_IN) ? 0x10 : 0); + unit->hu_DevBusyReq[devadrep] = NULL; + uhciFreeQContext(hc, (struct UhciQH *) cmpioreq->iouh_DriverPrivate1); + cmpioreq->iouh_Req.io_Error = IOERR_ABORTED; + ReplyMsg(&cmpioreq->iouh_Req.io_Message); + cmpioreq = (struct IOUsbHWReq *) hc->hc_TDQueue.lh_Head; + } + break; + + case HCITYPE_EHCI: + cmpioreq = (struct IOUsbHWReq *) hc->hc_TDQueue.lh_Head; + while(((struct Node *) cmpioreq)->ln_Succ) + { + Remove(&cmpioreq->iouh_Req.io_Message.mn_Node); + devadrep = (cmpioreq->iouh_DevAddr<<5) + cmpioreq->iouh_Endpoint + ((cmpioreq->iouh_Dir == UHDIR_IN) ? 0x10 : 0); + unit->hu_DevBusyReq[devadrep] = NULL; + ehciFreeAsyncContext(hc, (struct EhciQH *) cmpioreq->iouh_DriverPrivate1); + cmpioreq->iouh_Req.io_Error = IOERR_ABORTED; + ReplyMsg(&cmpioreq->iouh_Req.io_Message); + cmpioreq = (struct IOUsbHWReq *) hc->hc_TDQueue.lh_Head; + } + cmpioreq = (struct IOUsbHWReq *) hc->hc_PeriodicTDQueue.lh_Head; + while(((struct Node *) cmpioreq)->ln_Succ) + { + Remove(&cmpioreq->iouh_Req.io_Message.mn_Node); + devadrep = (cmpioreq->iouh_DevAddr<<5) + cmpioreq->iouh_Endpoint + ((cmpioreq->iouh_Dir == UHDIR_IN) ? 0x10 : 0); + unit->hu_DevBusyReq[devadrep] = NULL; + ehciFreePeriodicContext(hc, (struct EhciQH *) cmpioreq->iouh_DriverPrivate1); + cmpioreq->iouh_Req.io_Error = IOERR_ABORTED; + ReplyMsg(&cmpioreq->iouh_Req.io_Message); + cmpioreq = (struct IOUsbHWReq *) hc->hc_PeriodicTDQueue.lh_Head; + } + break; + } + hc = (struct PCIController *) hc->hc_Node.ln_Succ; + } + Enable(); + /* Return success + */ + return RC_OK; +} +/* \\\ */ + +/* /// "NSD stuff" */ + +static +const UWORD NSDSupported[] = +{ + CMD_FLUSH, CMD_RESET, + UHCMD_QUERYDEVICE, UHCMD_USBRESET, + UHCMD_USBRESUME, UHCMD_USBSUSPEND, + UHCMD_USBOPER, UHCMD_CONTROLXFER , + UHCMD_ISOXFER, UHCMD_INTXFER, + UHCMD_BULKXFER, + NSCMD_DEVICEQUERY, 0 +}; + +WORD cmdNSDeviceQuery(struct IOStdReq *ioreq, + struct PCIUnit *unit, + struct PCIDevice *base) +{ + struct my_NSDeviceQueryResult *query; + + query = (struct my_NSDeviceQueryResult *) ioreq->io_Data; + + KPRINTF(10, ("NSCMD_DEVICEQUERY ioreq: 0x%08lx query: 0x%08lx\n", ioreq, query)); + + /* NULL ptr? + Enough data? + Valid request? + */ + if((!query) || + (ioreq->io_Length < sizeof(struct my_NSDeviceQueryResult)) || + (query->DevQueryFormat != 0) || + (query->SizeAvailable != 0)) + { + /* Return error. This is special handling, since iorequest is only + guaranteed to be sizeof(struct IOStdReq). If we'd let our + devBeginIO dispatcher return the error, it would trash some + memory past end of the iorequest (ios2_WireError field). + */ + ioreq->io_Error = IOERR_NOCMD; + TermIO((struct IOUsbHWReq *) ioreq, base); + + /* Don't reply, we already did. + */ + return RC_DONTREPLY; + } + + ioreq->io_Actual = query->SizeAvailable + = sizeof(struct my_NSDeviceQueryResult); + query->DeviceType = NSDEVTYPE_USBHARDWARE; + query->DeviceSubType = 0; + query->SupportedCommands = NSDSupported; + + /* Return success (note that this will NOT poke ios2_WireError). + */ + return RC_OK; +} +/* \\\ */ + +/* /// "TermIO()" */ +/* + *=========================================================== + * TermIO(ioreq, base) + *=========================================================== + * + * Return completed ioreq to sender. + * + */ + +void TermIO(struct IOUsbHWReq *ioreq, + struct PCIDevice *base) +{ + ioreq->iouh_Req.io_Message.mn_Node.ln_Type = NT_FREEMSG; + + /* If not quick I/O, reply the message + */ + if(!(ioreq->iouh_Req.io_Flags & IOF_QUICK)) + { + ReplyMsg(&ioreq->iouh_Req.io_Message); + } +} +/* \\\ */ + +/* /// "cmdAbortIO()" */ +BOOL cmdAbortIO(struct IOUsbHWReq *ioreq, struct PCIDevice *base) +{ + struct PCIUnit *unit = (struct PCIUnit *) ioreq->iouh_Req.io_Unit; + struct IOUsbHWReq *cmpioreq; + struct PCIController *hc; + UWORD devadrep; + BOOL foundit = FALSE; + + KPRINTF(10, ("cmdAbort(%08lx)\n", ioreq)); + + Disable(); + cmpioreq = (struct IOUsbHWReq *) unit->hu_RHIOQueue.lh_Head; + while(((struct Node *) cmpioreq)->ln_Succ) + { + if(ioreq == cmpioreq) + { + Remove(&ioreq->iouh_Req.io_Message.mn_Node); + Enable(); + return TRUE; + } + cmpioreq = (struct IOUsbHWReq *) cmpioreq->iouh_Req.io_Message.mn_Node.ln_Succ; + } + + hc = (struct PCIController *) unit->hu_Controllers.lh_Head; + while(hc->hc_Node.ln_Succ) + { + cmpioreq = (struct IOUsbHWReq *) hc->hc_CtrlXFerQueue.lh_Head; + while(((struct Node *) cmpioreq)->ln_Succ) + { + if(ioreq == cmpioreq) + { + foundit = TRUE; + break; + } + cmpioreq = (struct IOUsbHWReq *) cmpioreq->iouh_Req.io_Message.mn_Node.ln_Succ; + } + if(!foundit) + { + cmpioreq = (struct IOUsbHWReq *) hc->hc_IntXFerQueue.lh_Head; + while(((struct Node *) cmpioreq)->ln_Succ) + { + if(ioreq == cmpioreq) + { + foundit = TRUE; + break; + } + cmpioreq = (struct IOUsbHWReq *) cmpioreq->iouh_Req.io_Message.mn_Node.ln_Succ; + } + } + if(!foundit) + { + cmpioreq = (struct IOUsbHWReq *) hc->hc_IsoXFerQueue.lh_Head; + while(((struct Node *) cmpioreq)->ln_Succ) + { + if(ioreq == cmpioreq) + { + foundit = TRUE; + break; + } + cmpioreq = (struct IOUsbHWReq *) cmpioreq->iouh_Req.io_Message.mn_Node.ln_Succ; + } + } + if(!foundit) + { + cmpioreq = (struct IOUsbHWReq *) hc->hc_BulkXFerQueue.lh_Head; + while(((struct Node *) cmpioreq)->ln_Succ) + { + if(ioreq == cmpioreq) + { + foundit = TRUE; + break; + } + cmpioreq = (struct IOUsbHWReq *) cmpioreq->iouh_Req.io_Message.mn_Node.ln_Succ; + } + } + if(foundit) + { + Remove(&ioreq->iouh_Req.io_Message.mn_Node); + break; + } else { + // IOReq is probably pending in some transfer structure + devadrep = (ioreq->iouh_DevAddr<<5) + ioreq->iouh_Endpoint + ((ioreq->iouh_Dir == UHDIR_IN) ? 0x10 : 0); + switch(hc->hc_HCIType) + { + case HCITYPE_UHCI: + cmpioreq = (struct IOUsbHWReq *) hc->hc_TDQueue.lh_Head; + while(((struct Node *) cmpioreq)->ln_Succ) + { + if(ioreq == cmpioreq) + { + foundit = TRUE; + unit->hu_DevBusyReq[devadrep] = NULL; + uhciFreeQContext(hc, (struct UhciQH *) ioreq->iouh_DriverPrivate1); + break; + } + cmpioreq = (struct IOUsbHWReq *) cmpioreq->iouh_Req.io_Message.mn_Node.ln_Succ; + } + break; + + case HCITYPE_OHCI: + cmpioreq = (struct IOUsbHWReq *) hc->hc_TDQueue.lh_Head; + while(((struct Node *) cmpioreq)->ln_Succ) + { + if(ioreq == cmpioreq) + { + foundit = TRUE; + unit->hu_DevBusyReq[devadrep] = NULL; + ohciFreeEDContext(hc, (struct OhciED *) ioreq->iouh_DriverPrivate1); + break; + } + cmpioreq = (struct IOUsbHWReq *) cmpioreq->iouh_Req.io_Message.mn_Node.ln_Succ; + } + break; + + case HCITYPE_EHCI: + cmpioreq = (struct IOUsbHWReq *) hc->hc_TDQueue.lh_Head; + while(((struct Node *) cmpioreq)->ln_Succ) + { + if(ioreq == cmpioreq) + { + foundit = TRUE; + unit->hu_DevBusyReq[devadrep] = NULL; + ehciFreeAsyncContext(hc, (struct EhciQH *) ioreq->iouh_DriverPrivate1); + break; + } + cmpioreq = (struct IOUsbHWReq *) cmpioreq->iouh_Req.io_Message.mn_Node.ln_Succ; + } + cmpioreq = (struct IOUsbHWReq *) hc->hc_PeriodicTDQueue.lh_Head; + while(((struct Node *) cmpioreq)->ln_Succ) + { + if(ioreq == cmpioreq) + { + foundit = TRUE; + unit->hu_DevBusyReq[devadrep] = NULL; + ehciFreePeriodicContext(hc, (struct EhciQH *) ioreq->iouh_DriverPrivate1); + break; + } + cmpioreq = (struct IOUsbHWReq *) cmpioreq->iouh_Req.io_Message.mn_Node.ln_Succ; + } + break; + } + if(foundit) + { + Remove(&ioreq->iouh_Req.io_Message.mn_Node); + break; + } + } + hc = (struct PCIController *) hc->hc_Node.ln_Succ; + } + Enable(); + if(!foundit) + { + KPRINTF(20, ("WARNING, could not abort unknown IOReq %08lx\n", ioreq)); + } + return(foundit); +} +/* \\\ */ + +/* /// "uhwCheckRootHubChanges()" */ +void uhwCheckRootHubChanges(struct PCIUnit *unit) +{ + struct IOUsbHWReq *ioreq; + + if(unit->hu_RootPortChanges && unit->hu_RHIOQueue.lh_Head->ln_Succ) + { + KPRINTF(1, ("Portchange map %04lx\n", unit->hu_RootPortChanges)); + Disable(); + ioreq = (struct IOUsbHWReq *) unit->hu_RHIOQueue.lh_Head; + while(((struct Node *) ioreq)->ln_Succ) + { + Remove(&ioreq->iouh_Req.io_Message.mn_Node); + if((ioreq->iouh_Length > 0) || (unit->hu_RootHubPorts < 8)) + { + *((UBYTE *) ioreq->iouh_Data) = unit->hu_RootPortChanges; + ioreq->iouh_Actual = 1; + } + else if(ioreq->iouh_Length > 1) + { + ((UBYTE *) ioreq->iouh_Data)[0] = unit->hu_RootPortChanges; + ((UBYTE *) ioreq->iouh_Data)[1] = unit->hu_RootPortChanges>>8; + ioreq->iouh_Actual = 2; + } + + ReplyMsg(&ioreq->iouh_Req.io_Message); + ioreq = (struct IOUsbHWReq *) unit->hu_RHIOQueue.lh_Head; + } + unit->hu_RootPortChanges = 0; + Enable(); + } +} +/* \\\ */ + +/* /// "uhwCheckSpecialCtrlTransfers()" */ +void uhwCheckSpecialCtrlTransfers(struct PCIController *hc, struct IOUsbHWReq *ioreq) +{ + struct PCIUnit *unit = hc->hc_Unit; + + /* Clear Feature(Endpoint halt) */ + if((ioreq->iouh_SetupData.bmRequestType == (URTF_STANDARD|URTF_ENDPOINT)) && + (ioreq->iouh_SetupData.bRequest == USR_CLEAR_FEATURE) && + (ioreq->iouh_SetupData.wValue == AROS_WORD2LE(UFS_ENDPOINT_HALT))) + { + KPRINTF(10, ("Resetting toggle bit for endpoint %ld\n", AROS_WORD2LE(ioreq->iouh_SetupData.wIndex) & 0xf)); + unit->hu_DevDataToggle[(ioreq->iouh_DevAddr<<5)|(AROS_WORD2LE(ioreq->iouh_SetupData.wIndex) & 0xf)|((AROS_WORD2LE(ioreq->iouh_SetupData.wIndex) & 0x80)>>3)] = 0; + } + else if((ioreq->iouh_SetupData.bmRequestType == (URTF_STANDARD|URTF_DEVICE)) && + (ioreq->iouh_SetupData.bRequest == USR_SET_ADDRESS)) + { + /* Set Address -> clear all endpoints */ + ULONG epnum; + ULONG adr = ioreq->iouh_SetupData.wValue>>3; + KPRINTF(10, ("Resetting toggle bits for device address %ld\n", adr>>5)); + for(epnum = 0; epnum < 31; epnum++) + { + unit->hu_DevDataToggle[adr+epnum] = 0; + } + // transfer host controller ownership + unit->hu_DevControllers[ioreq->iouh_DevAddr] = NULL; + unit->hu_DevControllers[adr>>5] = hc; + } + else if((ioreq->iouh_SetupData.bmRequestType == (URTF_CLASS|URTF_OTHER)) && + (ioreq->iouh_SetupData.bRequest == USR_SET_FEATURE) && + (ioreq->iouh_SetupData.wValue == AROS_WORD2LE(UFS_PORT_RESET))) + { + // a hub will be enumerating a device on this host controller soon! + KPRINTF(10, ("Hub RESET caught, assigning Dev0 to %08lx!\n", hc)); + unit->hu_DevControllers[0] = hc; + } +} +/* \\\ */ + +/* ---------------------------------------------------------------------- * + * UHCI Specific Stuff * + * ---------------------------------------------------------------------- */ + +/* /// "uhciFreeQContext()" */ +void uhciFreeQContext(struct PCIController *hc, struct UhciQH *uqh) +{ + struct UhciTD *utd = NULL; + struct UhciTD *nextutd; + + KPRINTF(5, ("Unlinking QContext %08lx\n", uqh)); + // unlink from schedule + uqh->uqh_Pred->uxx_Link = uqh->uqh_Succ->uxx_Self; + SYNC; + EIEIO; + uqh->uqh_Succ->uxx_Pred = uqh->uqh_Pred; + uqh->uqh_Pred->uxx_Succ = uqh->uqh_Succ; + SYNC; + EIEIO; + + nextutd = uqh->uqh_FirstTD; + while(nextutd) + { + KPRINTF(1, ("FreeTD %08lx\n", nextutd)); + utd = nextutd; + nextutd = (struct UhciTD *) utd->utd_Succ; + uhciFreeTD(hc, utd); + } + uhciFreeQH(hc, uqh); +} +/* \\\ */ + +/* /// "uhciAllocQH()" */ +inline struct UhciQH * uhciAllocQH(struct PCIController *hc) +{ + struct UhciQH *uqh = hc->hc_UhciQHPool; + + if(!uqh) + { + // out of QHs! + KPRINTF(20, ("Out of QHs!\n")); + return NULL; + } + + hc->hc_UhciQHPool = (struct UhciQH *) uqh->uqh_Succ; + return(uqh); +} +/* \\\ */ + +/* /// "uhciFreeQH()" */ +inline void uhciFreeQH(struct PCIController *hc, struct UhciQH *uqh) +{ + uqh->uqh_Succ = (struct UhciXX *) hc->hc_UhciQHPool; + hc->hc_UhciQHPool = uqh; +} +/* \\\ */ + +/* /// "uhciAllocTD()" */ +inline struct UhciTD * uhciAllocTD(struct PCIController *hc) +{ + struct UhciTD *utd = hc->hc_UhciTDPool; + + if(!utd) + { + // out of TDs! + KPRINTF(20, ("Out of TDs!\n")); + return NULL; + } + + hc->hc_UhciTDPool = (struct UhciTD *) utd->utd_Succ; + return(utd); +} +/* \\\ */ + +/* /// "uhciFreeTD()" */ +inline void uhciFreeTD(struct PCIController *hc, struct UhciTD *utd) +{ + utd->utd_Succ = (struct UhciXX *) hc->hc_UhciTDPool; + hc->hc_UhciTDPool = utd; +} +/* \\\ */ + +/* /// "uhciUpdateIntTree()" */ +void uhciUpdateIntTree(struct PCIController *hc) +{ + struct UhciXX *uxx; + struct UhciXX *preduxx; + struct UhciXX *lastuseduxx; + UWORD cnt; + + // optimize linkage between queue heads + preduxx = lastuseduxx = (struct UhciXX *) hc->hc_UhciCtrlQH; //hc->hc_UhciIsoTD; + for(cnt = 0; cnt < 9; cnt++) + { + uxx = (struct UhciXX *) hc->hc_UhciIntQH[cnt]; + if(uxx->uxx_Succ != preduxx) + { + lastuseduxx = uxx->uxx_Succ; + } + uxx->uxx_Link = lastuseduxx->uxx_Self; + preduxx = uxx; + } +} +/* \\\ */ + +/* /// "uhciCheckPortStatusChange()" */ +void uhciCheckPortStatusChange(struct PCIController *hc) +{ + struct PCIUnit *unit = hc->hc_Unit; + UWORD oldval; + UWORD hciport; + + // check for port status change for UHCI and frame rollovers + + for(hciport = 0; hciport < 2; hciport++) + { + UWORD portreg; + UWORD idx = hc->hc_PortNum20[hciport]; + // don't pay attention to UHCI port changes when pwned by EHCI + if(!unit->hu_EhciOwned[idx]) + { + portreg = hciport ? UHCI_PORT2STSCTRL : UHCI_PORT1STSCTRL; + oldval = READREG16_LE(hc->hc_RegBase, portreg); + if(oldval & UHPF_ENABLECHANGE) + { + KPRINTF(10, ("Port %ld (%ld) Enable changed\n", idx, hciport)); + hc->hc_PortChangeMap[hciport] |= UPSF_PORT_ENABLE; + } + if(oldval & UHPF_CONNECTCHANGE) + { + KPRINTF(10, ("Port %ld (%ld) Connect changed\n", idx, hciport)); + hc->hc_PortChangeMap[hciport] |= UPSF_PORT_CONNECTION; + if(!(oldval & UHPF_PORTCONNECTED)) + { + if(unit->hu_PortMap20[idx]) + { + KPRINTF(20, ("Transferring Port %ld back to EHCI\n", idx)); + unit->hu_EhciOwned[idx] = TRUE; + } + } + } + if(oldval & UHPF_RESUMEDTX) + { + KPRINTF(10, ("Port %ld (%ld) Resume changed\n", idx, hciport)); + hc->hc_PortChangeMap[hciport] |= UPSF_PORT_SUSPEND|UPSF_PORT_ENABLE; + oldval &= ~UHPF_RESUMEDTX; + } + if(hc->hc_PortChangeMap[hciport]) + { + unit->hu_RootPortChanges |= 1UL<<(idx+1); + /*KPRINTF(10, ("Port %ld (%ld) contributes %04lx to portmap %04lx\n", + idx, hciport, hc->hc_PortChangeMap[hciport], unit->hu_RootPortChanges));*/ + } + WRITEREG16_LE(hc->hc_RegBase, portreg, oldval); + } + } +} +/* \\\ */ + +/* /// "uhciHandleFinishedTDs()" */ +void uhciHandleFinishedTDs(struct PCIController *hc) +{ + struct PCIUnit *unit = hc->hc_Unit; + struct IOUsbHWReq *ioreq; + struct IOUsbHWReq *nextioreq; + struct UhciQH *uqh; + struct UhciTD *utd; + UWORD devadrep; + ULONG len; + ULONG linkelem; + UWORD inspect; + BOOL shortpkt; + ULONG ctrlstatus; + ULONG token = 0; + ULONG actual; + BOOL updatetree = FALSE; + + KPRINTF(1, ("Checking for work done...\n")); + ioreq = (struct IOUsbHWReq *) hc->hc_TDQueue.lh_Head; + while((nextioreq = (struct IOUsbHWReq *) ((struct Node *) ioreq)->ln_Succ)) + { + uqh = (struct UhciQH *) ioreq->iouh_DriverPrivate1; + if(uqh) + { + KPRINTF(1, ("Examining IOReq=%08lx with UQH=%08lx\n", ioreq, uqh)); + linkelem = READMEM32_LE(&uqh->uqh_Element); + inspect = 0; + devadrep = (ioreq->iouh_DevAddr<<5) + ioreq->iouh_Endpoint + ((ioreq->iouh_Dir == UHDIR_IN) ? 0x10 : 0); + if(linkelem & UHCI_TERMINATE) + { + KPRINTF(1, ("UQH terminated %08lx\n", linkelem)); + inspect = 2; + } else { + utd = (struct UhciTD *) ((linkelem & UHCI_PTRMASK) - hc->hc_PCIVirtualAdjust - 16); // struct UhciTD starts 16 bytes before physical TD + ctrlstatus = READMEM32_LE(&utd->utd_CtrlStatus); + if(!(ctrlstatus & UTCF_ACTIVE)) + { + KPRINTF(1, ("CtrlStatus inactive %08lx\n", ctrlstatus)); + inspect = 1; + } + else if(unit->hu_NakTimeoutFrame[devadrep] && (hc->hc_FrameCounter > unit->hu_NakTimeoutFrame[devadrep])) + { + ioreq->iouh_Req.io_Error = UHIOERR_NAKTIMEOUT; + inspect = 1; + } + } + if(inspect) + { + shortpkt = FALSE; + if(inspect < 2) // if all went okay, don't traverse list, assume all bytes successfully transferred + { + utd = uqh->uqh_FirstTD; + actual = 0; + do + { + ctrlstatus = READMEM32_LE(&utd->utd_CtrlStatus); + if(ctrlstatus & UTCF_ACTIVE) + { + KPRINTF(20, ("Internal error! Still active?!\n")); + if(ctrlstatus & UTSF_BABBLE) + { + KPRINTF(200, ("HOST CONTROLLER IS DEAD!!!\n")); + ioreq->iouh_Req.io_Error = UHIOERR_HOSTERROR; + CONSTWRITEREG16_LE(hc->hc_RegBase, UHCI_USBCMD, UHCF_HCRESET|UHCF_MAXPACKET64|UHCF_CONFIGURE|UHCF_RUNSTOP); + inspect = 0; + break; + } + break; + } + token = READMEM32_LE(&utd->utd_Token); + KPRINTF(1, ("TD=%08lx CS=%08lx Token=%08lx\n", utd, ctrlstatus, token)); + if(ctrlstatus & (UTSF_BABBLE|UTSF_STALLED|UTSF_CRCTIMEOUT|UTSF_DATABUFFERERR|UTSF_BITSTUFFERR)) + { + if(ctrlstatus & UTSF_BABBLE) + { + KPRINTF(20, ("Babble error %08lx/%08lx\n", ctrlstatus, token)); + ioreq->iouh_Req.io_Error = UHIOERR_OVERFLOW; +#if 0 + // VIA chipset seems to die on babble!?! + KPRINTF(10, ("HW Regs USBCMD=%04lx\n", READREG16_LE(hc->hc_RegBase, UHCI_USBCMD))); + CONSTWRITEREG16_LE(hc->hc_RegBase, UHCI_USBCMD, UHCF_MAXPACKET64|UHCF_CONFIGURE|UHCF_RUNSTOP); + SYNC; + EIEIO; +#endif + //retry + //ctrlstatus &= ~(UTSF_BABBLE|UTSF_STALLED|UTSF_CRCTIMEOUT|UTSF_DATABUFFERERR|UTSF_BITSTUFFERR|UTSF_NAK); + ctrlstatus |= UTCF_ACTIVE; + WRITEMEM32_LE(&utd->utd_CtrlStatus, ctrlstatus); + SYNC; + EIEIO; + inspect = 3; + break; + } + else if(ctrlstatus & UTSF_CRCTIMEOUT) + { + KPRINTF(20, ("CRC/Timeout error IOReq=%08lx DIR=%ld\n", ioreq, ioreq->iouh_Dir)); + if(ctrlstatus & UTSF_STALLED) + { + ioreq->iouh_Req.io_Error = UHIOERR_TIMEOUT; + } else { + ioreq->iouh_Req.io_Error = (ioreq->iouh_Dir == UHDIR_IN) ? UHIOERR_CRCERROR : UHIOERR_TIMEOUT; + } + } + else if(ctrlstatus & UTSF_STALLED) + { + KPRINTF(20, ("STALLED!\n")); + ioreq->iouh_Req.io_Error = UHIOERR_STALL; + } + else if(ctrlstatus & UTSF_BITSTUFFERR) + { + KPRINTF(20, ("Bitstuff error\n")); + ioreq->iouh_Req.io_Error = UHIOERR_CRCERROR; + } + else if(ctrlstatus & UTSF_DATABUFFERERR) + { + KPRINTF(20, ("Databuffer error\n")); + ioreq->iouh_Req.io_Error = UHIOERR_HOSTERROR; + } + inspect = 0; + break; + } + if(unit->hu_NakTimeoutFrame[devadrep] && (hc->hc_FrameCounter > unit->hu_NakTimeoutFrame[devadrep]) && (ctrlstatus & UTSF_NAK)) + { + ioreq->iouh_Req.io_Error = UHIOERR_NAKTIMEOUT; + inspect = 0; + } + + len = (ctrlstatus & UTSM_ACTUALLENGTH)>>UTSS_ACTUALLENGTH; + if((len != (token & UTTM_TRANSLENGTH)>>UTTS_TRANSLENGTH)) + { + shortpkt = TRUE; + } + len = (len+1) & 0x7ff; // get real length + if((token & UTTM_PID)>>UTTS_PID != PID_SETUP) // don't count setup packet + { + actual += len; + } + if(shortpkt) + { + break; + } + } while((utd = (struct UhciTD *) utd->utd_Succ)); + if(inspect == 3) + { + // bail out from babble + ioreq = (struct IOUsbHWReq *) ((struct Node *) ioreq)->ln_Succ; + continue; + } + if((actual < uqh->uqh_Actual) && (!ioreq->iouh_Req.io_Error) && (!(ioreq->iouh_Flags & UHFF_ALLOWRUNTPKTS))) + { + KPRINTF(10, ("Short packet: %ld < %ld\n", actual, ioreq->iouh_Length)); + ioreq->iouh_Req.io_Error = UHIOERR_RUNTPACKET; + } + ioreq->iouh_Actual += actual; + } else { + KPRINTF(10, ("all %ld bytes transferred\n", uqh->uqh_Actual)); + ioreq->iouh_Actual += uqh->uqh_Actual; + } + // this is actually no short packet but result of the VIA babble fix + if(shortpkt && (ioreq->iouh_Actual == ioreq->iouh_Length)) + { + shortpkt = FALSE; + } + unit->hu_DevBusyReq[devadrep] = NULL; + Remove(&ioreq->iouh_Req.io_Message.mn_Node); + uhciFreeQContext(hc, uqh); + if(ioreq->iouh_Req.io_Command == UHCMD_INTXFER) + { + updatetree = TRUE; + } + if(inspect) + { + if(inspect < 2) // otherwise, toggle will be right already + { + // use next data toggle bit based on last successful transaction + unit->hu_DevDataToggle[devadrep] = (token & UTTF_DATA1) ? FALSE : TRUE; + } + if(!shortpkt && (ioreq->iouh_Actual < ioreq->iouh_Length)) + { + // fragmented, do some more work + switch(ioreq->iouh_Req.io_Command) + { + case UHCMD_CONTROLXFER: + KPRINTF(10, ("Rescheduling CtrlTransfer at %ld of %ld\n", ioreq->iouh_Actual, ioreq->iouh_Length)); + AddHead(&hc->hc_CtrlXFerQueue, (struct Node *) ioreq); + break; + + case UHCMD_INTXFER: + KPRINTF(10, ("Rescheduling IntTransfer at %ld of %ld\n", ioreq->iouh_Actual, ioreq->iouh_Length)); + AddHead(&hc->hc_IntXFerQueue, (struct Node *) ioreq); + break; + + case UHCMD_BULKXFER: + KPRINTF(10, ("Rescheduling BulkTransfer at %ld of %ld\n", ioreq->iouh_Actual, ioreq->iouh_Length)); + AddHead(&hc->hc_BulkXFerQueue, (struct Node *) ioreq); + break; + + default: + KPRINTF(10, ("Uhm, internal error, dunno where to queue this req\n")); + ReplyMsg(&ioreq->iouh_Req.io_Message); + } + } else { + // check for sucessful clear feature and set address ctrl transfers + if(ioreq->iouh_Req.io_Command == UHCMD_CONTROLXFER) + { + uhwCheckSpecialCtrlTransfers(hc, ioreq); + } + ReplyMsg(&ioreq->iouh_Req.io_Message); + } + } else { + // be sure to save the data toggle bit where the error occurred + unit->hu_DevDataToggle[devadrep] = (token & UTTF_DATA1) ? TRUE : FALSE; + ReplyMsg(&ioreq->iouh_Req.io_Message); + } + } + } else { + KPRINTF(20, ("IOReq=%08lx has no UQH!\n", ioreq)); + } + ioreq = nextioreq; + } + if(updatetree) + { + KPRINTF(10, ("Updating Tree\n")); + uhciUpdateIntTree(hc); + } +} +/* \\\ */ + +/* /// "uhciScheduleCtrlTDs()" */ +void uhciScheduleCtrlTDs(struct PCIController *hc) +{ + struct PCIUnit *unit = hc->hc_Unit; + struct IOUsbHWReq *ioreq; + UWORD devadrep; + struct UhciQH *uqh; + struct UhciTD *setuputd; + struct UhciTD *datautd; + struct UhciTD *termutd; + struct UhciTD *predutd; + ULONG actual; + ULONG ctrlstatus; + ULONG token; + ULONG len; + ULONG phyaddr; + BOOL cont; + + /* *** CTRL Transfers *** */ + KPRINTF(1, ("Scheduling new CTRL transfers...\n")); + ioreq = (struct IOUsbHWReq *) hc->hc_CtrlXFerQueue.lh_Head; + while(((struct Node *) ioreq)->ln_Succ) + { + devadrep = (ioreq->iouh_DevAddr<<5) + ioreq->iouh_Endpoint; + KPRINTF(10, ("New CTRL transfer to %ld.%ld: %ld bytes\n", ioreq->iouh_DevAddr, ioreq->iouh_Endpoint, ioreq->iouh_Length)); + /* is endpoint already in use or do we have to wait for next transaction */ + if(unit->hu_DevBusyReq[devadrep]) + { + KPRINTF(5, ("Endpoint %02lx in use!\n", devadrep)); + ioreq = (struct IOUsbHWReq *) ((struct Node *) ioreq)->ln_Succ; + continue; + } + + uqh = uhciAllocQH(hc); + if(!uqh) + { + break; + } + + setuputd = uhciAllocTD(hc); + if(!setuputd) + { + uhciFreeQH(hc, uqh); + break; + } + termutd = uhciAllocTD(hc); + if(!termutd) + { + uhciFreeTD(hc, setuputd); + uhciFreeQH(hc, uqh); + break; + } + uqh->uqh_IOReq = ioreq; + + //termutd->utd_QueueHead = setuputd->utd_QueueHead = uqh; + + KPRINTF(1, ("SetupTD=%08lx, TermTD=%08lx\n", setuputd, termutd)); + + // fill setup td + ctrlstatus = UTCF_ACTIVE|UTCF_3ERRORSLIMIT; + if(ioreq->iouh_Flags & UHFF_LOWSPEED) + { + KPRINTF(5, ("*** LOW SPEED ***\n")); + ctrlstatus |= UTCF_LOWSPEED; + } + token = (ioreq->iouh_DevAddr<iouh_Endpoint<utd_Pred = NULL; + if(ioreq->iouh_Actual) + { + // this is a continuation of a fragmented ctrl transfer! + KPRINTF(1, ("Continuing FRAGMENT at %ld of %ld\n", ioreq->iouh_Actual, ioreq->iouh_Length)); + cont = TRUE; + } else { + cont = FALSE; + uqh->uqh_FirstTD = setuputd; + uqh->uqh_Element = setuputd->utd_Self; // start of queue + WRITEMEM32_LE(&setuputd->utd_CtrlStatus, ctrlstatus); + WRITEMEM32_LE(&setuputd->utd_Token, (PID_SETUP<utd_BufferPtr, (ULONG) pciGetPhysical(hc, &ioreq->iouh_SetupData)); + } + + token |= (ioreq->iouh_SetupData.bmRequestType & URTF_IN) ? PID_IN : PID_OUT; + predutd = setuputd; + actual = ioreq->iouh_Actual; + if(ioreq->iouh_Length) + { + ctrlstatus |= UTCF_SHORTPACKET; + if(cont) + { + phyaddr = (ULONG) pciGetPhysical(hc, &(((UBYTE *) ioreq->iouh_Data)[ioreq->iouh_Actual])); + if(!unit->hu_DevDataToggle[devadrep]) + { + // continue with data toggle 0 + token |= UTTF_DATA1; + } + } else { + phyaddr = (ULONG) pciGetPhysical(hc, ioreq->iouh_Data); + } + do + { + datautd = uhciAllocTD(hc); + if(!datautd) + { + break; + } + token ^= UTTF_DATA1; // toggle bit + predutd->utd_Link = datautd->utd_Self; + predutd->utd_Succ = (struct UhciXX *) datautd; + //datautd->utd_Pred = (struct UhciXX *) predutd; + //datautd->utd_QueueHead = uqh; + len = ioreq->iouh_Length - actual; + if(len > ioreq->iouh_MaxPktSize) + { + len = ioreq->iouh_MaxPktSize; + } + WRITEMEM32_LE(&datautd->utd_CtrlStatus, ctrlstatus); +#if 1 +#warning "this workaround for a VIA babble bug will potentially overwrite innocent memory (very rarely), but will avoid the host controller dropping dead completely." + if((len < ioreq->iouh_MaxPktSize) && (ioreq->iouh_SetupData.bmRequestType & URTF_IN)) + { + WRITEMEM32_LE(&datautd->utd_Token, token|((ioreq->iouh_MaxPktSize-1)<= 1 + } else { + WRITEMEM32_LE(&datautd->utd_Token, token|((len-1)<= 1 + } +#else + WRITEMEM32_LE(&datautd->utd_Token, token|((len-1)<= 1 +#endif + WRITEMEM32_LE(&datautd->utd_BufferPtr, phyaddr); + phyaddr += len; + actual += len; + predutd = datautd; + } while((actual < ioreq->iouh_Length) && (actual - ioreq->iouh_Actual < UHCI_TD_CTRL_LIMIT)); + if(actual == ioreq->iouh_Actual) + { + // not at least one data TD? try again later + uhciFreeTD(hc, setuputd); + uhciFreeTD(hc, termutd); + uhciFreeQH(hc, uqh); + break; + } + if(cont) + { + // free Setup packet + KPRINTF(1, ("Freeing setup\n")); + uqh->uqh_FirstTD = (struct UhciTD *) setuputd->utd_Succ; + //uqh->uqh_FirstTD->utd_Pred = NULL; + uqh->uqh_Element = setuputd->utd_Succ->uxx_Self; // start of queue after setup packet + uhciFreeTD(hc, setuputd); + // set toggle for next batch + unit->hu_DevDataToggle[devadrep] = (token & UTTF_DATA1) ? FALSE : TRUE; + } + } + uqh->uqh_Actual = actual - ioreq->iouh_Actual; + ctrlstatus |= UTCF_READYINTEN; + if(actual == ioreq->iouh_Length) + { + // TERM packet + KPRINTF(1, ("Activating TERM\n")); + token |= UTTF_DATA1; + token ^= (PID_IN^PID_OUT)<utd_Link = termutd->utd_Self; + predutd->utd_Succ = (struct UhciXX *) termutd; + //termutd->utd_Pred = (struct UhciXX *) predutd; + WRITEMEM32_LE(&termutd->utd_CtrlStatus, ctrlstatus); + WRITEMEM32_LE(&termutd->utd_Token, token|(0x7ff<utd_Link, UHCI_TERMINATE); + termutd->utd_Succ = NULL; + //uqh->uqh_LastTD = termutd; + } else { + KPRINTF(1, ("Setup data phase fragmented\n")); + // don't create TERM, we don't know the final data toggle bit + // but mark the last data TD for interrupt generation + WRITEMEM32_LE(&predutd->utd_CtrlStatus, ctrlstatus); + uhciFreeTD(hc, termutd); + CONSTWRITEMEM32_LE(&predutd->utd_Link, UHCI_TERMINATE); + predutd->utd_Succ = NULL; + //uqh->uqh_LastTD = predutd; + } + + Remove(&ioreq->iouh_Req.io_Message.mn_Node); + ioreq->iouh_DriverPrivate1 = uqh; + + // manage endpoint going busy + unit->hu_DevBusyReq[devadrep] = ioreq; + unit->hu_NakTimeoutFrame[devadrep] = (ioreq->iouh_Flags & UHFF_NAKTIMEOUT) ? hc->hc_FrameCounter + ioreq->iouh_NakTimeout : 0; + + Disable(); + AddTail(&hc->hc_TDQueue, (struct Node *) ioreq); + + // looks good to me, now enqueue this entry (just behind the CtrlQH) + uqh->uqh_Succ = hc->hc_UhciCtrlQH->uqh_Succ; + uqh->uqh_Link = uqh->uqh_Succ->uxx_Self; + SYNC; + EIEIO; + uqh->uqh_Pred = (struct UhciXX *) hc->hc_UhciCtrlQH; + uqh->uqh_Succ->uxx_Pred = (struct UhciXX *) uqh; + hc->hc_UhciCtrlQH->uqh_Succ = (struct UhciXX *) uqh; + hc->hc_UhciCtrlQH->uqh_Link = uqh->uqh_Self; + SYNC; + EIEIO; + Enable(); + + ioreq = (struct IOUsbHWReq *) hc->hc_CtrlXFerQueue.lh_Head; + } +} +/* \\\ */ + +/* /// "uhciScheduleIntTDs()" */ +void uhciScheduleIntTDs(struct PCIController *hc) +{ + struct PCIUnit *unit = hc->hc_Unit; + struct IOUsbHWReq *ioreq; + UWORD cnt; + UWORD devadrep; + struct UhciQH *uqh; + struct UhciQH *intuqh; + struct UhciTD *utd; + struct UhciTD *predutd; + ULONG actual; + ULONG ctrlstatus; + ULONG token; + ULONG len; + ULONG phyaddr; + + /* *** INT Transfers *** */ + KPRINTF(1, ("Scheduling new INT transfers...\n")); + ioreq = (struct IOUsbHWReq *) hc->hc_IntXFerQueue.lh_Head; + while(((struct Node *) ioreq)->ln_Succ) + { + devadrep = (ioreq->iouh_DevAddr<<5) + ioreq->iouh_Endpoint + ((ioreq->iouh_Dir == UHDIR_IN) ? 0x10 : 0); + KPRINTF(10, ("New INT transfer to %ld.%ld: %ld bytes\n", ioreq->iouh_DevAddr, ioreq->iouh_Endpoint, ioreq->iouh_Length)); + /* is endpoint already in use or do we have to wait for next transaction */ + if(unit->hu_DevBusyReq[devadrep]) + { + KPRINTF(5, ("Endpoint %02lx in use!\n", devadrep)); + ioreq = (struct IOUsbHWReq *) ((struct Node *) ioreq)->ln_Succ; + continue; + } + + uqh = uhciAllocQH(hc); + if(!uqh) + { + break; + } + + uqh->uqh_IOReq = ioreq; + + ctrlstatus = UTCF_ACTIVE|UTCF_1ERRORLIMIT; + if(ioreq->iouh_Flags & UHFF_LOWSPEED) + { + KPRINTF(5, ("*** LOW SPEED ***\n")); + ctrlstatus |= UTCF_LOWSPEED; + } + token = (ioreq->iouh_DevAddr<iouh_Endpoint<iouh_Dir == UHDIR_IN) ? PID_IN : PID_OUT; + predutd = NULL; + actual = ioreq->iouh_Actual; + ctrlstatus |= UTCF_SHORTPACKET; + phyaddr = (ULONG) pciGetPhysical(hc, &(((UBYTE *) ioreq->iouh_Data)[ioreq->iouh_Actual])); + if(unit->hu_DevDataToggle[devadrep]) + { + // continue with data toggle 1 + KPRINTF(1, ("Data1\n")); + token |= UTTF_DATA1; + } else { + KPRINTF(1, ("Data0\n")); + } + do + { + utd = uhciAllocTD(hc); + if(!utd) + { + break; + } + if(predutd) + { + WRITEMEM32_LE(&predutd->utd_Link, READMEM32_LE(utd->utd_Self)|UHCI_DFS); + predutd->utd_Succ = (struct UhciXX *) utd; + //utd->utd_Pred = (struct UhciXX *) predutd; + } else { + uqh->uqh_FirstTD = utd; + uqh->uqh_Element = utd->utd_Self; + //utd->utd_Pred = NULL; + } + //utd->utd_QueueHead = uqh; + len = ioreq->iouh_Length - actual; + if(len > ioreq->iouh_MaxPktSize) + { + len = ioreq->iouh_MaxPktSize; + } + + WRITEMEM32_LE(&utd->utd_CtrlStatus, ctrlstatus); + WRITEMEM32_LE(&utd->utd_Token, token|(((len-1) & 0x7ff)<utd_BufferPtr, phyaddr); + phyaddr += len; + actual += len; + predutd = utd; + token ^= UTTF_DATA1; // toggle bit + } while((actual < ioreq->iouh_Length) && (actual - ioreq->iouh_Actual < UHCI_TD_INT_LIMIT)); + + if(!utd) + { + // not at least one data TD? try again later + uhciFreeQH(hc, uqh); + break; + } + + uqh->uqh_Actual = actual - ioreq->iouh_Actual; + // set toggle for next batch / succesful transfer + unit->hu_DevDataToggle[devadrep] = (token & UTTF_DATA1) ? TRUE : FALSE; + if(unit->hu_DevDataToggle[devadrep]) + { + // continue with data toggle 1 + KPRINTF(1, ("NewData1\n")); + } else { + KPRINTF(1, ("NewData0\n")); + } + ctrlstatus |= UTCF_READYINTEN; + WRITEMEM32_LE(&predutd->utd_CtrlStatus, ctrlstatus); + CONSTWRITEMEM32_LE(&utd->utd_Link, UHCI_TERMINATE); + utd->utd_Succ = NULL; + //uqh->uqh_LastTD = utd; + + if(ioreq->iouh_Interval >= 255) + { + intuqh = hc->hc_UhciIntQH[8]; // 256ms interval + } else { + cnt = 0; + do + { + intuqh = hc->hc_UhciIntQH[cnt++]; + } while(ioreq->iouh_Interval > (1<iouh_Req.io_Message.mn_Node); + ioreq->iouh_DriverPrivate1 = uqh; + + // manage endpoint going busy + unit->hu_DevBusyReq[devadrep] = ioreq; + unit->hu_NakTimeoutFrame[devadrep] = (ioreq->iouh_Flags & UHFF_NAKTIMEOUT) ? hc->hc_FrameCounter + ioreq->iouh_NakTimeout : 0; + + Disable(); + AddTail(&hc->hc_TDQueue, (struct Node *) ioreq); + + // looks good to me, now enqueue this entry (just behind the right IntQH) + uqh->uqh_Succ = intuqh->uqh_Succ; + uqh->uqh_Link = intuqh->uqh_Self; + SYNC; + EIEIO; + uqh->uqh_Pred = (struct UhciXX *) intuqh; + uqh->uqh_Succ->uxx_Pred = (struct UhciXX *) uqh; + intuqh->uqh_Succ = (struct UhciXX *) uqh; + intuqh->uqh_Link = uqh->uqh_Self; + SYNC; + EIEIO; + Enable(); + + uhciUpdateIntTree(hc); + + ioreq = (struct IOUsbHWReq *) hc->hc_IntXFerQueue.lh_Head; + } +} +/* \\\ */ + +/* /// "uhciScheduleBulkTDs()" */ +void uhciScheduleBulkTDs(struct PCIController *hc) +{ + struct PCIUnit *unit = hc->hc_Unit; + struct IOUsbHWReq *ioreq; + UWORD devadrep; + struct UhciQH *uqh; + struct UhciTD *utd; + struct UhciTD *predutd; + ULONG actual; + ULONG ctrlstatus; + ULONG token; + ULONG len; + ULONG phyaddr; + BOOL forcezero; + + /* *** BULK Transfers *** */ + KPRINTF(1, ("Scheduling new BULK transfers...\n")); + ioreq = (struct IOUsbHWReq *) hc->hc_BulkXFerQueue.lh_Head; + while(((struct Node *) ioreq)->ln_Succ) + { + devadrep = (ioreq->iouh_DevAddr<<5) + ioreq->iouh_Endpoint + ((ioreq->iouh_Dir == UHDIR_IN) ? 0x10 : 0); + KPRINTF(10, ("New BULK transfer to %ld.%ld: %ld bytes\n", ioreq->iouh_DevAddr, ioreq->iouh_Endpoint, ioreq->iouh_Length)); + /* is endpoint already in use or do we have to wait for next transaction */ + if(unit->hu_DevBusyReq[devadrep]) + { + KPRINTF(5, ("Endpoint %02lx in use!\n", devadrep)); + ioreq = (struct IOUsbHWReq *) ((struct Node *) ioreq)->ln_Succ; + continue; + } + + uqh = uhciAllocQH(hc); + if(!uqh) + { + break; + } + + uqh->uqh_IOReq = ioreq; + + // fill setup td + ctrlstatus = UTCF_ACTIVE|UTCF_1ERRORLIMIT; + token = (ioreq->iouh_DevAddr<iouh_Endpoint<iouh_Dir == UHDIR_IN) ? PID_IN : PID_OUT; + predutd = NULL; + actual = ioreq->iouh_Actual; + ctrlstatus |= UTCF_SHORTPACKET; + phyaddr = (ULONG) pciGetPhysical(hc, &(((UBYTE *) ioreq->iouh_Data)[ioreq->iouh_Actual])); + if(unit->hu_DevDataToggle[devadrep]) + { + // continue with data toggle 1 + token |= UTTF_DATA1; + } + do + { + utd = uhciAllocTD(hc); + if(!utd) + { + break; + } + forcezero = FALSE; + if(predutd) + { + WRITEMEM32_LE(&predutd->utd_Link, READMEM32_LE(utd->utd_Self)|UHCI_DFS); + predutd->utd_Succ = (struct UhciXX *) utd; + //utd->utd_Pred = (struct UhciXX *) predutd; + } else { + uqh->uqh_FirstTD = utd; + uqh->uqh_Element = utd->utd_Self; + //utd->utd_Pred = NULL; + } + //utd->utd_QueueHead = uqh; + len = ioreq->iouh_Length - actual; + if(len > ioreq->iouh_MaxPktSize) + { + len = ioreq->iouh_MaxPktSize; + } + + WRITEMEM32_LE(&utd->utd_CtrlStatus, ctrlstatus); + WRITEMEM32_LE(&utd->utd_Token, token|(((len-1) & 0x7ff)<utd_BufferPtr, phyaddr); + phyaddr += len; + actual += len; + predutd = utd; + token ^= UTTF_DATA1; // toggle bit + if((actual == ioreq->iouh_Length) && len) + { + if((ioreq->iouh_Flags & UHFF_NOSHORTPKT) || (ioreq->iouh_Dir == UHDIR_IN) || (actual % ioreq->iouh_MaxPktSize)) + { + // no last zero byte packet + break; + } else { + // avoid rare case that the zero byte packet is reached on TD_BULK_LIMIT + forcezero = TRUE; + } + } + } while(forcezero || (len && (actual <= ioreq->iouh_Length) && (actual - ioreq->iouh_Actual < UHCI_TD_BULK_LIMIT))); + + if(!utd) + { + // not at least one data TD? try again later + uhciFreeQH(hc, uqh); + break; + } + uqh->uqh_Actual = actual - ioreq->iouh_Actual; + // set toggle for next batch / succesful transfer + unit->hu_DevDataToggle[devadrep] = (token & UTTF_DATA1) ? TRUE : FALSE; + + ctrlstatus |= UTCF_READYINTEN; + WRITEMEM32_LE(&predutd->utd_CtrlStatus, ctrlstatus); + CONSTWRITEMEM32_LE(&utd->utd_Link, UHCI_TERMINATE); + utd->utd_Succ = NULL; + //uqh->uqh_LastTD = utd; + + Remove(&ioreq->iouh_Req.io_Message.mn_Node); + ioreq->iouh_DriverPrivate1 = uqh; + + // manage endpoint going busy + unit->hu_DevBusyReq[devadrep] = ioreq; + unit->hu_NakTimeoutFrame[devadrep] = (ioreq->iouh_Flags & UHFF_NAKTIMEOUT) ? hc->hc_FrameCounter + ioreq->iouh_NakTimeout : 0; + + Disable(); + AddTail(&hc->hc_TDQueue, (struct Node *) ioreq); + + // looks good to me, now enqueue this entry (just behind the BulkQH) + uqh->uqh_Succ = hc->hc_UhciBulkQH->uqh_Succ; + uqh->uqh_Link = uqh->uqh_Succ->uxx_Self; + SYNC; + EIEIO; + uqh->uqh_Pred = (struct UhciXX *) hc->hc_UhciBulkQH; + uqh->uqh_Succ->uxx_Pred = (struct UhciXX *) uqh; + hc->hc_UhciBulkQH->uqh_Succ = (struct UhciXX *) uqh; + hc->hc_UhciBulkQH->uqh_Link = uqh->uqh_Self; + SYNC; + EIEIO; + Enable(); + + ioreq = (struct IOUsbHWReq *) hc->hc_BulkXFerQueue.lh_Head; + } +} +/* \\\ */ + +/* /// "uhciCompleteInt()" */ +void uhciCompleteInt(struct PCIController *hc) +{ + ULONG framecnt = READREG16_LE(hc->hc_RegBase, UHCI_FRAMECOUNT); + + KPRINTF(1, ("CompleteInt!\n")); + if(framecnt < (hc->hc_FrameCounter & 0xffff)) + { + hc->hc_FrameCounter |= 0xffff; + hc->hc_FrameCounter++; + hc->hc_FrameCounter += framecnt; + KPRINTF(10, ("Frame Counter Rollover %ld\n", hc->hc_FrameCounter)); + } + + /* **************** PROCESS DONE TRANSFERS **************** */ + + uhciCheckPortStatusChange(hc); + uhwCheckRootHubChanges(hc->hc_Unit); + + uhciHandleFinishedTDs(hc); + + if(hc->hc_CtrlXFerQueue.lh_Head->ln_Succ) + { + uhciScheduleCtrlTDs(hc); + } + + if(hc->hc_IntXFerQueue.lh_Head->ln_Succ) + { + uhciScheduleIntTDs(hc); + } + + if(hc->hc_BulkXFerQueue.lh_Head->ln_Succ) + { + uhciScheduleBulkTDs(hc); + } + + KPRINTF(1, ("CompleteDone\n")); +} +/* \\\ */ + +/* /// "uhciIntCode()" */ +void uhciIntCode(HIDDT_IRQ_Handler *irq, HIDDT_IRQ_HwInfo *hw) +{ + struct PCIController *hc = (struct PCIController *) irq->h_Data; + struct PCIDevice *base = hc->hc_Device; + UWORD intr; + + //KPRINTF(10, ("pciUhciInt()\n")); + intr = READREG16_LE(hc->hc_RegBase, UHCI_USBSTATUS); + if(intr & (UHSF_USBINT|UHSF_USBERRORINT|UHSF_RESUMEDTX|UHSF_HCSYSERROR|UHSF_HCPROCERROR|UHSF_HCHALTED)) + { + WRITEREG16_LE(hc->hc_RegBase, UHCI_USBSTATUS, intr); + KPRINTF(1, ("INT=%04lx\n", intr)); + if(intr & (UHSF_HCSYSERROR|UHSF_HCPROCERROR|UHSF_HCHALTED)) + { + KPRINTF(200, ("Host ERROR!\n")); + CONSTWRITEREG16_LE(hc->hc_RegBase, UHCI_USBCMD, UHCF_HCRESET|UHCF_GLOBALRESET|UHCF_MAXPACKET64|UHCF_CONFIGURE); + //CONSTWRITEREG16_LE(hc->hc_RegBase, UHCI_USBINTEN, 0); + } + if(!hc->hc_Online) + { + return; + } + if(intr & (UHSF_USBINT|UHSF_USBERRORINT)) + { + SureCause(base, &hc->hc_CompleteInt); + } + } +} +/* \\\ */ + +/* ---------------------------------------------------------------------- * + * OHCI Specific Stuff * + * ---------------------------------------------------------------------- */ + +/* /// "ohciDebugSchedule()" */ +void ohciDebugSchedule(struct PCIController *hc) +{ + ULONG ctrlhead; + ULONG hced; + ULONG epcaps; + ULONG headptr; + ULONG headptrbits; + ULONG tailptr; + ULONG nexted; + ULONG ctrl; + ULONG currptr; + ULONG nexttd; + ULONG buffend; + KPRINTF(10, ("*** Schedule debug!!! ***\n")); + ctrlhead = READREG32_LE(hc->hc_RegBase, OHCI_CTRL_HEAD_ED) - hc->hc_PCIVirtualAdjust; + KPRINTF(10, ("CtrlHead = %08lx, should be %08lx\n", ctrlhead, &hc->hc_OhciCtrlHeadED->oed_EPCaps)); + hced = ctrlhead; + do + { + epcaps = READMEM32_LE(hced); + tailptr = READMEM32_LE(hced+4); + headptr = headptrbits = READMEM32_LE(hced+8); + headptr &= OHCI_PTRMASK; + nexted = READMEM32_LE(hced+12); + KPRINTF(10, ("ED %08lx: EPCaps=%08lx, HeadP=%08lx, TailP=%08lx, NextED=%08lx\n", + hced, epcaps, headptrbits, tailptr, nexted)); + if((!(epcaps & OECF_SKIP)) && (tailptr != headptr) && (!(headptrbits & OEHF_HALTED))) + { + while(tailptr != headptr) + { + headptr -= hc->hc_PCIVirtualAdjust; + ctrl = READMEM32_LE(headptr); + currptr = READMEM32_LE(headptr+4); + nexttd = READMEM32_LE(headptr+8); + buffend = READMEM32_LE(headptr+12); + + KPRINTF(5, (" TD %08lx: Ctrl=%08lx, CurrPtr=%08lx, NextTD=%08lx, BuffEnd=%08lx\n", + headptr, ctrl, currptr, nexttd, buffend)); + headptr = nexttd; + } + } + if(!nexted) + { + break; + } + hced = nexted - hc->hc_PCIVirtualAdjust; + } while(TRUE); +} +/* \\\ */ + +/* /// "ohciFreeEDContext()" */ +void ohciFreeEDContext(struct PCIController *hc, struct OhciED *oed) +{ + struct OhciTD *otd; + struct OhciTD *nextotd; + + KPRINTF(5, ("Unlinking EDContext %08lx\n", oed)); + + // unlink from schedule + oed->oed_Succ->oed_Pred = oed->oed_Pred; + oed->oed_Pred->oed_Succ = oed->oed_Succ; + oed->oed_Pred->oed_NextED = oed->oed_Succ->oed_Self; + SYNC + EIEIO; + +#if 0 + // need to make sure that the endpoint is no longer + Disable(); + oed->oed_Succ = hc->hc_OhciAsyncFreeED; + hc->hc_OhciAsyncFreeED = oed; + Enable(); +#else + Disable(); + nextotd = oed->oed_FirstTD; + while(nextotd) + { + KPRINTF(1, ("FreeTD %08lx\n", nextotd)); + otd = nextotd; + nextotd = (struct OhciTD *) otd->otd_Succ; + ohciFreeTD(hc, otd); + } + + ohciFreeED(hc, oed); + Enable(); +#endif +} +/* \\\ */ + +/* /// "ohciAllocED()" */ +inline struct OhciED * ohciAllocED(struct PCIController *hc) +{ + struct OhciED *oed = hc->hc_OhciEDPool; + + if(!oed) + { + // out of QHs! + KPRINTF(20, ("Out of EDs!\n")); + return NULL; + } + + hc->hc_OhciEDPool = oed->oed_Succ; + return(oed); +} +/* \\\ */ + +/* /// "ohciFreeED()" */ +inline void ohciFreeED(struct PCIController *hc, struct OhciED *oed) +{ + oed->oed_Succ = hc->hc_OhciEDPool; + hc->hc_OhciEDPool = oed; +} +/* \\\ */ + +/* /// "ohciAllocTD()" */ +inline struct OhciTD * ohciAllocTD(struct PCIController *hc) +{ + struct OhciTD *otd = hc->hc_OhciTDPool; + + if(!otd) + { + // out of TDs! + KPRINTF(20, ("Out of TDs!\n")); + return NULL; + } + + hc->hc_OhciTDPool = otd->otd_Succ; + return(otd); +} +/* \\\ */ + +/* /// "ohciFreeTD()" */ +inline void ohciFreeTD(struct PCIController *hc, struct OhciTD *otd) +{ + otd->otd_Succ = hc->hc_OhciTDPool; + hc->hc_OhciTDPool = otd; +} +/* \\\ */ + +/* /// "ohciUpdateIntTree()" */ +void ohciUpdateIntTree(struct PCIController *hc) +{ + struct OhciED *oed; + struct OhciED *predoed; + struct OhciED *lastusedoed; + UWORD cnt; + + // optimize linkage between queue heads + predoed = lastusedoed = hc->hc_OhciTermED; + for(cnt = 0; cnt < 5; cnt++) + { + oed = hc->hc_OhciIntED[cnt]; + if(oed->oed_Succ != predoed) + { + lastusedoed = oed->oed_Succ; + } + oed->oed_NextED = lastusedoed->oed_Self; + predoed = oed; + } +} +/* \\\ */ + +/* /// "ohciHandleFinishedTDs()" */ +void ohciHandleFinishedTDs(struct PCIController *hc) +{ + struct PCIUnit *unit = hc->hc_Unit; + struct IOUsbHWReq *ioreq; + struct IOUsbHWReq *nextioreq; + struct OhciED *oed; + struct OhciTD *otd; + UWORD devadrep; + ULONG len; + ULONG ctrlstatus; + BOOL updatetree = FALSE; + ULONG donehead; + BOOL retire; + + KPRINTF(1, ("Checking for work done...\n")); + Disable(); + donehead = hc->hc_OhciDoneQueue; + hc->hc_OhciDoneQueue = 0UL; + Enable(); + if(!donehead) + { + KPRINTF(1, ("Nothing to do!\n")); + return; + } + otd = (struct OhciTD *) (donehead - hc->hc_PCIVirtualAdjust - 16); + KPRINTF(10, ("DoneHead=%08lx, OTD=%08lx, Frame=%ld\n", donehead, otd, READREG32_LE(hc->hc_RegBase, OHCI_FRAMECOUNT))); + do + { + oed = otd->otd_ED; + ctrlstatus = READMEM32_LE(&otd->otd_Ctrl); + if(otd->otd_BufferPtr) + { + // FIXME this will blow up if physical memory is ever going to be discontinuous + len = READMEM32_LE(&otd->otd_BufferEnd) - READMEM32_LE(&otd->otd_BufferPtr) + 1; + } else { + len = otd->otd_Length; + } + ioreq = oed->oed_IOReq; + KPRINTF(1, ("Examining TD %08lx for ED %08lx (IOReq=%08lx), Status %08lx, len=%ld\n", otd, oed, ioreq, ctrlstatus, len)); + ioreq->iouh_Actual += len; + retire = (ioreq->iouh_Actual == ioreq->iouh_Length); + if((ctrlstatus & OTCM_DELAYINT) != OTCF_NOINT) + { + retire = TRUE; + } + switch((ctrlstatus & OTCM_COMPLETIONCODE)>>OTCS_COMPLETIONCODE) + { + case (OTCF_CC_NOERROR>>OTCS_COMPLETIONCODE): + break; + + case (OTCF_CC_CRCERROR>>OTCS_COMPLETIONCODE): + KPRINTF(200, ("CRC Error!\n")); + ioreq->iouh_Req.io_Error = UHIOERR_CRCERROR; + retire = TRUE; + break; + + case (OTCF_CC_BABBLE>>OTCS_COMPLETIONCODE): + KPRINTF(200, ("Babble/Bitstuffing Error!\n")); + ioreq->iouh_Req.io_Error = UHIOERR_CRCERROR; + retire = TRUE; + break; + + case (OTCF_CC_WRONGTOGGLE>>OTCS_COMPLETIONCODE): + KPRINTF(200, ("Data toggle mismatch length = %ld\n", len)); + break; + + case (OTCF_CC_STALL>>OTCS_COMPLETIONCODE): + KPRINTF(200, ("STALLED!\n")); + ioreq->iouh_Req.io_Error = UHIOERR_STALL; + retire = TRUE; + break; + + case (OTCF_CC_TIMEOUT>>OTCS_COMPLETIONCODE): + KPRINTF(200, ("TIMEOUT!\n")); + ioreq->iouh_Req.io_Error = UHIOERR_TIMEOUT; + retire = TRUE; + break; + + case (OTCF_CC_PIDCORRUPT>>OTCS_COMPLETIONCODE): + KPRINTF(200, ("PID Error!\n")); + ioreq->iouh_Req.io_Error = UHIOERR_CRCERROR; + retire = TRUE; + break; + + case (OTCF_CC_WRONGPID>>OTCS_COMPLETIONCODE): + KPRINTF(200, ("Illegal PID!\n")); + ioreq->iouh_Req.io_Error = UHIOERR_CRCERROR; + retire = TRUE; + break; + + case (OTCF_CC_OVERFLOW>>OTCS_COMPLETIONCODE): + KPRINTF(200, ("Overflow Error!\n")); + ioreq->iouh_Req.io_Error = UHIOERR_OVERFLOW; + retire = TRUE; + break; + + case (OTCF_CC_SHORTPKT>>OTCS_COMPLETIONCODE): + KPRINTF(10, ("Short packet %ld < %ld\n", len, otd->otd_Length)); + if((!ioreq->iouh_Req.io_Error) && (!(ioreq->iouh_Flags & UHFF_ALLOWRUNTPKTS))) + { + ioreq->iouh_Req.io_Error = UHIOERR_RUNTPACKET; + } + retire = TRUE; + break; + + case (OTCF_CC_OVERRUN>>OTCS_COMPLETIONCODE): + KPRINTF(200, ("Data Overrun Error!\n")); + ioreq->iouh_Req.io_Error = UHIOERR_HOSTERROR; + retire = TRUE; + break; + + case (OTCF_CC_UNDERRUN>>OTCS_COMPLETIONCODE): + KPRINTF(200, ("Data Underrun Error!\n")); + ioreq->iouh_Req.io_Error = UHIOERR_HOSTERROR; + retire = TRUE; + break; + + case (OTCF_CC_INVALID>>OTCS_COMPLETIONCODE): + KPRINTF(200, ("Not touched?!?\n")); + break; + } + if(READMEM32_LE(&oed->oed_HeadPtr) & OEHF_HALTED) + { + KPRINTF(100, ("OED halted!\n")); + retire = TRUE; + } + + if(retire) + { + Remove(&ioreq->iouh_Req.io_Message.mn_Node); + AddHead(&hc->hc_OhciRetireQueue, &ioreq->iouh_Req.io_Message.mn_Node); + } + + if(!otd->otd_NextTD) + { + break; + } + KPRINTF(1, ("NextTD=%08lx\n", otd->otd_NextTD)); + otd = (struct OhciTD *) (READMEM32_LE(&otd->otd_NextTD) - hc->hc_PCIVirtualAdjust - 16); + KPRINTF(1, ("NextOTD = %08lx\n", otd)); + } while(TRUE); + + ioreq = (struct IOUsbHWReq *) hc->hc_OhciRetireQueue.lh_Head; + while((nextioreq = (struct IOUsbHWReq *) ((struct Node *) ioreq)->ln_Succ)) + { + Remove(&ioreq->iouh_Req.io_Message.mn_Node); + oed = (struct OhciED *) ioreq->iouh_DriverPrivate1; + if(oed) + { + KPRINTF(10, ("Retiring IOReq=%08lx ED=%08lx, Frame=%ld\n", ioreq, oed, READREG32_LE(hc->hc_RegBase, OHCI_FRAMECOUNT))); + + if(oed->oed_Continue) + { + ULONG actual = ioreq->iouh_Actual; + ULONG oldenables; + ULONG phyaddr; + struct OhciTD *predotd = NULL; + + KPRINTF(10, ("Reloading Bulk transfer at %ld of %ld\n", ioreq->iouh_Actual, ioreq->iouh_Length)); + otd = oed->oed_FirstTD; + phyaddr = (ULONG) pciGetPhysical(hc, &(((UBYTE *) ioreq->iouh_Data)[actual])); + do + { + len = ioreq->iouh_Length - actual; + if(len > OHCI_PAGE_SIZE) + { + len = OHCI_PAGE_SIZE; + } + if((!otd->otd_Succ) && (actual + len == ioreq->iouh_Length) && (!ioreq->iouh_Flags & UHFF_NOSHORTPKT) && ((actual % ioreq->iouh_MaxPktSize) == 0)) + { + // special case -- zero padding would not fit in this run, + // and next time, we would forget about it. So rather abort + // reload now, so the zero padding goes with the next reload + break; + } + predotd = otd; + otd->otd_Length = len; + KPRINTF(1, ("TD with %ld bytes\n", len)); + CONSTWRITEMEM32_LE(&otd->otd_Ctrl, OTCF_CC_INVALID|OTCF_NOINT); + if(otd->otd_Succ) + { + otd->otd_NextTD = otd->otd_Succ->otd_Self; + } + if(len) + { + WRITEMEM32_LE(&otd->otd_BufferPtr, phyaddr); + phyaddr += len - 1; + WRITEMEM32_LE(&otd->otd_BufferEnd, phyaddr); + phyaddr++; + } else { + CONSTWRITEMEM32_LE(&otd->otd_BufferPtr, 0); + CONSTWRITEMEM32_LE(&otd->otd_BufferEnd, 0); + } + actual += len; + otd = otd->otd_Succ; + } while(otd && ((actual < ioreq->iouh_Length) || (len && (ioreq->iouh_Dir == UHDIR_OUT) && (actual == ioreq->iouh_Length) && (!ioreq->iouh_Flags & UHFF_NOSHORTPKT) && ((actual % ioreq->iouh_MaxPktSize) == 0)))); + oed->oed_Continue = (actual < ioreq->iouh_Length); + predotd->otd_NextTD = hc->hc_OhciTermTD->otd_Self; + + CONSTWRITEMEM32_LE(&predotd->otd_Ctrl, OTCF_CC_INVALID); + + Disable(); + AddTail(&hc->hc_TDQueue, &ioreq->iouh_Req.io_Message.mn_Node); + + // keep toggle bit + ctrlstatus = READMEM32_LE(oed->oed_HeadPtr) & OEHF_DATA1; + WRITEMEM32_LE(&oed->oed_HeadPtr, READMEM32_LE(oed->oed_FirstTD->otd_Self)|ctrlstatus); + + oldenables = READREG32_LE(hc->hc_RegBase, OHCI_CMDSTATUS); + oldenables |= OCSF_BULKENABLE; + WRITEREG32_LE(hc->hc_RegBase, OHCI_CMDSTATUS, oldenables); + SYNC; + EIEIO; + Enable(); + } else { + // disable ED + ctrlstatus = READMEM32_LE(&oed->oed_HeadPtr); + ctrlstatus |= OEHF_HALTED; + WRITEMEM32_LE(&oed->oed_HeadPtr, ctrlstatus); + + devadrep = (ioreq->iouh_DevAddr<<5) + ioreq->iouh_Endpoint + ((ioreq->iouh_Dir == UHDIR_IN) ? 0x10 : 0); + unit->hu_DevBusyReq[devadrep] = NULL; + unit->hu_DevDataToggle[devadrep] = (ctrlstatus & OEHF_DATA1) ? TRUE : FALSE; + + ohciFreeEDContext(hc, oed); + if(ioreq->iouh_Req.io_Command == UHCMD_INTXFER) + { + updatetree = TRUE; + } + // check for sucessful clear feature and set address ctrl transfers + if((!ioreq->iouh_Req.io_Error) && (ioreq->iouh_Req.io_Command == UHCMD_CONTROLXFER)) + { + uhwCheckSpecialCtrlTransfers(hc, ioreq); + } + ReplyMsg(&ioreq->iouh_Req.io_Message); + } + } else { + KPRINTF(20, ("IOReq=%08lx has no OED!\n", ioreq)); + } + ioreq = nextioreq; + } + if(updatetree) + { + ohciUpdateIntTree(hc); + } +} +/* \\\ */ + +/* /// "ohciScheduleCtrlTDs()" */ +void ohciScheduleCtrlTDs(struct PCIController *hc) +{ + struct PCIUnit *unit = hc->hc_Unit; + struct IOUsbHWReq *ioreq; + UWORD devadrep; + struct OhciED *oed; + struct OhciTD *setupotd; + struct OhciTD *dataotd; + struct OhciTD *termotd; + struct OhciTD *predotd; + ULONG actual; + ULONG epcaps; + ULONG ctrl; + ULONG len; + ULONG phyaddr; + ULONG oldenables; + + /* *** CTRL Transfers *** */ + KPRINTF(1, ("Scheduling new CTRL transfers...\n")); + ioreq = (struct IOUsbHWReq *) hc->hc_CtrlXFerQueue.lh_Head; + while(((struct Node *) ioreq)->ln_Succ) + { + devadrep = (ioreq->iouh_DevAddr<<5) + ioreq->iouh_Endpoint; + KPRINTF(10, ("New CTRL transfer to %ld.%ld: %ld bytes\n", ioreq->iouh_DevAddr, ioreq->iouh_Endpoint, ioreq->iouh_Length)); + /* is endpoint already in use or do we have to wait for next transaction */ + if(unit->hu_DevBusyReq[devadrep]) + { + KPRINTF(5, ("Endpoint %02lx in use!\n", devadrep)); + ioreq = (struct IOUsbHWReq *) ((struct Node *) ioreq)->ln_Succ; + continue; + } + + oed = ohciAllocED(hc); + if(!oed) + { + break; + } + + setupotd = ohciAllocTD(hc); + if(!setupotd) + { + ohciFreeED(hc, oed); + break; + } + termotd = ohciAllocTD(hc); + if(!termotd) + { + ohciFreeTD(hc, setupotd); + ohciFreeED(hc, oed); + break; + } + oed->oed_IOReq = ioreq; + + KPRINTF(1, ("SetupTD=%08lx, TermTD=%08lx\n", setupotd, termotd)); + + // fill setup td + epcaps = (ioreq->iouh_DevAddr<iouh_Endpoint<iouh_MaxPktSize<iouh_Flags & UHFF_LOWSPEED) + { + KPRINTF(5, ("*** LOW SPEED ***\n")); + epcaps |= OECF_LOWSPEED; + } + + WRITEMEM32_LE(&oed->oed_EPCaps, epcaps); + + oed->oed_TailPtr = hc->hc_OhciTermTD->otd_Self; + oed->oed_HeadPtr = setupotd->otd_Self; + oed->oed_FirstTD = setupotd; + + setupotd->otd_ED = oed; + setupotd->otd_Length = 0; // don't increase io_Actual for that transfer + CONSTWRITEMEM32_LE(&setupotd->otd_Ctrl, OTCF_PIDCODE_SETUP|OTCF_CC_INVALID|OTCF_NOINT); + WRITEMEM32_LE(&setupotd->otd_BufferPtr, (ULONG) pciGetPhysical(hc, &ioreq->iouh_SetupData)); + WRITEMEM32_LE(&setupotd->otd_BufferEnd, (ULONG) pciGetPhysical(hc, ((UBYTE *) (&ioreq->iouh_SetupData)) + 7)); + + ctrl = (ioreq->iouh_SetupData.bmRequestType & URTF_IN) ? (OTCF_PIDCODE_IN|OTCF_CC_INVALID|OTCF_NOINT) : (OTCF_PIDCODE_OUT|OTCF_CC_INVALID|OTCF_NOINT); + + predotd = setupotd; + if(ioreq->iouh_Length) + { + phyaddr = (ULONG) pciGetPhysical(hc, ioreq->iouh_Data); + actual = 0; + do + { + dataotd = ohciAllocTD(hc); + if(!dataotd) + { + predotd->otd_Succ = NULL; + break; + } + dataotd->otd_ED = oed; + predotd->otd_Succ = dataotd; + predotd->otd_NextTD = dataotd->otd_Self; + len = ioreq->iouh_Length - actual; + if(len > OHCI_PAGE_SIZE) + { + len = OHCI_PAGE_SIZE; + } + dataotd->otd_Length = len; + KPRINTF(1, ("TD with %ld bytes\n", len)); + WRITEMEM32_LE(&dataotd->otd_Ctrl, ctrl); + WRITEMEM32_LE(&dataotd->otd_BufferPtr, phyaddr); + phyaddr += len - 1; + WRITEMEM32_LE(&dataotd->otd_BufferEnd, phyaddr); + phyaddr++; + actual += len; + predotd = dataotd; + } while(actual < ioreq->iouh_Length); + + if(actual != ioreq->iouh_Length) + { + // out of TDs + KPRINTF(200, ("Out of TDs for Ctrl Transfer!\n")); + dataotd = setupotd->otd_Succ; + ohciFreeTD(hc, setupotd); + while(dataotd) + { + predotd = dataotd; + dataotd = dataotd->otd_Succ; + ohciFreeTD(hc, predotd); + } + ohciFreeTD(hc, termotd); + ohciFreeED(hc, oed); + break; + } + predotd->otd_Succ = termotd; + predotd->otd_NextTD = termotd->otd_Self; + } else { + setupotd->otd_Succ = termotd; + setupotd->otd_NextTD = termotd->otd_Self; + } + + ctrl ^= (OTCF_PIDCODE_IN^OTCF_PIDCODE_OUT)|OTCF_NOINT|OTCF_DATA1|OTCF_TOGGLEFROMTD; + + termotd->otd_Length = 0; + termotd->otd_ED = oed; + termotd->otd_Succ = NULL; + termotd->otd_NextTD = hc->hc_OhciTermTD->otd_Self; + CONSTWRITEMEM32_LE(&termotd->otd_Ctrl, ctrl); + CONSTWRITEMEM32_LE(&termotd->otd_BufferPtr, 0); + CONSTWRITEMEM32_LE(&termotd->otd_BufferEnd, 0); + + Remove(&ioreq->iouh_Req.io_Message.mn_Node); + ioreq->iouh_DriverPrivate1 = oed; + + // manage endpoint going busy + unit->hu_DevBusyReq[devadrep] = ioreq; + unit->hu_NakTimeoutFrame[devadrep] = (ioreq->iouh_Flags & UHFF_NAKTIMEOUT) ? hc->hc_FrameCounter + ioreq->iouh_NakTimeout : 0; + + Disable(); + AddTail(&hc->hc_TDQueue, (struct Node *) ioreq); + + // looks good to me, now enqueue this entry + oed->oed_Succ = hc->hc_OhciCtrlTailED; + oed->oed_NextED = oed->oed_Succ->oed_Self; + oed->oed_Pred = hc->hc_OhciCtrlTailED->oed_Pred; + oed->oed_Pred->oed_Succ = oed; + oed->oed_Pred->oed_NextED = oed->oed_Self; + oed->oed_Succ->oed_Pred = oed; + SYNC; + EIEIO; + + KPRINTF(5, ("ED: EPCaps=%08lx, HeadPtr=%08lx, TailPtr=%08lx, NextED=%08lx\n", + READMEM32_LE(&oed->oed_EPCaps), + READMEM32_LE(&oed->oed_HeadPtr), + READMEM32_LE(&oed->oed_TailPtr), + READMEM32_LE(&oed->oed_NextED))); + + oldenables = READREG32_LE(hc->hc_RegBase, OHCI_CMDSTATUS); + if(!(oldenables & OCSF_CTRLENABLE)) + { + CONSTWRITEREG32_LE(hc->hc_RegBase, OHCI_CTRL_ED, 0); + } + oldenables |= OCSF_CTRLENABLE; + WRITEREG32_LE(hc->hc_RegBase, OHCI_CMDSTATUS, oldenables); + SYNC; + EIEIO; + Enable(); + + ioreq = (struct IOUsbHWReq *) hc->hc_CtrlXFerQueue.lh_Head; + } +} +/* \\\ */ + +/* /// "ohciScheduleIntTDs()" */ +void ohciScheduleIntTDs(struct PCIController *hc) +{ + struct PCIUnit *unit = hc->hc_Unit; + struct IOUsbHWReq *ioreq; + UWORD devadrep; + struct OhciED *intoed; + struct OhciED *oed; + struct OhciTD *otd; + struct OhciTD *predotd; + ULONG actual; + ULONG epcaps; + ULONG len; + ULONG phyaddr; + + /* *** INT Transfers *** */ + KPRINTF(1, ("Scheduling new INT transfers...\n")); + ioreq = (struct IOUsbHWReq *) hc->hc_IntXFerQueue.lh_Head; + while(((struct Node *) ioreq)->ln_Succ) + { + devadrep = (ioreq->iouh_DevAddr<<5) + ioreq->iouh_Endpoint + ((ioreq->iouh_Dir == UHDIR_IN) ? 0x10 : 0); + KPRINTF(10, ("New INT transfer to %ld.%ld: %ld bytes\n", ioreq->iouh_DevAddr, ioreq->iouh_Endpoint, ioreq->iouh_Length)); + /* is endpoint already in use or do we have to wait for next transaction */ + if(unit->hu_DevBusyReq[devadrep]) + { + KPRINTF(5, ("Endpoint %02lx in use!\n", devadrep)); + ioreq = (struct IOUsbHWReq *) ((struct Node *) ioreq)->ln_Succ; + continue; + } + + oed = ohciAllocED(hc); + if(!oed) + { + break; + } + + oed->oed_IOReq = ioreq; + + epcaps = (ioreq->iouh_DevAddr<iouh_Endpoint<iouh_MaxPktSize<iouh_Dir == UHDIR_IN) ? OECF_DIRECTION_IN : OECF_DIRECTION_OUT; + + if(ioreq->iouh_Flags & UHFF_LOWSPEED) + { + KPRINTF(5, ("*** LOW SPEED ***\n")); + epcaps |= OECF_LOWSPEED; + } + + WRITEMEM32_LE(&oed->oed_EPCaps, epcaps); + oed->oed_TailPtr = hc->hc_OhciTermTD->otd_Self; + + predotd = NULL; + phyaddr = (ULONG) pciGetPhysical(hc, ioreq->iouh_Data); + actual = 0; + do + { + otd = ohciAllocTD(hc); + if(!otd) + { + predotd->otd_Succ = NULL; + break; + } + otd->otd_ED = oed; + if(predotd) + { + predotd->otd_Succ = otd; + predotd->otd_NextTD = otd->otd_Self; + } else { + WRITEMEM32_LE(&oed->oed_HeadPtr, READMEM32_LE(otd->otd_Self)|(unit->hu_DevDataToggle[devadrep] ? OEHF_DATA1 : 0)); + oed->oed_FirstTD = otd; + } + len = ioreq->iouh_Length - actual; + if(len > OHCI_PAGE_SIZE) + { + len = OHCI_PAGE_SIZE; + } + otd->otd_Length = len; + KPRINTF(1, ("TD with %ld bytes\n", len)); + CONSTWRITEMEM32_LE(&otd->otd_Ctrl, OTCF_CC_INVALID|OTCF_NOINT); + if(len) + { + WRITEMEM32_LE(&otd->otd_BufferPtr, phyaddr); + phyaddr += len - 1; + WRITEMEM32_LE(&otd->otd_BufferEnd, phyaddr); + phyaddr++; + } else { + CONSTWRITEMEM32_LE(&otd->otd_BufferPtr, 0); + CONSTWRITEMEM32_LE(&otd->otd_BufferEnd, 0); + } + actual += len; + predotd = otd; + } while(actual < ioreq->iouh_Length); + + if(actual != ioreq->iouh_Length) + { + // out of TDs + KPRINTF(200, ("Out of TDs for Int Transfer!\n")); + otd = oed->oed_FirstTD; + while(otd) + { + predotd = otd; + otd = otd->otd_Succ; + ohciFreeTD(hc, predotd); + } + ohciFreeED(hc, oed); + break; + } + predotd->otd_Succ = NULL; + predotd->otd_NextTD = hc->hc_OhciTermTD->otd_Self; + + CONSTWRITEMEM32_LE(&predotd->otd_Ctrl, OTCF_CC_INVALID); + + if(ioreq->iouh_Interval >= 31) + { + intoed = hc->hc_OhciIntED[4]; // 32ms interval + } else { + UWORD cnt = 0; + do + { + intoed = hc->hc_OhciIntED[cnt++]; + } while(ioreq->iouh_Interval > (1<iouh_Req.io_Message.mn_Node); + ioreq->iouh_DriverPrivate1 = oed; + + // manage endpoint going busy + unit->hu_DevBusyReq[devadrep] = ioreq; + unit->hu_NakTimeoutFrame[devadrep] = (ioreq->iouh_Flags & UHFF_NAKTIMEOUT) ? hc->hc_FrameCounter + ioreq->iouh_NakTimeout : 0; + + Disable(); + AddTail(&hc->hc_TDQueue, (struct Node *) ioreq); + + // looks good to me, now enqueue this entry (behind Int head) + oed->oed_Succ = intoed->oed_Succ; + oed->oed_NextED = intoed->oed_Succ->oed_Self; + oed->oed_Pred = intoed; + intoed->oed_Succ = oed; + intoed->oed_NextED = oed->oed_Self; + oed->oed_Succ->oed_Pred = oed; + SYNC; + EIEIO; + + KPRINTF(5, ("ED: EPCaps=%08lx, HeadPtr=%08lx, TailPtr=%08lx, NextED=%08lx\n", + READMEM32_LE(&oed->oed_EPCaps), + READMEM32_LE(&oed->oed_HeadPtr), + READMEM32_LE(&oed->oed_TailPtr), + READMEM32_LE(&oed->oed_NextED))); + Enable(); + + ioreq = (struct IOUsbHWReq *) hc->hc_IntXFerQueue.lh_Head; + } +} +/* \\\ */ + +/* /// "ohciScheduleBulkTDs()" */ +void ohciScheduleBulkTDs(struct PCIController *hc) +{ + struct PCIUnit *unit = hc->hc_Unit; + struct IOUsbHWReq *ioreq; + UWORD devadrep; + struct OhciED *oed; + struct OhciTD *otd; + struct OhciTD *predotd; + ULONG actual; + ULONG epcaps; + ULONG len; + ULONG phyaddr; + ULONG oldenables; + + /* *** BULK Transfers *** */ + KPRINTF(1, ("Scheduling new BULK transfers...\n")); + ioreq = (struct IOUsbHWReq *) hc->hc_BulkXFerQueue.lh_Head; + while(((struct Node *) ioreq)->ln_Succ) + { + devadrep = (ioreq->iouh_DevAddr<<5) + ioreq->iouh_Endpoint + ((ioreq->iouh_Dir == UHDIR_IN) ? 0x10 : 0); + KPRINTF(10, ("New BULK transfer to %ld.%ld: %ld bytes\n", ioreq->iouh_DevAddr, ioreq->iouh_Endpoint, ioreq->iouh_Length)); + /* is endpoint already in use or do we have to wait for next transaction */ + if(unit->hu_DevBusyReq[devadrep]) + { + KPRINTF(5, ("Endpoint %02lx in use!\n", devadrep)); + ioreq = (struct IOUsbHWReq *) ((struct Node *) ioreq)->ln_Succ; + continue; + } + + oed = ohciAllocED(hc); + if(!oed) + { + break; + } + + oed->oed_IOReq = ioreq; + + epcaps = (ioreq->iouh_DevAddr<iouh_Endpoint<iouh_MaxPktSize<iouh_Dir == UHDIR_IN) ? OECF_DIRECTION_IN : OECF_DIRECTION_OUT; + + if(ioreq->iouh_Flags & UHFF_LOWSPEED) + { + KPRINTF(5, ("*** LOW SPEED ***\n")); + epcaps |= OECF_LOWSPEED; + } + + WRITEMEM32_LE(&oed->oed_EPCaps, epcaps); + oed->oed_TailPtr = hc->hc_OhciTermTD->otd_Self; + + predotd = NULL; + phyaddr = (ULONG) pciGetPhysical(hc, ioreq->iouh_Data); + actual = 0; + do + { + if((actual >= OHCI_TD_BULK_LIMIT) && (actual < ioreq->iouh_Length)) + { + KPRINTF(10, ("Bulk too large, splitting...\n")); + break; + } + otd = ohciAllocTD(hc); + if(!otd) + { + predotd->otd_Succ = NULL; + break; + } + otd->otd_ED = oed; + if(predotd) + { + predotd->otd_Succ = otd; + predotd->otd_NextTD = otd->otd_Self; + } else { + WRITEMEM32_LE(&oed->oed_HeadPtr, READMEM32_LE(otd->otd_Self)|(unit->hu_DevDataToggle[devadrep] ? OEHF_DATA1 : 0)); + oed->oed_FirstTD = otd; + } + len = ioreq->iouh_Length - actual; + if(len > OHCI_PAGE_SIZE) + { + len = OHCI_PAGE_SIZE; + } + otd->otd_Length = len; + KPRINTF(1, ("TD with %ld bytes\n", len)); + CONSTWRITEMEM32_LE(&otd->otd_Ctrl, OTCF_CC_INVALID|OTCF_NOINT); + if(len) + { + WRITEMEM32_LE(&otd->otd_BufferPtr, phyaddr); + phyaddr += len - 1; + WRITEMEM32_LE(&otd->otd_BufferEnd, phyaddr); + phyaddr++; + } else { + CONSTWRITEMEM32_LE(&otd->otd_BufferPtr, 0); + CONSTWRITEMEM32_LE(&otd->otd_BufferEnd, 0); + } + actual += len; + + predotd = otd; + } while((actual < ioreq->iouh_Length) || (len && (ioreq->iouh_Dir == UHDIR_OUT) && (actual == ioreq->iouh_Length) && (!ioreq->iouh_Flags & UHFF_NOSHORTPKT) && ((actual % ioreq->iouh_MaxPktSize) == 0))); + + if(!actual) + { + // out of TDs + KPRINTF(200, ("Out of TDs for Bulk Transfer!\n")); + otd = oed->oed_FirstTD; + while(otd) + { + predotd = otd; + otd = otd->otd_Succ; + ohciFreeTD(hc, predotd); + } + ohciFreeED(hc, oed); + break; + } + oed->oed_Continue = (actual < ioreq->iouh_Length); + predotd->otd_Succ = NULL; + predotd->otd_NextTD = hc->hc_OhciTermTD->otd_Self; + + CONSTWRITEMEM32_LE(&predotd->otd_Ctrl, OTCF_CC_INVALID); + + Remove(&ioreq->iouh_Req.io_Message.mn_Node); + ioreq->iouh_DriverPrivate1 = oed; + + // manage endpoint going busy + unit->hu_DevBusyReq[devadrep] = ioreq; + unit->hu_NakTimeoutFrame[devadrep] = (ioreq->iouh_Flags & UHFF_NAKTIMEOUT) ? hc->hc_FrameCounter + ioreq->iouh_NakTimeout : 0; + + Disable(); + AddTail(&hc->hc_TDQueue, (struct Node *) ioreq); + + // looks good to me, now enqueue this entry + oed->oed_Succ = hc->hc_OhciBulkTailED; + oed->oed_NextED = oed->oed_Succ->oed_Self; + oed->oed_Pred = hc->hc_OhciBulkTailED->oed_Pred; + oed->oed_Pred->oed_Succ = oed; + oed->oed_Pred->oed_NextED = oed->oed_Self; + oed->oed_Succ->oed_Pred = oed; + SYNC; + EIEIO; + + KPRINTF(10, ("Activating BULK at %ld\n", READREG32_LE(hc->hc_RegBase, OHCI_FRAMECOUNT))); + + KPRINTF(5, ("ED: EPCaps=%08lx, HeadPtr=%08lx, TailPtr=%08lx, NextED=%08lx\n", + READMEM32_LE(&oed->oed_EPCaps), + READMEM32_LE(&oed->oed_HeadPtr), + READMEM32_LE(&oed->oed_TailPtr), + READMEM32_LE(&oed->oed_NextED))); + + oldenables = READREG32_LE(hc->hc_RegBase, OHCI_CMDSTATUS); + if(!(oldenables & OCSF_BULKENABLE)) + { + CONSTWRITEREG32_LE(hc->hc_RegBase, OHCI_BULK_ED, 0); + } + oldenables |= OCSF_BULKENABLE; + WRITEREG32_LE(hc->hc_RegBase, OHCI_CMDSTATUS, oldenables); + SYNC; + EIEIO; + Enable(); + ioreq = (struct IOUsbHWReq *) hc->hc_BulkXFerQueue.lh_Head; + } +} +/* \\\ */ + +/* /// "ohciCompleteInt()" */ +void ohciCompleteInt(struct PCIController *hc) +{ + ULONG framecnt = READREG32_LE(hc->hc_RegBase, OHCI_FRAMECOUNT); + + KPRINTF(1, ("CompleteInt!\n")); + if(framecnt < (hc->hc_FrameCounter & 0xffff)) + { + hc->hc_FrameCounter |= 0xffff; + hc->hc_FrameCounter++; + hc->hc_FrameCounter += framecnt; + KPRINTF(10, ("Frame Counter Rollover %ld\n", hc->hc_FrameCounter)); + } else { + hc->hc_FrameCounter = (hc->hc_FrameCounter & 0xffff0000)|framecnt; + } + + /* **************** PROCESS DONE TRANSFERS **************** */ + + if(hc->hc_OhciDoneQueue) + { + ohciHandleFinishedTDs(hc); + } + + if(hc->hc_CtrlXFerQueue.lh_Head->ln_Succ) + { + ohciScheduleCtrlTDs(hc); + } + + if(hc->hc_IntXFerQueue.lh_Head->ln_Succ) + { + ohciScheduleIntTDs(hc); + } + + if(hc->hc_BulkXFerQueue.lh_Head->ln_Succ) + { + ohciScheduleBulkTDs(hc); + } + + KPRINTF(1, ("CompleteDone\n")); +} +/* \\\ */ + +/* /// "ohciIntCode()" */ +void ohciIntCode(HIDDT_IRQ_Handler *irq, HIDDT_IRQ_HwInfo *hw) +{ + struct PCIController *hc = (struct PCIController *) irq->h_Data; + struct PCIDevice *base = hc->hc_Device; + struct PCIUnit *unit = hc->hc_Unit; + ULONG intr = 0; + ULONG donehead = READMEM32_LE(&hc->hc_OhciHCCA->oha_DoneHead); + + if(donehead) + { + intr = OISF_DONEHEAD; + if(donehead & 1) + { + intr |= READREG32_LE(hc->hc_RegBase, OHCI_INTSTATUS); + } + donehead &= OHCI_PTRMASK; + KPRINTF(5, ("New Donehead %08lx for old %08lx\n", donehead, hc->hc_OhciDoneQueue)); + if(hc->hc_OhciDoneQueue) + { + struct OhciTD *donetd = (struct OhciTD *) (hc->hc_OhciDoneQueue - hc->hc_PCIVirtualAdjust - 16); + WRITEMEM32_LE(donetd->otd_NextTD, donehead); + } + hc->hc_OhciDoneQueue = donehead; + CONSTWRITEMEM32_LE(&hc->hc_OhciHCCA->oha_DoneHead, 0); + } else { + intr = READREG32_LE(hc->hc_RegBase, OHCI_INTSTATUS); + } + if(intr & hc->hc_PCIIntEnMask) + { + WRITEREG32_LE(hc->hc_RegBase, OHCI_INTSTATUS, intr); + KPRINTF(1, ("INT=%02lx\n", intr)); + if(intr & OISF_HOSTERROR) + { + KPRINTF(200, ("Host ERROR!\n")); + } + if(intr & OISF_SCHEDOVERRUN) + { + KPRINTF(200, ("Schedule overrun!\n")); + } + if(!hc->hc_Online) + { + return; + } + if(intr & OISF_FRAMECOUNTOVER) + { + ULONG framecnt = READREG32_LE(hc->hc_RegBase, OHCI_FRAMECOUNT); + hc->hc_FrameCounter |= 0x7fff; + hc->hc_FrameCounter++; + hc->hc_FrameCounter |= framecnt; + KPRINTF(10, ("Frame Counter Rollover %ld\n", hc->hc_FrameCounter)); + } + if(intr & OISF_HUBCHANGE) + { + UWORD hciport; + ULONG oldval; + UWORD portreg = OHCI_PORTSTATUS; + for(hciport = 0; hciport < hc->hc_NumPorts; hciport++, portreg += 4) + { + oldval = READREG32_LE(hc->hc_RegBase, portreg); + if(oldval & OHPF_OVERCURRENTCHG) + { + hc->hc_PortChangeMap[hciport] |= UPSF_PORT_OVER_CURRENT; + } + if(oldval & OHPF_RESETCHANGE) + { + hc->hc_PortChangeMap[hciport] |= UPSF_PORT_RESET; + } + if(oldval & OHPF_ENABLECHANGE) + { + hc->hc_PortChangeMap[hciport] |= UPSF_PORT_ENABLE; + } + if(oldval & OHPF_CONNECTCHANGE) + { + hc->hc_PortChangeMap[hciport] |= UPSF_PORT_CONNECTION; + } + if(oldval & OHPF_RESUMEDTX) + { + hc->hc_PortChangeMap[hciport] |= UPSF_PORT_SUSPEND; + } + KPRINTF(20, ("PCI Int Port %ld (glob %ld) Change %08lx\n", hciport, hc->hc_PortNum20[hciport] + 1, oldval)); + if(hc->hc_PortChangeMap[hciport]) + { + unit->hu_RootPortChanges |= 1UL<<(hc->hc_PortNum20[hciport] + 1); + } + } + uhwCheckRootHubChanges(unit); + } + if(intr & OISF_DONEHEAD) + { + KPRINTF(10, ("DoneHead %ld\n", READREG32_LE(hc->hc_RegBase, OHCI_FRAMECOUNT))); + SureCause(base, &hc->hc_CompleteInt); + } + } +} +/* \\\ */ + +/* ---------------------------------------------------------------------- * + * EHCI Specific Stuff * + * ---------------------------------------------------------------------- */ + +/* /// "ehciFreeAsyncContext()" */ +void ehciFreeAsyncContext(struct PCIController *hc, struct EhciQH *eqh) +{ + KPRINTF(5, ("Unlinking AsyncContext %08lx\n", eqh)); + // unlink from schedule + eqh->eqh_Pred->eqh_NextQH = eqh->eqh_Succ->eqh_Self; + SYNC; + EIEIO; + eqh->eqh_Succ->eqh_Pred = eqh->eqh_Pred; + eqh->eqh_Pred->eqh_Succ = eqh->eqh_Succ; + SYNC; + EIEIO; + + // need to wait until an async schedule rollover before freeing these + Disable(); + eqh->eqh_Succ = hc->hc_EhciAsyncFreeQH; + hc->hc_EhciAsyncFreeQH = eqh; + // activate doorbell + WRITEREG32_LE(hc->hc_RegBase, EHCI_USBCMD, hc->hc_EhciUsbCmd|EHUF_ASYNCDOORBELL); + Enable(); +} +/* \\\ */ + +/* /// "ehciFreePeriodicContext()" */ +void ehciFreePeriodicContext(struct PCIController *hc, struct EhciQH *eqh) +{ + struct EhciTD *etd; + struct EhciTD *nextetd; + + KPRINTF(5, ("Unlinking PeriodicContext %08lx\n", eqh)); + // unlink from schedule + eqh->eqh_Pred->eqh_NextQH = eqh->eqh_Succ->eqh_Self; + SYNC; + EIEIO; + eqh->eqh_Succ->eqh_Pred = eqh->eqh_Pred; + eqh->eqh_Pred->eqh_Succ = eqh->eqh_Succ; + SYNC; + EIEIO; + + Disable(); // avoid race condition with interrupt + nextetd = eqh->eqh_FirstTD; + while((etd = nextetd)) + { + KPRINTF(1, ("FreeTD %08lx\n", nextetd)); + nextetd = etd->etd_Succ; + ehciFreeTD(hc, etd); + } + ehciFreeQH(hc, eqh); + Enable(); +} +/* \\\ */ + +/* /// "ehciFreeQHandTDs()" */ +void ehciFreeQHandTDs(struct PCIController *hc, struct EhciQH *eqh) +{ + struct EhciTD *etd = NULL; + struct EhciTD *nextetd; + + KPRINTF(5, ("Unlinking QContext %08lx\n", eqh)); + nextetd = eqh->eqh_FirstTD; + while(nextetd) + { + KPRINTF(1, ("FreeTD %08lx\n", nextetd)); + etd = nextetd; + nextetd = (struct EhciTD *) etd->etd_Succ; + ehciFreeTD(hc, etd); + } + + ehciFreeQH(hc, eqh); +} +/* \\\ */ + +/* /// "ehciAllocQH()" */ +inline struct EhciQH * ehciAllocQH(struct PCIController *hc) +{ + struct EhciQH *eqh = hc->hc_EhciQHPool; + + if(!eqh) + { + // out of QHs! + KPRINTF(20, ("Out of QHs!\n")); + return NULL; + } + + hc->hc_EhciQHPool = (struct EhciQH *) eqh->eqh_Succ; + return(eqh); +} +/* \\\ */ + +/* /// "ehciFreeQH()" */ +inline void ehciFreeQH(struct PCIController *hc, struct EhciQH *eqh) +{ + eqh->eqh_Succ = hc->hc_EhciQHPool; + hc->hc_EhciQHPool = eqh; +} +/* \\\ */ + +/* /// "ehciAllocTD()" */ +inline struct EhciTD * ehciAllocTD(struct PCIController *hc) +{ + struct EhciTD *etd = hc->hc_EhciTDPool; + + if(!etd) + { + // out of TDs! + KPRINTF(20, ("Out of TDs!\n")); + return NULL; + } + + hc->hc_EhciTDPool = (struct EhciTD *) etd->etd_Succ; + return(etd); +} +/* \\\ */ + +/* /// "ehciFreeTD()" */ +inline void ehciFreeTD(struct PCIController *hc, struct EhciTD *etd) +{ + etd->etd_Succ = hc->hc_EhciTDPool; + hc->hc_EhciTDPool = etd; +} +/* \\\ */ + +/* /// "ehciUpdateIntTree()" */ +void ehciUpdateIntTree(struct PCIController *hc) +{ + struct EhciQH *eqh; + struct EhciQH *predeqh; + struct EhciQH *lastusedeqh; + UWORD cnt; + + // optimize linkage between queue heads + predeqh = lastusedeqh = hc->hc_EhciTermQH; + for(cnt = 0; cnt < 11; cnt++) + { + eqh = hc->hc_EhciIntQH[cnt]; + if(eqh->eqh_Succ != predeqh) + { + lastusedeqh = eqh->eqh_Succ; + } + eqh->eqh_NextQH = lastusedeqh->eqh_Self; + predeqh = eqh; + } +} +/* \\\ */ + +/* /// "ehciHandleFinishedTDs()" */ +void ehciHandleFinishedTDs(struct PCIController *hc) +{ + struct PCIUnit *unit = hc->hc_Unit; + struct IOUsbHWReq *ioreq; + struct IOUsbHWReq *nextioreq; + struct EhciQH *eqh; + struct EhciTD *etd; + struct EhciTD *predetd; + UWORD devadrep; + ULONG len; + UWORD inspect; + ULONG nexttd; + BOOL shortpkt; + ULONG ctrlstatus; + ULONG epctrlstatus; + ULONG actual; + BOOL halted; + BOOL updatetree = FALSE; + BOOL zeroterm; + ULONG phyaddr; + + KPRINTF(1, ("Checking for Async work done...\n")); + ioreq = (struct IOUsbHWReq *) hc->hc_TDQueue.lh_Head; + while((nextioreq = (struct IOUsbHWReq *) ((struct Node *) ioreq)->ln_Succ)) + { + eqh = (struct EhciQH *) ioreq->iouh_DriverPrivate1; + if(eqh) + { + KPRINTF(1, ("Examining IOReq=%08lx with EQH=%08lx\n", ioreq, eqh)); + SYNC; + EIEIO; + epctrlstatus = READMEM32_LE(&eqh->eqh_CtrlStatus); + nexttd = READMEM32_LE(&eqh->eqh_NextTD); + devadrep = (ioreq->iouh_DevAddr<<5) + ioreq->iouh_Endpoint + ((ioreq->iouh_Dir == UHDIR_IN) ? 0x10 : 0); + halted = ((epctrlstatus & (ETCF_ACTIVE|ETSF_HALTED)) == ETSF_HALTED); + if(halted || (!(epctrlstatus & ETCF_ACTIVE) && (nexttd & EHCI_TERMINATE))) + { + KPRINTF(1, ("AS: CS=%08lx CP=%08lx NX=%08lx\n", epctrlstatus, READMEM32_LE(&eqh->eqh_CurrTD), nexttd)); + shortpkt = FALSE; + actual = 0; + inspect = 1; + etd = eqh->eqh_FirstTD; + do + { + ctrlstatus = READMEM32_LE(&etd->etd_CtrlStatus); + KPRINTF(1, ("AS: CS=%08lx SL=%08lx TD=%08lx\n", ctrlstatus, READMEM32_LE(&etd->etd_Self), etd)); + if(ctrlstatus & ETCF_ACTIVE) + { + if(halted) + { + KPRINTF(20, ("Async: Halted before TD\n")); + //ctrlstatus = eqh->eqh_CtrlStatus; + inspect = 0; + if(unit->hu_NakTimeoutFrame[devadrep] && (hc->hc_FrameCounter > unit->hu_NakTimeoutFrame[devadrep])) + { + KPRINTF(20, ("NAK timeout\n")); + ioreq->iouh_Req.io_Error = UHIOERR_NAKTIMEOUT; + } + break; + } else { + // what happened here? The host controller was just updating the fields and has not finished yet + ctrlstatus = epctrlstatus; + + /*KPRINTF(20, ("AS: CS=%08lx CP=%08lx NX=%08lx\n", epctrlstatus, READMEM32_LE(&eqh->eqh_CurrTD), nexttd)); + KPRINTF(20, ("AS: CS=%08lx CP=%08lx NX=%08lx\n", READMEM32_LE(&eqh->eqh_CtrlStatus), READMEM32_LE(&eqh->eqh_CurrTD), READMEM32_LE(&eqh->eqh_NextTD))); + KPRINTF(20, ("AS: CS=%08lx SL=%08lx TD=%08lx\n", ctrlstatus, READMEM32_LE(&etd->etd_Self), etd)); + etd = eqh->eqh_FirstTD; + do + { + KPRINTF(20, ("XX: CS=%08lx SL=%08lx TD=%08lx\n", READMEM32_LE(&etd->etd_CtrlStatus), READMEM32_LE(&etd->etd_Self), etd)); + } while(etd = etd->etd_Succ); + KPRINTF(20, ("Async: Internal error! Still active?!\n")); + inspect = 2; + break;*/ + } + } + + if(ctrlstatus & (ETSF_HALTED|ETSF_TRANSERR|ETSF_BABBLE|ETSF_DATABUFFERERR)) + { + if(ctrlstatus & ETSF_BABBLE) + { + KPRINTF(20, ("Babble error %08lx\n", ctrlstatus)); + ioreq->iouh_Req.io_Error = UHIOERR_OVERFLOW; + } + else if(ctrlstatus & ETSF_DATABUFFERERR) + { + KPRINTF(20, ("Databuffer error\n")); + ioreq->iouh_Req.io_Error = UHIOERR_HOSTERROR; + } + else if(ctrlstatus & ETSF_TRANSERR) + { + if((ctrlstatus & ETCM_ERRORLIMIT)>>ETCS_ERRORLIMIT) + { + KPRINTF(20, ("STALLED!\n")); + ioreq->iouh_Req.io_Error = UHIOERR_STALL; + } else { + KPRINTF(20, ("TIMEOUT!\n")); + ioreq->iouh_Req.io_Error = UHIOERR_TIMEOUT; + } + } + inspect = 0; + break; + } + + len = etd->etd_Length - ((ctrlstatus & ETSM_TRANSLENGTH)>>ETSS_TRANSLENGTH); + if((ctrlstatus & ETCM_PIDCODE) != ETCF_PIDCODE_SETUP) // don't count setup packet + { + actual += len; + } + if(ctrlstatus & ETSM_TRANSLENGTH) + { + KPRINTF(10, ("Short packet: %ld < %ld\n", len, etd->etd_Length)); + shortpkt = TRUE; + break; + } + etd = etd->etd_Succ; + } while(etd && (!(ctrlstatus & ETCF_READYINTEN))); + /*if(inspect == 2) + { + // phantom halted + ioreq = nextioreq; + continue; + }*/ + + if(((actual + ioreq->iouh_Actual) < eqh->eqh_Actual) && (!ioreq->iouh_Req.io_Error) && (!(ioreq->iouh_Flags & UHFF_ALLOWRUNTPKTS))) + { + ioreq->iouh_Req.io_Error = UHIOERR_RUNTPACKET; + } + ioreq->iouh_Actual += actual; + if(inspect && (!shortpkt) && (eqh->eqh_Actual < ioreq->iouh_Length)) + { + KPRINTF(10, ("Reloading BULK at %ld/%ld\n", eqh->eqh_Actual, ioreq->iouh_Length)); + // reload + ctrlstatus = (ioreq->iouh_Dir == UHDIR_IN) ? (ETCF_3ERRORSLIMIT|ETCF_ACTIVE|ETCF_PIDCODE_IN) : (ETCF_3ERRORSLIMIT|ETCF_ACTIVE|ETCF_PIDCODE_OUT); + phyaddr = (ULONG) pciGetPhysical(hc, &(((UBYTE *) ioreq->iouh_Data)[ioreq->iouh_Actual])); + predetd = etd = eqh->eqh_FirstTD; + + CONSTWRITEMEM32_LE(&eqh->eqh_CurrTD, EHCI_TERMINATE); + CONSTWRITEMEM32_LE(&eqh->eqh_NextTD, EHCI_TERMINATE); + CONSTWRITEMEM32_LE(&eqh->eqh_AltNextTD, EHCI_TERMINATE); + do + { + len = ioreq->iouh_Length - eqh->eqh_Actual; + if(len > 4*EHCI_PAGE_SIZE) + { + len = 4*EHCI_PAGE_SIZE; + } + etd->etd_Length = len; + KPRINTF(1, ("Reload Bulk TD %08lx len %ld (%ld/%ld) phy=%08lx\n", + etd, len, eqh->eqh_Actual, ioreq->iouh_Length, phyaddr)); + WRITEMEM32_LE(&etd->etd_CtrlStatus, ctrlstatus|(len<etd_BufferPtr[0], phyaddr); + WRITEMEM32_LE(&etd->etd_BufferPtr[1], (phyaddr & EHCI_PAGE_MASK) + (1*EHCI_PAGE_SIZE)); + WRITEMEM32_LE(&etd->etd_BufferPtr[2], (phyaddr & EHCI_PAGE_MASK) + (2*EHCI_PAGE_SIZE)); + WRITEMEM32_LE(&etd->etd_BufferPtr[3], (phyaddr & EHCI_PAGE_MASK) + (3*EHCI_PAGE_SIZE)); + WRITEMEM32_LE(&etd->etd_BufferPtr[4], (phyaddr & EHCI_PAGE_MASK) + (4*EHCI_PAGE_SIZE)); + phyaddr += len; + eqh->eqh_Actual += len; + zeroterm = (len && (ioreq->iouh_Dir == UHDIR_OUT) && (eqh->eqh_Actual == ioreq->iouh_Length) && (!ioreq->iouh_Flags & UHFF_NOSHORTPKT) && ((eqh->eqh_Actual % ioreq->iouh_MaxPktSize) == 0)); + predetd = etd; + etd = etd->etd_Succ; + if((!etd) && zeroterm) + { + // rare case where the zero packet would be lost, allocate etd and append zero packet. + etd = ehciAllocTD(hc); + if(!etd) + { + KPRINTF(200, ("INTERNAL ERROR! This should not happen! Could not allocate zero packet TD\n")); + break; + } + predetd->etd_Succ = etd; + predetd->etd_NextTD = etd->etd_Self; + predetd->etd_AltNextTD = hc->hc_ShortPktEndTD->etd_Self; + etd->etd_Succ = NULL; + CONSTWRITEMEM32_LE(&etd->etd_NextTD, EHCI_TERMINATE); + CONSTWRITEMEM32_LE(&etd->etd_AltNextTD, EHCI_TERMINATE); + } + } while(etd && ((eqh->eqh_Actual < ioreq->iouh_Length) || zeroterm)); + ctrlstatus |= ETCF_READYINTEN|(predetd->etd_Length<etd_CtrlStatus, ctrlstatus); + CONSTWRITEMEM32_LE(&predetd->etd_NextTD, EHCI_TERMINATE); + CONSTWRITEMEM32_LE(&predetd->etd_AltNextTD, EHCI_TERMINATE); + SYNC; + EIEIO; + etd = eqh->eqh_FirstTD; + eqh->eqh_NextTD = etd->etd_Self; + SYNC; + EIEIO; + unit->hu_NakTimeoutFrame[devadrep] = (ioreq->iouh_Flags & UHFF_NAKTIMEOUT) ? hc->hc_FrameCounter + (ioreq->iouh_NakTimeout<<3) : 0; + } else { + unit->hu_DevBusyReq[devadrep] = NULL; + Remove(&ioreq->iouh_Req.io_Message.mn_Node); + ehciFreeAsyncContext(hc, eqh); + // use next data toggle bit based on last successful transaction + KPRINTF(1, ("Old Toggle %04lx:%ld\n", devadrep, unit->hu_DevDataToggle[devadrep])); + unit->hu_DevDataToggle[devadrep] = (ctrlstatus & ETCF_DATA1) ? TRUE : FALSE; + KPRINTF(1, ("Toggle now %04lx:%ld\n", devadrep, unit->hu_DevDataToggle[devadrep])); + if(inspect) + { + if(ioreq->iouh_Req.io_Command == UHCMD_CONTROLXFER) + { + // check for sucessful clear feature and set address ctrl transfers + uhwCheckSpecialCtrlTransfers(hc, ioreq); + } + } + ReplyMsg(&ioreq->iouh_Req.io_Message); + } + } + } else { + KPRINTF(20, ("IOReq=%08lx has no UQH!\n", ioreq)); + } + ioreq = nextioreq; + } + + KPRINTF(1, ("Checking for Periodic work done...\n")); + ioreq = (struct IOUsbHWReq *) hc->hc_PeriodicTDQueue.lh_Head; + while((nextioreq = (struct IOUsbHWReq *) ((struct Node *) ioreq)->ln_Succ)) + { + eqh = (struct EhciQH *) ioreq->iouh_DriverPrivate1; + if(eqh) + { + KPRINTF(1, ("Examining IOReq=%08lx with EQH=%08lx\n", ioreq, eqh)); + nexttd = READMEM32_LE(&eqh->eqh_NextTD); + etd = eqh->eqh_FirstTD; + ctrlstatus = READMEM32_LE(&eqh->eqh_CtrlStatus); + devadrep = (ioreq->iouh_DevAddr<<5) + ioreq->iouh_Endpoint + ((ioreq->iouh_Dir == UHDIR_IN) ? 0x10 : 0); + halted = ((ctrlstatus & (ETCF_ACTIVE|ETSF_HALTED)) == ETSF_HALTED); + if(halted || (!(ctrlstatus & ETCF_ACTIVE) && (nexttd & EHCI_TERMINATE))) + { + KPRINTF(1, ("EQH not active %08lx\n", ctrlstatus)); + shortpkt = FALSE; + actual = 0; + inspect = 1; + do + { + ctrlstatus = READMEM32_LE(&etd->etd_CtrlStatus); + KPRINTF(1, ("Periodic: TD=%08lx CS=%08lx\n", etd, ctrlstatus)); + if(ctrlstatus & ETCF_ACTIVE) + { + if(halted) + { + KPRINTF(20, ("Periodic: Halted before TD\n")); + //ctrlstatus = eqh->eqh_CtrlStatus; + inspect = 0; + if(unit->hu_NakTimeoutFrame[devadrep] && (hc->hc_FrameCounter > unit->hu_NakTimeoutFrame[devadrep])) + { + KPRINTF(20, ("NAK timeout\n")); + ioreq->iouh_Req.io_Error = UHIOERR_NAKTIMEOUT; + } + break; + } else { + KPRINTF(20, ("Periodic: Internal error! Still active?!\n")); + break; + } + } + + if(ctrlstatus & (ETSF_HALTED|ETSF_TRANSERR|ETSF_BABBLE|ETSF_DATABUFFERERR|ETSF_MISSEDCSPLIT)) + { + if(ctrlstatus & ETSF_BABBLE) + { + KPRINTF(20, ("Babble error %08lx\n", ctrlstatus)); + ioreq->iouh_Req.io_Error = UHIOERR_OVERFLOW; + } + else if(ctrlstatus & ETSF_MISSEDCSPLIT) + { + KPRINTF(20, ("Missed CSplit %08lx\n", ctrlstatus)); + ioreq->iouh_Req.io_Error = UHIOERR_STALL; + } + else if(ctrlstatus & ETSF_DATABUFFERERR) + { + KPRINTF(20, ("Databuffer error\n")); + ioreq->iouh_Req.io_Error = UHIOERR_HOSTERROR; + } + else if(ctrlstatus & ETSF_TRANSERR) + { + if((ctrlstatus & ETCM_ERRORLIMIT)>>ETCS_ERRORLIMIT) + { + KPRINTF(20, ("STALLED!\n")); + ioreq->iouh_Req.io_Error = UHIOERR_STALL; + } else { + KPRINTF(20, ("TIMEOUT!\n")); + ioreq->iouh_Req.io_Error = UHIOERR_TIMEOUT; + } + } + else if(unit->hu_NakTimeoutFrame[devadrep] && (hc->hc_FrameCounter > unit->hu_NakTimeoutFrame[devadrep])) + { + ioreq->iouh_Req.io_Error = UHIOERR_NAKTIMEOUT; + } + inspect = 0; + break; + } + + len = etd->etd_Length - ((ctrlstatus & ETSM_TRANSLENGTH)>>ETSS_TRANSLENGTH); + actual += len; + if(ctrlstatus & ETSM_TRANSLENGTH) + { + KPRINTF(10, ("Short packet: %ld < %ld\n", len, etd->etd_Length)); + shortpkt = TRUE; + break; + } + etd = etd->etd_Succ; + } while(etd); + if((actual < eqh->eqh_Actual) && (!ioreq->iouh_Req.io_Error) && (!(ioreq->iouh_Flags & UHFF_ALLOWRUNTPKTS))) + { + ioreq->iouh_Req.io_Error = UHIOERR_RUNTPACKET; + } + ioreq->iouh_Actual += actual; + unit->hu_DevBusyReq[devadrep] = NULL; + Remove(&ioreq->iouh_Req.io_Message.mn_Node); + ehciFreePeriodicContext(hc, eqh); + updatetree = TRUE; + // use next data toggle bit based on last successful transaction + KPRINTF(1, ("Old Toggle %04lx:%ld\n", devadrep, unit->hu_DevDataToggle[devadrep])); + unit->hu_DevDataToggle[devadrep] = (ctrlstatus & ETCF_DATA1) ? TRUE : FALSE; + KPRINTF(1, ("Toggle now %04lx:%ld\n", devadrep, unit->hu_DevDataToggle[devadrep])); + ReplyMsg(&ioreq->iouh_Req.io_Message); + } + } else { + KPRINTF(20, ("IOReq=%08lx has no UQH!\n", ioreq)); + } + ioreq = nextioreq; + } + if(updatetree) + { + ehciUpdateIntTree(hc); + } +} +/* \\\ */ + +/* /// "ehciScheduleCtrlTDs()" */ +void ehciScheduleCtrlTDs(struct PCIController *hc) +{ + struct PCIUnit *unit = hc->hc_Unit; + struct IOUsbHWReq *ioreq; + UWORD devadrep; + struct EhciQH *eqh; + struct EhciTD *setupetd; + struct EhciTD *dataetd; + struct EhciTD *termetd; + struct EhciTD *predetd; + ULONG epcaps; + ULONG ctrlstatus; + ULONG len; + ULONG phyaddr; + + /* *** CTRL Transfers *** */ + KPRINTF(1, ("Scheduling new CTRL transfers...\n")); + ioreq = (struct IOUsbHWReq *) hc->hc_CtrlXFerQueue.lh_Head; + while(((struct Node *) ioreq)->ln_Succ) + { + devadrep = (ioreq->iouh_DevAddr<<5) + ioreq->iouh_Endpoint; + KPRINTF(10, ("New CTRL transfer to %ld.%ld: %ld bytes\n", ioreq->iouh_DevAddr, ioreq->iouh_Endpoint, ioreq->iouh_Length)); + /* is endpoint already in use or do we have to wait for next transaction */ + if(unit->hu_DevBusyReq[devadrep]) + { + KPRINTF(5, ("Endpoint %02lx in use!\n", devadrep)); + ioreq = (struct IOUsbHWReq *) ((struct Node *) ioreq)->ln_Succ; + continue; + } + + eqh = ehciAllocQH(hc); + if(!eqh) + { + break; + } + + setupetd = ehciAllocTD(hc); + if(!setupetd) + { + ehciFreeQH(hc, eqh); + break; + } + termetd = ehciAllocTD(hc); + if(!termetd) + { + ehciFreeTD(hc, setupetd); + ehciFreeQH(hc, eqh); + break; + } + eqh->eqh_IOReq = ioreq; + eqh->eqh_FirstTD = setupetd; + eqh->eqh_Actual = 0; + + epcaps = ((0<iouh_MaxPktSize<iouh_DevAddr<iouh_Endpoint<iouh_Flags & UHFF_SPLITTRANS) + { + KPRINTF(10, ("*** SPLIT TRANSACTION to HubPort %ld at Addr %ld\n", ioreq->iouh_SplitHubPort, ioreq->iouh_SplitHubAddr)); + // full speed and low speed handling + WRITEMEM32_LE(&eqh->eqh_SplitCtrl, EQSF_MULTI_1|(ioreq->iouh_SplitHubPort<iouh_SplitHubAddr<iouh_Flags & UHFF_LOWSPEED) + { + KPRINTF(10, ("*** LOW SPEED ***\n")); + epcaps |= EQEF_LOWSPEED; + } + } else { + CONSTWRITEMEM32_LE(&eqh->eqh_SplitCtrl, EQSF_MULTI_1); + epcaps |= EQEF_HIGHSPEED; + } + WRITEMEM32_LE(&eqh->eqh_EPCaps, epcaps); + //eqh->eqh_CtrlStatus = eqh->eqh_CurrTD = 0; + //eqh->eqh_AltNextTD = eqh->eqh_NextTD = setupetd->etd_Self; + + //termetd->etd_QueueHead = setupetd->etd_QueueHead = eqh; + + KPRINTF(1, ("SetupTD=%08lx, TermTD=%08lx\n", setupetd, termetd)); + + // fill setup td + setupetd->etd_Length = 8; + + CONSTWRITEMEM32_LE(&setupetd->etd_CtrlStatus, (8<iouh_SetupData); + WRITEMEM32_LE(&setupetd->etd_BufferPtr[0], phyaddr); + WRITEMEM32_LE(&setupetd->etd_BufferPtr[1], (phyaddr + 8) & EHCI_PAGE_MASK); // theoretically, setup data may cross one page + setupetd->etd_BufferPtr[2] = 0; // clear for overlay bits + + ctrlstatus = (ioreq->iouh_SetupData.bmRequestType & URTF_IN) ? (ETCF_3ERRORSLIMIT|ETCF_ACTIVE|ETCF_PIDCODE_IN) : (ETCF_3ERRORSLIMIT|ETCF_ACTIVE|ETCF_PIDCODE_OUT); + predetd = setupetd; + if(ioreq->iouh_Length) + { + phyaddr = (ULONG) pciGetPhysical(hc, ioreq->iouh_Data); + do + { + dataetd = ehciAllocTD(hc); + if(!dataetd) + { + break; + } + ctrlstatus ^= ETCF_DATA1; // toggle bit + predetd->etd_Succ = dataetd; + predetd->etd_NextTD = dataetd->etd_Self; + dataetd->etd_AltNextTD = termetd->etd_Self; + + len = ioreq->iouh_Length - eqh->eqh_Actual; + if(len > 4*EHCI_PAGE_SIZE) + { + len = 4*EHCI_PAGE_SIZE; + } + dataetd->etd_Length = len; + WRITEMEM32_LE(&dataetd->etd_CtrlStatus, ctrlstatus|(len<etd_BufferPtr[0], phyaddr); + WRITEMEM32_LE(&dataetd->etd_BufferPtr[1], (phyaddr & EHCI_PAGE_MASK) + (1*EHCI_PAGE_SIZE)); + WRITEMEM32_LE(&dataetd->etd_BufferPtr[2], (phyaddr & EHCI_PAGE_MASK) + (2*EHCI_PAGE_SIZE)); + WRITEMEM32_LE(&dataetd->etd_BufferPtr[3], (phyaddr & EHCI_PAGE_MASK) + (3*EHCI_PAGE_SIZE)); + WRITEMEM32_LE(&dataetd->etd_BufferPtr[4], (phyaddr & EHCI_PAGE_MASK) + (4*EHCI_PAGE_SIZE)); + phyaddr += len; + eqh->eqh_Actual += len; + predetd = dataetd; + } while(eqh->eqh_Actual < ioreq->iouh_Length); + if(!dataetd) + { + // not enough dataetds? try again later + ehciFreeQHandTDs(hc, eqh); + ehciFreeTD(hc, termetd); // this one's not linked yet + break; + } + } + // TERM packet + ctrlstatus |= ETCF_DATA1|ETCF_READYINTEN; + ctrlstatus ^= (ETCF_PIDCODE_IN^ETCF_PIDCODE_OUT); + + predetd->etd_NextTD = termetd->etd_Self; + predetd->etd_Succ = termetd; + CONSTWRITEMEM32_LE(&termetd->etd_NextTD, EHCI_TERMINATE); + CONSTWRITEMEM32_LE(&termetd->etd_AltNextTD, EHCI_TERMINATE); + WRITEMEM32_LE(&termetd->etd_CtrlStatus, ctrlstatus); + termetd->etd_Length = 0; + termetd->etd_BufferPtr[0] = 0; // clear for overlay bits + termetd->etd_BufferPtr[1] = 0; // clear for overlay bits + termetd->etd_BufferPtr[2] = 0; // clear for overlay bits + termetd->etd_Succ = NULL; + + // due to sillicon bugs, we fill in the first overlay ourselves. + eqh->eqh_CurrTD = setupetd->etd_Self; + eqh->eqh_NextTD = setupetd->etd_NextTD; + eqh->eqh_AltNextTD = setupetd->etd_AltNextTD; + eqh->eqh_CtrlStatus = setupetd->etd_CtrlStatus; + eqh->eqh_BufferPtr[0] = setupetd->etd_BufferPtr[0]; + eqh->eqh_BufferPtr[1] = setupetd->etd_BufferPtr[1]; + eqh->eqh_BufferPtr[2] = 0; + + Remove(&ioreq->iouh_Req.io_Message.mn_Node); + ioreq->iouh_DriverPrivate1 = eqh; + + // manage endpoint going busy + unit->hu_DevBusyReq[devadrep] = ioreq; + unit->hu_NakTimeoutFrame[devadrep] = (ioreq->iouh_Flags & UHFF_NAKTIMEOUT) ? hc->hc_FrameCounter + (ioreq->iouh_NakTimeout<<3) : 0; + + Disable(); + AddTail(&hc->hc_TDQueue, (struct Node *) ioreq); + + // looks good to me, now enqueue this entry (just behind the asyncQH) + eqh->eqh_Succ = hc->hc_EhciAsyncQH->eqh_Succ; + eqh->eqh_NextQH = eqh->eqh_Succ->eqh_Self; + SYNC; + EIEIO; + eqh->eqh_Pred = hc->hc_EhciAsyncQH; + eqh->eqh_Succ->eqh_Pred = eqh; + hc->hc_EhciAsyncQH->eqh_Succ = eqh; + hc->hc_EhciAsyncQH->eqh_NextQH = eqh->eqh_Self; + SYNC; + EIEIO; + Enable(); + + ioreq = (struct IOUsbHWReq *) hc->hc_CtrlXFerQueue.lh_Head; + } +} +/* \\\ */ + +/* /// "ehciScheduleIntTDs()" */ +void ehciScheduleIntTDs(struct PCIController *hc) +{ + struct PCIUnit *unit = hc->hc_Unit; + struct IOUsbHWReq *ioreq; + UWORD devadrep; + UWORD cnt; + struct EhciQH *eqh; + struct EhciQH *inteqh; + struct EhciTD *etd; + struct EhciTD *predetd; + ULONG epcaps; + ULONG ctrlstatus; + ULONG splitctrl; + ULONG len; + ULONG phyaddr; + + /* *** INT Transfers *** */ + KPRINTF(1, ("Scheduling new INT transfers...\n")); + ioreq = (struct IOUsbHWReq *) hc->hc_IntXFerQueue.lh_Head; + while(((struct Node *) ioreq)->ln_Succ) + { + devadrep = (ioreq->iouh_DevAddr<<5) + ioreq->iouh_Endpoint + ((ioreq->iouh_Dir == UHDIR_IN) ? 0x10 : 0); + KPRINTF(10, ("New INT transfer to %ld.%ld: %ld bytes\n", ioreq->iouh_DevAddr, ioreq->iouh_Endpoint, ioreq->iouh_Length)); + /* is endpoint already in use or do we have to wait for next transaction */ + if(unit->hu_DevBusyReq[devadrep]) + { + KPRINTF(5, ("Endpoint %02lx in use!\n", devadrep)); + ioreq = (struct IOUsbHWReq *) ((struct Node *) ioreq)->ln_Succ; + continue; + } + + eqh = ehciAllocQH(hc); + if(!eqh) + { + break; + } + + eqh->eqh_IOReq = ioreq; + eqh->eqh_Actual = 0; + + epcaps = (0<iouh_MaxPktSize<iouh_DevAddr<iouh_Endpoint<iouh_Flags & UHFF_SPLITTRANS) + { + KPRINTF(10, ("*** SPLIT TRANSACTION to HubPort %ld at Addr %ld\n", ioreq->iouh_SplitHubPort, ioreq->iouh_SplitHubAddr)); + // full speed and low speed handling + if(ioreq->iouh_Flags & UHFF_LOWSPEED) + { + KPRINTF(10, ("*** LOW SPEED ***\n")); + epcaps |= EQEF_LOWSPEED; + } + WRITEMEM32_LE(&eqh->eqh_SplitCtrl, (EQSF_MULTI_1|(0x01<iouh_SplitHubPort<iouh_SplitHubAddr<iouh_Interval >= 255) + { + inteqh = hc->hc_EhciIntQH[8]; // 256ms interval + } else { + cnt = 0; + do + { + inteqh = hc->hc_EhciIntQH[cnt++]; + } while(ioreq->iouh_Interval > (1<iouh_Flags & UHFF_MULTI_3) + { + splitctrl = EQSF_MULTI_3; + } + else if(ioreq->iouh_Flags & UHFF_MULTI_2) + { + splitctrl = EQSF_MULTI_2; + } else { + splitctrl = EQSF_MULTI_1; + } + if(ioreq->iouh_Interval < 2) // 0-1 µFrames + { + splitctrl |= (0xff<iouh_Interval < 4) // 2-3 µFrames + { + splitctrl |= (0x55<iouh_Interval < 8) // 4-7 µFrames + { + splitctrl |= (0x22<iouh_Interval > 511) // 64ms and higher + { + splitctrl |= (0x10<iouh_Interval >= 8) // 1-64ms + { + splitctrl |= (0x01<eqh_SplitCtrl, splitctrl); + if(ioreq->iouh_Interval >= 1024) + { + inteqh = hc->hc_EhciIntQH[10]; // 1024µFrames interval + } else { + cnt = 0; + do + { + inteqh = hc->hc_EhciIntQH[cnt++]; + } while(ioreq->iouh_Interval > (1<eqh_EPCaps, epcaps); + //eqh->eqh_CtrlStatus = eqh->eqh_CurrTD = 0; + eqh->eqh_FirstTD = NULL; // clear for ehciFreeQHandTDs() + + ctrlstatus = (ioreq->iouh_Dir == UHDIR_IN) ? (ETCF_3ERRORSLIMIT|ETCF_ACTIVE|ETCF_PIDCODE_IN) : (ETCF_3ERRORSLIMIT|ETCF_ACTIVE|ETCF_PIDCODE_OUT); + if(unit->hu_DevDataToggle[devadrep]) + { + // continue with data toggle 0 + ctrlstatus |= ETCF_DATA1; + } + predetd = NULL; + phyaddr = (ULONG) pciGetPhysical(hc, ioreq->iouh_Data); + do + { + etd = ehciAllocTD(hc); + if(!etd) + { + break; + } + if(predetd) + { + predetd->etd_Succ = etd; + predetd->etd_NextTD = etd->etd_Self; + predetd->etd_AltNextTD = hc->hc_ShortPktEndTD->etd_Self; + } else { + eqh->eqh_FirstTD = etd; + //eqh->eqh_AltNextTD = eqh->eqh_NextTD = etd->etd_Self; + } + + len = ioreq->iouh_Length - eqh->eqh_Actual; + if(len > 4*EHCI_PAGE_SIZE) + { + len = 4*EHCI_PAGE_SIZE; + } + etd->etd_Length = len; + WRITEMEM32_LE(&etd->etd_CtrlStatus, ctrlstatus|(len<etd_BufferPtr[0], phyaddr); + WRITEMEM32_LE(&etd->etd_BufferPtr[1], (phyaddr & EHCI_PAGE_MASK) + (1*EHCI_PAGE_SIZE)); + WRITEMEM32_LE(&etd->etd_BufferPtr[2], (phyaddr & EHCI_PAGE_MASK) + (2*EHCI_PAGE_SIZE)); + WRITEMEM32_LE(&etd->etd_BufferPtr[3], (phyaddr & EHCI_PAGE_MASK) + (3*EHCI_PAGE_SIZE)); + WRITEMEM32_LE(&etd->etd_BufferPtr[4], (phyaddr & EHCI_PAGE_MASK) + (4*EHCI_PAGE_SIZE)); + phyaddr += len; + eqh->eqh_Actual += len; + predetd = etd; + } while(eqh->eqh_Actual < ioreq->iouh_Length); + + if(!etd) + { + // not enough etds? try again later + ehciFreeQHandTDs(hc, eqh); + break; + } + ctrlstatus |= ETCF_READYINTEN|(etd->etd_Length<etd_CtrlStatus, ctrlstatus); + + CONSTWRITEMEM32_LE(&predetd->etd_NextTD, EHCI_TERMINATE); + CONSTWRITEMEM32_LE(&predetd->etd_AltNextTD, EHCI_TERMINATE); + predetd->etd_Succ = NULL; + + // due to sillicon bugs, we fill in the first overlay ourselves. + etd = eqh->eqh_FirstTD; + eqh->eqh_CurrTD = etd->etd_Self; + eqh->eqh_NextTD = etd->etd_NextTD; + eqh->eqh_AltNextTD = etd->etd_AltNextTD; + eqh->eqh_CtrlStatus = etd->etd_CtrlStatus; + eqh->eqh_BufferPtr[0] = etd->etd_BufferPtr[0]; + eqh->eqh_BufferPtr[1] = etd->etd_BufferPtr[1]; + eqh->eqh_BufferPtr[2] = etd->etd_BufferPtr[2]; + eqh->eqh_BufferPtr[3] = etd->etd_BufferPtr[3]; + eqh->eqh_BufferPtr[4] = etd->etd_BufferPtr[4]; + + Remove(&ioreq->iouh_Req.io_Message.mn_Node); + ioreq->iouh_DriverPrivate1 = eqh; + + // manage endpoint going busy + unit->hu_DevBusyReq[devadrep] = ioreq; + unit->hu_NakTimeoutFrame[devadrep] = (ioreq->iouh_Flags & UHFF_NAKTIMEOUT) ? hc->hc_FrameCounter + (ioreq->iouh_NakTimeout<<3) : 0; + + Disable(); + AddTail(&hc->hc_PeriodicTDQueue, (struct Node *) ioreq); + + // looks good to me, now enqueue this entry in the right IntQH + eqh->eqh_Succ = inteqh->eqh_Succ; + eqh->eqh_NextQH = eqh->eqh_Succ->eqh_Self; + SYNC; + EIEIO; + eqh->eqh_Pred = inteqh; + eqh->eqh_Succ->eqh_Pred = eqh; + inteqh->eqh_Succ = eqh; + inteqh->eqh_NextQH = eqh->eqh_Self; + SYNC; + EIEIO; + Enable(); + + ehciUpdateIntTree(hc); + + ioreq = (struct IOUsbHWReq *) hc->hc_IntXFerQueue.lh_Head; + } +} +/* \\\ */ + +/* /// "ehciScheduleBulkTDs()" */ +void ehciScheduleBulkTDs(struct PCIController *hc) +{ + struct PCIUnit *unit = hc->hc_Unit; + struct IOUsbHWReq *ioreq; + UWORD devadrep; + struct EhciQH *eqh; + struct EhciTD *etd = NULL; + struct EhciTD *predetd; + ULONG epcaps; + ULONG ctrlstatus; + ULONG splitctrl; + ULONG len; + ULONG phyaddr; + + /* *** BULK Transfers *** */ + KPRINTF(1, ("Scheduling new BULK transfers...\n")); + ioreq = (struct IOUsbHWReq *) hc->hc_BulkXFerQueue.lh_Head; + while(((struct Node *) ioreq)->ln_Succ) + { + devadrep = (ioreq->iouh_DevAddr<<5) + ioreq->iouh_Endpoint + ((ioreq->iouh_Dir == UHDIR_IN) ? 0x10 : 0); + KPRINTF(10, ("New BULK transfer to %ld.%ld: %ld bytes\n", ioreq->iouh_DevAddr, ioreq->iouh_Endpoint, ioreq->iouh_Length)); + /* is endpoint already in use or do we have to wait for next transaction */ + if(unit->hu_DevBusyReq[devadrep]) + { + KPRINTF(5, ("Endpoint %02lx in use!\n", devadrep)); + ioreq = (struct IOUsbHWReq *) ((struct Node *) ioreq)->ln_Succ; + continue; + } + + eqh = ehciAllocQH(hc); + if(!eqh) + { + break; + } + + eqh->eqh_IOReq = ioreq; + eqh->eqh_Actual = 0; + + epcaps = (0<iouh_MaxPktSize<iouh_DevAddr<iouh_Endpoint<iouh_Flags & UHFF_SPLITTRANS) + { + KPRINTF(10, ("*** SPLIT TRANSACTION to HubPort %ld at Addr %ld\n", ioreq->iouh_SplitHubPort, ioreq->iouh_SplitHubAddr)); + // full speed and low speed handling + if(ioreq->iouh_Flags & UHFF_LOWSPEED) + { + KPRINTF(10, ("*** LOW SPEED ***\n")); + epcaps |= EQEF_LOWSPEED; + } + WRITEMEM32_LE(&eqh->eqh_SplitCtrl, EQSF_MULTI_1|(ioreq->iouh_SplitHubPort<iouh_SplitHubAddr<iouh_Flags & UHFF_MULTI_3) + { + splitctrl = EQSF_MULTI_3; + } + else if(ioreq->iouh_Flags & UHFF_MULTI_2) + { + splitctrl = EQSF_MULTI_2; + } else { + splitctrl = EQSF_MULTI_1; + } + WRITEMEM32_LE(&eqh->eqh_SplitCtrl, splitctrl); + } + WRITEMEM32_LE(&eqh->eqh_EPCaps, epcaps); + //eqh->eqh_CtrlStatus = eqh->eqh_CurrTD = 0; + eqh->eqh_FirstTD = NULL; // clear for ehciFreeQHandTDs() + + ctrlstatus = (ioreq->iouh_Dir == UHDIR_IN) ? (ETCF_3ERRORSLIMIT|ETCF_ACTIVE|ETCF_PIDCODE_IN) : (ETCF_3ERRORSLIMIT|ETCF_ACTIVE|ETCF_PIDCODE_OUT); + if(unit->hu_DevDataToggle[devadrep]) + { + // continue with data toggle 0 + ctrlstatus |= ETCF_DATA1; + } + predetd = NULL; + phyaddr = (ULONG) pciGetPhysical(hc, ioreq->iouh_Data); + do + { + if((eqh->eqh_Actual >= EHCI_TD_BULK_LIMIT) && (eqh->eqh_Actual < ioreq->iouh_Length)) + { + KPRINTF(10, ("Bulk too large, splitting...\n")); + break; + } + etd = ehciAllocTD(hc); + if(!etd) + { + break; + } + if(predetd) + { + predetd->etd_Succ = etd; + predetd->etd_NextTD = etd->etd_Self; + predetd->etd_AltNextTD = hc->hc_ShortPktEndTD->etd_Self; + } else { + eqh->eqh_FirstTD = etd; + //eqh->eqh_AltNextTD = eqh->eqh_NextTD = etd->etd_Self; + } + + len = ioreq->iouh_Length - eqh->eqh_Actual; + if(len > 4*EHCI_PAGE_SIZE) + { + len = 4*EHCI_PAGE_SIZE; + } + etd->etd_Length = len; + KPRINTF(1, ("Bulk TD %08lx len %ld (%ld/%ld) phy=%08lx\n", + etd, len, eqh->eqh_Actual, ioreq->iouh_Length, phyaddr)); + WRITEMEM32_LE(&etd->etd_CtrlStatus, ctrlstatus|(len<etd_BufferPtr[0], phyaddr); + WRITEMEM32_LE(&etd->etd_BufferPtr[1], (phyaddr & EHCI_PAGE_MASK) + (1*EHCI_PAGE_SIZE)); + WRITEMEM32_LE(&etd->etd_BufferPtr[2], (phyaddr & EHCI_PAGE_MASK) + (2*EHCI_PAGE_SIZE)); + WRITEMEM32_LE(&etd->etd_BufferPtr[3], (phyaddr & EHCI_PAGE_MASK) + (3*EHCI_PAGE_SIZE)); + WRITEMEM32_LE(&etd->etd_BufferPtr[4], (phyaddr & EHCI_PAGE_MASK) + (4*EHCI_PAGE_SIZE)); + phyaddr += len; + eqh->eqh_Actual += len; + + predetd = etd; + } while((eqh->eqh_Actual < ioreq->iouh_Length) || (len && (ioreq->iouh_Dir == UHDIR_OUT) && (eqh->eqh_Actual == ioreq->iouh_Length) && (!ioreq->iouh_Flags & UHFF_NOSHORTPKT) && ((eqh->eqh_Actual % ioreq->iouh_MaxPktSize) == 0))); + + if(!etd) + { + // not enough etds? try again later + ehciFreeQHandTDs(hc, eqh); + break; + } + ctrlstatus |= ETCF_READYINTEN|(predetd->etd_Length<etd_CtrlStatus, ctrlstatus); + + predetd->etd_Succ = NULL; + CONSTWRITEMEM32_LE(&predetd->etd_NextTD, EHCI_TERMINATE); + CONSTWRITEMEM32_LE(&predetd->etd_AltNextTD, EHCI_TERMINATE); + + // due to sillicon bugs, we fill in the first overlay ourselves. + etd = eqh->eqh_FirstTD; + eqh->eqh_CurrTD = etd->etd_Self; + eqh->eqh_NextTD = etd->etd_NextTD; + eqh->eqh_AltNextTD = etd->etd_AltNextTD; + eqh->eqh_CtrlStatus = etd->etd_CtrlStatus; + eqh->eqh_BufferPtr[0] = etd->etd_BufferPtr[0]; + eqh->eqh_BufferPtr[1] = etd->etd_BufferPtr[1]; + eqh->eqh_BufferPtr[2] = etd->etd_BufferPtr[2]; + eqh->eqh_BufferPtr[3] = etd->etd_BufferPtr[3]; + eqh->eqh_BufferPtr[4] = etd->etd_BufferPtr[4]; + + Remove(&ioreq->iouh_Req.io_Message.mn_Node); + ioreq->iouh_DriverPrivate1 = eqh; + + // manage endpoint going busy + unit->hu_DevBusyReq[devadrep] = ioreq; + unit->hu_NakTimeoutFrame[devadrep] = (ioreq->iouh_Flags & UHFF_NAKTIMEOUT) ? hc->hc_FrameCounter + (ioreq->iouh_NakTimeout<<3) : 0; + + Disable(); + AddTail(&hc->hc_TDQueue, (struct Node *) ioreq); + + // looks good to me, now enqueue this entry (just behind the asyncQH) + eqh->eqh_Succ = hc->hc_EhciAsyncQH->eqh_Succ; + eqh->eqh_NextQH = eqh->eqh_Succ->eqh_Self; + SYNC; + EIEIO; + eqh->eqh_Pred = hc->hc_EhciAsyncQH; + eqh->eqh_Succ->eqh_Pred = eqh; + hc->hc_EhciAsyncQH->eqh_Succ = eqh; + hc->hc_EhciAsyncQH->eqh_NextQH = eqh->eqh_Self; + SYNC; + EIEIO; + Enable(); + + ioreq = (struct IOUsbHWReq *) hc->hc_BulkXFerQueue.lh_Head; + } +} +/* \\\ */ + +/* /// "ehciCompleteInt()" */ +void ehciCompleteInt(struct PCIController *hc) +{ + ULONG framecnt = READREG32_LE(hc->hc_RegBase, EHCI_FRAMECOUNT); + + KPRINTF(1, ("CompleteInt!\n")); + hc->hc_FrameCounter = (hc->hc_FrameCounter & 0xffffc000) + framecnt; + + /* **************** PROCESS DONE TRANSFERS **************** */ + + if(hc->hc_AsyncAdvanced) + { + struct EhciQH *eqh; + struct EhciTD *etd; + struct EhciTD *nextetd; + + hc->hc_AsyncAdvanced = FALSE; + + KPRINTF(1, ("AsyncAdvance %08lx\n", hc->hc_EhciAsyncFreeQH)); + + while((eqh = hc->hc_EhciAsyncFreeQH)) + { + KPRINTF(1, ("FreeQH %08lx\n", eqh)); + nextetd = eqh->eqh_FirstTD; + while((etd = nextetd)) + { + KPRINTF(1, ("FreeTD %08lx\n", nextetd)); + nextetd = etd->etd_Succ; + ehciFreeTD(hc, etd); + } + hc->hc_EhciAsyncFreeQH = eqh->eqh_Succ; + ehciFreeQH(hc, eqh); + } + } + + ehciHandleFinishedTDs(hc); + + if(hc->hc_CtrlXFerQueue.lh_Head->ln_Succ) + { + ehciScheduleCtrlTDs(hc); + } + + if(hc->hc_IntXFerQueue.lh_Head->ln_Succ) + { + ehciScheduleIntTDs(hc); + } + + if(hc->hc_BulkXFerQueue.lh_Head->ln_Succ) + { + ehciScheduleBulkTDs(hc); + } + + KPRINTF(1, ("CompleteDone\n")); +} +/* \\\ */ + +/* /// "ehciIntCode()" */ +void ehciIntCode(HIDDT_IRQ_Handler *irq, HIDDT_IRQ_HwInfo *hw) +{ + struct PCIController *hc = (struct PCIController *) irq->h_Data; + struct PCIDevice *base = hc->hc_Device; + struct PCIUnit *unit = hc->hc_Unit; + ULONG intr; + + KPRINTF(1, ("pciEhciInt()\n")); + intr = READREG32_LE(hc->hc_RegBase, EHCI_USBSTATUS); + if(intr & hc->hc_PCIIntEnMask) + { + WRITEREG32_LE(hc->hc_RegBase, EHCI_USBSTATUS, intr); + KPRINTF(1, ("INT=%04lx\n", intr)); + if(!hc->hc_Online) + { + return; + } + if(intr & EHSF_FRAMECOUNTOVER) + { + ULONG framecnt = READREG32_LE(hc->hc_RegBase, EHCI_FRAMECOUNT); + hc->hc_FrameCounter = (hc->hc_FrameCounter|0x3fff) + 1 + framecnt; + KPRINTF(5, ("Frame Counter Rollover %ld\n", hc->hc_FrameCounter)); + } + if(intr & EHSF_ASYNCADVANCE) + { + KPRINTF(1, ("AsyncAdvance\n")); + hc->hc_AsyncAdvanced = TRUE; + } + if(intr & (EHSF_TDDONE|EHSF_TDERROR|EHSF_ASYNCADVANCE)) + { + SureCause(base, &hc->hc_CompleteInt); + } + if(intr & EHSF_HOSTERROR) + { + KPRINTF(200, ("Host ERROR!\n")); + } + if(intr & EHSF_PORTCHANGED) + { + UWORD hciport; + ULONG oldval; + UWORD portreg = EHCI_PORTSC1; + for(hciport = 0; hciport < hc->hc_NumPorts; hciport++, portreg += 4) + { + oldval = READREG32_LE(hc->hc_RegBase, portreg); + // reflect port ownership (shortcut without hc->hc_PortNum20[hciport], as usb 2.0 maps 1:1) + unit->hu_EhciOwned[hciport] = (oldval & EHPF_NOTPORTOWNER) ? FALSE : TRUE; + if(oldval & EHPF_ENABLECHANGE) + { + hc->hc_PortChangeMap[hciport] |= UPSF_PORT_ENABLE; + } + if(oldval & EHPF_CONNECTCHANGE) + { + hc->hc_PortChangeMap[hciport] |= UPSF_PORT_CONNECTION; + } + if(oldval & EHPF_RESUMEDTX) + { + hc->hc_PortChangeMap[hciport] |= UPSF_PORT_SUSPEND|UPSF_PORT_ENABLE; + } + if(oldval & EHPF_OVERCURRENTCHG) + { + hc->hc_PortChangeMap[hciport] |= UPSF_PORT_OVER_CURRENT; + } + WRITEREG32_LE(hc->hc_RegBase, portreg, oldval); + KPRINTF(20, ("PCI Int Port %ld Change %08lx\n", hciport + 1, oldval)); + if(hc->hc_PortChangeMap[hciport]) + { + unit->hu_RootPortChanges |= 1UL<<(hciport + 1); + } + } + uhwCheckRootHubChanges(unit); + } + } +} +/* \\\ */ + +/* /// "uhwNakTimeoutInt()" */ +AROS_UFH1(void, uhwNakTimeoutInt, + AROS_UFHA(struct PCIUnit *, unit, A1)) +{ + AROS_USERFUNC_INIT + + struct PCIDevice *base = unit->hu_Device; + struct PCIController *hc; + struct IOUsbHWReq *ioreq; + struct UhciQH *uqh; + struct UhciTD *utd; + struct EhciQH *eqh; + struct OhciED *oed; + UWORD devadrep; + UWORD cnt; + ULONG linkelem; + ULONG ctrlstatus; + + //KPRINTF(10, ("NakTimeoutInt()\n")); + + // check for port status change for UHCI and frame rollovers and NAK Timeouts + hc = (struct PCIController *) unit->hu_Controllers.lh_Head; + while(hc->hc_Node.ln_Succ) + { + if(!hc->hc_Online) + { + hc = (struct PCIController *) hc->hc_Node.ln_Succ; + continue; + } + switch(hc->hc_HCIType) + { + case HCITYPE_UHCI: + { + ULONG framecnt = READREG16_LE(hc->hc_RegBase, UHCI_FRAMECOUNT); + + if(framecnt < (hc->hc_FrameCounter & 0xffff)) + { + hc->hc_FrameCounter = (hc->hc_FrameCounter|0xffff) + 1 + framecnt; + KPRINTF(10, ("Frame Counter Rollover %ld\n", hc->hc_FrameCounter)); + } + framecnt = hc->hc_FrameCounter; + + // NakTimeout + ioreq = (struct IOUsbHWReq *) hc->hc_TDQueue.lh_Head; + while(((struct Node *) ioreq)->ln_Succ) + { + if(ioreq->iouh_Flags & UHFF_NAKTIMEOUT) + { + uqh = (struct UhciQH *) ioreq->iouh_DriverPrivate1; + if(uqh) + { + KPRINTF(1, ("Examining IOReq=%08lx with UQH=%08lx\n", ioreq, uqh)); + devadrep = (ioreq->iouh_DevAddr<<5) + ioreq->iouh_Endpoint + ((ioreq->iouh_Dir == UHDIR_IN) ? 0x10 : 0); + linkelem = READMEM32_LE(&uqh->uqh_Element); + if(linkelem & UHCI_TERMINATE) + { + KPRINTF(1, ("UQH terminated %08lx\n", linkelem)); + if(framecnt > unit->hu_NakTimeoutFrame[devadrep]) + { + // give the thing the chance to exit gracefully + KPRINTF(20, ("Terminated? NAK timeout %ld > %ld, IOReq=%08lx\n", framecnt, unit->hu_NakTimeoutFrame[devadrep], ioreq)); + SureCause(base, &hc->hc_CompleteInt); + } + } else { + utd = (struct UhciTD *) ((linkelem & UHCI_PTRMASK) - hc->hc_PCIVirtualAdjust - 16); // struct UhciTD starts 16 before physical TD + ctrlstatus = READMEM32_LE(&utd->utd_CtrlStatus); + if(ctrlstatus & UTCF_ACTIVE) + { + if(framecnt > unit->hu_NakTimeoutFrame[devadrep]) + { + // give the thing the chance to exit gracefully + KPRINTF(20, ("NAK timeout %ld > %ld, IOReq=%08lx\n", framecnt, unit->hu_NakTimeoutFrame[devadrep], ioreq)); + ctrlstatus &= ~UTCF_ACTIVE; + WRITEMEM32_LE(&utd->utd_CtrlStatus, ctrlstatus); + SureCause(base, &hc->hc_CompleteInt); + } + } else { + if(framecnt > unit->hu_NakTimeoutFrame[devadrep]) + { + // give the thing the chance to exit gracefully + KPRINTF(20, ("Terminated? NAK timeout %ld > %ld, IOReq=%08lx\n", framecnt, unit->hu_NakTimeoutFrame[devadrep], ioreq)); + SureCause(base, &hc->hc_CompleteInt); + } + } + } + } + } + ioreq = (struct IOUsbHWReq *) ((struct Node *) ioreq)->ln_Succ; + } + + uhciCheckPortStatusChange(hc); + break; + } + + case HCITYPE_OHCI: + { + ULONG framecnt = READREG32_LE(hc->hc_RegBase, OHCI_FRAMECOUNT); + framecnt = hc->hc_FrameCounter = (hc->hc_FrameCounter & 0xffff0000) + framecnt; + // NakTimeout + ioreq = (struct IOUsbHWReq *) hc->hc_TDQueue.lh_Head; + while(((struct Node *) ioreq)->ln_Succ) + { + if(ioreq->iouh_Flags & UHFF_NAKTIMEOUT) + { + oed = (struct OhciED *) ioreq->iouh_DriverPrivate1; + if(oed) + { + KPRINTF(1, ("CTRL=%04lx, CMD=%01lx, F=%ld, hccaDH=%08lx, hcDH=%08lx, CH=%08lx, CCH=%08lx, IntEn=%08lx\n", + READREG32_LE(hc->hc_RegBase, OHCI_CONTROL), + READREG32_LE(hc->hc_RegBase, OHCI_CMDSTATUS), + READREG32_LE(hc->hc_RegBase, OHCI_FRAMECOUNT), + READMEM32_LE(&hc->hc_OhciHCCA->oha_DoneHead), + READREG32_LE(hc->hc_RegBase, OHCI_DONEHEAD), + READREG32_LE(hc->hc_RegBase, OHCI_CTRL_HEAD_ED), + READREG32_LE(hc->hc_RegBase, OHCI_CTRL_ED), + READREG32_LE(hc->hc_RegBase, OHCI_INTEN))); + + devadrep = (ioreq->iouh_DevAddr<<5) + ioreq->iouh_Endpoint + ((ioreq->iouh_Dir == UHDIR_IN) ? 0x10 : 0); + ctrlstatus = READMEM32_LE(&oed->oed_HeadPtr); + KPRINTF(1, ("Examining IOReq=%08lx with OED=%08lx HeadPtr=%08lx\n", ioreq, oed, ctrlstatus)); + if(framecnt > unit->hu_NakTimeoutFrame[devadrep]) + { + //ohciDebugSchedule(hc); + if(ctrlstatus & OEHF_HALTED) + { + // give the thing the chance to exit gracefully + KPRINTF(20, ("Terminated? NAK timeout %ld > %ld, IOReq=%08lx\n", framecnt, unit->hu_NakTimeoutFrame[devadrep], ioreq)); + SureCause(base, &hc->hc_CompleteInt); + } else { + // give the thing the chance to exit gracefully + KPRINTF(20, ("NAK timeout %ld > %ld, IOReq=%08lx\n", framecnt, unit->hu_NakTimeoutFrame[devadrep], ioreq)); + ctrlstatus |= OEHF_HALTED; + WRITEMEM32_LE(&oed->oed_HeadPtr, ctrlstatus); + ioreq->iouh_Req.io_Error = UHIOERR_NAKTIMEOUT; + unit->hu_DevBusyReq[devadrep] = NULL; + Remove(&ioreq->iouh_Req.io_Message.mn_Node); + ohciFreeEDContext(hc, oed); + KPRINTF(1, ("Old Toggle %04lx:%ld\n", devadrep, unit->hu_DevDataToggle[devadrep])); + unit->hu_DevDataToggle[devadrep] = (ctrlstatus & OEHF_DATA1) ? TRUE : FALSE; + KPRINTF(1, ("Toggle now %04lx:%ld\n", devadrep, unit->hu_DevDataToggle[devadrep])); + ReplyMsg(&ioreq->iouh_Req.io_Message); + } + } + } + } + ioreq = (struct IOUsbHWReq *) ((struct Node *) ioreq)->ln_Succ; + } + break; + } + + case HCITYPE_EHCI: + { + ULONG framecnt = READREG32_LE(hc->hc_RegBase, EHCI_FRAMECOUNT); + framecnt = hc->hc_FrameCounter = (hc->hc_FrameCounter & 0xffffc000) + framecnt; + // NakTimeout + for(cnt = 0; cnt < 1; cnt++) + { + ioreq = (struct IOUsbHWReq *) (cnt ? hc->hc_PeriodicTDQueue.lh_Head : hc->hc_TDQueue.lh_Head); + while(((struct Node *) ioreq)->ln_Succ) + { + if(ioreq->iouh_Flags & UHFF_NAKTIMEOUT) + { + eqh = (struct EhciQH *) ioreq->iouh_DriverPrivate1; + if(eqh) + { + KPRINTF(1, ("Examining IOReq=%08lx with EQH=%08lx\n", ioreq, eqh)); + devadrep = (ioreq->iouh_DevAddr<<5) + ioreq->iouh_Endpoint + ((ioreq->iouh_Dir == UHDIR_IN) ? 0x10 : 0); + ctrlstatus = READMEM32_LE(&eqh->eqh_CtrlStatus); + if(ctrlstatus & ETCF_ACTIVE) + { + if(framecnt > unit->hu_NakTimeoutFrame[devadrep]) + { + // give the thing the chance to exit gracefully + KPRINTF(20, ("NAK timeout %ld > %ld, IOReq=%08lx\n", framecnt, unit->hu_NakTimeoutFrame[devadrep], ioreq)); + ctrlstatus &= ~ETCF_ACTIVE; + ctrlstatus |= ETSF_HALTED; + WRITEMEM32_LE(&eqh->eqh_CtrlStatus, ctrlstatus); + SureCause(base, &hc->hc_CompleteInt); + } + } else { + if(ctrlstatus & ETCF_READYINTEN) + { + KPRINTF(10, ("INT missed?!? Manually causing it! %08lx, IOReq=%08lx\n", + ctrlstatus, ioreq)); + SureCause(base, &hc->hc_CompleteInt); + } + } + } + } + ioreq = (struct IOUsbHWReq *) ((struct Node *) ioreq)->ln_Succ; + } + } + break; + } + } + hc = (struct PCIController *) hc->hc_Node.ln_Succ; + } + + uhwCheckRootHubChanges(unit); + + /* Update frame counter */ + unit->hu_NakTimeoutReq.tr_time.tv_micro = 150*1000; + SendIO((APTR) &unit->hu_NakTimeoutReq); + + AROS_USERFUNC_EXIT +} +/* \\\ */ + diff --git a/rom/usb/pciusb/uhwcmd.h b/rom/usb/pciusb/uhwcmd.h new file mode 100644 index 000000000..5e6c1b516 --- /dev/null +++ b/rom/usb/pciusb/uhwcmd.h @@ -0,0 +1,93 @@ +#ifndef UHWCMD_H +#define UHWCMD_H + +#include "debug.h" +#include "pci_aros.h" + +#include "uhcichip.h" +#include "ohcichip.h" +#include "ehcichip.h" +#include "pciusb.h" + +struct Unit *Open_Unit(struct IOUsbHWReq *ioreq, + LONG unitnr, + struct PCIDevice *base); +void Close_Unit(struct PCIDevice *base, struct PCIUnit *unit, + struct IOUsbHWReq *ioreq); + +void uhwDelayMS(ULONG milli, struct PCIUnit *unit, struct PCIDevice *base); + +WORD cmdReset(struct IOUsbHWReq *ioreq, struct PCIUnit *unit, struct PCIDevice *base); +WORD cmdUsbReset(struct IOUsbHWReq *ioreq, struct PCIUnit *unit, struct PCIDevice *base); +WORD cmdUsbResume(struct IOUsbHWReq *ioreq, struct PCIUnit *unit, struct PCIDevice *base); +WORD cmdUsbSuspend(struct IOUsbHWReq *ioreq, struct PCIUnit *unit, struct PCIDevice *base); +WORD cmdUsbOper(struct IOUsbHWReq *ioreq, struct PCIUnit *unit, struct PCIDevice *base); + +WORD cmdQueryDevice(struct IOUsbHWReq *ioreq, struct PCIUnit *unit, struct PCIDevice *base); + +WORD cmdControlXFer(struct IOUsbHWReq *ioreq, struct PCIUnit *unit, struct PCIDevice *base); +WORD cmdBulkXFer(struct IOUsbHWReq *ioreq, struct PCIUnit *unit, struct PCIDevice *base); +WORD cmdIntXFer(struct IOUsbHWReq *ioreq, struct PCIUnit *unit, struct PCIDevice *base); +WORD cmdIsoXFer(struct IOUsbHWReq *ioreq, struct PCIUnit *unit, struct PCIDevice *base); + +WORD cmdFlush(struct IOUsbHWReq *ioreq, struct PCIUnit *unit, struct PCIDevice *base); + +WORD cmdNSDeviceQuery(struct IOStdReq *ioreq, struct PCIUnit *unit, struct PCIDevice *base); + +BOOL cmdAbortIO(struct IOUsbHWReq *ioreq, struct PCIDevice *base); + +void TermIO(struct IOUsbHWReq *ioreq, struct PCIDevice *base); + +AROS_UFP1(void, uhwNakTimeoutInt, + AROS_UFPA(struct PCIUnit *, unit, A1)); + +BOOL pciInit(struct PCIDevice *hd); +void pciExpunge(struct PCIDevice *hd); +BOOL pciAllocUnit(struct PCIUnit *hu); +void pciFreeUnit(struct PCIUnit *hu); +APTR pciGetPhysical(struct PCIController *hc, APTR virtaddr); + +void uhciCompleteInt(struct PCIController *hc); +void uhciIntCode(HIDDT_IRQ_Handler *irq, HIDDT_IRQ_HwInfo *hw); + +void uhciUpdateIntTree(struct PCIController *hc); +void uhciFreeQContext(struct PCIController *hc, struct UhciQH *uqh); +inline struct UhciQH * uhciAllocQH(struct PCIController *hc); +inline void uhciFreeQH(struct PCIController *hc, struct UhciQH *uqh); +inline struct UhciTD * uhciAllocTD(struct PCIController *hc); +inline void uhciFreeTD(struct PCIController *hc, struct UhciTD *utd); + + +void ohciCompleteInt(struct PCIController *hc); +void ohciIntCode(HIDDT_IRQ_Handler *irq, HIDDT_IRQ_HwInfo *hw); + +void ohciUpdateIntTree(struct PCIController *hc); +void ohciFreeEDContext(struct PCIController *hc, struct OhciED *oed); +inline struct OhciED * ohciAllocED(struct PCIController *hc); +inline void ohciFreeED(struct PCIController *hc, struct OhciED *oed); +inline struct OhciTD * ohciAllocTD(struct PCIController *hc); +inline void ohciFreeTD(struct PCIController *hc, struct OhciTD *otd); + + +void ehciCompleteInt(struct PCIController *hc); +void ehciIntCode(HIDDT_IRQ_Handler *irq, HIDDT_IRQ_HwInfo *hw); + +void ehciUpdateIntTree(struct PCIController *hc); +void ehciFreeAsyncContext(struct PCIController *hc, struct EhciQH *eqh); +void ehciFreePeriodicContext(struct PCIController *hc, struct EhciQH *eqh); +inline struct EhciQH * ehciAllocQH(struct PCIController *hc); +inline void ehciFreeQH(struct PCIController *hc, struct EhciQH *eqh); +inline struct EhciTD * ehciAllocTD(struct PCIController *hc); +inline void ehciFreeTD(struct PCIController *hc, struct EhciTD *etd); + +struct my_NSDeviceQueryResult +{ + ULONG DevQueryFormat; /* this is type 0 */ + ULONG SizeAvailable; /* bytes available */ + UWORD DeviceType; /* what the device does */ + UWORD DeviceSubType; /* depends on the main type */ + const UWORD *SupportedCommands; /* 0 terminated list of cmd's */ +}; + +#endif /* UHWCMD_H */ + diff --git a/rom/usb/poseidon/AddUSBClasses.c b/rom/usb/poseidon/AddUSBClasses.c new file mode 100644 index 000000000..6343ef4db --- /dev/null +++ b/rom/usb/poseidon/AddUSBClasses.c @@ -0,0 +1,167 @@ +/* +** AddUSBClasses by Chris Hodges +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ARGS_QUIET 0 +#define ARGS_REMOVE 1 +#define ARGS_SIZEOF 2 + +static const char *template = "QUIET/S,REMOVE/S"; +static const char *version = "$VER: AddUSBClasses 1.7 (03.06.09) by Chris Hodges "; +static IPTR ArgsArray[ARGS_SIZEOF]; +static struct RDArgs *ArgsHook = NULL; + +void fail(char *str) +{ + if(ArgsHook) + { + FreeArgs(ArgsHook); + ArgsHook = NULL; + } + if(str) + { + PutStr(str); + exit(20); + } + exit(0); +} + +int main(int argc, char *argv[]) +{ + struct Library *ps; + struct ExAllControl *exall; + BPTR lock; + STRPTR errmsg = NULL; + struct ExAllData *exdata; + ULONG ents; + struct List *puclist; + UBYTE buf[1024]; + STRPTR sbuf; + BOOL exready; + struct Node *puc; + ULONG namelen; + STRPTR classpath; + + if(!(ArgsHook = ReadArgs(template, ArgsArray, NULL))) + { + fail("Wrong arguments!\n"); + } + + if((ps = OpenLibrary("poseidon.library", 4))) + { + if(ArgsArray[ARGS_REMOVE]) + { + psdLockWritePBase(); + psdGetAttrs(PGA_STACK, NULL, PA_ClassList, &puclist, TAG_END); + while(puclist->lh_Head->ln_Succ) + { + if(!ArgsArray[ARGS_QUIET]) + { + Printf("Removing class %s...\n", puclist->lh_Head->ln_Name); + } + psdUnlockPBase(); + psdRemClass(puclist->lh_Head); + psdLockWritePBase(); + } + psdUnlockPBase(); + } else { + if((exall = AllocDosObject(DOS_EXALLCONTROL, NULL))) + { + classpath = "SYS:Classes/USB"; + lock = Lock(classpath, ACCESS_READ); + if(lock) + { + exall->eac_LastKey = 0; + exall->eac_MatchString = NULL; + exall->eac_MatchFunc = NULL; + do + { + exready = ExAll(lock, (struct ExAllData *) buf, 1024, ED_NAME, exall); + exdata = (struct ExAllData *) buf; + ents = exall->eac_Entries; + while(ents--) + { + sbuf = psdCopyStrFmt("%s/%s", classpath, exdata->ed_Name); + if(!sbuf) + { + break; + } + namelen = strlen(sbuf); + if(namelen > 4) + { + if(!strcmp(&sbuf[namelen-4], ".elf")) + { + sbuf[namelen-4] = 0; + } + } + psdGetAttrs(PGA_STACK, NULL, PA_ClassList, &puclist, TAG_END); + Forbid(); + puc = puclist->lh_Head; + while(puc->ln_Succ) + { + if(!strncmp(puc->ln_Name, exdata->ed_Name, strlen(puc->ln_Name))) + { + break; + } + puc = puc->ln_Succ; + } + if(puc->ln_Succ) + { + Permit(); + if(!ArgsArray[ARGS_QUIET]) + { + Printf("Skipping class %s...\n", exdata->ed_Name); + } + exdata = exdata->ed_Next; + continue; + } + Permit(); + + if(!ArgsArray[ARGS_QUIET]) + { + Printf("Adding class %s...", exdata->ed_Name); + } + if(psdAddClass(sbuf, 0)) + { + if(!ArgsArray[ARGS_QUIET]) + { + PutStr("okay!\n"); + } + } else { + if(!ArgsArray[ARGS_QUIET]) + { + PutStr("failed!\n"); + } + } + psdFreeVec(sbuf); + exdata = exdata->ed_Next; + } + } while(exready); + UnLock(lock); + psdClassScan(); + } else { + errmsg = "Could not lock on SYS:Classes/USB.\n"; + } + FreeDosObject(DOS_EXALLCONTROL, exall); + } + } + CloseLibrary(ps); + } else { + errmsg = "Unable to open poseidon.library\n"; + } + fail(errmsg); + return(0); // never gets here, just to shut the compiler up +} diff --git a/rom/usb/poseidon/AddUSBHardware.c b/rom/usb/poseidon/AddUSBHardware.c new file mode 100644 index 000000000..d25bbd5ea --- /dev/null +++ b/rom/usb/poseidon/AddUSBHardware.c @@ -0,0 +1,146 @@ +/* +** AddUSBHardware by Chris Hodges +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ARGS_DEVICE 0 +#define ARGS_UNIT 1 +#define ARGS_QUIET 2 +#define ARGS_REMOVE 3 +#define ARGS_ALL 4 +#define ARGS_SIZEOF 5 + +static const char *template = "DEVICE,UNIT/N,QUIET/S,REMOVE/S,ALL/S"; +static const char *version = "$VER: AddUSBHardware 1.7 (03.06.09) by Chris Hodges "; +static IPTR ArgsArray[ARGS_SIZEOF]; +static struct RDArgs *ArgsHook = NULL; + +//extern struct DOSBase *DOSBase; + +void fail(char *str) +{ + if(ArgsHook) + { + FreeArgs(ArgsHook); + ArgsHook = NULL; + } + if(str) + { + PutStr(str); + exit(20); + } + exit(0); +} + +int main(int argc, char *argv[]) +{ + struct Library *ps; + char *errmsg = NULL; + struct List *phwlist; + struct Node *phw; + struct Node *next; + ULONG unit; + STRPTR devname = NULL; + ULONG cmpunit; + STRPTR cmpdevname; + + if(!(ArgsHook = ReadArgs(template, ArgsArray, NULL))) + { + fail("Wrong arguments!\n"); + } + + if((!ArgsArray[ARGS_DEVICE]) && (!(ArgsArray[ARGS_REMOVE] && ArgsArray[ARGS_ALL]))) + { + fail("DEVICE argument is mandatory except for REMOVE ALL!\n"); + } + + if((ps = OpenLibrary("poseidon.library", 4))) + { + unit = 0; + if(ArgsArray[ARGS_DEVICE]) + { + devname = (STRPTR) ArgsArray[ARGS_DEVICE]; + } + if(ArgsArray[ARGS_UNIT]) + { + unit = *((ULONG *) ArgsArray[ARGS_UNIT]); + } + if(ArgsArray[ARGS_REMOVE]) + { + psdLockReadPBase(); + do + { + psdGetAttrs(PGA_STACK, NULL, PA_HardwareList, &phwlist, TAG_END); + phw = phwlist->lh_Head; + while((next = phw->ln_Succ)) + { + psdGetAttrs(PGA_HARDWARE, phw, + HA_DeviceName, &cmpdevname, + HA_DeviceUnit, &cmpunit, + TAG_END); + if(ArgsArray[ARGS_ALL] || ((!stricmp(FilePart(cmpdevname), FilePart(devname))) && (cmpunit == unit))) + { + if(!ArgsArray[ARGS_QUIET]) + { + Printf("Removing hardware %s, unit %ld...\n", cmpdevname, cmpunit); + } + psdUnlockPBase(); + psdRemHardware(phw); + psdLockReadPBase(); + break; + } + phw = next; + } + } while(ArgsArray[ARGS_ALL] && next); + psdUnlockPBase(); + } else { + do + { + if(!ArgsArray[ARGS_QUIET]) + { + Printf("Adding hardware %s, unit %ld...", devname, unit); + } + if((phw = psdAddHardware(devname, unit))) + { + if(!ArgsArray[ARGS_QUIET]) + { + if(psdEnumerateHardware(phw)) + { + PutStr("okay!\n"); + } else { + PutStr("enumeration failed!\n"); + } + } else { + psdEnumerateHardware(phw); + } + } else { + if(!ArgsArray[ARGS_QUIET]) + { + PutStr("failed!\n"); + } + errmsg = ""; + break; + } + unit++; + } while(ArgsArray[ARGS_ALL]); + psdClassScan(); + } + CloseLibrary(ps); + } else { + errmsg = "Unable to open poseidon.library\n"; + } + fail(errmsg); + return(0); // never gets here, just to shut the compiler up +} diff --git a/rom/usb/poseidon/PsdDevLister.c b/rom/usb/poseidon/PsdDevLister.c new file mode 100644 index 000000000..73095f9c5 --- /dev/null +++ b/rom/usb/poseidon/PsdDevLister.c @@ -0,0 +1,535 @@ +/* +** PsdDevLister by Chris Hodges +*/ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define ARGS_SHOWROOT 0 +#define ARGS_QUICK 1 +#define ARGS_STRINGS 2 +#define ARGS_SIZEOF 3 + +static const char *template = "SHOWROOT/S,QUICK/S,STRINGS/S"; +static const char *version = "$VER: PsdDevLister 4.0 (03.06.09) by Chris Hodges "; +static IPTR ArgsArray[ARGS_SIZEOF]; +static struct RDArgs *ArgsHook = NULL; + +void fail(char *str) +{ + if(ArgsHook) + { + FreeArgs(ArgsHook); + ArgsHook = NULL; + } + if(str) + { + PutStr(str); + exit(20); + } + exit(0); +} + +int main(int argc, char *argv[]) +{ + struct Library *ps; + STRPTR errmsg = NULL; + APTR pd; + APTR pp; + struct MsgPort *mp; + IPTR devadr; + IPTR devhubport; + struct Node *devhub; + IPTR devusbvers; + IPTR devclass; + IPTR devsubclass; + IPTR devproto; + IPTR devvendorid; + IPTR devprodid; + IPTR devversion; + STRPTR devmanufact; + STRPTR devprodname; + STRPTR devserial; + STRPTR devidstr; + STRPTR devhubname; + IPTR devcurrlang; + IPTR devclonecount; + UWORD *devlangarray; + IPTR devislowspeed; + IPTR devishighspeed; + IPTR devisconnected; + IPTR devhasaddress; + IPTR devhasdevdesc; + IPTR devisconfigured; + IPTR devissuspended; + IPTR devneedssplit; + IPTR devnumcfgs; + IPTR devlowpower; + IPTR devpoweravail; + IPTR devpowerdrain; + IPTR devmaxpktsize0; + IPTR devhubthinktime; + + struct List *cfgs; + struct Node *pc; + IPTR cfgselfpow; + IPTR cfgremwake; + IPTR cfgnum; + IPTR cfgmaxpower; + STRPTR cfgname; + IPTR cfgnumifs; + + struct List *ifs; + struct Node *pif; + struct Node *altpif; + struct List *altpiflist; + + struct List *descriptors = NULL; + struct Node *pdd; + IPTR desctype; + UBYTE *descdata; + IPTR desclen; + UWORD cnt; + STRPTR descname; + + IPTR ifnum; + IPTR ifaltnum; + IPTR ifclass; + IPTR ifsubclass; + IPTR ifproto; + STRPTR ifname; + STRPTR ifidstr; + IPTR ifnumeps; + + APTR binding; + IPTR hasappbinding; + struct Task *apptask; + struct Library *bindingcls; + + struct List *eps; + struct Node *pep; + IPTR episin; + IPTR epnum; + IPTR eptranstype; + IPTR epmaxpktsize; + IPTR epinterval; + IPTR epnumtransmu; + IPTR epsynctype; + IPTR epusagetype; + + STRPTR strdesc; + STRPTR strthinktime; + + if(!(ArgsHook = ReadArgs(template, ArgsArray, NULL))) + { + fail("Wrong arguments!\n"); + } + + if((ps = OpenLibrary("poseidon.library", 4))) + { + pd = NULL; + mp = CreateMsgPort(); + psdLockReadPBase(); + while((pd = psdGetNextDevice(pd))) + { + psdLockReadDevice(pd); + devhubport = 0; + devneedssplit = 0; + devlowpower = 0; + devpoweravail = 0; + devpowerdrain = 0; + devmaxpktsize0 = 0; + devhubthinktime = 0; + devissuspended = 0; + psdGetAttrs(PGA_DEVICE, pd, + DA_Address, &devadr, + DA_HubDevice, &devhub, + DA_HubThinkTime, &devhubthinktime, + DA_AtHubPortNumber, &devhubport, + DA_UsbVersion, &devusbvers, + DA_MaxPktSize0, &devmaxpktsize0, + DA_Class, &devclass, + DA_SubClass, &devsubclass, + DA_Protocol, &devproto, + DA_VendorID, &devvendorid, + DA_ProductID, &devprodid, + DA_Version, &devversion, + DA_Manufacturer, &devmanufact, + DA_ProductName, &devprodname, + DA_SerialNumber, &devserial, + DA_CloneCount, &devclonecount, + DA_IDString, &devidstr, + DA_CurrLangID, &devcurrlang, + DA_LangIDArray, &devlangarray, + DA_IsLowspeed, &devislowspeed, + DA_IsHighspeed, &devishighspeed, + DA_IsConnected, &devisconnected, + DA_NeedsSplitTrans, &devneedssplit, + DA_HasAddress, &devhasaddress, + DA_HasDevDesc, &devhasdevdesc, + DA_IsConfigured, &devisconfigured, + DA_IsSuspended, &devissuspended, + DA_NumConfigs, &devnumcfgs, + DA_ConfigList, &cfgs, + DA_Binding, &binding, + DA_BindingClass, &bindingcls, + DA_HasAppBinding, &hasappbinding, + DA_LowPower, &devlowpower, + DA_PowerDrained, &devpowerdrain, + DA_PowerSupply, &devpoweravail, + DA_DescriptorList, &descriptors, + TAG_END); + if(devhub) + { + psdGetAttrs(PGA_DEVICE, devhub, + DA_ProductName, &devhubname, + TAG_END); + } else { + devhubname = "Root"; + if(!ArgsArray[ARGS_SHOWROOT]) + { + Printf("Skipping '%s' (use SHOWROOT to list)\n", devidstr); + PutStr("---------------------------------------------------------------------------\n"); + continue; + } + } + strthinktime = ""; + if((devclass == HUB_CLASSCODE) && devishighspeed) + { + switch(devhubthinktime) + { + case 0: + strthinktime = " (Hub Think Time: 8 bit times)"; + break; + case 1: + strthinktime = " (Hub Think Time: 16 bit times)"; + break; + case 2: + strthinktime = " (Hub Think Time: 24 bit times)"; + break; + case 3: + strthinktime = " (Hub Think Time: 32 bit times)"; + break; + } + } + Printf(" Poseidon DevID : '%s'\n" + " Product Name : '%s' (ID: %04lx, Vers: %04lx)\n" + " Manufacturer : '%s' (Vendor: %04lx (%s))\n" + " Serial Number : '%s' (USBVers: %04lx)\n" + " Device State : %s%s%s%s%s%s%s\n" + " Device Address : %ld (Port %ld at %s)\n" + " Class/Sub/Proto : %ld/%ld/%ld (%s)\n" + " MaxPktSize EP 0 : %ld%s\n" + " Power Check : Supply = %ldmA, Drain = %ldmA%s\n" + " Current Language: %s\n", + devidstr, + devprodname, devprodid, devversion, + devmanufact, devvendorid, + psdNumToStr(NTS_VENDORID, (LONG) devvendorid, "unknown"), + devserial, devusbvers, + devislowspeed ? "lowspeed " : (devishighspeed ? "highspeed " : "fullspeed "), + devisconnected ? "connected " : "disconnected ", + devhasaddress ? "hasaddress " : "", + devhasdevdesc ? "hasdevdesc " : "", + devisconfigured ? "configured " : "", + devissuspended ? "suspended " : "", + devneedssplit ? "\n SplitTransaction: USB1.1 at USB2.0 port!" : "", + devadr, + devhubport, devhubname, + devclass, devsubclass, devproto, + psdNumToStr(NTS_COMBOCLASS, (devclass<"), + devmaxpktsize0, strthinktime, + devpoweravail, devpowerdrain, + devlowpower ? " LOWPOWER!" : "", + psdNumToStr(NTS_LANGID, devcurrlang, "")); + if(devlangarray && (!ArgsArray[ARGS_QUICK])) + { + UWORD *wptr = devlangarray; + ULONG perline = 0; + PutStr(" Supported Langs : "); + while(*wptr) + { + PutStr(psdNumToStr(NTS_LANGID, (ULONG) *wptr, "")); + wptr++; + if(*wptr) + { + PutStr(", "); + } + if(++perline > 2) + { + PutStr("\n "); + perline = 0; + } + } + PutStr("\n"); + if(ArgsArray[ARGS_STRINGS]) + { + ULONG idx = 1; + pp = psdAllocPipe(pd, mp, NULL); + while(pp) + { + strdesc = psdGetStringDescriptor(pp, idx); + if(strdesc) + { + Printf(" String descriptor %04ld: '%s'\n", idx, strdesc); + psdFreeVec(strdesc); + } else { + if(idx > 10) + { + break; + } + } + idx++; + if(idx > 100) + { + PutStr(" ... aborting\n"); + break; + } + } + psdFreePipe(pp); + } + } + if(binding) + { + if(hasappbinding) + { + psdGetAttrs(PGA_APPBINDING, binding, + ABA_Task, &apptask, + TAG_END); + Printf("\n This device is bound to application %s with context %08lx.\n", + apptask->tc_Node.ln_Name, binding); + } else { + Printf("\n This device is bound to %s, context %08lx.\n", + bindingcls->lib_Node.ln_Name, binding); + } + } + Printf("\n %ld configuration(s):\n", devnumcfgs); + pc = cfgs->lh_Head; + while(pc->ln_Succ) + { + psdGetAttrs(PGA_CONFIG, pc, + CA_SelfPowered, &cfgselfpow, + CA_RemoteWakeup, &cfgremwake, + CA_ConfigNum, &cfgnum, + CA_MaxPower, &cfgmaxpower, + CA_ConfigName, &cfgname, + CA_NumInterfaces, &cfgnumifs, + CA_InterfaceList, &ifs, + TAG_END); + Printf("\n · Config %ld (%s)\n" + " Attrs : %s %s\n" + " MaxPower: %ld mA\n", + cfgnum, cfgname, + cfgselfpow ? "self-powered " : "bus-powered ", + cfgremwake ? "remote-wakeup" : "", + cfgmaxpower); + Printf("\n %ld interface(s) for this config:", cfgnumifs); + pif = ifs->lh_Head; + while(pif->ln_Succ) + { + altpif = pif; + do + { + psdGetAttrs(PGA_INTERFACE, altpif, + IFA_InterfaceNum, &ifnum, + IFA_AlternateNum, &ifaltnum, + IFA_Class, &ifclass, + IFA_SubClass, &ifsubclass, + IFA_Protocol, &ifproto, + IFA_InterfaceName, &ifname, + IFA_IDString, &ifidstr, + IFA_NumEndpoints, &ifnumeps, + IFA_EndpointList, &eps, + IFA_AlternateIfList, &altpiflist, + IFA_Binding, &binding, + IFA_BindingClass, &bindingcls, + TAG_END); + Printf("\n · Interface %ld (%s) (ID: '%s')\n" + " Alternate Setting: %ld\n" + " Class/Sub/Proto : %ld/%ld/%ld (%s)\n", + ifnum, ifname, ifidstr, + ifaltnum, + ifclass, ifsubclass, ifproto, + psdNumToStr(NTS_COMBOCLASS, (ifclass<")); + if(binding) + { + Printf("\n This interface is bound to %s, context %08lx.\n", + bindingcls->lib_Node.ln_Name, binding); + } + if(ArgsArray[ARGS_QUICK]) + { + Printf("\n %ld endpoint(s).\n", ifnumeps); + } else { + Printf("\n %ld endpoint(s) for this interface:\n", ifnumeps); + pep = eps->lh_Head; + while(pep->ln_Succ) + { + epnumtransmu = 0; + epsynctype = 0; + epusagetype = 0; + psdGetAttrs(PGA_ENDPOINT, pep, + EA_IsIn, &episin, + EA_EndpointNum, &epnum, + EA_TransferType, &eptranstype, + EA_MaxPktSize, &epmaxpktsize, + EA_Interval, &epinterval, + EA_NumTransMuFrame, &epnumtransmu, + EA_SyncType, &epsynctype, + EA_UsageType, &epusagetype, + TAG_END); + Printf(" · Endpoint %ld (%s %s)\n" + " MaxPktSize: %s%ld\n", + epnum, psdNumToStr(NTS_TRANSTYPE, eptranstype, "?"), + episin ? "<-[ IN" : "OUT ]->", + (epnumtransmu == 2) ? "2x " : ((epnumtransmu == 3) ? "3x " : ""), + epmaxpktsize); + + if(devishighspeed || ((eptranstype != USEAF_CONTROL) && (eptranstype != USEAF_BULK))) + { + Printf(" %s : %ld %s\n", + (((eptranstype == USEAF_CONTROL) || (eptranstype == USEAF_BULK)) && devishighspeed) ? "NAK-Rate" : "Interval", + epinterval, + devishighspeed ? "µFrames" : "ms"); + } + if(eptranstype == USEAF_ISOCHRONOUS) + { + Printf(" SyncType : %s\n" + " UsageType : %s\n", + psdNumToStr(NTS_SYNCTYPE, epsynctype, "?"), + psdNumToStr(NTS_USAGETYPE, epusagetype, "?")); + } + pep = pep->ln_Succ; + } + } + if(altpif == pif) + { + altpif = (struct Node *) altpiflist->lh_Head; + /* check for alternate settings */ + if(!altpif->ln_Succ) + { + Printf("\n No alternate settings.\n"); + break; + } + Printf("\n Alternate settings:\n"); + } else { + altpif = altpif->ln_Succ; + if(!altpif->ln_Succ) + { + break; + } + } + } while(TRUE); + pif = pif->ln_Succ; + } + pc = pc->ln_Succ; + } + if(descriptors && (!ArgsArray[ARGS_QUICK])) + { + pdd = descriptors->lh_Head; + PutStr("\n Standard Descriptors:"); + while(pdd->ln_Succ) + { + pc = NULL; + pif = NULL; + pep = NULL; + ifclass = 0; + descname = NULL; + psdGetAttrs(PGA_DESCRIPTOR, pdd, + DDA_Config, &pc, + DDA_Interface, &pif, + DDA_Endpoint, &pep, + DDA_DescriptorType, &desctype, + DDA_DescriptorLength, &desclen, + DDA_DescriptorData, &descdata, + DDA_Name, &descname, + TAG_END); + if(pif) + { + psdGetAttrs(PGA_INTERFACE, pif, + IFA_Class, &ifclass, + TAG_END); + } + if(!descname) + { + descname = psdNumToStr(NTS_DESCRIPTOR, desctype|(ifclass<<8), NULL); + } + if(!descname) + { + descname = psdNumToStr(NTS_DESCRIPTOR, desctype, ""); + } + Printf("\n Desc. %02lx (%s), %ld bytes", + desctype, + descname, + desclen); + if(pc) + { + psdGetAttrs(PGA_CONFIG, pc, + CA_ConfigNum, &cfgnum, + TAG_END); + if(pif) + { + psdGetAttrs(PGA_INTERFACE, pif, + IFA_InterfaceNum, &ifnum, + IFA_AlternateNum, &ifaltnum, + TAG_END); + if(pep) + { + psdGetAttrs(PGA_ENDPOINT, pep, + EA_EndpointNum, &epnum, + TAG_END); + Printf(" (EP %ld, IF %ld/%ld, Cfg %ld)", epnum, ifnum, ifaltnum, cfgnum); + } else { + Printf(" (Iface %ld/%ld, Cfg %ld)", ifnum, ifaltnum, cfgnum); + } + } else { + Printf(" (Config %ld)", cfgnum); + } + } + // skip basic descriptors + if(!((desctype >= UDT_DEVICE) && (desctype <= UDT_ENDPOINT))) + { + PutStr("\n"); + cnt = 0; + while(desclen--) + { + if(!(cnt & 15)) + { + Printf(" %02lx:", cnt); + } + Printf(" %02lx", *descdata++); + if((!(++cnt & 15)) && desclen) + { + PutStr("\n"); + } + } + } + pdd = pdd->ln_Succ; + } + PutStr("\n"); + } + Printf("\n Google: http://www.google.com/search?q=usb+0x%04lx+0x%04lx\n", + devvendorid, devprodid); + psdUnlockDevice(pd); + PutStr("---------------------------------------------------------------------------\n"); + } + psdUnlockPBase(); + DeleteMsgPort(mp); + CloseLibrary(ps); + } else { + errmsg = "Unable to open poseidon.library\n"; + } + + fail(errmsg); + return(0); // never gets here, just to shut the compiler up +} + diff --git a/rom/usb/poseidon/PsdErrorlog.c b/rom/usb/poseidon/PsdErrorlog.c new file mode 100644 index 000000000..b148078c9 --- /dev/null +++ b/rom/usb/poseidon/PsdErrorlog.c @@ -0,0 +1,116 @@ +/* +** PsdErrorlog by Chris Hodges +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ARGS_NOFLUSH 0 +#define ARGS_NOTS 1 +#define ARGS_SIZEOF 2 + +static const char *template = "NOFLUSH/S,NOTIMESTAMPS=NOTS/S"; +static const char *version = "$VER: PsdErrorlog 4.0 (03.06.09) by Chris Hodges "; +static IPTR ArgsArray[ARGS_SIZEOF]; +static struct RDArgs *ArgsHook = NULL; + +void fail(char *str) +{ + if(ArgsHook) + { + FreeArgs(ArgsHook); + ArgsHook = NULL; + } + if(str) + { + PutStr(str); + exit(20); + } + exit(0); +} + +int main(int argc, char *argv[]) +{ + struct Library *ps; + struct List *errmsgs; + struct Node *pem; + ULONG level; + IPTR origin; + IPTR errstr; + STRPTR errmsg = NULL; + struct DateStamp *ds; + struct DateTime dt; + struct DateStamp currdate; + UBYTE strdate[LEN_DATSTRING]; + UBYTE strtime[LEN_DATSTRING]; + + if(!(ArgsHook = ReadArgs(template, ArgsArray, NULL))) + fail("Wrong arguments!\n"); + + if((ps = OpenLibrary("poseidon.library", 3))) + { + DateStamp(&currdate); + if(ArgsArray[ARGS_NOFLUSH]) + { + psdLockReadPBase(); + } else { + psdLockWritePBase(); + } + psdGetAttrs(PGA_STACK, NULL, PA_ErrorMsgList, &errmsgs, TAG_END); + pem = errmsgs->lh_Head; + while(pem->ln_Succ) + { + ds = NULL; + psdGetAttrs(PGA_ERRORMSG, pem, + EMA_Level, &level, + EMA_Origin, &origin, + EMA_Msg, &errstr, + EMA_DateStamp, &ds, + TAG_END); + if(ds && (!ArgsArray[ARGS_NOTS])) + { + dt.dat_Stamp.ds_Days = ds->ds_Days; + dt.dat_Stamp.ds_Minute = ds->ds_Minute; + dt.dat_Stamp.ds_Tick = ds->ds_Tick; + dt.dat_Format = FORMAT_DEF; + dt.dat_Flags = 0; + dt.dat_StrDay = NULL; + dt.dat_StrDate = strdate; + dt.dat_StrTime = strtime; + DateToStr(&dt); + if(currdate.ds_Days == ds->ds_Days) + { + Printf("%s| %2ld-%s: %s\n", strtime, level, origin, errstr); + } else { + Printf("%s %s| %2ld-%s: %s\n", strdate, strtime, level, origin, errstr); + } + } else { + Printf("%2ld-%s: %s\n", level, origin, errstr); + } + pem = pem->ln_Succ; + } + if(!ArgsArray[ARGS_NOFLUSH]) + { + Forbid(); + while(errmsgs->lh_Head->ln_Succ) + { + psdRemErrorMsg(errmsgs->lh_Head); + } + Permit(); + } + psdUnlockPBase(); + CloseLibrary(ps); + } else { + errmsg = "Unable to open poseidon.library\n"; + } + fail(errmsg); + return(0); // never gets here, just to shut the compiler up +} + diff --git a/rom/usb/poseidon/PsdStackLoader.c b/rom/usb/poseidon/PsdStackLoader.c new file mode 100644 index 000000000..f7d727036 --- /dev/null +++ b/rom/usb/poseidon/PsdStackLoader.c @@ -0,0 +1,32 @@ +/* +** PsdStackloader loads the ENVARC:Sys/poseidon.prefs file and starts the stack. +** This is AROS specific, as under AmigaOS, the PsdStackloader is the config itself +** and under MorphOS, IPrefs loads the prefs. +*/ + +#include +#include +#include + +static const char *version = "$VER: PsdStackloader 4.0 (03.06.09) by Chris Hodges "; + +int main(void) +{ + struct Library *ps; + int ret = RETURN_FAIL; + if((ps = OpenLibrary("poseidon.library", 4))) + { + if(psdLoadCfgFromDisk(NULL)) + { + ret = RETURN_OK; + psdParseCfg(); + } else { + ret = RETURN_ERROR; + PutStr("Error loading poseidon.prefs!\n"); + } + CloseLibrary(ps); + } else { + PutStr("Unable to open poseidon.library\n"); + } + return(ret); +} diff --git a/rom/usb/poseidon/debug.c b/rom/usb/poseidon/debug.c new file mode 100644 index 000000000..f29021b6b --- /dev/null +++ b/rom/usb/poseidon/debug.c @@ -0,0 +1,38 @@ +#include "debug.h" + +#ifdef DEBUG +void dumpmem(void *mem, unsigned long int len) +{ + unsigned char *p; + + if (!mem || !len) { return; } + + p = (unsigned char *) mem; + + bug("\n"); + + do + { + unsigned char b, c, str[17]; + + for (b = 0; b < 16; b++) + { + c = *p++; + str[b] = ((c >= ' ') && (c <= 'z')) ? c : '.'; + str[b + 1] = 0; + bug("%02lx ", c); + if (--len == 0) break; + } + + while (++b < 16) + { + bug(" "); + } + + bug(" %s\n", str); + } while (len); + + bug("\n\n"); +} + +#endif /* DEBUG */ diff --git a/rom/usb/poseidon/debug.h b/rom/usb/poseidon/debug.h new file mode 100644 index 000000000..cab8e625f --- /dev/null +++ b/rom/usb/poseidon/debug.h @@ -0,0 +1,26 @@ +#ifndef __DEBUG_H__ +#define __DEBUG_H__ + +#define DB_LEVEL 1 + +//#define DEBUG 1 + +//#define MEMDEBUG + +#include + +#ifdef DEBUG +#define XPRINTF(l, x) do { if ((l) >= DB_LEVEL) \ + { bug("%s:%s/%lu: ", __FILE__, __FUNCTION__, __LINE__); bug x;} } while (0) +#define KPRINTF(l, x) +#define DB(x) x + void dumpmem(void *mem, unsigned long int len); +#else /* !DEBUG */ + +#define KPRINTF(l, x) +#define XPRINTF(l, x) +#define DB(x) + +#endif /* DEBUG */ + +#endif /* __DEBUG_H__ */ diff --git a/rom/usb/poseidon/mmakefile.src b/rom/usb/poseidon/mmakefile.src new file mode 100644 index 000000000..b7ad51b90 --- /dev/null +++ b/rom/usb/poseidon/mmakefile.src @@ -0,0 +1,31 @@ +# $Id: mmakefile.src $ +include $(TOP)/config/make.cfg + +FILES := poseidon.library popo.gui numtostr debug + +FUNCS := \ + +SHELLFILES := PsdDevLister PsdErrorlog AddUSBClasses AddUSBHardware PsdStackLoader + +#MM rom-usb-poseidon-includes : \ +#MM kernel-exec-includes \ +#MM kernel-dos-includes \ +#MM kernel-utility-includes \ +#MM rom-usb-usbclass-includes \ +#MM includes-copy +#MM- rom-usb-poseidon : linklibs + +#MM- rom-usb-shelltools : rom-usb-poseidon + +%build_module mmake=rom-usb-poseidon \ + modname=poseidon modtype=library \ + files="$(FUNCS) $(FILES)" \ + uselibs="amiga rom mui" + + +%build_progs mmake=rom-usb-shelltools \ + files=$(SHELLFILES) targetdir=$(AROS_C) \ + uselibs="arossupport amiga arosc m" + + +%common diff --git a/rom/usb/poseidon/numtostr.c b/rom/usb/poseidon/numtostr.c new file mode 100644 index 000000000..bbdbc4fc8 --- /dev/null +++ b/rom/usb/poseidon/numtostr.c @@ -0,0 +1,2317 @@ +#include "numtostr.h" + +/* /// "usbclasscodestr[]" */ +const struct PsdWStringMap usbclasscodestr[] = +{ + { AUDIO_CLASSCODE, "Audio" }, + { CDCCTRL_CLASSCODE, "CDC control" }, + { CDCDATA_CLASSCODE, "CDC data" }, + { HID_CLASSCODE, "HID" }, + { PHYSICAL_CLASSCODE, "Physical" }, + { STILLIMG_CLASSCODE, "Still Images" }, + { PRINTER_CLASSCODE, "Printer" }, + { MASSSTORE_CLASSCODE, "MassStorage" }, + { HUB_CLASSCODE, "Hub" }, + { SMARTCARD_CLASSCODE, "Chip-/Smartcard" }, + { SECURITY_CLASSCODE, "Content security" }, + { VIDEO_CLASSCODE, "Video Device" }, + { MISC_CLASSCODE, "Miscellaneous Device" }, + { BLUETOOTH_CLASSCODE, "Bluetooth" }, + { FWUPGRADE_CLASSCODE, "Firmware upgrade" }, + { VENDOR_CLASSCODE, "Vendor" }, + { 0, NULL } +}; +/* \\\ */ + +/* /// "usbcomboclasscodestr[]" */ +/* 010000CS Class + 0300SCCS Subclass-Class + 07PRSCCS Proto-Subclass-Class + 05PR00CS Proto-Class */ + +const struct PsdULStringMap usbcomboclasscodestr[] = +{ + { (3<<24)|(AUDIO_CTRL_SUBCLASS <<8)|AUDIO_CLASSCODE , "Audio Control" }, + { (3<<24)|(AUDIO_STREAM_SUBCLASS<<8)|AUDIO_CLASSCODE , "Audio Streaming" }, + { (3<<24)|(AUDIO_MIDI_SUBCLASS <<8)|AUDIO_CLASSCODE , "Midi" }, + { (1<<24) |AUDIO_CLASSCODE , "Audio" }, + + { (3<<24)|(CDC_DLCM_SUBCLASS <<8)|CDCCTRL_CLASSCODE , "Direct Line Control" }, + { (3<<24)|(CDC_ACM_SUBCLASS <<8)|CDCCTRL_CLASSCODE , "Abstract Control (Modem)" }, + { (3<<24)|(CDC_TCM_SUBCLASS <<8)|CDCCTRL_CLASSCODE , "Telephone Control" }, + { (3<<24)|(CDC_MCCM_SUBCLASS <<8)|CDCCTRL_CLASSCODE , "Multi-Channel Control" }, + { (3<<24)|(CDC_CAPICM_SUBCLASS <<8)|CDCCTRL_CLASSCODE , "CAPI Control (ISDN)" }, + { (3<<24)|(CDC_ETHCM_SUBCLASS <<8)|CDCCTRL_CLASSCODE , "Ethernet Networking Control" }, + { (3<<24)|(CDC_ATMCM_SUBCLASS <<8)|CDCCTRL_CLASSCODE , "ATM Networking Control" }, + { (3<<24)|(CDC_WHCM_SUBCLASS <<8)|CDCCTRL_CLASSCODE , "Wireless Handset Control" }, + { (3<<24)|(CDC_DEVMANGM_SUBCLASS<<8)|CDCCTRL_CLASSCODE , "Device Management" }, + { (3<<24)|(CDC_MDLM_SUBCLASS <<8)|CDCCTRL_CLASSCODE , "Mobile Direct Line" }, + { (3<<24)|(CDC_OBEX_SUBCLASS <<8)|CDCCTRL_CLASSCODE , "OBEX" }, + { (1<<24) |CDCCTRL_CLASSCODE , "CDC Control" }, + + { (1<<24) |CDCDATA_CLASSCODE , "CDC Data" }, + + { (7<<24)|(HID_PROTO_KEYBOARD<<16)|(HID_BOOT_SUBCLASS<<8)|HID_CLASSCODE, "HID (Keyboard)" }, + { (7<<24)|(HID_PROTO_MOUSE <<16)|(HID_BOOT_SUBCLASS<<8)|HID_CLASSCODE, "HID (Mouse)" }, + { (1<<24) |HID_CLASSCODE , "HID" }, + + { (1<<24) |PHYSICAL_CLASSCODE , "Physical" }, + + { (7<<24)|(1<<16)|(1<<8) |STILLIMG_CLASSCODE , "PTP Camera" }, + { (3<<24)|(1<<8) |STILLIMG_CLASSCODE , "Still Images" }, + { (1<<24) |STILLIMG_CLASSCODE , "Imaging" }, + + { (7<<24)|(PRT_PROTO_UNIDIR <<16)|(1<<8)|PRINTER_CLASSCODE, "Printer (Unidirectional)" }, + { (7<<24)|(PRT_PROTO_BIDIR <<16)|(1<<8)|PRINTER_CLASSCODE, "Printer (Bidirectional)" }, + { (7<<24)|(PRT_PROTO_IEEE1284<<16)|(1<<8)|PRINTER_CLASSCODE, "Printer (IEEE1284.4)" }, + { (1<<24) |PRINTER_CLASSCODE , "Printer" }, + + { (7<<24)|(MS_PROTO_CBI <<16)|(MS_UFI_SUBCLASS <<8)|MASSSTORE_CLASSCODE, "Floppy" }, + { (7<<24)|(MS_PROTO_CBI <<16)|(MS_FDDATAPI_SUBCLASS<<8)|MASSSTORE_CLASSCODE, "Floppy" }, + { (7<<24)|(MS_PROTO_CB <<16)|(MS_UFI_SUBCLASS <<8)|MASSSTORE_CLASSCODE, "Floppy" }, + { (7<<24)|(MS_PROTO_CB <<16)|(MS_FDDATAPI_SUBCLASS<<8)|MASSSTORE_CLASSCODE, "Floppy" }, + { (7<<24)|(MS_PROTO_BULK<<16)|(MS_ATAPI_SUBCLASS <<8)|MASSSTORE_CLASSCODE, "MassStorage (CD/DVD)" }, + { (7<<24)|(MS_PROTO_BULK<<16)|(MS_SCSI_SUBCLASS <<8)|MASSSTORE_CLASSCODE, "MassStorage (SCSI)" }, + { (3<<24) |(MS_RBC_SUBCLASS <<8)|MASSSTORE_CLASSCODE, "MassStorage (Flash)" }, + { (5<<24)|(MS_PROTO_CBI <<16) |MASSSTORE_CLASSCODE, "MassStorage (CBI)" }, + { (5<<24)|(MS_PROTO_CB <<16) |MASSSTORE_CLASSCODE, "MassStorage (CB)" }, + { (1<<24) |MASSSTORE_CLASSCODE, "MassStorage" }, + + { (7<<24)|(1<<16)|(0<<8) |HUB_CLASSCODE , "Hub (2.0 Single TT)" }, + { (7<<24)|(2<<16)|(0<<8) |HUB_CLASSCODE , "Hub (2.0 Multi TT)" }, + { (1<<24) |HUB_CLASSCODE , "Hub" }, + + { (1<<24) |SMARTCARD_CLASSCODE, "Chip-/Smartcard" }, + { (1<<24) |SECURITY_CLASSCODE , "Content security" }, + { (1<<24) |MISC_CLASSCODE , "Miscellaneous Device" }, + + { (3<<24)|(1<<8) |VIDEO_CLASSCODE , "Video Control" }, + { (3<<24)|(2<<8) |VIDEO_CLASSCODE , "Video Streaming" }, + { (3<<24)|(3<<8) |VIDEO_CLASSCODE , "Video Interface Collection" }, + { (1<<24) |VIDEO_CLASSCODE , "Video Device" }, + + { (7<<24)|(1<<16)|(1<<8) |BLUETOOTH_CLASSCODE, "Bluetooth" }, + { (3<<24)|(1<<8) |BLUETOOTH_CLASSCODE, "Wireless Radio" }, + { (3<<24)|(2<<8) |BLUETOOTH_CLASSCODE, "Wireless USB Wire Adapter" }, + { (1<<24) |BLUETOOTH_CLASSCODE, "Wireless" }, + + { (3<<24)|(1<<8) |FWUPGRADE_CLASSCODE, "Firmware upgrade" }, + { (3<<24)|(2<<8) |FWUPGRADE_CLASSCODE, "IrDA Bridge" }, + { (3<<24)|(3<<8) |FWUPGRADE_CLASSCODE, "Test and Measurement" }, + { (1<<24) |FWUPGRADE_CLASSCODE, "Application Specific" }, + + { (1<<24) |VENDOR_CLASSCODE , "Vendor" }, + + { 0, NULL } +}; +/* \\\ */ + +/* /// "usbdesccodestr[]" */ +/* 000000DT DescriptorType + 0000CSDT Class-DescriptorType + 00SCCSDT Subclass-Class-DescriptorType + ST00CSDT SubType-Class-DescriptorType + STSCCSDT SubType-Subclass-Class-DescriptorType */ + +const struct PsdULStringMap usbdesctypestr[] = +{ + { UDT_DEVICE, "Device" }, + { UDT_CONFIGURATION, "Configuration" }, + { UDT_STRING, "String" }, + { UDT_INTERFACE, "Interface" }, + { UDT_ENDPOINT, "Endpoint" }, + { UDT_DEVICE_QUALIFIER, "Device Qualifier" }, + { UDT_OTHERSPEED_QUALIFIER, "Otherspeed Qualifier" }, + { UDT_INTERFACE_POWER, "Interface Power" }, + { UDT_OTG, "On-The-Go" }, + { UDT_DEBUG, "Debug" }, + { UDT_INTERFACE_ASSOCIATION, "Interface Association" }, + { UDT_SECURITY, "WUSB Security" }, + { UDT_BOS, "WUSB Binary Device Object" }, + { UDT_DEVICE_CAPABILITY, "WUSB Device Capability" }, + { UDT_ENCRYPTION_TYPE, "WUSB Encryption Type" }, + { UDT_WIRELESS_EP_COMP, "WUSB Wireless Endpoint Companion" }, + + { UDT_CS_DEVICE, "Class-specific Device" }, + { UDT_CS_CONFIGURATION, "Class-specific Configuration" }, + { UDT_CS_STRING, "Class-specific String" }, + { UDT_CS_INTERFACE, "Class-specific Interface" }, + { UDT_CS_ENDPOINT, "Class-specific Endpoint" }, + + { (HUB_CLASSCODE<<8)|UDT_HUB, "Hub" }, + + { (HID_CLASSCODE<<8)|UDT_HID, "HID" }, + { (HID_CLASSCODE<<8)|UDT_REPORT, "HID Report" }, + { (HID_CLASSCODE<<8)|UDT_PHYSICAL, "HID Physical" }, + + { (FWUPGRADE_CLASSCODE<<8)|UDT_DFU, "Firmware Upgrade Info" }, + + { (MISC_COMMON_SUBCLASS<<16)|(MISC_CLASSCODE<<8)|UDT_WIREADAPTER_CLASS, "WUSB Wire Adapter" }, + + { (UDST_AUDIO_CTRL_HEADER <<24)|(AUDIO_CTRL_SUBCLASS<<16)|(AUDIO_CLASSCODE<<8)|UDT_CS_INTERFACE, "Audio Control Header" }, + { (UDST_AUDIO_CTRL_INPUT_TERMINAL <<24)|(AUDIO_CTRL_SUBCLASS<<16)|(AUDIO_CLASSCODE<<8)|UDT_CS_INTERFACE, "Audio Input Terminal" }, + { (UDST_AUDIO_CTRL_OUTPUT_TERMINAL<<24)|(AUDIO_CTRL_SUBCLASS<<16)|(AUDIO_CLASSCODE<<8)|UDT_CS_INTERFACE, "Audio Output Terminal" }, + { (UDST_AUDIO_CTRL_MIXER_UNIT <<24)|(AUDIO_CTRL_SUBCLASS<<16)|(AUDIO_CLASSCODE<<8)|UDT_CS_INTERFACE, "Audio Mixer Unit" }, + { (UDST_AUDIO_CTRL_SELECTOR_UNIT <<24)|(AUDIO_CTRL_SUBCLASS<<16)|(AUDIO_CLASSCODE<<8)|UDT_CS_INTERFACE, "Audio Selector Unit" }, + { (UDST_AUDIO_CTRL_FEATURE_UNIT <<24)|(AUDIO_CTRL_SUBCLASS<<16)|(AUDIO_CLASSCODE<<8)|UDT_CS_INTERFACE, "Audio Feature Unit" }, + { (UDST_AUDIO_CTRL_PROCESSING_UNIT<<24)|(AUDIO_CTRL_SUBCLASS<<16)|(AUDIO_CLASSCODE<<8)|UDT_CS_INTERFACE, "Audio Processing Unit" }, + { (UDST_AUDIO_CTRL_EXTENSION_UNIT <<24)|(AUDIO_CTRL_SUBCLASS<<16)|(AUDIO_CLASSCODE<<8)|UDT_CS_INTERFACE, "Audio Extension Unit" }, + + { (UDST_AUDIO_STREAM_GENERAL <<24)|(AUDIO_STREAM_SUBCLASS<<16)|(AUDIO_CLASSCODE<<8)|UDT_CS_INTERFACE, "Audio Stream General" }, + { (UDST_AUDIO_STREAM_FMT_TYPE <<24)|(AUDIO_STREAM_SUBCLASS<<16)|(AUDIO_CLASSCODE<<8)|UDT_CS_INTERFACE, "Audio Stream Format Type" }, + { (UDST_AUDIO_STREAM_FMT_SPECIFIC<<24)|(AUDIO_STREAM_SUBCLASS<<16)|(AUDIO_CLASSCODE<<8)|UDT_CS_INTERFACE, "Audio Stream Format Specific" }, + + { (UDST_AUDIO_MIDI_HEADER <<24)|(AUDIO_MIDI_SUBCLASS<<16)|(AUDIO_CLASSCODE<<8)|UDT_CS_INTERFACE, "Midi Header" }, + { (UDST_AUDIO_MIDI_IN_JACK <<24)|(AUDIO_MIDI_SUBCLASS<<16)|(AUDIO_CLASSCODE<<8)|UDT_CS_INTERFACE, "Midi IN Jack" }, + { (UDST_AUDIO_MIDI_OUT_JACK<<24)|(AUDIO_MIDI_SUBCLASS<<16)|(AUDIO_CLASSCODE<<8)|UDT_CS_INTERFACE, "Midi OUT Jack" }, + { (UDST_AUDIO_MIDI_ELEMENT <<24)|(AUDIO_MIDI_SUBCLASS<<16)|(AUDIO_CLASSCODE<<8)|UDT_CS_INTERFACE, "Midi Element" }, + + { (UDST_AUDIO_EP_GENERAL <<24)|(AUDIO_CLASSCODE<<8)|UDT_CS_ENDPOINT, "Audio Generic Endpoint" }, + + { (UDST_CDC_HEADER <<24)|(CDCCTRL_CLASSCODE<<8)|UDT_CS_INTERFACE, "CDC Header" }, + { (UDST_CDC_CALLMGM <<24)|(CDCCTRL_CLASSCODE<<8)|UDT_CS_INTERFACE, "Call Management" }, + { (UDST_CDC_ACM <<24)|(CDCCTRL_CLASSCODE<<8)|UDT_CS_INTERFACE, "Abstract Control Management" }, + { (UDST_CDC_DIRECTLINE <<24)|(CDCCTRL_CLASSCODE<<8)|UDT_CS_INTERFACE, "Direct Line Management" }, + { (UDST_CDC_PHONERING <<24)|(CDCCTRL_CLASSCODE<<8)|UDT_CS_INTERFACE, "Telephone Ringer" }, + { (UDST_CDC_PHONECALL <<24)|(CDCCTRL_CLASSCODE<<8)|UDT_CS_INTERFACE, "Telephone Call and Line State Reporting Capabilities" }, + { (UDST_CDC_UNION <<24)|(CDCCTRL_CLASSCODE<<8)|UDT_CS_INTERFACE, "Union" }, + { (UDST_CDC_COUNTRY <<24)|(CDCCTRL_CLASSCODE<<8)|UDT_CS_INTERFACE, "Country Selection" }, + { (UDST_CDC_PHONEOP <<24)|(CDCCTRL_CLASSCODE<<8)|UDT_CS_INTERFACE, "Telephone Operational Modes" }, + { (UDST_CDC_TERMINAL <<24)|(CDCCTRL_CLASSCODE<<8)|UDT_CS_INTERFACE, "USB Terminal" }, + { (UDST_CDC_NETWORK <<24)|(CDCCTRL_CLASSCODE<<8)|UDT_CS_INTERFACE, "Network Channel Terminal" }, + { (UDST_CDC_PROTOCOL <<24)|(CDCCTRL_CLASSCODE<<8)|UDT_CS_INTERFACE, "Protocol Unit" }, + { (UDST_CDC_EXTENSION <<24)|(CDCCTRL_CLASSCODE<<8)|UDT_CS_INTERFACE, "Extension Unit" }, + { (UDST_CDC_MCM <<24)|(CDCCTRL_CLASSCODE<<8)|UDT_CS_INTERFACE, "Multi-Channel Management" }, + { (UDST_CDC_CAPICTRL <<24)|(CDCCTRL_CLASSCODE<<8)|UDT_CS_INTERFACE, "CAPI Control Management" }, + { (UDST_CDC_ETHERNET <<24)|(CDCCTRL_CLASSCODE<<8)|UDT_CS_INTERFACE, "Ethernet Networking" }, + { (UDST_CDC_ATM <<24)|(CDCCTRL_CLASSCODE<<8)|UDT_CS_INTERFACE, "ATM Networking" }, + { (UDST_CDC_WMC <<24)|(CDCCTRL_CLASSCODE<<8)|UDT_CS_INTERFACE, "Wireless Handset Control Model" }, + { (UDST_CDC_MDLM <<24)|(CDCCTRL_CLASSCODE<<8)|UDT_CS_INTERFACE, "Mobile Direct Line Model" }, + { (UDST_CDC_MDLMDETAIL <<24)|(CDCCTRL_CLASSCODE<<8)|UDT_CS_INTERFACE, "MDLM Detail" }, + { (UDST_CDC_DEVMANGM <<24)|(CDCCTRL_CLASSCODE<<8)|UDT_CS_INTERFACE, "Device Management Model" }, + { (UDST_CDC_OBEX <<24)|(CDCCTRL_CLASSCODE<<8)|UDT_CS_INTERFACE, "OBEX" }, + { (UDST_CDC_CMDSET <<24)|(CDCCTRL_CLASSCODE<<8)|UDT_CS_INTERFACE, "Command Set" }, + { (UDST_CDC_CMDSETDETAIL<<24)|(CDCCTRL_CLASSCODE<<8)|UDT_CS_INTERFACE, "Command Set Detail" }, + { (UDST_CDC_TCM <<24)|(CDCCTRL_CLASSCODE<<8)|UDT_CS_INTERFACE, "Telephone Control Model" }, + + { (SMARTCARD_CLASSCODE<<8)|UDT_CCID, "Smartcard Functional Descriptor" }, + + { (UDST_VIDEO_CTRL_HEADER <<24)|(VIDEO_CTRL_SUBCLASS<<16)|(VIDEO_CLASSCODE<<8)|UDT_CS_INTERFACE, "Video Control Header" }, + { (UDST_VIDEO_CTRL_INPUT_TERMINAL <<24)|(VIDEO_CTRL_SUBCLASS<<16)|(VIDEO_CLASSCODE<<8)|UDT_CS_INTERFACE, "Video Input Terminal" }, + { (UDST_VIDEO_CTRL_OUTPUT_TERMINAL<<24)|(VIDEO_CTRL_SUBCLASS<<16)|(VIDEO_CLASSCODE<<8)|UDT_CS_INTERFACE, "Video Output Terminal" }, + { (UDST_VIDEO_CTRL_SELECTOR_UNIT <<24)|(VIDEO_CTRL_SUBCLASS<<16)|(VIDEO_CLASSCODE<<8)|UDT_CS_INTERFACE, "Video Selector Unit" }, + { (UDST_VIDEO_CTRL_PROCESSING_UNIT<<24)|(VIDEO_CTRL_SUBCLASS<<16)|(VIDEO_CLASSCODE<<8)|UDT_CS_INTERFACE, "Video Processing Unit" }, + { (UDST_VIDEO_CTRL_EXTENSION_UNIT <<24)|(VIDEO_CTRL_SUBCLASS<<16)|(VIDEO_CLASSCODE<<8)|UDT_CS_INTERFACE, "Video Extension Unit" }, + + { (UDST_VIDEO_STREAM_INPUT_HEADER <<24)|(VIDEO_STREAM_SUBCLASS<<16)|(VIDEO_CLASSCODE<<8)|UDT_CS_INTERFACE, "Video Stream Input Header" }, + { (UDST_VIDEO_STREAM_OUTPUT_HEADER <<24)|(VIDEO_STREAM_SUBCLASS<<16)|(VIDEO_CLASSCODE<<8)|UDT_CS_INTERFACE, "Video Stream Output Header" }, + { (UDST_VIDEO_STREAM_STILL_IMAGE_FRAME <<24)|(VIDEO_STREAM_SUBCLASS<<16)|(VIDEO_CLASSCODE<<8)|UDT_CS_INTERFACE, "Video Stream Still Image Frame" }, + { (UDST_VIDEO_STREAM_FORMAT_UNCOMPRESSED<<24)|(VIDEO_STREAM_SUBCLASS<<16)|(VIDEO_CLASSCODE<<8)|UDT_CS_INTERFACE, "Video Stream Format Uncompressed" }, + { (UDST_VIDEO_STREAM_FRAME_UNCOMPRESSED <<24)|(VIDEO_STREAM_SUBCLASS<<16)|(VIDEO_CLASSCODE<<8)|UDT_CS_INTERFACE, "Video Stream Frame Uncompressed" }, + { (UDST_VIDEO_STREAM_FORMAT_MJPEG <<24)|(VIDEO_STREAM_SUBCLASS<<16)|(VIDEO_CLASSCODE<<8)|UDT_CS_INTERFACE, "Video Stream Format MJPEG" }, + { (UDST_VIDEO_STREAM_FRAME_MJPEG <<24)|(VIDEO_STREAM_SUBCLASS<<16)|(VIDEO_CLASSCODE<<8)|UDT_CS_INTERFACE, "Video Stream Frame MJPEG" }, + { (UDST_VIDEO_STREAM_FORMAT_MPEG2TS <<24)|(VIDEO_STREAM_SUBCLASS<<16)|(VIDEO_CLASSCODE<<8)|UDT_CS_INTERFACE, "Video Stream Format MPEG2-TS" }, + { (UDST_VIDEO_STREAM_FORMAT_DV <<24)|(VIDEO_STREAM_SUBCLASS<<16)|(VIDEO_CLASSCODE<<8)|UDT_CS_INTERFACE, "Video Stream Format DV" }, + { (UDST_VIDEO_STREAM_COLORFORMAT <<24)|(VIDEO_STREAM_SUBCLASS<<16)|(VIDEO_CLASSCODE<<8)|UDT_CS_INTERFACE, "Video Stream ColorFormat" }, + { (UDST_VIDEO_STREAM_FORMAT_FRAME_BASED <<24)|(VIDEO_STREAM_SUBCLASS<<16)|(VIDEO_CLASSCODE<<8)|UDT_CS_INTERFACE, "Video Stream Format Frame-based" }, + { (UDST_VIDEO_STREAM_FRAME_FRAME_BASED <<24)|(VIDEO_STREAM_SUBCLASS<<16)|(VIDEO_CLASSCODE<<8)|UDT_CS_INTERFACE, "Video Stream Frame Frame-based" }, + { (UDST_VIDEO_STREAM_FORMAT_STREAM_BASED<<24)|(VIDEO_STREAM_SUBCLASS<<16)|(VIDEO_CLASSCODE<<8)|UDT_CS_INTERFACE, "Video Stream Format Stream-based" }, + + { (UDST_VIDEO_EP_GENERAL <<24)|(VIDEO_CLASSCODE<<8)|UDT_CS_ENDPOINT, "Video Generic Endpoint" }, + { (UDST_VIDEO_EP_ENDPOINT <<24)|(VIDEO_CLASSCODE<<8)|UDT_CS_ENDPOINT, "Video Endpoint Endpoint" }, + { (UDST_VIDEO_EP_INTERRUPT<<24)|(VIDEO_CLASSCODE<<8)|UDT_CS_ENDPOINT, "Video Interrupt Endpoint" }, + + { 0, NULL } +}; +/* \\\ */ + +/* /// "usbhwioerrstr[]" */ +const struct PsdWStringMap usbhwioerrstr[] = +{ + { UHIOERR_USBOFFLINE, "usb bus offline" }, + { UHIOERR_NAK, "nak received" }, + { UHIOERR_HOSTERROR, "host error" }, + { UHIOERR_STALL, "endpoint stall" }, + { UHIOERR_PKTTOOLARGE, "packet too large" }, + { UHIOERR_TIMEOUT, "response timeout" }, + { UHIOERR_OVERFLOW, "packet overflow" }, + { UHIOERR_CRCERROR, "packet crc error" }, + { UHIOERR_RUNTPACKET, "short packet received" }, + { UHIOERR_NAKTIMEOUT, "nak timeout" }, + { UHIOERR_BADPARAMS, "illegal parameters specified" }, + { UHIOERR_OUTOFMEMORY, "out of auxiliary memory" }, + { UHIOERR_BABBLE, "babble condition" }, + { 666, "unlicenced hardware" }, + + { IOERR_OPENFAIL, "device/unit failed to open" }, + { IOERR_ABORTED, "request terminated" }, + { IOERR_NOCMD, "command not supported" }, + { IOERR_BADLENGTH, "bad length" }, + { IOERR_BADADDRESS, "invalid address" }, + { IOERR_UNITBUSY, "unit already open" }, + { IOERR_SELFTEST, "hardware failed self-test" }, + { 0, NULL }, +}; +/* \\\ */ + +/* /// "usblangids[]" */ +const struct PsdUWStringMap usblangids[] = +{ + { 0x1401, "Arabic (Algeria)" }, + { 0x3c01, "Arabic (Bahrain)" }, + { 0x0c01, "Arabic (Egypt)" }, + { 0x0801, "Arabic (Iraq)" }, + { 0x2c01, "Arabic (Jordan)" }, + { 0x3401, "Arabic (Kuwait)" }, + { 0x3001, "Arabic (Lebanon)" }, + { 0x1001, "Arabic (Libya)" }, + { 0x1801, "Arabic (Morocco)" }, + { 0x2001, "Arabic (Oman)" }, + { 0x4001, "Arabic (Qatar)" }, + { 0x0401, "Arabic (Saudi Arabia)" }, + { 0x2801, "Arabic (Syria)" }, + { 0x1c01, "Arabic (Tunisia)" }, + { 0x3801, "Arabic (U.A.E.)" }, + { 0x2401, "Arabic (Yemen)" }, + { 0x0402, "Bulgarian" }, + { 0x0403, "Catalan" }, + { 0x0c04, "Chinese (Hong Kong SAR, PRC)" }, + { 0x1404, "Chinese (Macau SAR)" }, + { 0x0804, "Chinese (PRC)" }, + { 0x1004, "Chinese (Singapore)" }, + { 0x0404, "Chinese (Taiwan)" }, + { 0x0405, "Czech" }, + { 0x0406, "Danish" }, + { 0x0c07, "German (Austria)" }, + { 0x1407, "German (Liechtenstein)" }, + { 0x1007, "German (Luxembourg)" }, + { 0x0407, "German (Standard)" }, + { 0x0807, "German (Switzerland)" }, + { 0x0408, "Greek" }, + { 0x0c09, "English (Australian)" }, + { 0x2809, "English (Belize)" }, + { 0x1009, "English (Canadian)" }, + { 0x2409, "English (Caribbean)" }, + { 0x1809, "English (Ireland)" }, + { 0x2009, "English (Jamaica)" }, + { 0x1409, "English (New Zealand)" }, + { 0x3409, "English (Philippines)" }, + { 0x1c09, "English (South Africa)" }, + { 0x2c09, "English (Trinidad)" }, + { 0x0809, "English (United Kingdom)" }, + { 0x0409, "English (United States)" }, + { 0x3009, "English (Zimbabwe)" }, + { 0x2c0a, "Spanish (Argentina)" }, + { 0x400a, "Spanish (Bolivia)" }, + { 0x340a, "Spanish (Chile)" }, + { 0x240a, "Spanish (Colombia)" }, + { 0x140a, "Spanish (Costa Rica)" }, + { 0x1c0a, "Spanish (Dominican Republic)" }, + { 0x300a, "Spanish (Ecuador)" }, + { 0x440a, "Spanish (El Salvador)" }, + { 0x100a, "Spanish (Guatemala)" }, + { 0x480a, "Spanish (Honduras)" }, + { 0x080a, "Spanish (Mexican)" }, + { 0x0c0a, "Spanish (Modern Sort)" }, + { 0x4c0a, "Spanish (Nicaragua)" }, + { 0x180a, "Spanish (Panama)" }, + { 0x3c0a, "Spanish (Paraguay)" }, + { 0x280a, "Spanish (Peru)" }, + { 0x500a, "Spanish (Puerto Rico)" }, + { 0x040a, "Spanish (Traditional Sort)" }, + { 0x380a, "Spanish (Uruguay)" }, + { 0x200a, "Spanish (Venezuela)" }, + { 0x040b, "Finnish" }, + { 0x080c, "French (Belgian)" }, + { 0x0c0c, "French (Canadian)" }, + { 0x140c, "French (Luxembourg)" }, + { 0x180c, "French (Monaco)" }, + { 0x040c, "French (Standard)" }, + { 0x100c, "French (Switzerland)" }, + { 0x040d, "Hebrew" }, + { 0x040e, "Hungarian" }, + { 0x040f, "Icelandic" }, + { 0x0410, "Italian (Standard)" }, + { 0x0810, "Italian (Switzerland)" }, + { 0x0411, "Japanese" }, + { 0x0812, "Korean (Johab)" }, + { 0x0412, "Korean" }, + { 0x0813, "Dutch (Belgium)" }, + { 0x0413, "Dutch (Netherlands)" }, + { 0x0414, "Norwegian (Bokmal)" }, + { 0x0814, "Norwegian (Nynorsk)" }, + { 0x0415, "Polish" }, + { 0x0416, "Portuguese (Brazil)" }, + { 0x0816, "Portuguese (Standard)" }, + { 0x0418, "Romanian" }, + { 0x0419, "Russian" }, + { 0x041a, "Croatian" }, + { 0x0c1a, "Serbian (Cyrillic)" }, + { 0x081a, "Serbian (Latin)" }, + { 0x041b, "Slovak" }, + { 0x041c, "Albanian" }, + { 0x081d, "Swedish (Finland)" }, + { 0x041d, "Swedish" }, + { 0x041e, "Thai" }, + { 0x041f, "Turkish" }, + { 0x0820, "Urdu (India)" }, + { 0x0420, "Urdu (Pakistan)" }, + { 0x0421, "Indonesian" }, + { 0x0422, "Ukrainian" }, + { 0x0423, "Belarussian" }, + { 0x0424, "Slovenian" }, + { 0x0425, "Estonian" }, + { 0x0426, "Latvian" }, + { 0x0827, "Lithuanian (Classic)" }, + { 0x0427, "Lithuanian" }, + { 0x0429, "Farsi" }, + { 0x042a, "Vietnamese" }, + { 0x042b, "Armenian" }, + { 0x082c, "Azeri (Cyrillic)" }, + { 0x042c, "Azeri (Latin)" }, + { 0x042d, "Basque" }, + { 0x042f, "Macedonian" }, + { 0x0430, "Sutu" }, + { 0x0436, "Afrikaans" }, + { 0x0437, "Georgian" }, + { 0x0438, "Faeroese" }, + { 0x0439, "Hindi" }, + { 0x083e, "Malay (Brunei Darussalam)" }, + { 0x043e, "Malay (Malaysian)" }, + { 0x043f, "Kazakh" }, + { 0x0441, "Swahili (Kenya)" }, + { 0x0843, "Uzbek (Cyrillic)" }, + { 0x0443, "Uzbek (Latin)" }, + { 0x0444, "Tatar (Tatarstan)" }, + { 0x0445, "Bengali" }, + { 0x0446, "Punjabi" }, + { 0x0447, "Gujarati" }, + { 0x0448, "Oriya" }, + { 0x0449, "Tamil" }, + { 0x044a, "Telugu" }, + { 0x044b, "Kannada" }, + { 0x044c, "Malayalam" }, + { 0x044d, "Assamese" }, + { 0x044e, "Marathi" }, + { 0x044f, "Sanskrit" }, + { 0x0455, "Burmese" }, + { 0x0457, "Konkani" }, + { 0x0458, "Manipuri" }, + { 0x0459, "Sindhi" }, + { 0x0860, "Kashmiri (India)" }, + { 0x0861, "Nepali (India)" }, + { 0x04ff, "HID (Usage Data Descriptor)" }, + { 0xf0ff, "HID (Vendor Defined 1)" }, + { 0xf4ff, "HID (Vendor Defined 2)" }, + { 0xf8ff, "HID (Vendor Defined 3)" }, + { 0xfcff, "HID (Vendor Defined 4)" }, + { 0x0000, NULL } +}; +/* \\\ */ + +/* /// "usbvendorids[]" */ +const struct PsdUWStringMap usbvendorids[] = +{ + /* new OpenBSD: usbdevs,v 1.77 2004/02/27, usb.ids,v 1.147 2004/04/30 16:18:32 vojtech */ + { 0x0386, "LTS" }, + { 0x03e8, "EndPoints, Inc." }, + { 0x03e9, "Thesys Microelectronics" }, + { 0x03ea, "Data Broadcasting Corp." }, + { 0x03eb, "Atmel Corp." }, + { 0x03ec, "Iwatsu America, Inc." }, + { 0x03ed, "Mitel Corp." }, + { 0x03ee, "Mitsumi" }, + { 0x03f0, "Hewlett Packard" }, + { 0x03f1, "Genoa Technology" }, + { 0x03f2, "Oak Technology, Inc." }, + { 0x03f3, "Adaptec, Inc." }, + { 0x03f4, "Diebold, Inc." }, + { 0x03f5, "Siemens Electromechanical" }, + { 0x03f8, "Epson Imaging Technology Center" }, + { 0x03f9, "KeyTronic Corp." }, + { 0x03fb, "OPTi, Inc." }, + { 0x03fc, "Elitegroup Computer Systems" }, + { 0x03fd, "Xilinx, Inc." }, + { 0x03fe, "Farallon Comunications" }, + { 0x0400, "National Semiconductor Corp." }, + { 0x0401, "National Registry, Inc." }, + { 0x0402, "ALi Corp." }, + { 0x0403, "Future Technology Devices International, Ltd" }, + { 0x0404, "NCR Corp." }, + { 0x0405, "Synopsys, Inc." }, + { 0x0406, "Fujitsu-ICL Computers" }, + { 0x0407, "Fujitsu Personal Systems, Inc." }, + { 0x0408, "Quanta Computer, Inc." }, + { 0x0409, "NEC Corp." }, + { 0x040a, "Kodak Co." }, + { 0x040b, "Weltrend Semiconductor" }, + { 0x040c, "VTech Computers, Ltd" }, + { 0x040d, "VIA Technologies, Inc." }, + { 0x040e, "MCCI" }, + { 0x040f, "Echo Speech Corp." }, + { 0x0411, "MelCo., Inc." }, + { 0x0412, "Award Software International" }, + { 0x0413, "Leadtek Research, Inc." }, + { 0x0414, "Giga-Byte Technology Co., Ltd" }, + { 0x0416, "Winbond Electronics Corp." }, + { 0x0417, "Symbios Logic" }, + { 0x0418, "AST Research" }, + { 0x0419, "Samsung Info. Systems America, Inc." }, + { 0x041a, "Phoenix Technologies, Ltd" }, + { 0x041b, "d'TV" }, + { 0x041d, "S3, Inc." }, + { 0x041e, "Creative Technology, Ltd" }, + { 0x041f, "LCS Telegraphics" }, + { 0x0420, "Chips and Technologies" }, + { 0x0421, "Nokia Mobile Phones" }, + { 0x0422, "ADI Systems, Inc." }, + { 0x0423, "Computer Access Technology Corp." }, + { 0x0424, "Standard Microsystems Corp." }, + { 0x0425, "Motorola Semiconductors HK, Ltd" }, + { 0x0426, "Integrated Device Technology, Inc." }, + { 0x0427, "Motorola Electronics Taiwan, Ltd" }, + { 0x0428, "Advanced Gravis Computer Tech, Ltd" }, + { 0x0429, "Cirrus Logic" }, + { 0x042a, "Ericsson Austrian, AG" }, + { 0x042b, "Intel Corp." }, + { 0x042c, "Innovative Semiconductors, Inc." }, + { 0x042d, "Micronics" }, + { 0x042e, "Acer, Inc." }, + { 0x042f, "Molex, Inc." }, + { 0x0430, "Sun Microsystems, Inc." }, + { 0x0431, "Itac Systems, Inc." }, + { 0x0432, "Unisys Corp." }, + { 0x0433, "Alps Electric, Inc." }, + { 0x0434, "Samsung Info. Systems America, Inc." }, + { 0x0435, "Hyundai Electronics America" }, + { 0x0436, "Taugagreining HF" }, + { 0x0437, "Framatome Connectors USA" }, + { 0x0438, "Advanced Micro Devices, Inc." }, + { 0x0439, "Voice Technologies Group" }, + { 0x043d, "Lexmark International, Inc." }, + { 0x043e, "LG Electronics USA, Inc." }, + { 0x043f, "RadiSys Corp." }, + { 0x0440, "Eizo Nanao Corp." }, + { 0x0441, "Winbond Systems Lab." }, + { 0x0442, "Ericsson, Inc." }, + { 0x0443, "Gateway, Inc." }, + { 0x0445, "Lucent Technologies, Inc." }, + { 0x0446, "NMB Technologies Corp." }, + { 0x0447, "Momentum Microsystems" }, + { 0x0449, "Eldim" }, + { 0x044a, "Shamrock Tech. Co., Ltd" }, + { 0x044b, "WSI" }, + { 0x044c, "CCL/ITRI" }, + { 0x044d, "Siemens Nixdorf AG" }, + { 0x044e, "Alps Electric Co., Ltd" }, + { 0x044f, "ThrustMaster, Inc." }, + { 0x0450, "DFI, Inc." }, + { 0x0451, "Texas Instruments, Inc." }, + { 0x0452, "Mitsubishi Electronics America, Inc." }, + { 0x0453, "CMD Technology" }, + { 0x0454, "Vobis Microcomputer AG" }, + { 0x0455, "Telematics International, Inc." }, + { 0x0456, "Analog Devices, Inc." }, + { 0x0457, "Silicon Integrated Systems Corp." }, + { 0x0458, "KYE Systems Corp. (Mouse Systems)" }, + { 0x0459, "Adobe Systems, Inc." }, + { 0x045a, "SONICblue, Inc." }, + { 0x045b, "Hitachi, Ltd" }, + { 0x045d, "Nortel Networks, Ltd" }, + { 0x045e, "Microsoft Corp." }, + { 0x0460, "Ace Cad Enterprise Co., Ltd" }, + { 0x0461, "Primax Electronics, Ltd" }, + { 0x0463, "MGE UPS Systems" }, + { 0x0464, "AMP/Tycoelectronics Corp." }, + { 0x0467, "AT&T Paradyne" }, + { 0x0468, "Wieson Technologies Co., Ltd" }, + { 0x046a, "Cherry GmbH" }, + { 0x046b, "American Megatrends, Inc." }, + { 0x046c, "Toshiba Corp., Digital Media Equipment" }, + { 0x046d, "Logitech, Inc." }, + { 0x046e, "Behavior Tech. Computer Corp." }, + { 0x046f, "Crystal Semiconductor" }, + { 0x0471, "Philips" }, + { 0x0472, "Chicony Electronics Co., Ltd" }, + { 0x0473, "Sanyo Information Business Co., Ltd" }, + { 0x0474, "Sanyo Electric Co., Ltd" }, + { 0x0475, "Relisys/Teco Information System" }, + { 0x0476, "AESP" }, + { 0x0477, "Seagate Technology, Inc." }, + { 0x0478, "Connectix Corp." }, + { 0x0479, "Advanced Peripheral Laboratories" }, + { 0x047a, "Semtech Corp." }, + { 0x047b, "Silitek Corp." }, + { 0x047c, "Dell Computer Corp." }, + { 0x047d, "Kensington" }, + { 0x047e, "Agere Systems, Inc. (Lucent)" }, + { 0x047f, "Plantronics, Inc." }, + { 0x0480, "Toshiba America Info. Systems, Inc." }, + { 0x0481, "Zenith Data Systems" }, + { 0x0482, "Kyocera Corp." }, + { 0x0483, "SGS Thomson Microelectronics" }, + { 0x0484, "Specialix" }, + { 0x0485, "Nokia Monitors" }, + { 0x0486, "ASUS Computers, Inc." }, + { 0x0487, "Stewart Connector" }, + { 0x0488, "Cirque Corp." }, + { 0x0489, "Foxconn / Hon Hai" }, + { 0x048a, "S-MOS Systems, Inc." }, + { 0x048c, "Alps Electric Ireland, Ltd" }, + { 0x048d, "Integrated Technology Express, Inc." }, + { 0x048f, "Eicon Tech." }, + { 0x0490, "United Microelectronics Corp." }, + { 0x0491, "Capetronic" }, + { 0x0492, "Samsung SemiConductor, Inc." }, + { 0x0493, "MAG Technology Co., Ltd" }, + { 0x0495, "ESS Technology, Inc." }, + { 0x0496, "Micron Electronics" }, + { 0x0497, "Smile International" }, + { 0x0498, "Capetronic (Kaohsiung) Corp." }, + { 0x0499, "Yamaha Corp." }, + { 0x049a, "Gandalf Technologies, Ltd" }, + { 0x049b, "Curtis Computer Products" }, + { 0x049c, "Acer Advanced Labs, Inc." }, + { 0x049d, "VLSI Technology" }, + { 0x049f, "Compaq Computer Corp." }, + { 0x04a0, "Digital Equipment Corp." }, + { 0x04a1, "SystemSoft Corp." }, + { 0x04a2, "FirePower Systems" }, + { 0x04a3, "Trident Microsystems, Inc." }, + { 0x04a4, "Hitachi, Ltd" }, + { 0x04a5, "Acer Peripherals Inc. (now BenQ Corp.)" }, + { 0x04a6, "Nokia Display Products" }, + { 0x04a7, "Visioneer" }, + { 0x04a8, "Multivideo Labs, Inc." }, + { 0x04a9, "Canon, Inc." }, + { 0x04aa, "DaeWoo Telecom, Ltd" }, + { 0x04ab, "Chromatic Research" }, + { 0x04ac, "Micro Audiometrics Corp." }, + { 0x04ad, "Dooin Electronics" }, + { 0x04af, "Winnov L.P." }, + { 0x04b0, "Nikon Corp." }, + { 0x04b1, "Pan International" }, + { 0x04b3, "IBM Corp." }, + { 0x04b4, "Cypress Semiconductor Corp." }, + { 0x04b5, "ROHM LSI Systems USA, LLC" }, + { 0x04b6, "Hint Corp." }, + { 0x04b7, "Compal Electronics, Inc." }, + { 0x04b8, "Seiko Epson Corp." }, + { 0x04b9, "Rainbow Technologies, Inc." }, + { 0x04ba, "Toucan Systems, Ltd" }, + { 0x04bb, "I-O Data Device, Inc." }, + { 0x04bd, "Toshiba Electronics Taiwan Corp." }, + { 0x04be, "Telia Research AB" }, + { 0x04bf, "TDK Corp." }, + { 0x04c1, "U.S. Robotics (3Com)" }, + { 0x04c2, "Methode Electronics Far East PTE, Ltd" }, + { 0x04c3, "Maxi Switch, Inc." }, + { 0x04c4, "Lockheed Martin Energy Research" }, + { 0x04c5, "Fujitsu, Ltd" }, + { 0x04c6, "Toshiba America Electronic Components" }, + { 0x04c7, "Micro Macro Technologies" }, + { 0x04c8, "Konica Corp." }, + { 0x04ca, "Lite-On Technology Corp." }, + { 0x04cb, "Fuji Photo Film Co., Ltd" }, + { 0x04cc, "Philips Semiconductors" }, + { 0x04cd, "Tatung Co. Of America" }, + { 0x04ce, "ScanLogic Corp." }, + { 0x04cf, "Myson Century, Inc." }, + { 0x04d0, "Digi International" }, + { 0x04d1, "ITT Canon" }, + { 0x04d2, "Altec Lansing Technologies" }, + { 0x04d3, "VidUS, Inc." }, + { 0x04d4, "LSI Logic, Inc." }, + { 0x04d5, "Forte Technologies, Inc." }, + { 0x04d6, "Mentor Graphics" }, + { 0x04d7, "Oki Semiconductor" }, + { 0x04d8, "Microchip Technology, Inc." }, + { 0x04d9, "Holtek Semiconductor, Inc." }, + { 0x04da, "Panasonic (Matsushita)" }, + { 0x04db, "Hypertec Pty, Ltd" }, + { 0x04dc, "Huan Hsin Holdings, Ltd" }, + { 0x04dd, "Sharp Corp." }, + { 0x04de, "MindShare, Inc." }, + { 0x04df, "Interlink Electronics" }, + { 0x04e1, "Iiyama North America, Inc." }, + { 0x04e2, "Exar Corp." }, + { 0x04e3, "Zilog, Inc." }, + { 0x04e4, "ACC Microelectronics" }, + { 0x04e5, "Promise Technology" }, + { 0x04e6, "SCM Microsystems, Inc." }, + { 0x04e7, "Elo TouchSystems" }, + { 0x04e8, "Samsung Electronics Co., Ltd" }, + { 0x04e9, "PC-Tel, Inc." }, + { 0x04ea, "Brooktree Corp." }, + { 0x04eb, "Northstar Systems, Inc." }, + { 0x04ec, "Tokyo Electron Device, Ltd" }, + { 0x04ed, "Annabooks" }, + { 0x04ef, "Pacific Electronic International, Inc." }, + { 0x04f0, "Daewoo Electronics Co., Ltd" }, + { 0x04f1, "Victor Company of Japan, Ltd" }, + { 0x04f2, "Chicony Electronics Co., Ltd" }, + { 0x04f3, "Elan Microelectronics Corp." }, + { 0x04f4, "Harting Elektronik, Inc." }, + { 0x04f5, "Fujitsu-ICL Systems, Inc." }, + { 0x04f6, "Norand Corp." }, + { 0x04f7, "Newnex Technology Corp." }, + { 0x04f8, "FuturePlus Systems" }, + { 0x04f9, "Brother Industries, Ltd" }, + { 0x04fa, "Dallas Semiconductor" }, + { 0x04fb, "Biostar Microtech International Corp." }, + { 0x04fc, "Sunplus Technology Co., Ltd" }, + { 0x04fd, "Soliton Systems, K.K." }, + { 0x04fe, "PFU, Ltd" }, + { 0x04ff, "E-CMOS Corp." }, + { 0x0500, "Siam United Hi-Tech" }, + { 0x0501, "Fujikura DDK, Ltd" }, + { 0x0502, "Acer, Inc." }, + { 0x0503, "Hitachi America, Ltd" }, + { 0x0504, "Hayes Microcomputer Products" }, + { 0x0506, "3Com Corp." }, + { 0x0507, "Hosiden Corp." }, + { 0x0508, "Clarion Co., Ltd" }, + { 0x0509, "Aztech Systems, Ltd" }, + { 0x050a, "Cinch Connectors" }, + { 0x050b, "Cable System International" }, + { 0x050c, "InnoMedia, Inc." }, + { 0x050d, "Belkin Components" }, + { 0x050e, "Neon Technology, Inc." }, + { 0x050f, "KC Technology, Inc." }, + { 0x0510, "Sejin Electron, Inc." }, + { 0x0511, "N'Able (DataBook) Technologies, Inc." }, + { 0x0512, "Hualon Microelectronics Corp." }, + { 0x0513, "digital-X, Inc." }, + { 0x0514, "FCI Electronics" }, + { 0x0515, "ACTC" }, + { 0x0516, "Longwell Electronics" }, + { 0x0517, "Butterfly Communications" }, + { 0x0518, "EzKEY Corp." }, + { 0x0519, "Star Micronics Co., Ltd" }, + { 0x051a, "WYSE Technology" }, + { 0x051b, "Silicon Graphics" }, + { 0x051c, "Shuttle, Inc." }, + { 0x051d, "American Power Conversion" }, + { 0x051e, "Scientific Atlanta, Inc." }, + { 0x051f, "IO Systems (Elite Electronics), Inc." }, + { 0x0520, "Taiwan Semiconductor Manufacturing Co." }, + { 0x0521, "Airborn Connectors" }, + { 0x0522, "Advanced Connectek, Inc." }, + { 0x0523, "ATEN GmbH" }, + { 0x0524, "Sola Electronics" }, + { 0x0525, "Netchip Technology, Inc." }, + { 0x0526, "Temic MHS S.A." }, + { 0x0527, "ALTRA" }, + { 0x0528, "ATI Technologies, Inc." }, + { 0x0529, "Aladdin Knowledge Systems" }, + { 0x052a, "Crescent Heart Software" }, + { 0x052b, "Tekom Technologies, Inc." }, + { 0x052c, "Canon Information Systems, Inc." }, + { 0x052d, "Avid Electronics Corp." }, + { 0x052e, "Standard Microsystems Corp." }, + { 0x052f, "Unicore Software, Inc." }, + { 0x0530, "American Microsystems, Inc." }, + { 0x0531, "Wacom Technology Corp." }, + { 0x0532, "Systech Corp." }, + { 0x0533, "Alcatel Mobile Phones" }, + { 0x0534, "Motorola, Inc." }, + { 0x0535, "LIH TZU Electric Co., Ltd" }, + { 0x0536, "Hand Held Products (Welch Allyn, Inc.)" }, + { 0x0537, "Inventec Corp." }, + { 0x0538, "Caldera International, Inc. (SCO)" }, + { 0x0539, "Shyh Shiun Terminals Co., Ltd" }, + { 0x053a, "Preh Werke GmbH & Co. KG" }, + { 0x053b, "Global Village Communication" }, + { 0x053c, "Institut of Microelectronic & Mechatronic Systems" }, + { 0x053d, "Silicon Architect" }, + { 0x053e, "Mobility Electronics" }, + { 0x053f, "Synopsys, Inc." }, + { 0x0540, "UniAccess AB" }, + { 0x0541, "Sirf Technology, Inc." }, + { 0x0543, "ViewSonic Corp." }, + { 0x0544, "Cristie Electronics, Ltd" }, + { 0x0545, "Xirlink, Inc." }, + { 0x0546, "Polaroid Corp." }, + { 0x0547, "Anchor Chips, Inc." }, + { 0x0548, "Tyan Computer Corp." }, + { 0x0549, "Pixera Corp." }, + { 0x054a, "Fujitsu Microelectronics, Inc." }, + { 0x054b, "New Media Corp." }, + { 0x054c, "Sony Corp." }, + { 0x054d, "Try Corp." }, + { 0x054e, "Proside Corp." }, + { 0x054f, "WYSE Technology Taiwan" }, + { 0x0550, "Fuji Xerox Co., Ltd" }, + { 0x0551, "CompuTrend Systems, Inc." }, + { 0x0552, "Philips Monitors" }, + { 0x0553, "STMicroelectronics Imaging Division (VLSI Vision)" }, + { 0x0554, "Dictaphone Corp." }, + { 0x0555, "ANAM S&T Co., Ltd" }, + { 0x0556, "Asahi Kasei Microsystems Co., Ltd" }, + { 0x0557, "ATEN International Co., Ltd" }, + { 0x0558, "Truevision, Inc." }, + { 0x0559, "Cadence Design Systems, Inc." }, + { 0x055a, "Kenwood USA" }, + { 0x055b, "KnowledgeTek, Inc." }, + { 0x055c, "Proton Electronic Ind." }, + { 0x055d, "Samsung Electro-Mechanics Co." }, + { 0x055e, "CTX Opto-Electronics Corp." }, + { 0x055f, "Mustek Systems, Inc." }, + { 0x0560, "Interface Corp." }, + { 0x0561, "Oasis Design, Inc." }, + { 0x0562, "Telex Communications, Inc." }, + { 0x0563, "Immersion Corp." }, + { 0x0564, "Chinon Industries, Inc." }, + { 0x0565, "Peracom Networks, Inc." }, + { 0x0566, "Monterey International Corp." }, + { 0x0567, "Xyratex International, Ltd" }, + { 0x0568, "Quartz Ingenierie" }, + { 0x0569, "SegaSoft" }, + { 0x056a, "Wacom Co., Ltd" }, + { 0x056b, "Decicon, Inc." }, + { 0x056c, "eTEK Labs" }, + { 0x056d, "EIZO Corp." }, + { 0x056e, "Elecom Co., Ltd" }, + { 0x056f, "Korea Data Systems Co., Ltd" }, + { 0x0570, "Epson America" }, + { 0x0571, "Interex, Inc." }, + { 0x0572, "Conexant Systems (Rockwell), Inc." }, + { 0x0573, "Zoran Co. Personal Media Division (Nogatech)" }, + { 0x0574, "City University of Hong Kong" }, + { 0x0575, "Philips Creative Display Solutions" }, + { 0x0576, "BAFO/Quality Computer Accessories" }, + { 0x0577, "ELSA" }, + { 0x0578, "Intrinsix Corp." }, + { 0x0579, "GVC Corp." }, + { 0x057a, "Samsung Electronics America" }, + { 0x057b, "Y-E Data, Inc." }, + { 0x057c, "AVM GmbH" }, + { 0x057d, "Shark Multimedia, Inc." }, + { 0x057e, "Nintendo Co., Ltd" }, + { 0x057f, "QuickShot, Ltd" }, + { 0x0580, "Denron, Inc." }, + { 0x0581, "Racal Data Group" }, + { 0x0582, "Roland Corp." }, + { 0x0583, "Padix Co., Ltd (Rockfire)" }, + { 0x0584, "RATOC System, Inc." }, + { 0x0585, "FlashPoint Technology, Inc." }, + { 0x0586, "ZyXEL Communications Corp." }, + { 0x0587, "America Kotobuki Electronics Industries, Inc." }, + { 0x0588, "Sapien Design" }, + { 0x0589, "Victron" }, + { 0x058a, "Nohau Corp." }, + { 0x058b, "Infineon Technologies" }, + { 0x058c, "In Focus Systems" }, + { 0x058d, "Micrel Semiconductor" }, + { 0x058e, "Tripath Technology, Inc." }, + { 0x058f, "Alcor Micro Corp." }, + { 0x0590, "Omron Corp." }, + { 0x0591, "Questra Consulting" }, + { 0x0592, "Powerware Corp." }, + { 0x0593, "Incite" }, + { 0x0594, "Princeton Graphic Systems" }, + { 0x0595, "Zoran Microelectronics, Ltd" }, + { 0x0596, "MicroTouch Systems, Inc." }, + { 0x0597, "Trisignal Communications" }, + { 0x0598, "Niigata Canotec Co., Inc." }, + { 0x0599, "Brilliance Semiconductor, Inc." }, + { 0x059a, "Spectrum Signal Processing, Inc." }, + { 0x059b, "Iomega Corp." }, + { 0x059c, "A-Trend Technology Co., Ltd" }, + { 0x059d, "Advanced Input Devices" }, + { 0x059e, "Intelligent Instrumentation" }, + { 0x059f, "LaCie, Ltd" }, + { 0x05a0, "Vetronix Corp." }, + { 0x05a1, "USC Corp." }, + { 0x05a2, "Fuji Film Microdevices Co., Ltd" }, + { 0x05a3, "ARC International" }, + { 0x05a4, "Ortek Technology, Inc." }, + { 0x05a5, "Sampo Technology Corp." }, + { 0x05a6, "Cisco Systems, Inc." }, + { 0x05a7, "Bose Corp." }, + { 0x05a8, "Spacetec IMC Corp." }, + { 0x05a9, "OmniVision Technologies, Inc." }, + { 0x05aa, "Utilux South China, Ltd" }, + { 0x05ab, "In-System Design" }, + { 0x05ac, "Apple Computer, Inc." }, + { 0x05ad, "Y.C. Cable U.S.A., Inc." }, + { 0x05ae, "Synopsys, Inc." }, + { 0x05af, "Jing-Mold Enterprise Co., Ltd" }, + { 0x05b0, "Fountain Technologies, Inc." }, + { 0x05b1, "First International Computer, Inc." }, + { 0x05b4, "LG Semicon Co., Ltd" }, + { 0x05b5, "Dialogic Corp." }, + { 0x05b6, "Proxima Corp." }, + { 0x05b7, "Medianix Semiconductor, Inc." }, + { 0x05b8, "Agiler, Inc." }, + { 0x05b9, "Philips Research Laboratories" }, + { 0x05ba, "DigitalPersona, Inc." }, + { 0x05bd, "RAFI GmbH & Co. KG" }, + { 0x05be, "Tyco Electronics (Raychem)" }, + { 0x05bf, "S & S Research" }, + { 0x05c0, "Keil Software" }, + { 0x05c1, "Kawasaki Microelectronics, Inc." }, + { 0x05c2, "Media Phonics (Suisse) S.A." }, + { 0x05c5, "Digi International, Inc." }, + { 0x05c6, "Qualcomm, Inc." }, + { 0x05c7, "Qtronix Corp." }, + { 0x05c8, "Cheng Uei Precision Industry Co., Ltd (Foxlink)" }, + { 0x05c9, "Semtech Corp." }, + { 0x05ca, "Ricoh Co., Ltd" }, + { 0x05cb, "PowerVision Technologies, Inc." }, + { 0x05cc, "ELSA AG" }, + { 0x05cd, "Silicom, Ltd" }, + { 0x05ce, "sci-worx GmbH" }, + { 0x05cf, "Sung Forn Co., Ltd" }, + { 0x05d0, "GE Medical Systems Lunar" }, + { 0x05d1, "Brainboxes, Ltd" }, + { 0x05d2, "Wave Systems Corp." }, + { 0x05d6, "Philips Semiconductors, CICT" }, + { 0x05d7, "Thomas & Betts Corp." }, + { 0x05d8, "Ultima Electronics Corp." }, + { 0x05d9, "Axiohm Transaction Solutions" }, + { 0x05da, "Microtek International, Inc." }, + { 0x05db, "Sun Corp. (Suntac?)" }, + { 0x05dc, "Lexar Media, Inc." }, + { 0x05dd, "Delta Electronics, Inc." }, + { 0x05e0, "Symbol Technologies" }, + { 0x05e1, "Syntek Semiconductor Co., Ltd" }, + { 0x05e3, "Genesys Logic, Inc." }, + { 0x05e5, "Fuji Electric Co., Ltd" }, + { 0x05e6, "Keithley Instruments" }, + { 0x05e7, "EIZO Nanao" }, + { 0x05e9, "Kawasaki LSI" }, + { 0x05eb, "FFC, Ltd" }, + { 0x05ef, "AVB, Inc. [anko?]" }, + { 0x05f0, "Canopus Co., Ltd" }, + { 0x05f2, "Dexin Corp., Ltd" }, + { 0x05f3, "PI Engineering, Inc." }, + { 0x05f5, "Unixtar Technology, Inc." }, + { 0x05f6, "AOC International" }, + { 0x05f7, "RFC Distribution(s) PTE, Ltd" }, + { 0x05f9, "PSC Scanning, Inc." }, + { 0x05fa, "Siemens Telecommunications Systems, Ltd" }, + { 0x05fc, "Harman Multimedia" }, + { 0x05fd, "InterAct, Inc." }, + { 0x05fe, "Chic Technology Corp." }, + { 0x05ff, "LeCroy Corp." }, + { 0x0600, "Barco Display Systems" }, + { 0x0601, "Jazz Hipster Corp." }, + { 0x0602, "Vista Imaging, Inc." }, + { 0x0603, "Novatek Microelectronics Corp." }, + { 0x0604, "Jean Co., Ltd" }, + { 0x0606, "Royal Information Electronics Co., Ltd" }, + { 0x0607, "Bridge Information Co., Ltd" }, + { 0x0609, "SMK Manufacturing, Inc." }, + { 0x060a, "Worthington Data Solutions, Inc." }, + { 0x060b, "Solid Year (?)" }, + { 0x060c, "EEH Datalink GmbH" }, + { 0x060f, "Joinsoon Electronics Mfg. Co., Ltd" }, + { 0x0611, "Totoku Electric Co., Ltd" }, + { 0x0613, "TransAct Technologies, Inc." }, + { 0x0614, "Bio-Rad Laboratories" }, + { 0x0616, "Future Techno Designs PVT, Ltd" }, + { 0x0618, "MacAlly" }, + { 0x0619, "Seiko Instruments, Inc." }, + { 0x061c, "Act Labs, Ltd" }, + { 0x061d, "Quatech, Inc." }, + { 0x061e, "Nissei Electric Co." }, + { 0x0620, "Alaris, Inc." }, + { 0x0621, "ODU-Steckverbindungssysteme GmbH & Co. KG" }, + { 0x0623, "Littelfuse, Inc." }, + { 0x0624, "Apex, Inc." }, + { 0x0626, "Nippon Systems Development Co., Ltd" }, + { 0x0629, "Zida Technologies, Ltd" }, + { 0x062b, "Greatlink Electronics Taiwan, Ltd" }, + { 0x062d, "Taiwan Tai-Hao Enterprises Co., Ltd" }, + { 0x062e, "Mainsuper Enterprises Co., Ltd" }, + { 0x062f, "Sin Sheng Terminal & Machine, Inc." }, + { 0x0634, "Micron Technology, Inc." }, + { 0x0636, "Sierra Imaging, Inc." }, + { 0x0638, "Avision, Inc." }, + { 0x063d, "Fong Kai Industrial Co., Ltd" }, + { 0x063f, "New Technology Cable, Ltd" }, + { 0x0640, "Hitex Development Tools" }, + { 0x0641, "Woods Industries, Inc." }, + { 0x0642, "VIA Medical Corp." }, + { 0x0644, "TEAC Corp." }, + { 0x0645, "Who? Vision Systems, Inc." }, + { 0x0646, "UMAX" }, + { 0x0647, "Acton Research Corp." }, + { 0x0648, "Inside Out Networks" }, + { 0x064b, "White Mountain DSP, Inc." }, + { 0x064c, "Ji-Haw Industrial Co., Ltd" }, + { 0x064e, "Suyin Corp." }, + { 0x064f, "WIBU-Systems AG" }, + { 0x0651, "Likom Technology Sdn. Bhd." }, + { 0x0652, "Stargate Solutions, Inc." }, + { 0x0654, "Granite Microsystems, Inc." }, + { 0x0655, "Space Shuttle Hi-Tech Co., Ltd" }, + { 0x0656, "Glory Mark Electronic, Ltd" }, + { 0x0657, "Tekcon Electronics Corp." }, + { 0x065a, "Optoelectronics Co., Ltd" }, + { 0x065e, "Silicon Graphics" }, + { 0x065f, "Good Way Technology Co., Ltd & GWC technology Inc." }, + { 0x0660, "TSAY-E (BVI) International, Inc." }, + { 0x0661, "Hamamatsu Photonics K.K." }, + { 0x0663, "Topmax Electronic Co., Ltd" }, + { 0x0667, "Aiwa Co., Ltd" }, + { 0x0668, "WordWand" }, + { 0x0669, "Oce' Printing Systems GmbH" }, + { 0x066a, "Total Technologies, Ltd" }, + { 0x066b, "Linksys, Inc." }, + { 0x066d, "Entrega, Inc." }, + { 0x066e, "Acer Semiconductor America, Inc." }, + { 0x066f, "SigmaTel, Inc." }, + { 0x0672, "Labtec, Inc." }, + { 0x0673, "HCL" }, + { 0x0674, "Key Mouse Electronic Enterprise Co., Ltd" }, + { 0x0675, "Draytech" }, + { 0x0676, "Teles AG" }, + { 0x0677, "Aiwa Co., Ltd" }, + { 0x0678, "ACard Technology Corp." }, + { 0x067b, "Prolific Technology, Inc." }, + { 0x067c, "Efficient Networks, Inc." }, + { 0x067d, "Hohner Corp." }, + { 0x067e, "Intermec" }, + { 0x067f, "Virata, Ltd" }, + { 0x0680, "Realtek Semiconductor Corp., CPP Div. (Avance Logic)" }, + { 0x0681, "Siemens Information and Communication Products" }, + { 0x0684, "Actiontec Electronics, Inc." }, + { 0x0686, "Minolta Co., Ltd" }, + { 0x068a, "Pertech, Inc." }, + { 0x068e, "CH Products, Inc." }, + { 0x0690, "Golden Bridge Electech, Inc." }, + { 0x0693, "Hagiwara Sys-Com Co., Ltd" }, + { 0x0694, "Lego Group" }, + { 0x0698, "Chuntex (CTX)" }, + { 0x0699, "Tektronix, Inc." }, + { 0x069a, "Askey Computer Corp." }, + { 0x069b, "Thomson, Inc." }, + { 0x069d, "Hughes Network Systems (HNS)" }, + { 0x069e, "Marx" }, + { 0x069f, "Allied Data Technologies BV" }, + { 0x06a2, "Topro Technology, Inc." }, + { 0x06a3, "Saitek PLC" }, + { 0x06a4, "Xiamen Doowell Electron Co., Ltd" }, + { 0x06a5, "Divio" }, + { 0x06a8, "Topaz Systems, Inc." }, + { 0x06a9, "Westell" }, + { 0x06aa, "Sysgration, Ltd" }, + { 0x06ac, "Fujitsu Laboratories of America, Inc." }, + { 0x06ad, "Greatland Electronics Taiwan, Ltd" }, + { 0x06ae, "Professional Multimedia Testing Centre" }, + { 0x06b8, "Pixela Corp." }, + { 0x06b9, "Alcatel Telecom" }, + { 0x06ba, "Smooth Cord & Connector Co., Ltd" }, + { 0x06bb, "EDA, Inc." }, + { 0x06bc, "Oki Data Corp." }, + { 0x06bd, "AGFA-Gevaert NV" }, + { 0x06be, "AME Optimedia Technology Co., Ltd" }, + { 0x06bf, "Leoco Corp." }, + { 0x06c2, "GLAB Chester" }, + { 0x06c4, "Bizlink International Corp." }, + { 0x06c5, "Hagenuk, GmbH" }, + { 0x06c6, "Infowave Software, Inc." }, + { 0x06c8, "SIIG, Inc." }, + { 0x06c9, "Taxan (Europe), Ltd" }, + { 0x06ca, "Newer Technology, Inc." }, + { 0x06cb, "Synaptics, Inc." }, + { 0x06cc, "Terayon Communication Systems" }, + { 0x06cd, "Keyspan" }, + { 0x06cf, "SpheronVR AG" }, + { 0x06d0, "LapLink, Inc." }, + { 0x06d1, "Daewoo Electronics Co., Ltd" }, + { 0x06d3, "Mitsubishi Electric Corp." }, + { 0x06d5, "Toshiba" }, + { 0x06d6, "Aashima Technology B.V." }, + { 0x06d7, "Network Computing Devices (NCD)" }, + { 0x06d8, "Technical Marketing Research, Inc." }, + { 0x06da, "Phoenixtec Power Co., Ltd" }, + { 0x06db, "Paradyne" }, + { 0x06dc, "Foxlink Image Technology Co., Ltd" }, + { 0x06de, "Heisei Electronics Co., Ltd" }, + { 0x06e0, "Multi-Tech Systems, Inc." }, + { 0x06e1, "ADS Technologies, Inc." }, + { 0x06e4, "Alcatel Microelectronics" }, + { 0x06e6, "Tiger Jet Network, Inc." }, + { 0x06ea, "Sirius Technologies" }, + { 0x06ef, "I.A.C. Geometrische Ingenieurs B.V." }, + { 0x06f0, "T.N.C Industrial Co., Ltd" }, + { 0x06f1, "Opcode Systems, Inc." }, + { 0x06f2, "Emine Technology Co." }, + { 0x06f6, "Wintrend Technology Co., Ltd" }, + { 0x06fa, "HSD S.r.L" }, + { 0x06fd, "Boston Acoustics" }, + { 0x06fe, "Gallant Computer, Inc." }, + { 0x0701, "Supercomal Wire & Cable SDN. BHD." }, + { 0x0703, "Bvtech Industry, Inc." }, + { 0x0705, "NKK Corp." }, + { 0x0707, "Standard Microsystems Corp." }, + { 0x0708, "Putercom Co., Ltd" }, + { 0x0709, "Silicon Systems, Ltd (SSL)" }, + { 0x070a, "Oki Electric Industry Co., Ltd" }, + { 0x070d, "Comoss Electronic Co., Ltd" }, + { 0x070e, "Excel Cell Electronic Co., Ltd" }, + { 0x0710, "Connect Tech, Inc." }, + { 0x0711, "Magic Control Technology Corp." }, + { 0x0714, "NewMotion, Inc." }, + { 0x0718, "Imation Corp." }, + { 0x0719, "Tremon Enterprises Co., Ltd" }, + { 0x071b, "Domain Technologies, Inc." }, + { 0x071c, "Xionics Document Technologies, Inc." }, + { 0x071d, "Eicon Networks Corp." }, + { 0x0723, "Centillium Communications Corp." }, + { 0x0726, "Vanguard International Semiconductor-America" }, + { 0x0729, "Amitm" }, + { 0x072e, "Sunix Co., Ltd" }, + { 0x072f, "Advanced Card Systems, Ltd" }, + { 0x0731, "Susteen, Inc." }, + { 0x0732, "Goldfull Electronics & Telecommunications Corp." }, + { 0x0733, "ViewQuest Technologies, Inc." }, + { 0x0734, "Lasat Communications A/S" }, + { 0x0735, "Asuscom Network" }, + { 0x0736, "Lorom Industrial Co., Ltd" }, + { 0x0738, "Mad Catz, Inc." }, + { 0x073b, "Suncom Technologies" }, + { 0x073d, "Eutron S.p.a." }, + { 0x073e, "NEC, Inc." }, + { 0x0745, "Syntech Information Co., Ltd" }, + { 0x0746, "Onkyo Corp." }, + { 0x0747, "Labway Corp." }, + { 0x0748, "Strong Man Enterprise Co., Ltd" }, + { 0x0749, "EVer Electronics Corp." }, + { 0x074a, "Ming Fortune Industry Co., Ltd" }, + { 0x074b, "Polestar Tech. Corp." }, + { 0x074c, "C-C-C Group PLC" }, + { 0x074d, "Micronas GmbH" }, + { 0x074e, "Digital Stream Corp." }, + { 0x0755, "Aureal Semiconductor" }, + { 0x0757, "Network Technologies, Inc." }, + { 0x0763, "Midiman" }, + { 0x0764, "Cyber Power System, Inc." }, + { 0x0765, "X-Rite, Inc." }, + { 0x0766, "Jess-Link Products Co., Ltd" }, + { 0x0768, "Camtel Technology Corp." }, + { 0x0769, "Surecom Technology Corp." }, + { 0x076a, "Smart Technology Enablers, Inc." }, + { 0x076b, "OmniKey AG" }, + { 0x076c, "Partner Tech" }, + { 0x076d, "Denso Corp." }, + { 0x076e, "Kuan Tech Enterprise Co., Ltd" }, + { 0x076f, "Jhen Vei Electronic Co., Ltd" }, + { 0x0774, "AmTRAN Technology Co., Ltd" }, + { 0x0775, "Longshine Electronics Corp." }, + { 0x0776, "Inalways Corp." }, + { 0x0777, "Comda Enterprise Corp." }, + { 0x0779, "Fairchild Semiconductor" }, + { 0x077a, "Sankyo Seiki Mfg. Co., Ltd" }, + { 0x077b, "Linksys" }, + { 0x077c, "Forward Electronics Co., Ltd" }, + { 0x077d, "Griffin Technology" }, + { 0x077f, "Well Excellent & Most Corp." }, + { 0x0781, "SanDisk Corp." }, + { 0x0782, "Trackerball" }, + { 0x0784, "Vivitar, Inc." }, + { 0x0785, "NTT-ME" }, + { 0x0789, "Logitec Corp." }, + { 0x078b, "Happ Controls, Inc." }, + { 0x078e, "Brincom, Inc." }, + { 0x0790, "Pro-Image Manufacturing Co., Ltd" }, + { 0x0791, "Copartner Wire and Cable Mfg. Corp." }, + { 0x0792, "Axis Communications AB" }, + { 0x0793, "Wha Yu Industrial Co., Ltd" }, + { 0x0794, "ABL Electronics Corp." }, + { 0x0795, "RealChip, Inc." }, + { 0x0796, "Certicom Corp." }, + { 0x0797, "Grandtech Semiconductor Corp." }, + { 0x079b, "Sagem" }, + { 0x079d, "Alfadata Computer Corp." }, + { 0x07a1, "Digicom S.p.A." }, + { 0x07a2, "National Technical Systems" }, + { 0x07a3, "Onnto Corp." }, + { 0x07a4, "Be, Inc." }, + { 0x07a6, "ADMtek, Inc." }, + { 0x07aa, "Corega K.K." }, + { 0x07ab, "Freecom Technologies" }, + { 0x07af, "Microtech" }, + { 0x07b0, "Trust Technologies" }, + { 0x07b1, "IMP, Inc." }, + { 0x07b2, "Motorola BCS, Inc." }, + { 0x07b3, "Plustek, Inc." }, + { 0x07b4, "Olympus Optical Co., Ltd" }, + { 0x07b5, "Mega World International, Ltd" }, + { 0x07b6, "Marubun Corp." }, + { 0x07b7, "TIME Interconnect, Ltd" }, + { 0x07b8, "D-Link Corp." }, + { 0x07bc, "Canon Computer Systems, Inc." }, + { 0x07bd, "Webgear, Inc." }, + { 0x07be, "Veridicom" }, + { 0x07c0, "Code Mercenaries Hard- und Software GmbH" }, + { 0x07c1, "Keisokugiken" }, + { 0x07c4, "Datafab Systems, Inc." }, + { 0x07c5, "APG Cash Drawer" }, + { 0x07c6, "ShareWave, Inc." }, + { 0x07c7, "Powertech Industrial Co., Ltd" }, + { 0x07c8, "B.U.G., Inc." }, + { 0x07c9, "Allied Telesyn International" }, + { 0x07ca, "AVerMedia Technologies, Inc." }, + { 0x07cb, "Kingmax Technology, Inc." }, + { 0x07cc, "Carry Computer Eng., Co., Ltd" }, + { 0x07cd, "Elektor" }, + { 0x07cf, "Casio Computer Co., Ltd" }, + { 0x07d0, "Dazzle" }, + { 0x07d1, "D-Link System" }, + { 0x07d2, "Aptio Products, Inc." }, + { 0x07d3, "Cyberdata Corp." }, + { 0x07d7, "GCC Technologies, Inc." }, + { 0x07da, "Arasan Chip Systems" }, + { 0x07df, "David Electronics Co., Ltd" }, + { 0x07e1, "Ambient Technologies, Inc." }, + { 0x07e2, "Elmeg GmbH & Co., Ltd" }, + { 0x07e3, "Planex Communications, Inc." }, + { 0x07e4, "Movado Enterprise Co., Ltd" }, + { 0x07e5, "QPS, Inc." }, + { 0x07e6, "Allied Cable Corp." }, + { 0x07e7, "Mirvo Toys, Inc." }, + { 0x07e8, "Labsystems" }, + { 0x07ea, "Iwatsu Electric Co., Ltd" }, + { 0x07eb, "Double-H Technology Co., Ltd" }, + { 0x07ec, "Taiyo Electric Wire & Cable Co., Ltd" }, + { 0x07ef, "STSN" }, + { 0x07f6, "Circuit Assembly Corp." }, + { 0x07f7, "Century Corp." }, + { 0x07f9, "Dotop Technology, Inc." }, + { 0x07fa, "Draytek" }, + { 0x07fc, "Siemens Business Services" }, + { 0x07fd, "Mark of the Unicorn" }, + { 0x0801, "Mag-Tek" }, + { 0x0802, "Mako Technologies, LLC" }, + { 0x0803, "Zoom Telephonics, Inc." }, + { 0x0809, "Genicom Technology, Inc." }, + { 0x080a, "Evermuch Technology Co., Ltd" }, + { 0x080d, "Teco Image Systems Co., Ltd" }, + { 0x0810, "Personal Communication Systems, Inc." }, + { 0x0813, "Mattel, Inc." }, + { 0x081a, "MG Logic" }, + { 0x081b, "Indigita Corp." }, + { 0x081c, "Mipsys" }, + { 0x081e, "AlphaSmart, Inc." }, + { 0x0822, "Reudo Corp." }, + { 0x0825, "GC Protronics" }, + { 0x0826, "Data Transit" }, + { 0x0827, "BroadLogic, Inc." }, + { 0x0828, "Sato Corp." }, + { 0x0829, "DirecTV Broadband, Inc. (Telocity)" }, + { 0x082d, "Handspring" }, + { 0x0830, "Palm, Inc." }, + { 0x0832, "Kouwell Electronics Corp." }, + { 0x0833, "Sourcenext Corp." }, + { 0x0835, "Action Star Enterprise Co., Ltd" }, + { 0x0839, "Samsung Techwin Co., Ltd" }, + { 0x083a, "Accton Technology Corp." }, + { 0x083f, "Global Village" }, + { 0x0840, "Argosy Research, Inc." }, + { 0x0841, "Rioport.com, Inc." }, + { 0x0844, "Welland Industrial Co., Ltd" }, + { 0x0846, "NetGear, Inc." }, + { 0x084d, "Minton Optic Industry Co., Inc." }, + { 0x084e, "KB Gear" }, + { 0x084f, "Empeg" }, + { 0x0850, "Fast Point Technologies, Inc." }, + { 0x0851, "Macronix International Co., Ltd" }, + { 0x0852, "CSEM" }, + { 0x0854, "ActiveWire, Inc." }, + { 0x0858, "Hitachi Maxell, Ltd" }, + { 0x0859, "Minolta Systems Laboratory, Inc." }, + { 0x085a, "Xircom" }, + { 0x0862, "Teletrol Systems, Inc." }, + { 0x0863, "Filanet Corp." }, + { 0x0864, "NetGear, Inc." }, + { 0x086a, "Emagic Soft-und Hardware GmbH" }, + { 0x086c, "DeTeWe - Deutsche Telephonwerke AG & Co." }, + { 0x086e, "System TALKS, Inc." }, + { 0x086f, "MEC IMEX, Inc." }, + { 0x0870, "Metricom" }, + { 0x0871, "SanDisk, Inc." }, + { 0x0873, "Xpeed, Inc." }, + { 0x0874, "A-Tec Subsystem, Inc." }, + { 0x0879, "Comtrol Corp." }, + { 0x087c, "Adesso/Kbtek America, Inc." }, + { 0x087d, "Jaton Corp." }, + { 0x087e, "Fujitsu Computer Products of America" }, + { 0x087f, "Virtual IP Group, Inc." }, + { 0x0880, "APT Technologies, Inc." }, + { 0x0883, "Recording Industry Association of America (RIAA)" }, + { 0x0885, "Boca Research, Inc." }, + { 0x0886, "XAC Automation Corp." }, + { 0x0887, "Hannstar Electronics Corp." }, + { 0x088b, "MassWorks, Inc." }, + { 0x0892, "DioGraphy, Inc." }, + { 0x089c, "United Technologies Research Cntr." }, + { 0x089d, "Icron Technologies Corp." }, + { 0x089e, "NST Co., Ltd" }, + { 0x089f, "Primex Aerospace Co." }, + { 0x08a5, "e9, Inc." }, + { 0x08a8, "Andrea Electronics" }, + { 0x08ae, "Macally (Mace Group, Inc.)" }, + { 0x08b4, "Sorenson Vision, Inc." }, + { 0x08b8, "J. Gordon Electronic Design, Inc." }, + { 0x08b9, "RadioShack Corp. (Tandy)" }, + { 0x08bb, "Texas Instruments Japan" }, + { 0x08bd, "Citizen Watch Co., Ltd" }, + { 0x08c3, "Precise Biometrics" }, + { 0x08c4, "Proxim, Inc." }, + { 0x08c7, "Key Nice Enterprise Co., Ltd" }, + { 0x08c8, "2Wire, Inc." }, + { 0x08c9, "Nippon Telegraph and Telephone Corp." }, + { 0x08ca, "Aiptek International, Inc." }, + { 0x08cd, "Jue Hsun Ind. Corp." }, + { 0x08ce, "Long Well Electronics Corp." }, + { 0x08cf, "Productivity Enhancement Products" }, + { 0x08d1, "smartBridges, Inc." }, + { 0x08d3, "Virtual Ink" }, + { 0x08d4, "Fujitsu Siemens Computers" }, + { 0x08d9, "Increment P Corp." }, + { 0x08dd, "Billionton Systems, Inc." }, + { 0x08de, "???" }, + { 0x08df, "Spyrus, Inc." }, + { 0x08e3, "Olitec, Inc." }, + { 0x08e4, "Pioneer Corp." }, + { 0x08e5, "Litronic" }, + { 0x08e6, "Gemplus" }, + { 0x08e7, "Pan-International Wire & Cable" }, + { 0x08e8, "Integrated Memory Logic" }, + { 0x08e9, "Extended Systems, Inc." }, + { 0x08ea, "Ericsson, Inc., Blue Ridge Labs" }, + { 0x08ec, "M-Systems Flash Disk Pioneers" }, + { 0x08ee, "CCSI/Hesso" }, + { 0x08f0, "Corex Technologies" }, + { 0x08f1, "CTI Electronics Corp." }, + { 0x08f5, "SysTec Co., Ltd" }, + { 0x08f6, "Logic 3 International, Ltd" }, + { 0x08f8, "Keen Top International Enterprise Co., Ltd" }, + { 0x08f9, "Wipro Technologies" }, + { 0x08fa, "Caere" }, + { 0x08fb, "Socket Communications" }, + { 0x08fc, "Sicon Cable Technology Co., Ltd" }, + { 0x08fd, "Digianswer A/S" }, + { 0x08ff, "AuthenTec, Inc." }, + { 0x0900, "Pinnacle Systems, Inc." }, + { 0x0901, "VST Technologies" }, + { 0x0906, "Faraday Technology Corp." }, + { 0x0909, "Audio-Technica Corp." }, + { 0x090a, "Trumpion Microelectronics, Inc." }, + { 0x090b, "Neurosmith" }, + { 0x090c, "Feiya Technology Corp." }, + { 0x090d, "Multiport Computer Vertriebs GmbH" }, + { 0x090e, "Shining Technology, Inc." }, + { 0x090f, "Fujitsu Devices, Inc." }, + { 0x0910, "Alation Systems, Inc." }, + { 0x0911, "Philips Speech Processing" }, + { 0x0912, "Voquette, Inc." }, + { 0x0913, "Asante' Technologies, Inc." }, + { 0x0915, "GlobeSpan, Inc." }, + { 0x0917, "SmartDisk Corp." }, + { 0x0919, "Tiger Electronics" }, + { 0x091e, "Garmin International" }, + { 0x0920, "Echelon Co." }, + { 0x0921, "GoHubs, Inc." }, + { 0x0922, "Dymo-CoStar Corp." }, + { 0x0923, "IC Media Corp." }, + { 0x0924, "Xerox" }, + { 0x0925, "Wisegroup, Ltd" }, + { 0x0927, "Summus, Ltd" }, + { 0x0928, "Oxford Semiconductor, Ltd" }, + { 0x0929, "American Biometric Co." }, + { 0x092a, "Toshiba Information & Industrial Sys. And Services" }, + { 0x092b, "Sena Technologies, Inc." }, + { 0x0930, "Toshiba Corp." }, + { 0x0931, "Harmonic Data Systems, Ltd" }, + { 0x0932, "Crescentec Corp." }, + { 0x0933, "Quantum Corp." }, + { 0x0934, "Netcom Systems" }, + { 0x0939, "Lumberg, Inc." }, + { 0x093a, "Pixart Imaging, Inc." }, + { 0x093b, "Plextor Corp." }, + { 0x093d, "InnoSync, Inc." }, + { 0x093e, "J.S.T. Mfg. Co., Ltd" }, + { 0x093f, "Olympia Telecom Vertriebs GmbH" }, + { 0x0940, "Japan Storage Battery Co., Ltd" }, + { 0x0941, "Photobit Corp." }, + { 0x0942, "i2Go.com, LLC" }, + { 0x0943, "HCL Technologies India Private, Ltd" }, + { 0x0944, "KORG, Inc." }, + { 0x0945, "Pasco Scientific" }, + { 0x0948, "Kronauer music in digital" }, + { 0x094b, "Linkup Systems Corp." }, + { 0x094d, "Cable Television Laboratories" }, + { 0x094f, "Yano" }, + { 0x0951, "Kingston Technology" }, + { 0x0954, "RPM Systems Corp." }, + { 0x0955, "NVidia Corp." }, + { 0x0956, "BSquare Corp." }, + { 0x0957, "Agilent Technologies, Inc." }, + { 0x0958, "CompuLink Research, Inc." }, + { 0x0959, "Cologne Chip AG" }, + { 0x095a, "Portsmith" }, + { 0x095b, "Medialogic Corp." }, + { 0x095c, "K-Tec Electronics" }, + { 0x095d, "Polycom, Inc." }, + { 0x0967, "Acer (?)" }, + { 0x0968, "Catalyst Enterprises, Inc." }, + { 0x0971, "Gretag-Macbeth AG" }, + { 0x0973, "Schlumberger" }, + { 0x0974, "Datagraphix, a business unit of Anacomp" }, + { 0x0975, "OL'E Communications, Inc." }, + { 0x0976, "Adirondack Wire & Cable" }, + { 0x0977, "Lightsurf Technologies" }, + { 0x0978, "Beckhoff GmbH" }, + { 0x0979, "Jeilin Technology Corp., Ltd" }, + { 0x097a, "Minds At Work LLC" }, + { 0x097b, "Knudsen Engineering, Ltd" }, + { 0x097c, "Marunix Co., Ltd" }, + { 0x097d, "Rosun Technologies, Inc." }, + { 0x097f, "Barun Electronics Co., Ltd" }, + { 0x0981, "Oak Technology, Ltd" }, + { 0x0984, "Apricorn" }, + { 0x0985, "cab Produkttechnik GmbH & Co KG" }, + { 0x098c, "Vitana Corp." }, + { 0x098d, "INDesign" }, + { 0x098e, "Integrated Intellectual Property, Inc." }, + { 0x098f, "Kenwood TMI Corp." }, + { 0x0993, "Gemstar eBook Group, Ltd" }, + { 0x0996, "Integrated Telecom Express, Inc." }, + { 0x09a3, "PairGain Technologies" }, + { 0x09a4, "Contech Research, Inc." }, + { 0x09a5, "VCON Telecommunications" }, + { 0x09a6, "Poinchips" }, + { 0x09a7, "Data Transmission Network Corp." }, + { 0x09a8, "Lin Shiung Enterprise Co., Ltd" }, + { 0x09a9, "Smart Card Technologies Co., Ltd" }, + { 0x09aa, "Intersil Corp." }, + { 0x09ae, "Tripp Lite" }, + { 0x09b2, "Franklin Electronic Publishers, Inc." }, + { 0x09b3, "Altius Solutions, Inc." }, + { 0x09b4, "MDS Telephone Systems" }, + { 0x09b5, "Celltrix Technology Co., Ltd" }, + { 0x09bc, "Grundig" }, + { 0x09be, "MySmart.Com" }, + { 0x09bf, "Auerswald GmbH & Co. KG" }, + { 0x09c1, "Arris Interactive LLC" }, + { 0x09c2, "Nisca Corp." }, + { 0x09c3, "ActivCard, Inc." }, + { 0x09c4, "ACTiSYS Corp." }, + { 0x09c5, "Memory Corp." }, + { 0x09cc, "Workbit Corp." }, + { 0x09cd, "Psion Dacom Home Networks, Ltd" }, + { 0x09ce, "City Electronics, Ltd" }, + { 0x09cf, "Electronics Testing Center, Taiwan" }, + { 0x09d1, "NeoMagic, Inc." }, + { 0x09d2, "Vreelin Engineering, Inc." }, + { 0x09d3, "Com One" }, + { 0x09d9, "KRF Tech, Ltd" }, + { 0x09da, "A4 Tech Co., Ltd" }, + { 0x09db, "Measurement Computing Corp." }, + { 0x09dc, "Aimex Corp." }, + { 0x09dd, "Fellowes, Inc." }, + { 0x09df, "Addonics Technologies Corp." }, + { 0x09e1, "Intellon Corp." }, + { 0x09e5, "Jo-Dan International, Inc." }, + { 0x09e6, "Silutia, Inc." }, + { 0x09e7, "Real 3D, Inc." }, + { 0x09e8, "AKAI Professional M.I. Corp." }, + { 0x09e9, "Chen-Source, Inc." }, + { 0x09eb, "IM Networks, Inc." }, + { 0x09ef, "Xitel" }, + { 0x09f5, "AresCom" }, + { 0x09f6, "RocketChips, Inc." }, + { 0x09f7, "Edu-Science (H.K.), Ltd" }, + { 0x09f8, "SoftConnex Technologies, Inc." }, + { 0x09f9, "Bay Associates" }, + { 0x09fa, "Mtek Vision" }, + { 0x09fb, "Altera" }, + { 0x09ff, "Gain Technology Corp." }, + { 0x0a00, "Liquid Audio" }, + { 0x0a01, "ViA, Inc." }, + { 0x0a07, "Ontrak Control Systems Inc." }, + { 0x0a0b, "Cybex Computer Products Co." }, + { 0x0a11, "Xentec, Inc." }, + { 0x0a12, "Cambridge Silicon Radio, Ltd" }, + { 0x0a13, "Telebyte, Inc." }, + { 0x0a14, "Spacelabs Medical, Inc." }, + { 0x0a15, "Scalar Corp." }, + { 0x0a16, "Trek Technology (S) PTE, Ltd" }, + { 0x0a17, "Pentax Corp." }, + { 0x0a18, "Heidelberger Druckmaschinen AG" }, + { 0x0a19, "Hua Geng Technologies, Inc." }, + { 0x0a21, "Medtronic Physio Control Corp." }, + { 0x0a22, "Century Semiconductor USA, Inc." }, + { 0x0a2c, "AK-Modul-Bus Computer GmbH" }, + { 0x0a39, "Gilat Satellite Networks, Ltd" }, + { 0x0a3a, "PentaMedia Co., Ltd" }, + { 0x0a3c, "NTT DoCoMo, Inc." }, + { 0x0a3d, "Varo Vision" }, + { 0x0a43, "Boca Systems, Inc." }, + { 0x0a46, "Davicom Semiconductor, Inc." }, + { 0x0a47, "Hirose Electric" }, + { 0x0a48, "I/O Interconnect" }, + { 0x0a4b, "Fujitsu Media Devices, Ltd" }, + { 0x0a4c, "Computex Co., Ltd" }, + { 0x0a4d, "Evolution Electronics, Ltd" }, + { 0x0a4e, "Steinberg Soft-und Hardware GmbH" }, + { 0x0a4f, "Litton Systems, Inc." }, + { 0x0a50, "Mimaki Engineering Co., Ltd" }, + { 0x0a51, "Sony Electronics, Inc." }, + { 0x0a52, "Jebsee Electronics Co., Ltd" }, + { 0x0a53, "Portable Peripheral Co., Ltd" }, + { 0x0a5a, "Electronics For Imaging, Inc." }, + { 0x0a5b, "EAsics NV" }, + { 0x0a5c, "Broadcom Corp." }, + { 0x0a5d, "Diatrend Corp." }, + { 0x0a5f, "Zebra" }, + { 0x0a62, "MPMan" }, + { 0x0a66, "ClearCube Technology" }, + { 0x0a67, "Medeli Electronics Co., Ltd" }, + { 0x0a68, "Comaide Corp." }, + { 0x0a69, "Chroma ate, Inc." }, + { 0x0a6b, "Green House Co., Ltd" }, + { 0x0a6c, "Integrated Circuit Systems, Inc." }, + { 0x0a6d, "UPS Manufacturing" }, + { 0x0a6e, "Benwin" }, + { 0x0a6f, "Core Technology, Inc." }, + { 0x0a70, "International Game Technology" }, + { 0x0a72, "Sanwa Denshi" }, + { 0x0a79, "Geocast Network Systems" }, + { 0x0a7d, "NSTL, Inc." }, + { 0x0a7e, "Octagon Systems Corp." }, + { 0x0a80, "Rexon Technology Corp., Ltd" }, + { 0x0a81, "Chesen Electronics Corp." }, + { 0x0a82, "Syscan" }, + { 0x0a83, "NextComm, Inc." }, + { 0x0a84, "Maui Innovative Peripherals" }, + { 0x0a85, "Idexx Labs" }, + { 0x0a86, "NITGen Co., Ltd" }, + { 0x0a8d, "Picturetel" }, + { 0x0a8e, "Japan Aviation Electronics Industry, Ltd" }, + { 0x0a90, "Candy Technology Co., Ltd" }, + { 0x0a91, "Globlink Technology, Inc." }, + { 0x0a92, "EGO SYStems, Inc." }, + { 0x0a93, "C Technologies AB" }, + { 0x0a94, "Intersense" }, + { 0x0aa3, "Lava Computer Mfg., Inc." }, + { 0x0aa4, "Develco Elektronik" }, + { 0x0aa5, "First International Digital" }, + { 0x0aa6, "Perception Digital, Ltd" }, + { 0x0aa7, "Wincor Nixdorf GmbH & Co KG" }, + { 0x0aa8, "TriGem Computer, Inc." }, + { 0x0aa9, "Baromtec Co." }, + { 0x0aaa, "Japan CBM Corp." }, + { 0x0aab, "Vision Shape Europe SA" }, + { 0x0aac, "iCompression, Inc." }, + { 0x0aad, "Rohde & Schwarz GmbH & Co. KG" }, + { 0x0aae, "NEC infrontia Corp. (Nitsuko)" }, + { 0x0aaf, "Digitalway Co., Ltd" }, + { 0x0ab0, "Arrow Strong Electronics Co., Ltd" }, + { 0x0aba, "Ellisys" }, + { 0x0abe, "Stereo-Link" }, + { 0x0ac3, "Sanyo Semiconductor Company Micro" }, + { 0x0ac4, "Leco Corp." }, + { 0x0ac5, "I & C Corp." }, + { 0x0ac6, "Singing Electrons, Inc." }, + { 0x0ac7, "Panwest Corp." }, + { 0x0ac8, "Z-Star Microelectronics Corp." }, + { 0x0ac9, "Micro Solutions, Inc." }, + { 0x0acc, "Koga Electronics Co." }, + { 0x0acd, "ID Tech" }, + { 0x0acf, "Intoto, Inc." }, + { 0x0ad0, "Intellix Corp." }, + { 0x0ad1, "Remotec Technology, Ltd" }, + { 0x0ad2, "Service & Quality Technology Co., Ltd" }, + { 0x0ae3, "Allion Computer, Inc." }, + { 0x0ae4, "Taito Corp." }, + { 0x0ae7, "Neodym Systems, Inc." }, + { 0x0ae8, "System Support Co., Ltd" }, + { 0x0ae9, "North Shore Circuit Design L.L.P." }, + { 0x0aea, "SciEssence, LLC" }, + { 0x0aeb, "TTP Communications, Ltd" }, + { 0x0aec, "Neodio Technologies Corp." }, + { 0x0af0, "Option" }, + { 0x0af6, "Silver I Co., Ltd" }, + { 0x0af7, "B2C2, Inc." }, + { 0x0af9, "Hama, Inc." }, + { 0x0afc, "Zaptronix Ltd" }, + { 0x0afd, "Tateno Dennou, Inc." }, + { 0x0afe, "Cummins Engine Co." }, + { 0x0aff, "Jump Zone Network Products, Inc." }, + { 0x0b05, "ASUSTek Computer, Inc." }, + { 0x0b0c, "Todos Data System" }, + { 0x0b0e, "GN Netcom" }, + { 0x0b0f, "AVID Technology" }, + { 0x0b10, "Pcally" }, + { 0x0b11, "I Tech Solutions Co., Ltd" }, + { 0x0b1e, "Electronic Warfare Assoc., Inc. (EWA)" }, + { 0x0b1f, "Insyde Software Corp." }, + { 0x0b20, "TransDimension, Inc." }, + { 0x0b21, "Yokogawa Electric Corp." }, + { 0x0b22, "Japan System Development Co., Ltd" }, + { 0x0b23, "Pan-Asia Electronics Co., Ltd" }, + { 0x0b24, "Link Evolution Corp." }, + { 0x0b27, "Ritek Corp." }, + { 0x0b28, "Kenwood Corp." }, + { 0x0b2c, "Village Center, Inc." }, + { 0x0b30, "PNY Technologies, Inc." }, + { 0x0b33, "Contour Design, Inc." }, + { 0x0b37, "Hitachi ULSI Systems Co., Ltd" }, + { 0x0b39, "Omnidirectional Control Technology, Inc." }, + { 0x0b3a, "IPaxess" }, + { 0x0b3b, "Tekram Technology Co., Ltd" }, + { 0x0b3c, "Olivetti Techcenter" }, + { 0x0b3e, "Kikusui Electronics Corp." }, + { 0x0b41, "Hal Corp." }, + { 0x0b43, "Play.com, Inc." }, + { 0x0b47, "Sportbug.com, Inc." }, + { 0x0b48, "TechnoTrend AG" }, + { 0x0b49, "ASCII Corp." }, + { 0x0b4b, "Pine Corp. Ltd." }, + { 0x0b4e, "Musical Electronics, Ltd" }, + { 0x0b50, "Dumpries Co., Ltd" }, + { 0x0b52, "Colorado MicroDisplay, Inc." }, + { 0x0b54, "Sinbon Electronics Co., Ltd" }, + { 0x0b56, "TYI Systems, Ltd" }, + { 0x0b57, "Beijing HanwangTechnology Co., Ltd" }, + { 0x0b59, "Lake Communications, Ltd" }, + { 0x0b5a, "Corel Corp." }, + { 0x0b5f, "Green Electronics Co., Ltd" }, + { 0x0b60, "Nsine, Ltd" }, + { 0x0b61, "NEC Viewtechnology, Ltd" }, + { 0x0b62, "Orange Micro, Inc." }, + { 0x0b63, "ADLink Technology, Inc." }, + { 0x0b64, "Wonderful Wire Cable Co., Ltd" }, + { 0x0b65, "Expert Magnetics Corp." }, + { 0x0b69, "CacheVision" }, + { 0x0b6a, "Maxim Integrated Products" }, + { 0x0b6f, "Nagano Japan Radio Co., Ltd" }, + { 0x0b70, "PortalPlayer, Inc." }, + { 0x0b71, "SHIN-EI Sangyo Co., Ltd" }, + { 0x0b72, "Embedded Wireless Technology Co., Ltd" }, + { 0x0b73, "Computone Corp." }, + { 0x0b75, "Roland DG Corp." }, + { 0x0b79, "Sunrise Telecom, Inc." }, + { 0x0b7a, "Zeevo, Inc." }, + { 0x0b7b, "Taiko Denki Co., Ltd" }, + { 0x0b7c, "ITRAN Communications, Ltd" }, + { 0x0b7d, "Astrodesign, Inc." }, + { 0x0b7e, "Kurusugawa Electronics, Inc." }, + { 0x0b84, "Rextron Technology, Inc." }, + { 0x0b85, "Elkat Electronics, Sdn., Bhd." }, + { 0x0b86, "Exputer Systems, Inc." }, + { 0x0b87, "Plus-One I & T, Inc." }, + { 0x0b88, "Sigma Koki Co., Ltd, Technology Center" }, + { 0x0b89, "Advanced Digital Broadcast, Ltd" }, + { 0x0b95, "ASIX Electronics Corp." }, + { 0x0b96, "Sewon Telecom" }, + { 0x0b97, "O2 Micro, Inc." }, + { 0x0b98, "Playmates Toys, Inc." }, + { 0x0b99, "Audio International, Inc." }, + { 0x0b9d, "Softprotec Co." }, + { 0x0b9f, "Chippo Technologies" }, + { 0x0baf, "U.S. Robotics" }, + { 0x0bb0, "Concord Camera Corp." }, + { 0x0bb1, "Infinilink Corp." }, + { 0x0bb2, "Ambit Microsystems Corp." }, + { 0x0bb3, "Ofuji Technology" }, + { 0x0bb4, "High Tech Computer Corp." }, + { 0x0bb5, "Murata Manufacturing Co., Ltd" }, + { 0x0bb6, "Network Alchemy" }, + { 0x0bb7, "Joytech Computer Co., Ltd" }, + { 0x0bb8, "Hitachi Semiconductor and Devices Sales Co., Ltd" }, + { 0x0bb9, "Eiger M&C Co., Ltd" }, + { 0x0bba, "ZAccess Systems" }, + { 0x0bbb, "General Meters Corp." }, + { 0x0bbc, "Assistive Technology, Inc." }, + { 0x0bbd, "System Connection, Inc." }, + { 0x0bc0, "Knilink Technology, Inc." }, + { 0x0bc1, "Fuw Yng Electronics Co., Ltd" }, + { 0x0bc2, "Seagate RSS LLC" }, + { 0x0bc3, "IPWireless, Inc." }, + { 0x0bc4, "Microcube Corp." }, + { 0x0bc5, "JCN Co., Ltd" }, + { 0x0bc6, "ExWAY, Inc." }, + { 0x0bc7, "X10 Wireless Technology, Inc." }, + { 0x0bc8, "Telmax Communications" }, + { 0x0bc9, "ECI Telecom, Ltd" }, + { 0x0bca, "Startek Engineering, Inc." }, + { 0x0bcb, "Perfect Technic Enterprise Co., Ltd" }, + { 0x0bda, "Realtek Semiconductor Corp." }, + { 0x0bdb, "Ericsson Business Mobile Networks BV" }, + { 0x0bdc, "Y Media Corp." }, + { 0x0bdd, "Orange PCS" }, + { 0x0be2, "Kanda Tsushin Kogyo Co., Ltd" }, + { 0x0be3, "TOYO Corp." }, + { 0x0be4, "Elka International, Ltd" }, + { 0x0be5, "DOME imaging systems, Inc." }, + { 0x0be6, "Dong Guan Humen Wonderful Wire Cable Factory" }, + { 0x0bee, "LTK Industries, Ltd" }, + { 0x0bef, "Way2Call Communications" }, + { 0x0bf0, "Pace Micro Technology PLC" }, + { 0x0bf1, "Intracom S.A." }, + { 0x0bf2, "Konexx" }, + { 0x0bf6, "Addonics Technologies, Inc." }, + { 0x0bf7, "Sunny Giken, Inc." }, + { 0x0bf8, "Fujitsu Siemens Computers" }, + { 0x0c04, "MOTO Development Group, Inc." }, + { 0x0c05, "Appian Graphics" }, + { 0x0c06, "Hasbro Games, Inc." }, + { 0x0c07, "Infinite Data Storage, Ltd" }, + { 0x0c08, "Agate" }, + { 0x0c09, "Comjet Information System" }, + { 0x0c0a, "Highpoint Technologies, Inc." }, + { 0x0c0b, "Dura Micro, Inc. (Acomdata)" }, + { 0x0c12, "Zeroplus" }, + { 0x0c15, "Iris Graphics" }, + { 0x0c16, "Gyration, Inc." }, + { 0x0c17, "Cyberboard A/S" }, + { 0x0c18, "SynerTek Korea, Inc." }, + { 0x0c19, "cyberPIXIE, Inc." }, + { 0x0c1a, "Silicon Motion, Inc." }, + { 0x0c1b, "MIPS Technologies" }, + { 0x0c1c, "Hang Zhou Silan Electronics Co., Ltd" }, + { 0x0c22, "Tally Printer Corp." }, + { 0x0c23, "Lernout + Hauspie" }, + { 0x0c24, "Taiyo Yuden" }, + { 0x0c25, "Sampo Corp." }, + { 0x0c35, "Eagletron, Inc." }, + { 0x0c36, "E Ink Corp." }, + { 0x0c37, "e.Digital" }, + { 0x0c38, "Der An Electric Wire & Cable Co., Ltd" }, + { 0x0c39, "IFR" }, + { 0x0c3a, "Furui Precise Component (Kunshan) Co., Ltd" }, + { 0x0c3b, "Komatsu, Ltd" }, + { 0x0c3c, "Radius Co., Ltd" }, + { 0x0c3d, "Innocom, Inc." }, + { 0x0c3e, "Nextcell, Inc." }, + { 0x0c44, "Motorola iDEN" }, + { 0x0c45, "Microdia" }, + { 0x0c46, "WaveRider Communications, Inc." }, + { 0x0c52, "Sealevel Systems, Inc." }, + { 0x0c53, "ViewPLUS, Inc." }, + { 0x0c54, "Glory, Ltd" }, + { 0x0c55, "Spectrum Digital, Inc." }, + { 0x0c56, "Billion Bright, Ltd" }, + { 0x0c57, "Imaginative Design Operation Co., Ltd" }, + { 0x0c58, "Vidar Systems Corp." }, + { 0x0c59, "Dong Guan Shinko Wire Co., Ltd" }, + { 0x0c5a, "TRS International Mfg., Inc." }, + { 0x0c5e, "Xytronix Research & Design" }, + { 0x0c62, "Chant Sincere Co., Ltd" }, + { 0x0c63, "Toko, Inc." }, + { 0x0c64, "Signality System Engineering Co., Ltd" }, + { 0x0c65, "Eminence Enterprise Co., Ltd" }, + { 0x0c66, "Rexon Electronics Corp." }, + { 0x0c67, "Concept Telecom, Ltd" }, + { 0x0c70, "MCT Elektronikladen" }, + { 0x0c74, "Optronic Laboratories Inc." }, + { 0x0c76, "JMTek, LLC." }, + { 0x0c77, "Sipix Group, Ltd" }, + { 0x0c78, "Detto Corp." }, + { 0x0c79, "NuConnex Technologies Pte., Ltd" }, + { 0x0c7a, "Wing-Span Enterprise Co., Ltd" }, + { 0x0c86, "NDA Technologies, Inc." }, + { 0x0c88, "Kyocera Wireless Corp." }, + { 0x0c89, "Honda Tsushin Kogyo Co., Ltd" }, + { 0x0c8a, "Pathway Connectivity, Inc." }, + { 0x0c8b, "Wavefly Corp." }, + { 0x0c8c, "Coactive Networks" }, + { 0x0c8d, "Tempo" }, + { 0x0c8e, "Cesscom Co., Ltd" }, + { 0x0c8f, "Applied Microsystems" }, + { 0x0c99, "Innochips Co., Ltd" }, + { 0x0c9a, "Hanwool Robotics Corp." }, + { 0x0c9b, "Jobin Yvon, Inc." }, + { 0x0ca2, "Zyfer" }, + { 0x0ca3, "Sega Corp." }, + { 0x0ca4, "ST&T Instrument Corp." }, + { 0x0ca5, "BAE Systems Canada, Inc." }, + { 0x0ca6, "Castles Technology Co., Ltd" }, + { 0x0ca7, "Information Systems Laboratories" }, + { 0x0cad, "Motorola CGISS" }, + { 0x0cae, "Ascom Business Systems, Ltd" }, + { 0x0caf, "Buslink" }, + { 0x0cb0, "Flying Pig Systems" }, + { 0x0cb1, "Innovonics, Inc." }, + { 0x0cb6, "Celestix Networks, Pte., Ltd" }, + { 0x0cb7, "Singatron Enterprise Co., Ltd" }, + { 0x0cb8, "Opticis Co., Ltd" }, + { 0x0cba, "Trust Electronic (Shanghai) Co., Ltd" }, + { 0x0cbb, "Shanghai Darong Electronics Co., Ltd" }, + { 0x0cbc, "Palmax Technology Co., Ltd" }, + { 0x0cbd, "Pentel Co., Ltd (Electronics Equipment Div.)" }, + { 0x0cbe, "Keryx Technologies, Inc." }, + { 0x0cbf, "Union Genius Computer Co., Ltd" }, + { 0x0cc0, "Kuon Yi Industrial Corp." }, + { 0x0cc1, "Given Imaging, Ltd" }, + { 0x0cc2, "Timex Corp." }, + { 0x0cc3, "Rimage Corp." }, + { 0x0cc4, "emsys GmbH" }, + { 0x0cc5, "Sendo" }, + { 0x0cc6, "Intermagic Corp." }, + { 0x0cc7, "Kontron Medical AG" }, + { 0x0cc8, "Technotools Corp." }, + { 0x0cc9, "BroadMAX Technologies, Inc." }, + { 0x0cca, "Amphenol" }, + { 0x0ccb, "SKNet Co., Ltd" }, + { 0x0ccc, "Domex Technology Corp." }, + { 0x0ccd, "TerraTec Electronic GmbH" }, + { 0x0cd4, "Bang Olufsen" }, + { 0x0cd7, "NewChip S.r.l." }, + { 0x0cd8, "JS Digitech, Inc." }, + { 0x0cd9, "Hitachi Shin Din Cable, Ltd" }, + { 0x0cde, "Z-Com" }, + { 0x0cf1, "e-Conn Electronic Co., Ltd" }, + { 0x0cf2, "ENE Technology, Inc." }, + { 0x0cf3, "Atheros Communications, Inc." }, + { 0x0cf4, "Fomtex Corp." }, + { 0x0cf5, "Cellink Co., Ltd" }, + { 0x0cf6, "Compucable Corp." }, + { 0x0cf7, "ishoni Networks" }, + { 0x0cf8, "Clarisys, Inc." }, + { 0x0cf9, "Central System Research Co., Ltd" }, + { 0x0cfa, "Inviso, Inc." }, + { 0x0cfc, "Minolta-QMS, Inc." }, + { 0x0d06, "telos EDV Systementwicklung GmbH" }, + { 0x0d0b, "Contemporary Controls" }, + { 0x0d0c, "Astron Electronics Co., Ltd" }, + { 0x0d0d, "MKNet Corp." }, + { 0x0d0e, "Hybrid Networks, Inc." }, + { 0x0d0f, "Feng Shin Cable Co., Ltd" }, + { 0x0d10, "Elastic Networks" }, + { 0x0d11, "Maspro Denkoh Corp." }, + { 0x0d12, "Hansol Electronics, Inc." }, + { 0x0d13, "BMF Corp." }, + { 0x0d14, "Array Comm, Inc." }, + { 0x0d15, "OnStream b.v." }, + { 0x0d16, "Hi-Touch Imaging Technologies Co., Ltd" }, + { 0x0d17, "NALTEC, Inc." }, + { 0x0d18, "coaXmedia" }, + { 0x0d19, "Hank Connection Industrial Co., Ltd" }, + { 0x0d32, "Leo Hui Electric Wire & Cable Co., Ltd" }, + { 0x0d33, "AirSpeak, Inc." }, + { 0x0d34, "Rearden Steel Technologies" }, + { 0x0d35, "Dah Kun Co., Ltd" }, + { 0x0d3c, "Sri Cable Technology, Ltd" }, + { 0x0d3d, "Tangtop Technology Co., Ltd" }, + { 0x0d3e, "Fitcom, inc." }, + { 0x0d3f, "MTS Systems Corp." }, + { 0x0d40, "Ascor, Inc." }, + { 0x0d41, "Ta Yun Terminals Industrial Co., Ltd" }, + { 0x0d42, "Full Der Co., Ltd" }, + { 0x0d49, "Maxtor" }, + { 0x0d4a, "NF Corp." }, + { 0x0d4b, "Grape Systems, Inc." }, + { 0x0d4c, "Tedas AG" }, + { 0x0d4d, "Coherent, Inc." }, + { 0x0d4e, "Agere Systems Netherland BV" }, + { 0x0d4f, "EADS Airbus France" }, + { 0x0d50, "Cleware GmbH" }, + { 0x0d51, "Volex (Asia) Pte., Ltd" }, + { 0x0d53, "HMI Co., Ltd" }, + { 0x0d54, "Holon Corp." }, + { 0x0d55, "ASKA Technologies, Inc." }, + { 0x0d56, "AVLAB Technology, Inc." }, + { 0x0d57, "Solomon Microtech, Ltd" }, + { 0x0d5c, "Belkin" }, + { 0x0d5e, "Myacom, Ltd" }, + { 0x0d5f, "CSI, Inc." }, + { 0x0d60, "IVL Technologies, Ltd" }, + { 0x0d61, "Meilu Electronics (Shenzhen) Co., Ltd" }, + { 0x0d62, "Darfon Electronics Corp." }, + { 0x0d63, "Fritz Gegauf AG" }, + { 0x0d64, "DXG Technology Corp." }, + { 0x0d65, "KMJP Co., Ltd" }, + { 0x0d66, "TMT" }, + { 0x0d67, "Advanet, Inc." }, + { 0x0d68, "Super Link Electronics Co., Ltd" }, + { 0x0d69, "NSI" }, + { 0x0d6a, "Megapower International Corp." }, + { 0x0d6b, "And-Or Logic" }, + { 0x0d70, "Try Computer Co., Ltd" }, + { 0x0d71, "Hirakawa Hewtech Corp." }, + { 0x0d72, "Winmate Communication, Inc." }, + { 0x0d73, "Hit's Communications, Inc." }, + { 0x0d76, "MFP Korea, Inc." }, + { 0x0d77, "Power Sentry/Newpoint" }, + { 0x0d78, "Japan Distributor Corp." }, + { 0x0d7a, "MARX Datentechnik GmbH" }, + { 0x0d7b, "Wellco Technology Co., Ltd" }, + { 0x0d7c, "Taiwan Line Tek Electronic Co., Ltd" }, + { 0x0d7d, "Phison Electronics Corp." }, + { 0x0d7e, "American Computer & Digital Components" }, + { 0x0d7f, "Essential Reality LLC" }, + { 0x0d80, "H.R. Silvine Electronics, Inc." }, + { 0x0d81, "TechnoVision" }, + { 0x0d83, "Think Outside, Inc." }, + { 0x0d89, "Oz Software" }, + { 0x0d8a, "King Jim Co., Ltd" }, + { 0x0d8b, "Ascom Telecommunications, Ltd" }, + { 0x0d8c, "C-Media Electronics, Inc." }, + { 0x0d8d, "Promotion & Display Technology, Ltd" }, + { 0x0d8e, "Global Sun Technology, Inc." }, + { 0x0d8f, "Pitney Bowes" }, + { 0x0d90, "Sure-Fire Electrical Corp." }, + { 0x0d96, "Traveler" }, + { 0x0d97, "Santa Barbara Instrument Group" }, + { 0x0d98, "Mars Semiconductor Corp." }, + { 0x0d99, "Trazer Technologies, Inc." }, + { 0x0d9a, "RTX Telecom AS" }, + { 0x0d9b, "Tat Shing Electrical Co." }, + { 0x0d9c, "Chee Chen Hi-Technology Co., Ltd" }, + { 0x0d9d, "Sanwa Supply, Inc." }, + { 0x0d9e, "Avaya" }, + { 0x0d9f, "Powercom Co., Ltd" }, + { 0x0da0, "Danger Research" }, + { 0x0da1, "Suzhou Peter's Precise Industrial Co., Ltd" }, + { 0x0da2, "Land Instruments International, Ltd" }, + { 0x0da3, "Nippon Electro-Sensory Devices Corp." }, + { 0x0da4, "Polar Electro OY" }, + { 0x0da7, "IOGear, Inc." }, + { 0x0dad, "Westover Scientific" }, + { 0x0db0, "Micro Star International" }, + { 0x0db1, "Wen Te Electronics Co., Ltd" }, + { 0x0db2, "Shian Hwi Plug Parts, Plastic Factory" }, + { 0x0db3, "Tekram Technology Co., Ltd" }, + { 0x0db4, "Chung Fu Chen Yeh Enterprise Corp." }, + { 0x0dbe, "Jiuh Shiuh Precision Industry Co., Ltd" }, + { 0x0dbf, "Quik Tech Solutions" }, + { 0x0dc0, "Great Notions" }, + { 0x0dc1, "Tamagawa Seiki Co., Ltd" }, + { 0x0dc3, "Athena Smartcard Solutions, Inc." }, + { 0x0dc4, "Macpower Peripherals, Ltd" }, + { 0x0dc5, "SDK Co., Ltd" }, + { 0x0dc6, "Precision Squared Technology Corp." }, + { 0x0dc7, "First Cable Line, Inc." }, + { 0x0dcd, "NetworkFab Corp." }, + { 0x0dd1, "Contek Electronics Co., Ltd" }, + { 0x0dd2, "Power Quotient International Co., Ltd" }, + { 0x0dd3, "MediaQ" }, + { 0x0dd4, "Custom Engineering SPA" }, + { 0x0dd5, "California Micro Devices" }, + { 0x0dd7, "Kocom Co., Ltd" }, + { 0x0dd9, "HighSpeed Surfing" }, + { 0x0dda, "Integrated Circuit Solution, Inc." }, + { 0x0ddb, "Tamarack, Inc." }, + { 0x0ddc, "Takaotec" }, + { 0x0ddd, "Datelink Technology Co., Ltd" }, + { 0x0dde, "Ubicom, Inc." }, + { 0x0de0, "BD Consumer Healthcare" }, + { 0x0dea, "UTECH Electronic (D.G.) Co., Ltd." }, + { 0x0deb, "Lean Horn Co." }, + { 0x0dec, "Callserve Communications Ltd." }, + { 0x0ded, "Novasonics" }, + { 0x0dee, "Lifetime Memory Products" }, + { 0x0def, "Full Rise Electronic Co., Ltd" }, + { 0x0df5, "Yamatake Corp." }, + { 0x0df6, "Sitecom Europe B.V." }, + { 0x0df7, "Mobile Action Technology, Inc." }, + { 0x0df8, "Hoya Computer Co., Ltd." }, + { 0x0df9, "Nice Fountain Industrial Co., Ltd." }, + { 0x0dfa, "Toyo Communication Equipment Co., Ltd" }, + { 0x0dfc, "GeneralTouch Technology Co., Ltd" }, + { 0x0e01, "Sheng Xiang Investment Ltd." }, + { 0x0e02, "Doowon Co., LTD" }, + { 0x0e03, "Nippon Systemware Co., Ltd" }, + { 0x0e07, "Viewtek Co., Ltd" }, + { 0x0e08, "Winbest Technology Co., Ltd" }, + { 0x0e09, "Winskon Cabling Specialist Co., Ltd." }, + { 0x0e0c, "Gesytec" }, + { 0x0e12, "Danam Communications Inc." }, + { 0x0e13, "Lugh Networks, Inc." }, + { 0x0e15, "Tellert Elektronik GmbH" }, + { 0x0e16, "JMTek, LLC" }, + { 0x0e17, "Walex Electronic, Ltd" }, + { 0x0e18, "UNIWIDE Technologies" }, + { 0x0e1b, "Crewave" }, + { 0x0e1f, "Cabin Industrial Co., Ltd." }, + { 0x0e21, "Cowon Systems, Inc." }, + { 0x0e22, "Symbian Ltd." }, + { 0x0e23, "Liou Yuane Enterprise Co., Ltd" }, + { 0x0e24, "Samson Electric Wire Co., Ltd." }, + { 0x0e25, "VinChip Systems, Inc." }, + { 0x0e26, "J-Phone East Co., Ltd" }, + { 0x0e30, "HeartMath LLC" }, + { 0x0e34, "Micro Computer Control Corp." }, + { 0x0e35, "3Pea Technologies, Inc." }, + { 0x0e36, "TiePie engineering" }, + { 0x0e37, "Alpha Data Corp." }, + { 0x0e38, "Stratitec, Inc." }, + { 0x0e39, "Smart Modular Technologies, Inc." }, + { 0x0e3a, "Neostar Technology Co., Ltd" }, + { 0x0e3b, "Mansella, Ltd" }, + { 0x0e3c, "Raytec Electronic Co., Ltd." }, + { 0x0e48, "Julia Corp., Ltd" }, + { 0x0e4a, "Shenzhen Bao Hing Electric Wire & Cable Mfr. Co." }, + { 0x0e4c, "Radica Games, Ltd" }, + { 0x0e55, "Speed Dragon Multimedia, Ltd" }, + { 0x0e5a, "Active Co., Ltd" }, + { 0x0e5b, "Union Power Information Industrial Co., Ltd" }, + { 0x0e5c, "Bitland Information Technology Co., Ltd" }, + { 0x0e5d, "Neltron Industrial Co., Ltd" }, + { 0x0e66, "Hawking" }, + { 0x0e6a, "Megawin Technology Co., Ltd" }, + { 0x0e70, "Tokyo Electronic Industry Co., Ltd" }, + { 0x0e72, "Hsi-Chin Electronics Co., Ltd" }, + { 0x0e75, "TVS Electronics, Ltd" }, + { 0x0e7b, "On-Tech Industry Co., Ltd" }, + { 0x0e7e, "Gmate Inc." }, + { 0x0e82, "Ching Tai Electric Wire & Cable Co., Ltd" }, + { 0x0e8c, "Well Force Electronic Co., Ltd" }, + { 0x0e90, "WiebeTech, LLC" }, + { 0x0e91, "VTech Engineering Canada, Ltd" }, + { 0x0e92, "C's Glory Enterprise Co., Ltd" }, + { 0x0e93, "eM Technics Co., Ltd" }, + { 0x0e95, "Future Technology Co., Ltd" }, + { 0x0e96, "Aplux Communications, Ltd" }, + { 0x0e97, "Fingerworks, Inc." }, + { 0x0e98, "Advanced Analogic Technologies, Inc." }, + { 0x0e99, "Parallel Dice Co., Ltd" }, + { 0x0e9a, "TA HSING Industries, Ltd" }, + { 0x0e9b, "ADTEC Corp." }, + { 0x0e9f, "Tamura Corp." }, + { 0x0ea0, "Ours Technology, Inc." }, + { 0x0ea6, "Nihon Computer Co., Ltd" }, + { 0x0ea7, "MSL Enterprises Corp." }, + { 0x0ea8, "CenDyne, Inc." }, + { 0x0ead, "Humax Co., Ltd" }, + { 0x0eb1, "WIS Technologies, Inc." }, + { 0x0eb2, "Y-S Electronic Co., Ltd" }, + { 0x0eb3, "Saint Technology Corp." }, + { 0x0eb7, "Endor AG" }, + { 0x0ebe, "VWeb Corp." }, + { 0x0ebf, "Omega Technology of Taiwan, Inc." }, + { 0x0ec0, "LHI Technology (China) Co., Ltd" }, + { 0x0ec1, "Abit Computer Corp." }, + { 0x0ec2, "Sweetray Industrial, Ltd" }, + { 0x0ec3, "Axell Co., Ltd" }, + { 0x0ec4, "Ballracing Developments, Ltd" }, + { 0x0ec5, "GT Information System Co., Ltd" }, + { 0x0ec6, "InnoVISION Multimedia, Ltd" }, + { 0x0ec7, "Theta Link Corp." }, + { 0x0ecd, "Lite-On IT Corp." }, + { 0x0ece, "TaiSol Electronics Co., Ltd" }, + { 0x0ecf, "Phogenix Imaging, LLC" }, + { 0x0ed1, "WinMaxGroup" }, + { 0x0ed2, "Kyoto Micro Computer Co., Ltd" }, + { 0x0ed3, "Wing-Tech Enterprise Co., Ltd" }, + { 0x0eda, "Noriake Itron Corp." }, + { 0x0edf, "e-MDT Co., Ltd" }, + { 0x0ee0, "Shima Seiki Mfg., Ltd" }, + { 0x0ee1, "Sarotech Co., Ltd" }, + { 0x0ee2, "AMI Semiconductor, Inc." }, + { 0x0ee3, "ComTrue Technology Corp. " }, + { 0x0ee4, "Sunrich Technology, Ltd" }, + { 0x0eee, "Digital Stream Technology, Inc." }, + { 0x0eef, "D-WAV Scientific Co., Ltd" }, + { 0x0ef0, "Hitachi Cable, Ltd" }, + { 0x0ef1, "Aichi Micro Intelligent Corp." }, + { 0x0ef2, "I/O Magic Corp." }, + { 0x0ef3, "Lynn Products, Inc." }, + { 0x0ef4, "DSI Datotech" }, + { 0x0ef5, "PointChips" }, + { 0x0ef6, "Yield Microelectronics Corp." }, + { 0x0ef7, "SM Tech Co., Ltd (Tulip)" }, + { 0x0efd, "Oasis Semiconductor" }, + { 0x0efe, "Wem Technology, Inc." }, + { 0x0f06, "Visual Frontier Enterprise Co., Ltd" }, + { 0x0f08, "CSL Wire & Plug (Shen Zhen) Co." }, + { 0x0f0c, "CAS Corp." }, + { 0x0f0d, "Hori Co., Ltd" }, + { 0x0f0e, "Energy Full Corp." }, + { 0x0f12, "Mars Engineering Corp." }, + { 0x0f13, "Acetek Technology Co., Ltd" }, + { 0x0f19, "Oracom Co., Ltd" }, + { 0x0f1b, "Onset Computer Corp." }, + { 0x0f1c, "Funai Electric Co., Ltd" }, + { 0x0f1d, "Iwill Corp." }, + { 0x0f21, "IOI Technology Corp." }, + { 0x0f22, "Senior Industries, Inc." }, + { 0x0f23, "Leader Tech Manufacturer Co., Ltd" }, + { 0x0f24, "Flex-P Industries, Snd., Bhd. " }, + { 0x0f2d, "ViPower, Inc." }, + { 0x0f2e, "Geniality Maple Technology Co., Ltd" }, + { 0x0f2f, "Priva Design Services" }, + { 0x0f30, "Jess Technology Co., Ltd" }, + { 0x0f31, "Chrysalis Development" }, + { 0x0f32, "YFC-BonEagle Electric Co., Ltd" }, + { 0x0f37, "Kokuyo Co., Ltd" }, + { 0x0f38, "Nien-Yi Industrial Corp." }, + { 0x0f41, "RDC Semiconductor Co., Ltd" }, + { 0x0f42, "Nital Consulting Services, Inc." }, + { 0x0f4b, "St. John Technology Co., Ltd" }, + { 0x0f4c, "WorldWide Cable Opto Corp." }, + { 0x0f4d, "Microtune, Inc." }, + { 0x0f4e, "Freedom Scientific" }, + { 0x0f52, "Wing Key Electrical Co., Ltd" }, + { 0x0f53, "Dongguan White Horse Cable Factory, Ltd" }, + { 0x0f54, "Kawai Musical Instruments Mfg. Co., Ltd" }, + { 0x0f55, "AmbiCom, Inc." }, + { 0x0f5c, "Prairiecomm, Inc." }, + { 0x0f5d, "NewAge International, LLC" }, + { 0x0f5f, "Key Technology Corp." }, + { 0x0f60, "NTK, Ltd" }, + { 0x0f61, "Varian, Inc." }, + { 0x0f62, "Acrox Technologies Co., Ltd" }, + { 0x0f68, "Kobe Steel, Ltd" }, + { 0x0f69, "Dionex Corp." }, + { 0x0f6a, "Vibren Technologies, Inc." }, + { 0x0f73, "DFI" }, + { 0x0f7c, "DQ Technology, Inc." }, + { 0x0f7d, "NetBotz, Inc." }, + { 0x0f7e, "Fluke Corp." }, + { 0x0f88, "VTech Holdings, Ltd" }, + { 0x0f8b, "Yazaki Corp." }, + { 0x0f8c, "Young Generation International Corp." }, + { 0x0f8d, "Uniwill Computer Corp." }, + { 0x0f8e, "Kingnet Technology Co., Ltd" }, + { 0x0f8f, "Soma Networks" }, + { 0x0f97, "CviLux Corp." }, + { 0x0f98, "CyberBank Corp." }, + { 0x0f9e, "Lucent Technologies" }, + { 0x0fa3, "Starconn Electronic Co., Ltd" }, + { 0x0fa4, "ATL Technology" }, + { 0x0fa5, "Sotec Co., Ltd" }, + { 0x0fa7, "Epox Computer Co., Ltd" }, + { 0x0fa8, "Logic Controls, Inc." }, + { 0x0faf, "Winpoint Electronic Corp." }, + { 0x0fb0, "Haurtian Wire & Cable Co., Ltd" }, + { 0x0fb1, "Inclose Design, Inc." }, + { 0x0fb2, "Juan-Chern Industrial Co., Ltd" }, + { 0x0fb8, "Wistron Corp." }, + { 0x0fb9, "AACom Corp." }, + { 0x0fba, "San Shing Electronics Co., Ltd" }, + { 0x0fbb, "Bitwise Systems, Inc." }, + { 0x0fc1, "Mitac Internatinal Corp." }, + { 0x0fc2, "Plug and Jack Industrial, Inc." }, + { 0x0fc5, "Delcom Engineering" }, + { 0x0fc6, "Dataplus Supplies, Inc." }, + { 0x0fce, "Sony Ericsson Mobile Communications AB" }, + { 0x0fcf, "Dynastream Innovations, Inc." }, + { 0x0fd0, "Tulip Computers B.V." }, + { 0x0fd4, "Tenovis GmbH & Co., KG" }, + { 0x0fd5, "Direct Access Technology, Inc." }, + { 0x0fdc, "Micro Plus" }, + { 0x0fe4, "IN-Tech Electronics, Ltd" }, + { 0x0fe5, "Greenconn (U.S.A.), Inc." }, + { 0x0fea, "United Computer Accessories" }, + { 0x0feb, "CRS Electronic Co., Ltd" }, + { 0x0fec, "UMC Electronics Co., Ltd" }, + { 0x0fed, "Access Co., Ltd" }, + { 0x0fee, "Xsido Corp." }, + { 0x0fef, "MJ Research, Inc." }, + { 0x0ff6, "Core Valley Co., Ltd" }, + { 0x0ff7, "CHI SHING Computer Accessories Co., Ltd" }, + { 0x0fff, "Aopen, Inc." }, + { 0x1000, "Speed Tech Corp." }, + { 0x1001, "Ritronics Components (S) Pte., Ltd" }, + { 0x1003, "Sigma Corp." }, + { 0x1004, "LG Electronics, Inc." }, + { 0x1005, "Apacer Technology, Inc." }, + { 0x1009, "Emuzed, Inc." }, + { 0x100a, "AV Chaseway, Ltd" }, + { 0x100b, "Chou Chin Industrial Co., Ltd" }, + { 0x100d, "Netopia, Inc." }, + { 0x1010, "Fukuda Denshi Co., Ltd" }, + { 0x1011, "Mobile Media Tech." }, + { 0x1012, "SDKM Fibres, Wires & Cables Berhad" }, + { 0x1013, "TST-Touchless Sensor Technology AG" }, + { 0x1014, "Densitron Technologies PLC" }, + { 0x1015, "Softronics Pty., Ltd" }, + { 0x1016, "Xiamen Hung's Enterprise Co., Ltd" }, + { 0x1017, "Speedy Industrial Supplies, Pte., Ltd" }, + { 0x1022, "Shinko Shoji Co., Ltd" }, + { 0x1025, "Hyper-Paltek" }, + { 0x1026, "Newly Corp." }, + { 0x1027, "Time Domain" }, + { 0x1028, "Inovys Corp." }, + { 0x1029, "Atlantic Coast Telesys" }, + { 0x102a, "Ramos Technology Co., Ltd" }, + { 0x102b, "Infotronic America, Inc." }, + { 0x102c, "Etoms Electronics Corp." }, + { 0x102d, "Winic Corp." }, + { 0x1031, "Comax Technology, Inc." }, + { 0x1032, "C-One Technology Corp." }, + { 0x1033, "Nucam Corp." }, + { 0x1043, "iCreate Technologies Corp." }, + { 0x1044, "Chu Yuen Enterprise Co., Ltd" }, + { 0x1046, "Winbond Electronics Corp." }, + { 0x104c, "AMCO TEC International, Inc." }, + { 0x1053, "Immanuel Electronics Co., Ltd" }, + { 0x1054, "BMS International Beheer N.V." }, + { 0x1055, "Complex Micro Interconnection Co., Ltd" }, + { 0x1056, "Hsin Chen Ent Co., Ltd" }, + { 0x1057, "ON Semiconductor" }, + { 0x1058, "Western Digital Technologies, Inc." }, + { 0x1059, "Giesecke & Devrient GmbH" }, + { 0x105c, "Hong Ji Electric Wire & Cable (Dongguan) Co., Ltd" }, + { 0x105d, "Delkin Devices, Inc." }, + { 0x105e, "Valence Semiconductor Design, Ltd" }, + { 0x105f, "Chin Shong Enterprise Co., Ltd" }, + { 0x1060, "Easthome Industrial Co., Ltd" }, + { 0x1063, "Motorola Electronics Taiwan, Ltd" }, + { 0x1065, "CCYU Technology" }, + { 0x106a, "Loyal Legend, Ltd" }, + { 0x106c, "Curitel Communications, Inc." }, + { 0x106d, "San Chieh Manufacturing, Ltd" }, + { 0x106e, "ConectL" }, + { 0x106f, "Money Controls" }, + { 0x1076, "GCT Semiconductor, Inc." }, + { 0x107d, "Arlec Australia, Ltd" }, + { 0x107e, "Midoriya Electric Co., Ltd" }, + { 0x107f, "KidzMouse, Inc." }, + { 0x1082, "Shin-Etsukaken Co., Ltd" }, + { 0x1083, "Canon Electronics, Inc." }, + { 0x1084, "Pantech Co., Ltd" }, + { 0x108a, "Chloride Power Protection" }, + { 0x108b, "Grand-tek Technology Co., Ltd" }, + { 0x108c, "Robert Bosch GmbH" }, + { 0x1099, "Surface Optics Corp." }, + { 0x109a, "DATASOFT Systems GmbH" }, + { 0x109f, "eSOL Co., Ltd" }, + { 0x10a0, "Hirotech, Inc." }, + { 0x10a3, "Mitsubishi Materials Corp." }, + { 0x10a9, "SK Teletech Co., Ltd" }, + { 0x10aa, "Cables To Go" }, + { 0x10ab, "USI Co., Ltd" }, + { 0x10ac, "Honeywell, Inc." }, + { 0x10ae, "Princeton Technology Corp." }, + { 0x10b5, "Comodo (PLX?)" }, + { 0x10bb, "TM Technology, Inc." }, + { 0x10bc, "Dinging Technology Co., Ltd" }, + { 0x10bd, "TMT Technology, Inc." }, + { 0x10c4, "Cygnal Integrated Products, Inc." }, + { 0x10c5, "Sanei Electric, Inc." }, + { 0x10c6, "Intec, Inc." }, + { 0x10cb, "Eratech" }, + { 0x10cc, "GBM Connector Co., Ltd" }, + { 0x10cd, "Kycon, Inc." }, + { 0x10d1, "Hottinger Baldwin Measurement" }, + { 0x10d4, "Man Boon Manufactory, Ltd" }, + { 0x10d5, "Uni Class Technology Co., Ltd" }, + { 0x10d6, "Actions Semiconductor Co., Ltd" }, + { 0x10de, "Authenex, Inc." }, + { 0x10df, "In-Win Development, Inc." }, + { 0x10e0, "Post-Op Video, Inc." }, + { 0x10e1, "CablePlus, Ltd" }, + { 0x10e2, "Nada Electronics, Ltd" }, + { 0x10ec, "Vast Technologies, Inc." }, + { 0x10fb, "Pictos Technologies, Inc." }, + { 0x10fd, "Anubis Electronics, Ltd" }, + { 0x1100, "VirTouch, Ltd" }, + { 0x1101, "EasyPass Industrial Co., Ltd" }, + { 0x1108, "Brightcom Technologies, Ltd" }, + { 0x1110, "Analog Devices Canada, Ltd (Allied Telesyn)" }, + { 0x1112, "YM ELECTRIC CO., Ltd" }, + { 0x1113, "Medion AG" }, + { 0x111e, "VSO Electric Co., Ltd" }, + { 0x112e, "Master Hill Electric Wire and Cable Co., Ltd" }, + { 0x112f, "Cellon International, Inc." }, + { 0x1130, "Tenx Technology, Inc." }, + { 0x1131, "Integrated System Solution Corp." }, + { 0x1132, "Toshiba Corp., Digital Media Equipment" }, + { 0x113c, "Arin Tech Co., Ltd" }, + { 0x113d, "Mapower Electronics Co., Ltd" }, + { 0x1141, "V One Multimedia, Pte., Ltd" }, + { 0x1142, "CyberScan Technologies, Inc." }, + { 0x1147, "Ever Great Electric Wire and Cable Co., Ltd" }, + { 0x114c, "Tinius Olsen Testing Machine Co., Inc." }, + { 0x114d, "Alpha Imaging Technology Corp." }, + { 0x1162, "Secugen Corp." }, + { 0x1163, "DeLorme Publishing, Inc." }, + { 0x1164, "YUAN High-Tech Development Co., Ltd" }, + { 0x1165, "Telson Electronics Co., Ltd" }, + { 0x1166, "Bantam Interactive Technologies" }, + { 0x1167, "Salient Systems Corp." }, + { 0x1168, "BizConn International Corp." }, + { 0x116e, "Gigastorage Corp." }, + { 0x116f, "Silicon 10 Technology Corp." }, + { 0x1175, "Shengyih Steel Mold Co., Ltd" }, + { 0x117d, "Santa Electronic, Inc." }, + { 0x117e, "JNC, Inc." }, + { 0x1182, "Venture Corp., Ltd" }, + { 0x1183, "Compaq Computer Corp. (Digital Dream?)" }, + { 0x1184, "Kyocera Elco Corp." }, + { 0x118f, "You Yang Technology Co., Ltd" }, + { 0x1190, "Tripace" }, + { 0x1191, "Loyalty Founder Enterprise Co., Ltd" }, + { 0x1197, "Technoimagia Co., Ltd" }, + { 0x1198, "StarShine Technology Corp." }, + { 0x1199, "Sierra Wireless, Inc." }, + { 0x119a, "ZHAN QI Technology Co., Ltd" }, + { 0x11a3, "Technovas Co., Ltd" }, + { 0x11aa, "GlobalMedia Group, LLC" }, + { 0x11ab, "Exito Electronics Co., Ltd" }, + { 0x11db, "Topfield Co., Ltd." }, + { 0x1209, "InterBiometrics" }, + { 0x120e, "Hudson Soft Co., Ltd" }, + { 0x121e, "Jungsoft Co., Ltd" }, + { 0x1241, "Belkin (?)" }, + { 0x126e, "Strobe Data, Inc." }, + { 0x1275, "Xaxero Marine Software Engineering, Ltd." }, + { 0x1292, "Innomedia" }, + { 0x1293, "Belkin Components" }, + { 0x1312, "ICS Electronics" }, + { 0x1342, "Mobility" }, + { 0x13d2, "Shark Multimedia" }, + { 0x147a, "Formosa Industrial Computing, Inc." }, + { 0x1484, "Elsa AG" }, + { 0x14c2, "Gemlight Computer, Ltd" }, + { 0x1520, "Bitwire Corp." }, + { 0x1527, "Silicon Portals" }, + { 0x1554, "Prolink Microsystems Corp." }, + { 0x1568, "Sunf Pu Technology Co., Ltd" }, + { 0x15e8, "SohoWare" }, + { 0x15e9, "Pacific Digital Corp." }, + { 0x1604, "Tascam" }, + { 0x1606, "Umax" }, + { 0x1608, "Inside Out Networks" }, + { 0x1645, "Entrega" }, + { 0x1668, "Actiontec Electronics, Inc." }, + { 0x1690, "Askey Computer Corp." }, + { 0x1696, "Hitachi Video and Information System, Inc." }, + { 0x1697, "VTec Test, Inc." }, + { 0x1894, "Topseed" }, + { 0x1ebb, "NuCORE Technology, Inc." }, + { 0x2001, "D-Link Corp." }, + { 0x2162, "Creative (?)" }, + { 0x2222, "MacAlly" }, + { 0x22b8, "Motorola PCS" }, + { 0x22b9, "eTurboTouch Technology, Inc." }, + { 0x22ba, "Technology Innovation Holdings, Ltd" }, + { 0x2304, "Pinnacle Systems, Inc." }, + { 0x2318, "Shining Technologies, Inc." }, + { 0x2375, "Digit@lway, Inc." }, + { 0x2632, "TwinMOS" }, + { 0x2650, "Electronics For Imaging, Inc." }, + { 0x2770, "NHJ, Ltd" }, + { 0x2899, "Toptronic Industrial Co., Ltd" }, + { 0x3125, "Eagletron" }, + { 0x3176, "Whanam Electronics Co., Ltd" }, + { 0x3504, "Micro Star" }, + { 0x3538, "Power Quotient International Co., Ltd" }, + { 0x3579, "DIVA" }, + { 0x3636, "InVibro" }, + { 0x3838, "WEM" }, + { 0x3923, "National Instruments Corp." }, + { 0x413c, "Dell Computer Corp." }, + { 0x4242, "USB Design by Example" }, + { 0x544d, "Transmeta Corp." }, + { 0x5543, "UC-Logic Technology Corp." }, + { 0x55aa, "OnSpec Electronic, Inc." }, + { 0x6189, "Sitecom" }, + { 0x636c, "CoreLogic, Inc." }, + { 0x6666, "Prototype product Vendor ID" }, + { 0x6a75, "Shanghai Jujo Electronics Co., Ltd" }, + { 0x8086, "Intel Corp." }, + { 0xc251, "Keil Software, Inc." }, + { 0x0000, NULL } +}; +/* \\\ */ diff --git a/rom/usb/poseidon/numtostr.h b/rom/usb/poseidon/numtostr.h new file mode 100644 index 000000000..8cc8bd138 --- /dev/null +++ b/rom/usb/poseidon/numtostr.h @@ -0,0 +1,25 @@ +#ifndef NUMTOSTR_H +#define NUMTOSTR_H + +/* + *---------------------------------------------------------------------------- + * Includes for numtostr.c + *---------------------------------------------------------------------------- + * By Chris Hodges + */ + +#include + +#include "poseidon_intern.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif /* NUMTOSTR_H */ diff --git a/rom/usb/poseidon/popo.gui.c b/rom/usb/poseidon/popo.gui.c new file mode 100644 index 000000000..66dc9da78 --- /dev/null +++ b/rom/usb/poseidon/popo.gui.c @@ -0,0 +1,1578 @@ +/* + * GUI + */ + +#include "debug.h" +#include "poseidon.library.h" + +#include +#include +#include +#include +#include + +#define __NOLIBBASE__ +#include +#include +#include +#include +#include +#include +#include + +#include "numtostr.h" + +#define NewList NEWLIST + +#include "popo.gui.h" + +#include + +#define MUIMasterBase po->po_MUIBase +#define DataTypesBase po->po_DTBase +#define IntuitionBase po->po_IntBase + +extern struct ExecBase *SysBase; + +/* /// "pPoPoGUITask()" */ +AROS_UFH0(void, pPoPoGUITask) +{ + AROS_USERFUNC_INIT + struct Task *thistask; + LIBBASETYPEPTR ps; + struct PsdPoPo *po; + struct List *scrlist; + struct PubScreenNode *pubscr; + BOOL hasworkbench = FALSE; + + thistask = FindTask(NULL); + + ps = thistask->tc_UserData; + SetTaskPri(thistask, 0); + po = &ps->ps_PoPo; + + NewList(&po->po_GadgetList); + NewList(&po->po_Sounds); + + if(!(IntuitionBase = OpenLibrary("intuition.library", 39))) + { + KPRINTF(10, ("Couldn't open intuition.library.\n")); + pPoPoGUITaskCleanup(ps); + return; + } + + scrlist = LockPubScreenList(); + pubscr = (struct PubScreenNode *) scrlist->lh_Head; + while(pubscr->psn_Node.ln_Succ) + { + if(strcmp(pubscr->psn_Node.ln_Name, "Workbench") == 0) + { + if(pubscr->psn_Screen) + { + hasworkbench = TRUE; + } + break; + } + pubscr = (struct PubScreenNode *) pubscr->psn_Node.ln_Succ; + } + UnlockPubScreenList(); + + if(!hasworkbench) + { + KPRINTF(10, ("No screen open yet.\n")); + pPoPoGUITaskCleanup(ps); + return; + } + + if(!(MUIMasterBase = OpenLibrary(MUIMASTER_NAME, MUIMASTER_VMIN))) + { + KPRINTF(10, ("Couldn't open muimaster.library.\n")); + pPoPoGUITaskCleanup(ps); + return; + } + + if(!(DataTypesBase = OpenLibrary("datatypes.library", 39))) + { + KPRINTF(10, ("Couldn't open datatypes.library.\n")); + pPoPoGUITaskCleanup(ps); + return; + } + + if(!(po->po_MsgPort = CreateMsgPort())) + { + KPRINTF(10, ("Couldn't create MsgPort.\n")); + pPoPoGUITaskCleanup(ps); + return; + } + + po->po_EventHandler = psdAddEventHandler(po->po_MsgPort, EHMF_ADDDEVICE|EHMF_REMDEVICE|EHMF_ADDBINDING|EHMF_CONFIGCHG|EHMF_DEVICEDEAD|EHMF_DEVICELOWPW); + if(!po->po_EventHandler) + { + KPRINTF(10, ("Couldn't add EventHandler.\n")); + pPoPoGUITaskCleanup(ps); + return; + } + + if(!(po->po_TimerMsgPort = CreateMsgPort())) + { + KPRINTF(10, ("Couldn't create MsgPort.\n")); + pPoPoGUITaskCleanup(ps); + return; + } + + if(!(po->po_TimerIOReq = (struct timerequest *) CreateIORequest(po->po_TimerMsgPort, sizeof(struct timerequest)))) + { + KPRINTF(10, ("Couldn't create TimerIOReq.\n")); + pPoPoGUITaskCleanup(ps); + return; + } + + if(OpenDevice("timer.device", UNIT_VBLANK, (struct IORequest *) po->po_TimerIOReq, 0)) + { + KPRINTF(10, ("Couldn't open timer.device.\n")); + pPoPoGUITaskCleanup(ps); + return; + } + po->po_TimerIOReq->tr_node.io_Message.mn_Node.ln_Type = NT_REPLYMSG; + po->po_TimerIOReq->tr_node.io_Message.mn_Node.ln_Name = "PoPo"; + po->po_TimerIOReq->tr_node.io_Command = TR_ADDREQUEST; + + if(!(po->po_PoPoClass = MUI_CreateCustomClass(NULL, MUIC_Area, NULL, sizeof(struct PoPoData), PoPoDispatcher))) + { + KPRINTF(10, ("Couldn't create PoPo Class\n")); + pPoPoGUITaskCleanup(ps); + return; + } + po->po_PoPoClass->mcc_Class->cl_UserData = (ULONG) ps; + + po->po_AppObj = ApplicationObject, + MUIA_Application_Title , "PoPo -- Poseidon Popup Provider", + MUIA_Application_Version , VERSION_STRING, + MUIA_Application_Copyright , "©2004-2009 Chris Hodges", + MUIA_Application_Author , "Chris Hodges ", + MUIA_Application_Description, "Opens annoying windows", + MUIA_Application_Base , "POPO", + MUIA_Application_HelpFile , "HELP:Poseidon.guide", + MUIA_Application_Menustrip , MenustripObject, + Child, MenuObjectT("Project"), + Child, po->po_AboutMI = MenuitemObject, + MUIA_Menuitem_Title, "About...", + MUIA_Menuitem_Shortcut, "?", + End, + Child, MenuitemObject, + MUIA_Menuitem_Title, NM_BARLABEL, + End, + Child, po->po_CloseMI = MenuitemObject, + MUIA_Menuitem_Title, "Close", + MUIA_Menuitem_Shortcut, "Q", + End, + End, + Child, MenuObjectT("Settings"), + Child, po->po_TridentMI = MenuitemObject, + MUIA_Menuitem_Title, "Open Trident", + MUIA_Menuitem_Shortcut, "O", + End, + Child, MenuitemObject, + MUIA_Menuitem_Title, NM_BARLABEL, + End, + Child, po->po_MUIPrefsMI = MenuitemObject, + MUIA_Menuitem_Title, "MUI Settings", + MUIA_Menuitem_Shortcut, "M", + End, + End, + End, + + SubWindow, po->po_WindowObj = WindowObject, + MUIA_Window_ID , MAKE_ID('P','O','P','O'), + MUIA_Window_Title, "Poseidon Popups", + MUIA_HelpNode, "main", + + WindowContents, VGroup, + Child, po->po_PoPoObj = NewObject(po->po_PoPoClass->mcc_Class, 0, MUIA_ShowMe, FALSE, TAG_END), + Child, po->po_GroupObj = VGroup, + Child, HGroup, + Child, HSpace(0), + Child, Label("Messages"), + Child, HSpace(0), + End, + End, + Child, HGroup, + Child, po->po_StickyObj = ImageObject, ImageButtonFrame, + MUIA_Background, MUII_ButtonBack, + MUIA_CycleChain, 1, + MUIA_InputMode, MUIV_InputMode_Toggle, + MUIA_Image_Spec, MUII_CheckMark, + MUIA_Image_FreeVert, TRUE, + MUIA_Selected, FALSE, + MUIA_ShowSelState, FALSE, + End, + Child, Label("Hold on"), + Child, HGroup, + MUIA_Group_SameWidth, TRUE, + Child, po->po_SaveObj = TextObject, ButtonFrame, + MUIA_Disabled, (ps->ps_SavedConfigHash == ps->ps_ConfigHash), + MUIA_Background, MUII_ButtonBack, + MUIA_CycleChain, 1, + MUIA_InputMode, MUIV_InputMode_RelVerify, + MUIA_Text_Contents, "\33c Save Prefs ", + End, + Child, po->po_CloseObj = TextObject, ButtonFrame, + MUIA_Background, MUII_ButtonBack, + MUIA_CycleChain, 1, + MUIA_InputMode, MUIV_InputMode_RelVerify, + MUIA_Text_Contents, "\33c Close ", + End, + End, + End, + End, + End, + End; + + if(!po->po_AppObj) + { + KPRINTF(10, ("Couldn't create application\n")); + pPoPoGUITaskCleanup(ps); + return; + } + + DoMethod(po->po_WindowObj, MUIM_Notify, MUIA_Window_CloseRequest, TRUE, + po->po_AppObj, 2, MUIM_Application_ReturnID, MUIV_Application_ReturnID_Quit); + DoMethod(po->po_SaveObj, MUIM_Notify, MUIA_Pressed, FALSE, + po->po_PoPoObj, 1, MUIM_PoPo_SavePrefs); + DoMethod(po->po_CloseObj, MUIM_Notify, MUIA_Pressed, FALSE, + po->po_AppObj, 2, MUIM_Application_ReturnID, MUIV_Application_ReturnID_Quit); + DoMethod(po->po_StickyObj, MUIM_Notify, MUIA_Selected, MUIV_EveryTime, + po->po_PoPoObj, 1, MUIM_PoPo_Sticky); + + DoMethod(po->po_AboutMI, MUIM_Notify, MUIA_Menuitem_Trigger, MUIV_EveryTime, + po->po_PoPoObj, 1, MUIM_PoPo_About); + DoMethod(po->po_CloseMI, MUIM_Notify, MUIA_Menuitem_Trigger, MUIV_EveryTime, + po->po_AppObj, 2, MUIM_Application_ReturnID, MUIV_Application_ReturnID_Quit); + DoMethod(po->po_TridentMI, MUIM_Notify, MUIA_Menuitem_Trigger, MUIV_EveryTime, + po->po_PoPoObj, 1, MUIM_PoPo_OpenTrident); + DoMethod(po->po_MUIPrefsMI, MUIM_Notify, MUIA_Menuitem_Trigger, MUIV_EveryTime, + po->po_AppObj, 2, MUIM_Application_OpenConfigWindow, 0); + + + { + BOOL isopen = FALSE; + ULONG sigs; + ULONG sigmask; + LONG retid; + struct PsdPoPoGadgets *pog; + struct timeval currtime; + + po->po_Task = thistask; + Forbid(); + if(po->po_ReadySigTask) + { + Signal(po->po_ReadySigTask, 1L<po_ReadySignal); + } + Permit(); + + //set(po->po_WindowObj, MUIA_Window_Open, TRUE); + po->po_TimerIOReq->tr_time.tv_micro = 500*1000; + SendIO(&po->po_TimerIOReq->tr_node); + sigmask = (1UL<po_MsgPort->mp_SigBit)|(1UL<po_TimerMsgPort->mp_SigBit); + do + { + retid = DoMethod(po->po_AppObj, MUIM_Application_NewInput, &sigs); + if(sigs) + { + pEventHandler(ps); + if(CheckIO(&po->po_TimerIOReq->tr_node)) + { + WaitIO(&po->po_TimerIOReq->tr_node); + po->po_TimerIOReq->tr_time.tv_micro = 500*1000; + SendIO(&po->po_TimerIOReq->tr_node); + } + CurrentTime(&currtime.tv_secs, &currtime.tv_micro); + pog = (struct PsdPoPoGadgets *) po->po_GadgetList.lh_Head; + while(pog->pog_Node.ln_Succ) + { + if((currtime.tv_secs > pog->pog_TimeoutTime.tv_secs) || + ((currtime.tv_secs == pog->pog_TimeoutTime.tv_secs) && + (currtime.tv_micro > pog->pog_TimeoutTime.tv_micro))) + { + pFreePoPoGadgets(ps, pog); + pog = (struct PsdPoPoGadgets *) po->po_GadgetList.lh_Head; + } else { + pog = (struct PsdPoPoGadgets *) pog->pog_Node.ln_Succ; + } + } + + if(po->po_GadgetList.lh_Head->ln_Succ) + { + if(po->po_OpenRequest) + { + if(!isopen) + { + if(ps->ps_GlobalCfg->pgc_PopupActivateWin) + { + set(po->po_WindowObj, MUIA_Window_Activate, TRUE); + } else { + set(po->po_WindowObj, MUIA_Window_Activate, FALSE); + } + set(po->po_StickyObj, MUIA_Selected, FALSE); + set(po->po_WindowObj, MUIA_Window_Open, TRUE); + isopen = TRUE; + } else { + if(ps->ps_GlobalCfg->pgc_PopupWinToFront) + { + DoMethod(po->po_WindowObj, MUIM_Window_ToFront); + } + } + po->po_OpenRequest = FALSE; + } + } else { + if(isopen) + { + set(po->po_WindowObj, MUIA_Window_Open, FALSE); + isopen = FALSE; + } + } + + sigs = Wait(sigs | sigmask | SIGBREAKF_CTRL_C); + if(sigs & SIGBREAKF_CTRL_C) + { + break; + } + } + if(retid == MUIV_Application_ReturnID_Quit) + { + set(po->po_WindowObj, MUIA_Window_Open, FALSE); + /* remove all thingies */ + pog = (struct PsdPoPoGadgets *) po->po_GadgetList.lh_Head; + while(pog->pog_Node.ln_Succ) + { + pFreePoPoGadgets(ps, pog); + pog = (struct PsdPoPoGadgets *) po->po_GadgetList.lh_Head; + } + } + if((ps->ps_GlobalCfg->pgc_PopupDeviceNew == PGCP_NEVER) && + (!ps->ps_GlobalCfg->pgc_PopupDeviceDeath) && + (!ps->ps_GlobalCfg->pgc_PopupDeviceGone)) + { + psdAddErrorMsg0(RETURN_OK, (STRPTR) "PoPo", "PoPo has been abandoned (is it you, stuntzi?)."); + break; + } + + } while(TRUE); + set(po->po_WindowObj, MUIA_Window_Open, FALSE); + } + pPoPoGUITaskCleanup(ps); + AROS_USERFUNC_EXIT +} +/* \\\ */ + +/* /// "pPoPoGUITaskCleanup()" */ +void pPoPoGUITaskCleanup(LIBBASETYPEPTR ps) +{ + struct PsdPoPo *po = &ps->ps_PoPo; + struct PsdPoPoGadgets *pog; + struct PsdPoPoSound *pps; + + pog = (struct PsdPoPoGadgets *) po->po_GadgetList.lh_Head; + while(pog->pog_Node.ln_Succ) + { + pFreePoPoGadgets(ps, pog); + pog = (struct PsdPoPoGadgets *) po->po_GadgetList.lh_Head; + } + + pps = (struct PsdPoPoSound *) po->po_Sounds.lh_Head; + while(pps->pps_Node.ln_Succ) + { + pPoPoFreeSound(ps, pps); + pps = (struct PsdPoPoSound *) po->po_Sounds.lh_Head; + } + + if(po->po_TimerIOReq) + { + if(po->po_TimerIOReq->tr_node.io_Device) + { + AbortIO(&po->po_TimerIOReq->tr_node); + WaitIO(&po->po_TimerIOReq->tr_node); + CloseDevice((struct IORequest *) po->po_TimerIOReq); + } + DeleteIORequest((struct IORequest *) po->po_TimerIOReq); + po->po_TimerIOReq = NULL; + } + if(po->po_TimerMsgPort) + { + DeleteMsgPort(po->po_TimerMsgPort); + po->po_TimerMsgPort = NULL; + } + + if(po->po_EventHandler) + { + psdRemEventHandler(po->po_EventHandler); + po->po_EventHandler = NULL; + } + if(po->po_MsgPort) + { + DeleteMsgPort(po->po_MsgPort); + po->po_MsgPort = NULL; + } + if(po->po_AppObj) + { + MUI_DisposeObject(po->po_AppObj); + po->po_AppObj = NULL; + } + if(po->po_PoPoClass) + { + MUI_DeleteCustomClass(po->po_PoPoClass); + po->po_PoPoClass = NULL; + } + if(DataTypesBase) + { + CloseLibrary(DataTypesBase); + DataTypesBase = NULL; + } + if(MUIMasterBase) + { + CloseLibrary(MUIMasterBase); + MUIMasterBase = NULL; + } + if(IntuitionBase) + { + CloseLibrary(IntuitionBase); + IntuitionBase = NULL; + } + Forbid(); + po->po_Task = NULL; + if(po->po_ReadySigTask) + { + Signal(po->po_ReadySigTask, 1L<po_ReadySignal); + } +} +/* \\\ */ + +/* /// "pPoPoLoadSound()" */ +struct PsdPoPoSound * pPoPoLoadSound(LIBBASETYPEPTR ps, STRPTR name) +{ + struct PsdPoPo *po = &ps->ps_PoPo; + struct PsdPoPoSound *pps; + if((pps = psdAllocVec(sizeof(struct PsdPoPoSound)))) + { + if((pps->pps_Node.ln_Name = psdCopyStr(name))) + { + AddTail(&po->po_Sounds, &pps->pps_Node); + pps->pps_DTHandle = NewDTObject(name, + DTA_SourceType, DTST_FILE, + DTA_GroupID, GID_SOUND, + SDTA_Cycles, 1L, + TAG_END); + if(!pps->pps_DTHandle) + { + psdAddErrorMsg(RETURN_ERROR, "PoPo", "Could not load soundfile '%s'.", name); + } + return(pps); + } + psdFreeVec(pps); + } + return(NULL); +} +/* \\\ */ + +/* /// "pPoPoPlaySound()" */ +BOOL pPoPoPlaySound(LIBBASETYPEPTR ps, STRPTR name) +{ + struct PsdPoPo *po = &ps->ps_PoPo; + struct PsdPoPoSound *pps; + struct dtTrigger playmsg; + + pps = (struct PsdPoPoSound *) FindName(&po->po_Sounds, name); + if(!pps) + { + pps = pPoPoLoadSound(ps, name); + } + if(!pps) + { + return(FALSE); + } + if(!pps->pps_DTHandle) + { + return(FALSE); + } + + SetAttrs(pps->pps_DTHandle, + SDTA_Volume, 64, + TAG_END); + playmsg.MethodID = DTM_TRIGGER; + playmsg.dtt_GInfo = NULL; + playmsg.dtt_Function = STM_PLAY; + playmsg.dtt_Data = NULL; + DoMethodA(pps->pps_DTHandle, (Msg) &playmsg); + return(TRUE); +} +/* \\\ */ + +/* /// "pPoPoFreeSound()" */ +void pPoPoFreeSound(LIBBASETYPEPTR ps, struct PsdPoPoSound *pps) +{ + struct PsdPoPo *po = &ps->ps_PoPo; + Remove(&pps->pps_Node); + if(pps->pps_DTHandle) + { + DisposeDTObject(pps->pps_DTHandle); + } + psdFreeVec(pps->pps_Node.ln_Name); + psdFreeVec(pps); +} +/* \\\ */ + +/* /// "pIsDeviceStillValid()" */ +BOOL pIsDeviceStillValid(LIBBASETYPEPTR ps, struct PsdDevice *pd) +{ + struct PsdDevice *tmppd = NULL; + while((tmppd = psdGetNextDevice(tmppd))) + { + if(tmppd == pd) + { + return(TRUE); + } + } + return(FALSE); +} +/* \\\ */ + +/* /// "pIsClassStillValid()" */ +BOOL pIsClassStillValid(LIBBASETYPEPTR ps, struct Library *ucb) +{ + struct PsdUsbClass *puc = (struct PsdUsbClass *) ps->ps_Classes.lh_Head; + while(puc->puc_Node.ln_Succ) + { + if(puc->puc_ClassBase == ucb) + { + return(TRUE); + } + puc = (struct PsdUsbClass *) puc->puc_Node.ln_Succ; + } + return(FALSE); +} +/* \\\ */ + +/* /// "pRemoveOldBox()" */ +void pRemoveOldBox(LIBBASETYPEPTR ps, struct PsdDevice *pd) +{ + struct PsdPoPo *po = &ps->ps_PoPo; + struct PsdPoPoGadgets *pog; + // try to remove adding message, if it still existing + pog = (struct PsdPoPoGadgets *) po->po_GadgetList.lh_Head; + while(pog->pog_Node.ln_Succ) + { + if(pog->pog_Device == pd) + { + pFreePoPoGadgets(ps, pog); + pog = (struct PsdPoPoGadgets *) po->po_GadgetList.lh_Head; + } else { + pog = (struct PsdPoPoGadgets *) pog->pog_Node.ln_Succ; + } + } +} +/* \\\ */ + +/* /// "pGenerateAddBox()" */ +struct PsdPoPoGadgets * pGenerateAddBox(LIBBASETYPEPTR ps, struct PsdDevice *pd, struct PsdPoPoGadgets *pog) +{ + struct PsdPoPo *po = &ps->ps_PoPo; + STRPTR body = NULL; + STRPTR bindingsstr; + STRPTR bindinginfo; + STRPTR bodyinfo; + STRPTR wholebodyinfo; + STRPTR gad[4] = { NULL, NULL, NULL, NULL }; + STRPTR lpwarn; + STRPTR deadwarn; + ULONG configstate; + BOOL lowpower = FALSE; + BOOL isdead = FALSE; + BOOL updatetime = FALSE; + STRPTR oldbody = NULL; + BOOL update = FALSE; + UWORD cnt; + ULONG methods[4] = { MUIM_PoPo_ConfigureBinding, MUIM_PoPo_ConfigureClass, MUIM_PoPo_ShutUp, MUIM_PoPo_RemInfo }; + + bindingsstr = pBindingsString(ps, pd); + configstate = pCheckConfigurable(ps, pd); + + lowpower = pd->pd_Flags & PDFF_LOWPOWER; + isdead = pd->pd_Flags & PDFF_DEAD; + + body = "A new USB device was detected:\n\n\33b%s\33n\n\n"; + if(lowpower) + { + lpwarn = "\n\n\33bWARNING: Detected low power situation!"; + } else { + lpwarn = ""; + } + if(isdead) + { + deadwarn = "\n\n\33bWARNING: Device seems to be dead!"; + } else { + deadwarn = ""; + } + + if(bindingsstr) + { + bindinginfo = psdCopyStrFmt("It is bound to \33b%s\33n", bindingsstr); + } else { + bindinginfo = psdCopyStr("No class seems responsible (yet)!"); + } + if(!bindinginfo) + { + psdFreeVec(bindingsstr); + return(NULL); + } + if(!(bodyinfo = psdCopyStrFmt(body, pd->pd_ProductStr))) + { + psdFreeVec(bindingsstr); + psdFreeVec(bindinginfo); + return(NULL); + } + if(!(wholebodyinfo = psdCopyStrFmt("%s%s%s%s", bodyinfo, bindinginfo, lpwarn, deadwarn))) + { + psdFreeVec(bindingsstr); + psdFreeVec(bindinginfo); + psdFreeVec(bodyinfo); + return(NULL); + } + if(configstate & PPF_HasBindingGUI) + { + gad[0] = "Set Device Prefs"; + } + if(configstate & PPF_HasBindConfig) + { + gad[0] = "Change Device Prefs"; + } + if(configstate & PPF_HasClassGUI) + { + gad[1] = "Set Class Prefs"; + } + if(configstate & PPF_HasClsConfig) + { + gad[1] = "Change Class Prefs"; + } + if(isdead || lowpower) + { + gad[0] = "Disable Port"; + methods[0] = MUIM_PoPo_DisablePort; + gad[1] = NULL; + } + if(isdead && (!lowpower)) + { + gad[1] = "Powercycle Port"; + methods[1] = MUIM_PoPo_PowerCyclePort; + } + gad[2] = "No PopUps!"; + gad[3] = "Continue"; + if(!pog) + { + pog = pAllocPoPoGadgets(ps, wholebodyinfo, gad); + if(pog) + { + pog->pog_Device = pd; + } + } else { + update = TRUE; + get(pog->pog_BodyObj, MUIA_Text_Contents, &oldbody); + if(strcmp(oldbody, wholebodyinfo)) + { + set(pog->pog_BodyObj, MUIA_Text_Contents, wholebodyinfo); + updatetime = TRUE; + } + for(cnt = 0; cnt < 4; cnt++) + { + if(gad[cnt]) + { + set(pog->pog_GadgetObj[cnt], MUIA_Text_Contents, gad[cnt]); + set(pog->pog_GadgetObj[cnt], MUIA_ShowMe, TRUE); + } else { + set(pog->pog_GadgetObj[cnt], MUIA_ShowMe, FALSE); + } + } + } + for(cnt = 0; cnt < 4; cnt++) + { + DoMethod(pog->pog_GadgetObj[cnt], MUIM_KillNotify, MUIA_Pressed); + if(gad[cnt]) + { + DoMethod(pog->pog_GadgetObj[cnt], MUIM_Notify, MUIA_Pressed, FALSE, + po->po_AppObj, 5, MUIM_Application_PushMethod, po->po_PoPoObj, 2, methods[cnt], pog); + } + } + + psdFreeVec(bindingsstr); + psdFreeVec(bindinginfo); + psdFreeVec(bodyinfo); + psdFreeVec(wholebodyinfo); + + /* update delay */ + if(updatetime && pog) + { + CurrentTime(&pog->pog_TimeoutTime.tv_secs, &pog->pog_TimeoutTime.tv_micro); + if(ps->ps_GlobalCfg->pgc_PopupCloseDelay) + { + pog->pog_TimeoutTime.tv_secs += ps->ps_GlobalCfg->pgc_PopupCloseDelay; + } else { + pog->pog_TimeoutTime.tv_secs += 60*60*24; + } + } + + if((ps->ps_GlobalCfg->pgc_PopupDeviceNew >= PGCP_ISNEW) && pd->pd_IsNewToMe) + { + pog->pog_ShowMe = TRUE; + } + if((ps->ps_GlobalCfg->pgc_PopupDeviceNew >= PGCP_ERROR) && (isdead || lowpower)) + { + pog->pog_ShowMe = TRUE; + } + switch(ps->ps_GlobalCfg->pgc_PopupDeviceNew) + { + case PGCP_NEVER: + case PGCP_ERROR: + case PGCP_ISNEW: + break; + + case PGCP_NOBINDING: + if(configstate & PPF_HasBinding) + { + break; + } + // break missing on purpose + case PGCP_HASBINDING: + if(configstate & PPF_HasBinding) + { + pog->pog_ShowMe = TRUE; + } + break; + + case PGCP_ASKCONFIG: + if(configstate & PPF_HasBindingGUI) + { + if(!(configstate & PPF_HasBindConfig)) + { + pog->pog_ShowMe = TRUE; + } + break; // don't ask, if there is an unset default class config + } + if(configstate & PPF_HasClassGUI) + { + if(!(configstate & PPF_HasClsConfig)) + { + pog->pog_ShowMe = TRUE; + } + } + break; + + case PGCP_CANCONFIG: + if(configstate & (PPF_HasClassGUI|PPF_HasBindingGUI)) + { + pog->pog_ShowMe = TRUE; + } + break; + + case PGCP_ALWAYS: + pog->pog_ShowMe = TRUE; + break; + + default: + break; + } + return(pog); +} +/* \\\ */ + +/* /// "pEventHandler()" */ +void pEventHandler(LIBBASETYPEPTR ps) +{ + struct PsdPoPo *po = &ps->ps_PoPo; + struct PsdDevice *pd; + struct PsdEventNote *pen; + struct PsdPoPoGadgets *pog; + ULONG eventmask; + STRPTR body = NULL; + BOOL addsound = FALSE; + BOOL remsound = FALSE; + BOOL cfgchanged = FALSE; + + /* delete removed devices first */ + psdLockReadPBase(); + + pog = (struct PsdPoPoGadgets *) po->po_GadgetList.lh_Head; + while(pog->pog_Node.ln_Succ) + { + if(pog->pog_Device) + { + /* verify that device is still there */ + if(!pIsDeviceStillValid(ps, pog->pog_Device)) + { + /* huh, gone! */ + pFreePoPoGadgets(ps, pog); + pog = (struct PsdPoPoGadgets *) po->po_GadgetList.lh_Head; + continue; + } + } + pog = (struct PsdPoPoGadgets *) pog->pog_Node.ln_Succ; + } + + eventmask = 0; + while((pen = (struct PsdEventNote *) GetMsg(po->po_MsgPort))) + { + eventmask |= (1L<pen_Event); + switch(pen->pen_Event) + { + case EHMB_ADDDEVICE: + { + pd = (struct PsdDevice *) pen->pen_Param1; + if(pIsDeviceStillValid(ps, pd)) + { + pRemoveOldBox(ps, pd); + if(pd->pd_PoPoCfg.poc_InhibitPopup) + { + break; + } + addsound = TRUE; + pog = pGenerateAddBox(ps, pd, NULL); + if(!pog) + { + break; + } + pog->pog_Device = pd; + if(pog->pog_ShowMe && (!pog->pog_WaitBinding)) + { + po->po_OpenRequest = TRUE; + } + } + break; + } + + case EHMB_DEVICEDEAD: + case EHMB_DEVICELOWPW: + { + BOOL lowpower = FALSE; + BOOL isdead = FALSE; + BOOL autodis = FALSE; + STRPTR body; + STRPTR devname; + STRPTR gads[4] = { NULL, NULL, NULL, "Ignore" }; + STRPTR autodismsg = ""; + + pd = (struct PsdDevice *) pen->pen_Param1; + if(!pIsDeviceStillValid(ps, pd)) + { + break; + } + lowpower = pd->pd_Flags & PDFF_LOWPOWER; + isdead = pd->pd_Flags & PDFF_DEAD; + if(!(lowpower || isdead)) + { + break; + } + if((ps->ps_GlobalCfg->pgc_AutoDisableLP && lowpower) || + (ps->ps_GlobalCfg->pgc_AutoDisableDead && isdead) || + (ps->ps_GlobalCfg->pgc_AutoRestartDead && isdead)) + { + struct Library *UsbClsBase; + struct PsdDevice *hubpd = pd->pd_Hub; + Forbid(); + if(hubpd->pd_DevBinding) + { + UsbClsBase = hubpd->pd_ClsBinding->puc_ClassBase; + if(pIsClassStillValid(ps, UsbClsBase)) + { + if(ps->ps_GlobalCfg->pgc_AutoRestartDead && isdead) + { + usbDoMethod((ULONG) UCM_HubPowerCyclePort, hubpd, pd->pd_HubPort); + psdAddErrorMsg(RETURN_WARN, ps->ps_Library.lib_Node.ln_Name, + "Automatically powercycling port for '%s' due death event.", + pd->pd_ProductStr); + autodismsg = "\n\n\33bAutomatically powercycling port!\33n"; + } else { + usbDoMethod((ULONG) UCM_HubDisablePort, hubpd, pd->pd_HubPort); + psdAddErrorMsg(RETURN_WARN, ps->ps_Library.lib_Node.ln_Name, + "Automatically disabling port for '%s' due lowpower/death event.", + pd->pd_ProductStr); + autodismsg = "\n\n\33bAutomatically disabling port!\33n"; + } + autodis = TRUE; + } + } + Permit(); + } + if(pd->pd_PoPoCfg.poc_InhibitPopup) + { + break; + } + + remsound = TRUE; + if((ps->ps_GlobalCfg->pgc_PopupDeviceNew < PGCP_ERROR) && (!ps->ps_GlobalCfg->pgc_PopupDeviceDeath)) + { + break; + } + + pRemoveOldBox(ps, pd); + gads[0] = "Disable Port"; + devname = pd->pd_ProductStr; + if(!devname) + { + devname = "Unknown Soldier"; + } + if(lowpower && isdead) + { + body = psdCopyStrFmt("\33bWARNING: Detected LOW POWER situation\33n\n\nfor USB device\n\n\33b%s\33n\n\nand it has \33bdropped dead already\33n!%s", devname, autodismsg); + } + else if(lowpower) + { + body = psdCopyStrFmt("\33bWARNING: Detected LOW POWER situation\33n\n\nfor USB device\n\n\33b%s\33n\n\nand this might cause failures!%s", devname, autodismsg); + } else { + body = psdCopyStrFmt("\33bWARNING: DEAD DEVICE!\33n\n\nUSB device\n\n\33b%s\33n\n\ndropped dead for no apparent reason!%s", devname, autodismsg); + gads[1] = "Powercycle Port"; + } + pog = pAllocPoPoGadgets(ps, body, gads); + psdFreeVec(body); + if(!pog) + { + break; + } + + if(autodis) + { + set(pog->pog_GadgetObj[0], MUIA_Disabled, TRUE); + pog->pog_Device = NULL; // to keep the message on the screen + } else { + pog->pog_Device = pd; + } + DoMethod(pog->pog_GadgetObj[0], MUIM_Notify, MUIA_Pressed, FALSE, + po->po_AppObj, 5, MUIM_Application_PushMethod, po->po_PoPoObj, 2, MUIM_PoPo_DisablePort, pog); + if(gads[1]) + { + DoMethod(pog->pog_GadgetObj[1], MUIM_Notify, MUIA_Pressed, FALSE, + po->po_AppObj, 5, MUIM_Application_PushMethod, po->po_PoPoObj, 2, MUIM_PoPo_PowerCyclePort, pog); + } + DoMethod(pog->pog_GadgetObj[3], MUIM_Notify, MUIA_Pressed, FALSE, + po->po_AppObj, 5, MUIM_Application_PushMethod, po->po_PoPoObj, 2, MUIM_PoPo_RemInfo, pog); + po->po_OpenRequest = TRUE; + break; + } + + case EHMB_REMDEVICE: + { + pd = (struct PsdDevice *) pen->pen_Param1; + pRemoveOldBox(ps, pd); + if(pd->pd_PoPoCfg.poc_InhibitPopup) + { + break; + } + remsound = TRUE; + if(!ps->ps_GlobalCfg->pgc_PopupDeviceGone) + { + break; + } + if(pd->pd_ProductStr) + { + body = psdCopyStrFmt("The USB device\n\n\33b%s\33n\n\nhas been removed!", pd->pd_ProductStr); + /* late free */ + //psdFreeVec(pd->pd_ProductStr); + //pd->pd_ProductStr = NULL; + } else { + body = psdCopyStr("An USB device has been removed,\nbut I cannot recall its name."); + } + if(body) + { + STRPTR gads[4] = { NULL, NULL, NULL, "Bye bye!" }; + pog = pAllocPoPoGadgets(ps, body, gads); + psdFreeVec(body); + if(!pog) + { + break; + } + DoMethod(pog->pog_GadgetObj[3], MUIM_Notify, MUIA_Pressed, FALSE, + po->po_AppObj, 5, MUIM_Application_PushMethod, po->po_PoPoObj, 2, MUIM_PoPo_RemInfo, pog); + po->po_OpenRequest = TRUE; + } + break; + } + + case EHMB_ADDBINDING: + case EHMB_REMBINDING: + { + pog = (struct PsdPoPoGadgets *) po->po_GadgetList.lh_Head; + while(pog->pog_Node.ln_Succ) + { + if(pog->pog_Device == (struct PsdDevice *) pen->pen_Param1) + { + if(!pIsDeviceStillValid(ps, pog->pog_Device)) + { + break; + } + if(pog->pog_Device->pd_PoPoCfg.poc_InhibitPopup) + { + break; + } + pGenerateAddBox(ps, pog->pog_Device, pog); + if(pog->pog_ShowMe) + { + po->po_OpenRequest = TRUE; + } + break; + } + pog = (struct PsdPoPoGadgets *) pog->pog_Node.ln_Succ; + } + break; + } + + case EHMB_CONFIGCHG: + if(!cfgchanged) + { + psdDelayMS(100); + cfgchanged = TRUE; + } + break; + + } + ReplyMsg(&pen->pen_Msg); + } + psdUnlockPBase(); + if(addsound) + { + if(po->po_InsertSndFile) + { + if(*po->po_InsertSndFile) + { + pPoPoPlaySound(ps, po->po_InsertSndFile); + } + } + } + if(remsound) + { + if(po->po_RemoveSndFile) + { + if(*po->po_RemoveSndFile) + { + pPoPoPlaySound(ps, po->po_RemoveSndFile); + } + } + } + if(cfgchanged) + { + set(po->po_SaveObj, MUIA_Disabled, (ps->ps_SavedConfigHash == ps->ps_ConfigHash)); + } +} +/* \\\ */ + +/* /// "pBindingsString()" */ +STRPTR pBindingsString(LIBBASETYPEPTR ps, struct PsdDevice *pd) +{ + STRPTR oldstr = NULL; + STRPTR newstr = NULL; + struct PsdConfig *pc; + struct PsdInterface *pif; + + if(pd->pd_DevBinding) + { + if(pd->pd_Flags & PDFF_APPBINDING) + { + return(psdCopyStr(((struct PsdAppBinding *) pd->pd_DevBinding)->pab_Task->tc_Node.ln_Name)); + } else { + return(psdCopyStr(pd->pd_ClsBinding->puc_ClassBase->lib_Node.ln_Name)); + } + } else { + pc = (struct PsdConfig *) pd->pd_Configs.lh_Head; + while(pc->pc_Node.ln_Succ) + { + pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head; + while(pif->pif_Node.ln_Succ) + { + if(pif->pif_IfBinding) + { + if(oldstr) + { + newstr = psdCopyStrFmt("%s, %s", oldstr, pif->pif_ClsBinding->puc_ClassBase->lib_Node.ln_Name); + psdFreeVec(oldstr), + oldstr = newstr; + } else { + oldstr = psdCopyStr(pif->pif_ClsBinding->puc_ClassBase->lib_Node.ln_Name); + } + } + pif = (struct PsdInterface *) pif->pif_Node.ln_Succ; + } + pc = (struct PsdConfig *) pc->pc_Node.ln_Succ; + } + } + return(oldstr); +} +/* \\\ */ + +/* /// "pCheckConfigurable()" */ +ULONG pCheckConfigurable(LIBBASETYPEPTR ps, struct PsdDevice *pd) +{ + ULONG hasclassgui; + ULONG hasbindinggui; + ULONG noconfig; + struct PsdConfig *pc; + struct PsdInterface *pif; + struct Library *UsbClsBase; + ULONG result = 0; + + psdLockReadPBase(); + if(pd->pd_DevBinding) + { + if(!(pd->pd_Flags & PDFF_APPBINDING)) + { + UsbClsBase = pd->pd_ClsBinding->puc_ClassBase; + noconfig = FALSE; + hasclassgui = FALSE; + hasbindinggui = FALSE; + if(pIsClassStillValid(ps, UsbClsBase)) + { + usbGetAttrs(UGA_CLASS, NULL, + UCCA_HasClassCfgGUI, (ULONG) &hasclassgui, + UCCA_HasBindingCfgGUI, (ULONG) &hasbindinggui, + UCCA_UsingDefaultCfg, (ULONG) &noconfig, + TAG_END); + result |= PPF_HasBinding; + if(hasclassgui) + { + result |= PPF_HasClassGUI; + if(!noconfig) + { + result |= PPF_HasClsConfig; + } + } + if(hasbindinggui) + { + result |= PPF_HasBindingGUI; + usbGetAttrs(UGA_BINDING, pd->pd_DevBinding, + UCBA_UsingDefaultCfg, (ULONG) &noconfig, + TAG_END); + if(!noconfig) + { + result |= PPF_HasBindConfig; + } + } + } + } + } else { + pc = (struct PsdConfig *) pd->pd_Configs.lh_Head; + while(pc->pc_Node.ln_Succ) + { + pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head; + while(pif->pif_Node.ln_Succ) + { + if(pif->pif_IfBinding) + { + UsbClsBase = pif->pif_ClsBinding->puc_ClassBase; + noconfig = FALSE; + hasclassgui = FALSE; + hasbindinggui = FALSE; + if(pIsClassStillValid(ps, UsbClsBase)) + { + usbGetAttrs(UGA_CLASS, NULL, + UCCA_HasClassCfgGUI, (ULONG) &hasclassgui, + UCCA_HasBindingCfgGUI, (ULONG) &hasbindinggui, + UCCA_UsingDefaultCfg, (ULONG) &noconfig, + TAG_END); + result |= PPF_HasBinding; + if(hasclassgui) + { + result |= PPF_HasClassGUI; + if(!noconfig) + { + result |= PPF_HasClsConfig; + } + } + if(hasbindinggui) + { + result |= PPF_HasBindingGUI; + usbGetAttrs(UGA_BINDING, pif->pif_IfBinding, + UCBA_UsingDefaultCfg, (ULONG) &noconfig, + TAG_END); + if(!noconfig) + { + result |= PPF_HasBindConfig; + } + } + } + } + pif = (struct PsdInterface *) pif->pif_Node.ln_Succ; + } + pc = (struct PsdConfig *) pc->pc_Node.ln_Succ; + } + } + psdUnlockPBase(); + return(result); +} +/* \\\ */ + +/* /// "pOpenBindingsConfigGUI()" */ +void pOpenBindingsConfigGUI(LIBBASETYPEPTR ps, struct PsdDevice *pd) +{ + struct PsdConfig *pc; + struct PsdInterface *pif; + struct Library *UsbClsBase; + ULONG hascfggui; + psdLockReadPBase(); + if(!pIsDeviceStillValid(ps, pd)) + { + psdUnlockPBase(); + return; + } + if(pd->pd_DevBinding) + { + if(!(pd->pd_Flags & PDFF_APPBINDING)) + { + UsbClsBase = pd->pd_ClsBinding->puc_ClassBase; + if(pIsClassStillValid(ps, UsbClsBase)) + { + usbGetAttrs(UGA_CLASS, NULL, + UCCA_HasBindingCfgGUI, &hascfggui, + TAG_END); + if(hascfggui) + { + usbDoMethod(UCM_OpenBindingCfgWindow, pd->pd_DevBinding); + } + } + } + } else { + pc = (struct PsdConfig *) pd->pd_Configs.lh_Head; + while(pc->pc_Node.ln_Succ) + { + pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head; + while(pif->pif_Node.ln_Succ) + { + if(pif->pif_IfBinding) + { + UsbClsBase = pif->pif_ClsBinding->puc_ClassBase; + if(pIsClassStillValid(ps, UsbClsBase)) + { + usbGetAttrs(UGA_CLASS, NULL, + UCCA_HasBindingCfgGUI, &hascfggui, + TAG_END); + if(hascfggui) + { + usbDoMethod(UCM_OpenBindingCfgWindow, pif->pif_IfBinding); + } + } + } + pif = (struct PsdInterface *) pif->pif_Node.ln_Succ; + } + pc = (struct PsdConfig *) pc->pc_Node.ln_Succ; + } + } + psdUnlockPBase(); +} +/* \\\ */ + +/* /// "pOpenClassesConfigGUI()" */ +void pOpenClassesConfigGUI(LIBBASETYPEPTR ps, struct PsdDevice *pd) +{ + struct PsdConfig *pc; + struct PsdInterface *pif; + struct Library *UsbClsBase; + ULONG hascfggui; + + psdLockReadPBase(); + if(!pIsDeviceStillValid(ps, pd)) + { + psdUnlockPBase(); + return; + } + + if(pd->pd_DevBinding) + { + if(!(pd->pd_Flags & PDFF_APPBINDING)) + { + UsbClsBase = pd->pd_ClsBinding->puc_ClassBase; + if(pIsClassStillValid(ps, UsbClsBase)) + { + usbGetAttrs(UGA_CLASS, NULL, + UCCA_HasClassCfgGUI, &hascfggui, + TAG_END); + if(hascfggui) + { + usbDoMethod(UCM_OpenCfgWindow); + } + } + } + } else { + pc = (struct PsdConfig *) pd->pd_Configs.lh_Head; + while(pc->pc_Node.ln_Succ) + { + pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head; + while(pif->pif_Node.ln_Succ) + { + if(pif->pif_IfBinding) + { + UsbClsBase = pif->pif_ClsBinding->puc_ClassBase; + if(pIsClassStillValid(ps, UsbClsBase)) + { + usbGetAttrs(UGA_CLASS, NULL, + UCCA_HasClassCfgGUI, &hascfggui, + TAG_END); + if(hascfggui) + { + usbDoMethod(UCM_OpenCfgWindow); + } + } + } + pif = (struct PsdInterface *) pif->pif_Node.ln_Succ; + } + pc = (struct PsdConfig *) pc->pc_Node.ln_Succ; + } + } + psdUnlockPBase(); +} +/* \\\ */ + +/* /// "pDisableDevicePopup()" */ +void pDisableDevicePopup(LIBBASETYPEPTR ps, struct PsdDevice *pd) +{ + if(!pIsDeviceStillValid(ps, pd)) + { + return; + } + psdSetAttrs(PGA_DEVICE, pd, DA_InhibitPopup, TRUE, TAG_END); +} +/* \\\ */ + +/* /// "pAllocPoPoGadgets()" */ +struct PsdPoPoGadgets * pAllocPoPoGadgets(LIBBASETYPEPTR ps, STRPTR body, STRPTR *gad) +{ + struct PsdPoPo *po = &ps->ps_PoPo; + struct PsdPoPoGadgets *pog; + Object *hgrp; + if((pog = (struct PsdPoPoGadgets *) psdAllocVec(sizeof(struct PsdPoPoGadgets)))) + { + pog->pog_GroupObj = + VGroup, + Child, pog->pog_BodyObj = TextObject, + MUIA_Frame, MUIV_Frame_Text, + MUIA_Background, MUII_TextBack, + MUIA_Text_PreParse, "\33c", + MUIA_Text_Contents, body, + End, + Child, hgrp = HGroup, + MUIA_Group_SameWidth, TRUE, + Child, pog->pog_GadgetObj[0] = TextObject, ButtonFrame, + MUIA_Background, MUII_ButtonBack, + MUIA_CycleChain, 1, + MUIA_InputMode, MUIV_InputMode_RelVerify, + MUIA_Text_PreParse, "\33c", + MUIA_Text_Contents, gad[0] ? gad[0] : (STRPTR) "", + MUIA_ShowMe, gad[0], + End, + Child, pog->pog_GadgetObj[1] = TextObject, ButtonFrame, + MUIA_Background, MUII_ButtonBack, + MUIA_CycleChain, 1, + MUIA_InputMode, MUIV_InputMode_RelVerify, + MUIA_Text_PreParse, "\33c", + MUIA_Text_Contents, gad[1] ? gad[1] : (STRPTR) "", + MUIA_ShowMe, gad[1], + End, + Child, pog->pog_GadgetObj[2] = TextObject, ButtonFrame, + MUIA_Background, MUII_ButtonBack, + MUIA_CycleChain, 1, + MUIA_InputMode, MUIV_InputMode_RelVerify, + MUIA_Text_PreParse, "\33c", + MUIA_Text_Contents, gad[2] ? gad[2] : (STRPTR) "", + MUIA_ShowMe, gad[2], + End, + Child, pog->pog_GadgetObj[3] = TextObject, ButtonFrame, + MUIA_Background, MUII_ButtonBack, + MUIA_CycleChain, 1, + MUIA_InputMode, MUIV_InputMode_RelVerify, + MUIA_Text_PreParse, "\33c", + MUIA_Text_Contents, gad[3] ? gad[3] : (STRPTR) "", + MUIA_ShowMe, gad[3], + End, + End, + //Child, VSpace(0), + Child, BalanceObject, + End, + //Child, VSpace(0), + End; + + if(!pog->pog_GroupObj) + { + psdFreeVec(pog); + return(NULL); + } + DoMethod(po->po_GroupObj, MUIM_Group_InitChange); + DoMethod(po->po_GroupObj, OM_ADDMEMBER, pog->pog_GroupObj); + DoMethod(po->po_GroupObj, MUIM_Group_ExitChange); + AddTail(&po->po_GadgetList, &pog->pog_Node); + CurrentTime(&pog->pog_TimeoutTime.tv_secs, &pog->pog_TimeoutTime.tv_micro); + if(ps->ps_GlobalCfg->pgc_PopupCloseDelay && (!po->po_Sticky)) + { + pog->pog_TimeoutTime.tv_secs += ps->ps_GlobalCfg->pgc_PopupCloseDelay; + } else { + pog->pog_TimeoutTime.tv_secs += 60*60*24; + } + } + return(pog); +} +/* \\\ */ + +/* /// "pFreePoPoGadgets()" */ +void pFreePoPoGadgets(LIBBASETYPEPTR ps, struct PsdPoPoGadgets *pog) +{ + struct PsdPoPo *po = &ps->ps_PoPo; + Remove(&pog->pog_Node); + DoMethod(po->po_GroupObj, MUIM_Group_InitChange); + DoMethod(po->po_GroupObj, OM_REMMEMBER, pog->pog_GroupObj); + DoMethod(po->po_GroupObj, MUIM_Group_ExitChange); + MUI_DisposeObject(pog->pog_GroupObj); + psdFreeVec(pog); +} +/* \\\ */ + +/* /// "PoPoDispatcher()" */ +AROS_UFH3(ULONG, PoPoDispatcher, + AROS_UFHA(struct IClass *, cl, A0), + AROS_UFHA(Object *, obj, A2), + AROS_UFHA(Msg, msg, A1)) +{ + AROS_USERFUNC_INIT + // There should never be an uninitialized pointer, but just in case, try to get an mungwall hit if so. + struct PoPoData *data = (struct PoPoData *) 0xABADCAFE; + struct PsdPoPoGadgets *pog; + struct PsdPoPoGadgets *tmppog; + LIBBASETYPEPTR ps = (LIBBASETYPEPTR) cl->cl_UserData; + struct PsdPoPo *po = &ps->ps_PoPo; + ULONG sticky = 0; + + // on OM_NEW the obj pointer will be void, so don't try to get the data base in this case. + if(msg->MethodID != OM_NEW) + { + data = INST_DATA(cl, obj); + } + switch(msg->MethodID) + { + case OM_NEW: + if(!(obj = (Object *)DoSuperMethodA(cl,obj,msg))) + return(0); + return((ULONG)obj); + + case MUIM_PoPo_SavePrefs: + psdSaveCfgToDisk(NULL, FALSE); + set(po->po_SaveObj, MUIA_Disabled, (ps->ps_SavedConfigHash == ps->ps_ConfigHash)); + return(0); + + case MUIM_PoPo_Sticky: + get(po->po_StickyObj, MUIA_Selected, &sticky); + po->po_Sticky = sticky; + pog = (struct PsdPoPoGadgets *) po->po_GadgetList.lh_Head; + while(pog->pog_Node.ln_Succ) + { + CurrentTime(&pog->pog_TimeoutTime.tv_secs, &pog->pog_TimeoutTime.tv_micro); + if(ps->ps_GlobalCfg->pgc_PopupCloseDelay && (!po->po_Sticky)) + { + pog->pog_TimeoutTime.tv_secs += ps->ps_GlobalCfg->pgc_PopupCloseDelay; + } else { + pog->pog_TimeoutTime.tv_secs += 60*60*24; + } + pog = (struct PsdPoPoGadgets *) pog->pog_Node.ln_Succ; + } + return(0); + + case MUIM_PoPo_ConfigureBinding: + pog = (struct PsdPoPoGadgets *) ((ULONG *) msg)[1]; + //KPRINTF(20, ("Config Po=%08lx, Pog=%08lx, PS=%08lx\n", po, pog, ps)); + pog->pog_TimeoutTime.tv_secs += 60*60*24; + pOpenBindingsConfigGUI(ps, pog->pog_Device); + return(0); + + case MUIM_PoPo_ConfigureClass: + pog = (struct PsdPoPoGadgets *) ((ULONG *) msg)[1]; + //KPRINTF(20, ("Config Po=%08lx, Pog=%08lx, PS=%08lx\n", po, pog, ps)); + pog->pog_TimeoutTime.tv_secs += 60*60*24; + pOpenClassesConfigGUI(ps, pog->pog_Device); + return(0); + + case MUIM_PoPo_ShutUp: + pog = (struct PsdPoPoGadgets *) ((ULONG *) msg)[1]; + pDisableDevicePopup(ps, pog->pog_Device); + pRemoveOldBox(ps, pog->pog_Device); + return(0); + + case MUIM_PoPo_RemInfo: + pog = (struct PsdPoPoGadgets *) ((ULONG *) msg)[1]; + //KPRINTF(20, ("RemInfo Po=%08lx, Pog=%08lx, PS=%08lx\n", po, pog, ps)); + tmppog = (struct PsdPoPoGadgets *) po->po_GadgetList.lh_Head; + while(tmppog->pog_Node.ln_Succ) + { + if(tmppog == pog) + { + pFreePoPoGadgets(ps, pog); + break; + } + tmppog = (struct PsdPoPoGadgets *) tmppog->pog_Node.ln_Succ; + } + return(0); + + case MUIM_PoPo_DisablePort: + case MUIM_PoPo_PowerCyclePort: + { + struct PsdDevice *pd; + struct Library *UsbClsBase; + BOOL disable = (msg->MethodID == MUIM_PoPo_DisablePort); + + pog = (struct PsdPoPoGadgets *) ((ULONG *) msg)[1]; + pd = pog->pog_Device; + set(pog->pog_GadgetObj[0], MUIA_Disabled, TRUE); + if(pog->pog_GadgetObj[1] && (!disable)) + { + set(pog->pog_GadgetObj[1], MUIA_Disabled, TRUE); + } + Forbid(); + if(pIsDeviceStillValid(ps, pd)) + { + struct PsdDevice *hubpd = pd->pd_Hub; + if(hubpd->pd_DevBinding) + { + UsbClsBase = hubpd->pd_ClsBinding->puc_ClassBase; + if(pIsClassStillValid(ps, UsbClsBase)) + { + usbDoMethod((ULONG) (disable ? UCM_HubDisablePort : UCM_HubPowerCyclePort), hubpd, pd->pd_HubPort); + } + } + } + Permit(); + pog->pog_TimeoutTime.tv_secs += 60*60*24; + + return(0); + } + + case MUIM_PoPo_About: + MUI_RequestA(po->po_AppObj, po->po_WindowObj, 0, NULL, "Blimey!", "PoPo -- The Poseidon Popup Provider\n\nWritten by Chris Hodges.\n\nWichtig ist, was hinten rauskommt (Helmut Kohl).", NULL); + return(0); + + case MUIM_PoPo_OpenTrident: + { + struct Library *DOSBase; + if((DOSBase = OpenLibrary("dos.library", 39))) + { + BPTR fhandle; + if((fhandle = Open("NIL:", MODE_READWRITE))) + { + if(SystemTags("Trident", + NP_StackSize, 32*1024, + SYS_Input, fhandle, + SYS_Output, NULL, + SYS_Asynch, TRUE, + TAG_END)) + { + Close(fhandle); + MUI_RequestA(po->po_AppObj, po->po_WindowObj, 0, NULL, "Oh no!", "Bugger!\n\nI tried hard to load Trident,\nbut there was Cryptonite somewhere!", NULL); + } + } + CloseLibrary(DOSBase); + } + return(0); + } + } + return(DoSuperMethodA(cl,obj,msg)); + AROS_USERFUNC_EXIT +} +/* \\\ */ diff --git a/rom/usb/poseidon/popo.gui.h b/rom/usb/poseidon/popo.gui.h new file mode 100644 index 000000000..b37fd7ff3 --- /dev/null +++ b/rom/usb/poseidon/popo.gui.h @@ -0,0 +1,60 @@ +#ifndef POPOGUI_H +#define POPOGUI_H POPOGUI_H + +struct PoPoData +{ + BOOL nix; +}; + +struct PsdPoPoGadgets +{ + struct Node pog_Node; /* Linkage */ + struct PsdDevice *pog_Device; /* Linkage to the device used */ + ULONG *pog_GroupObj; /* Group object to link */ + ULONG *pog_BodyObj; /* Text body */ + ULONG *pog_GadgetObj[4]; /* gadgets */ + struct timeval pog_TimeoutTime; /* time at which the thing destroys itself */ + BOOL pog_ShowMe; /* popup window? */ + BOOL pog_WaitBinding; /* wait for class scan finished before popping up */ +}; + +struct PsdPoPoSound +{ + struct Node pps_Node; /* Linkage */ + ULONG *pps_DTHandle; /* Handle to DataType object */ +}; + +void pPoPoGUITaskCleanup(struct PsdBase *ps); +void pEventHandler(struct PsdBase *ps); +void pFreePoPoGadgets(struct PsdBase *ps, struct PsdPoPoGadgets *pog); +struct PsdPoPoGadgets * pAllocPoPoGadgets(struct PsdBase *ps, STRPTR body, STRPTR *gad); +STRPTR pBindingsString(struct PsdBase *ps, struct PsdDevice *pd); +ULONG pCheckConfigurable(struct PsdBase *ps, struct PsdDevice *pd); +struct PsdPoPoSound * pPoPoLoadSound(struct PsdBase *ps, STRPTR name); +BOOL pPoPoPlaySound(struct PsdBase *ps, STRPTR name); +void pPoPoFreeSound(struct PsdBase *ps, struct PsdPoPoSound *pps); + +#define PPF_HasBinding 0x0001 +#define PPF_HasClassGUI 0x0010 +#define PPF_HasClsConfig 0x0020 +#define PPF_HasBindingGUI 0x0100 +#define PPF_HasBindConfig 0x0200 + +#define TAGBASE_PoPo (TAG_USER | 29<<16) +#define MUIM_PoPo_RemInfo (TAGBASE_PoPo | 0x0010) +#define MUIM_PoPo_ConfigureClass (TAGBASE_PoPo | 0x0011) +#define MUIM_PoPo_ConfigureBinding (TAGBASE_PoPo | 0x0012) +#define MUIM_PoPo_ShutUp (TAGBASE_PoPo | 0x0013) +#define MUIM_PoPo_DisablePort (TAGBASE_PoPo | 0x0014) +#define MUIM_PoPo_PowerCyclePort (TAGBASE_PoPo | 0x0015) +#define MUIM_PoPo_Sticky (TAGBASE_PoPo | 0x0020) +#define MUIM_PoPo_SavePrefs (TAGBASE_PoPo | 0x0021) +#define MUIM_PoPo_About (TAGBASE_PoPo | 0x0030) +#define MUIM_PoPo_OpenTrident (TAGBASE_PoPo | 0x0031) + +AROS_UFP3(ULONG, PoPoDispatcher, + AROS_UFPA(struct IClass *, cl, A0), + AROS_UFPA(Object *, obj, A2), + AROS_UFPA(Msg, msg, A1)); + +#endif // POPOGUI_H diff --git a/rom/usb/poseidon/poseidon.conf b/rom/usb/poseidon/poseidon.conf new file mode 100644 index 000000000..92884cf23 --- /dev/null +++ b/rom/usb/poseidon/poseidon.conf @@ -0,0 +1,141 @@ +##begin config +version 4.3 +libbase ps +libbasetype struct PsdBase +libbasetypeextern struct Library +residentpri 48 +basename psd +copyright Copyright 2002-2009 Chris Hodges +##end config + +##begin cdef +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +LONG psdGetAttrs(ULONG type, APTR psdstruct, Tag tag1, ...) __stackparm; +LONG psdSetAttrs(ULONG type, APTR psdstruct, Tag tag1, ...) __stackparm; +APTR psdAddErrorMsg(UWORD level, STRPTR origin, STRPTR fmtstr, IPTR *fmt1, ...) __stackparm; +VOID psdSafeRawDoFmt(STRPTR buf, ULONG len, STRPTR fmtstr, IPTR *fmt1, ...) __stackparm; +APTR psdFindDevice(APTR pd, Tag tag1, ...) __stackparm; +APTR psdClaimAppBinding(Tag tag1, ...) __stackparm; +APTR psdFindInterface(APTR pd, APTR pif, Tag tag1, ...) __stackparm; +APTR psdFindEndpoint(APTR pif, APTR pep, Tag tag1, ...) __stackparm; +STRPTR psdCopyStrFmt(STRPTR fmtstr, IPTR *fmt1, ...) __stackparm; +APTR psdOpenStream(APTR pep, Tag tag1, ...) __stackparm; +APTR psdHubClaimAppBinding(Tag tag1, ...) __stackparm; +APTR psdFindDescriptor(APTR pd, APTR pdd, Tag tag1, ...) __stackparm; +IPTR psdDoHubMethod(APTR pd, ULONG methodid, IPTR *methoddata1) __stackparm; +APTR psdAllocRTIsoHandler(APTR pep, Tag tag1, ...) __stackparm; +##end cdef + +##begin cdefprivate +#include "poseidon_intern.h" +##end cdefprivate + +##begin functionlist +APTR psdAllocVec(ULONG size) (D0) +VOID psdFreeVec(APTR memptr) (A1) +VOID psdLockWritePBase() () +VOID psdLockReadPBase() () +VOID psdUnlockPBase() () +STRPTR psdCopyStr(STRPTR name) (A0) +VOID psdDelayMS(ULONG milli) (D0) +APTR psdAddHardware(STRPTR name, ULONG unit) (A0,D0) +VOID psdRemHardware(APTR phw) (A0) +APTR psdEnumerateHardware(APTR phw) (A0) +APTR psdAllocDevice(APTR phw) (A0) +VOID psdFreeDevice(APTR pd) (A0) +VOID psdLockReadDevice(APTR pd) (A0) +VOID psdLockWriteDevice(APTR pd) (A0) +VOID psdUnlockDevice(APTR pd) (A0) +APTR psdEnumerateDevice(APTR pp) (A1) +APTR psdGetNextDevice(APTR pd) (A0) +LONG psdGetAttrsA(ULONG type, APTR psdstruct, struct TagItem *taglist) (D0,A0,A1) +LONG psdSetAttrsA(ULONG type, APTR psdstruct, struct TagItem *taglist) (D0,A0,A1) +APTR psdAllocPipe(APTR pd, struct MsgPort *mp, APTR pep) (A0,A1,A2) +APTR psdFreePipe(APTR pp) (A1) +VOID psdPipeSetup(APTR pp, UWORD rt, UWORD rq, UWORD val, UWORD idx) (A1,D0,D1,D2,D3) +LONG psdDoPipe(APTR pp, APTR data, ULONG len) (A1,A0,D0) +VOID psdSendPipe(APTR pp, APTR data, ULONG len) (A1,A0,D0) +VOID psdAbortPipe(APTR pp) (A1) +LONG psdWaitPipe(APTR pp) (A1) +ULONG psdGetPipeActual(APTR pp) (A1) +LONG psdGetPipeError(APTR pp) (A1) +STRPTR psdGetStringDescriptor(APTR pp, UWORD idx) (A1,D0) +BOOL psdSetDeviceConfig(APTR pp, UWORD cfgnum) (A1,D0) +APTR psdAddClass(STRPTR name, ULONG version) (A1,D0) +VOID psdRemClass(APTR puc) (A1) +VOID psdClassScan() () +STRPTR psdNumToStr(UWORD type, LONG idx, STRPTR defstr) (D0,D1,A0) +struct Task * psdSpawnSubTask(STRPTR name, APTR initpc, APTR userdata) (A0,A1,A2) +APTR psdAddErrorMsgA(UWORD level, STRPTR origin, STRPTR fmtstr, IPTR *fmtdata) (D0,A0,A1,A2) +VOID psdRemErrorMsg(APTR pem) (A0) +VOID psdSafeRawDoFmtA(STRPTR buf, ULONG len, STRPTR fmtstr, IPTR *fmtdata) (A0,D0,A1,A2) +BOOL psdSetAltInterface(APTR pp, APTR pif) (A1,A0) +APTR psdFindDeviceA(APTR pd, struct TagItem *taglist) (A0,A1) +APTR psdClaimAppBindingA(struct TagItem *taglist) (A1) +APTR psdReleaseAppBinding(APTR pab) (A0) +APTR psdAddEventHandler(struct MsgPort *mp, ULONG msgmask) (A1,D0) +VOID psdRemEventHandler(APTR peh) (A0) +VOID psdSendEvent(ULONG ehmt, APTR param1, APTR param2) (D0,A0,A1) +VOID psdReleaseDevBinding(APTR pd) (A0) +VOID psdReleaseIfBinding(APTR pif) (A0) +BOOL psdReadCfg(APTR pic, APTR formdata) (A0,A1) +APTR psdWriteCfg(APTR pic) (A0) +APTR psdFindCfgForm(APTR pic, ULONG formid) (A0,D0) +APTR psdNextCfgForm(APTR pic) (A0) +BOOL psdRemCfgForm(APTR pic) (A0) +APTR psdAddCfgEntry(APTR pic, APTR formdata) (A0,A1) +BOOL psdRemCfgChunk(APTR pic, ULONG chnkid) (A0,D0) +APTR psdGetCfgChunk(APTR pic, ULONG chnkid) (A0,D0) +VOID psdParseCfg() () +VOID psdUnbindAll() () +BOOL psdSetClsCfg(STRPTR owner, APTR form) (A0,A1) +APTR psdGetClsCfg(STRPTR owner) (A0) +BOOL psdSetUsbDevCfg(STRPTR owner, STRPTR devid, STRPTR ifid, APTR form) (A0,A2,A3,A1) +APTR psdGetUsbDevCfg(STRPTR owner, STRPTR devid, STRPTR ifid) (A0,A2,A3) +APTR psdFindInterfaceA(APTR pd, APTR pif, struct TagItem *taglist) (A0,A2,A1) +APTR psdFindEndpointA(APTR pif, APTR pep, struct TagItem *taglist) (A0,A2,A1) +STRPTR psdCopyStrFmtA(STRPTR fmtstr, IPTR *fmtdata) (A0,A1) +BOOL psdSetForcedBinding(STRPTR owner, STRPTR devid, STRPTR ifid) (A2,A0,A1) +STRPTR psdGetForcedBinding(STRPTR devid, STRPTR ifid) (A0,A1) +APTR psdCheckPipe(APTR pp) (A1) +APTR psdOpenStreamA(APTR pep, struct TagItem *taglist) (A0,A1) +VOID psdCloseStream(APTR pps) (A1) +LONG psdStreamRead(APTR pps, APTR buffer, LONG length) (A1,A0,D0) +LONG psdStreamWrite(APTR pps, APTR buffer, LONG length) (A1,A0,D0) +LONG psdStreamFlush(APTR pps) (A1) +LONG psdGetStreamError(APTR pps) (A1) +VOID psdCalculatePower(APTR phw) (A0) +BOOL psdLoadCfgFromDisk(STRPTR filename) (A1) +BOOL psdSaveCfgToDisk(STRPTR filename, BOOL mode) (A1,D0) + +VOID psdHubClassScan(APTR pd) (A0) +APTR psdHubClaimAppBindingA(struct TagItem *taglist) (A1) +VOID psdHubReleaseDevBinding(APTR pd) (A0) +VOID psdHubReleaseIfBinding(APTR pif) (A0) +APTR psdAllocCfgForm(ULONG formid) (D0) +BOOL psdAddStringChunk(APTR pic, ULONG chunkid, STRPTR contents) (A0,D0,A1) +BOOL psdMatchStringChunk(APTR pic, ULONG chunkid, STRPTR contents) (A0,D0,A1) +STRPTR psdGetStringChunk(APTR pic, ULONG chunkid) (A0,D0) + +APTR psdFindDescriptorA(APTR pd, APTR pdd, struct TagItem *taglist) (A0,A2,A1) +IPTR psdDoHubMethodA(APTR pd, ULONG methodid, IPTR *methoddata) (A0,D0,A1) +APTR psdAllocRTIsoHandlerA(APTR pep, struct TagItem *taglist) (A0,A1) +VOID psdFreeRTIsoHandler(APTR prt) (A1) +LONG psdStartRTIso(APTR prt) (A1) +LONG psdStopRTIso(APTR prt) (A1) +ULONG psdBorrowLocksWait(struct Task *task, ULONG signals) (A1,D0) +BOOL psdSuspendDevice(APTR pd) (A0) +BOOL psdResumeDevice(APTR pd) (A0) +BOOL psdSuspendBindings(APTR pd) (A0) +BOOL psdResumeBindings(APTR pd) (A0) +##end functionlist diff --git a/rom/usb/poseidon/poseidon.doc b/rom/usb/poseidon/poseidon.doc new file mode 100644 index 000000000..d616c52e4 --- /dev/null +++ b/rom/usb/poseidon/poseidon.doc @@ -0,0 +1,2425 @@ +TABLE OF CONTENTS + +poseidon.library/--background-- +poseidon.library/psdAbortPipe +poseidon.library/psdAddClass +poseidon.library/psdAddErrorMsg +poseidon.library/psdAddHardware +poseidon.library/psdAllocDevice +poseidon.library/psdAllocPipe +poseidon.library/psdAllocVec +poseidon.library/psdClaimAppBinding +poseidon.library/psdClassScan +poseidon.library/psdCopyStr +poseidon.library/psdDelayMS +poseidon.library/psdDoPipe +poseidon.library/psdEnumerateDevice +poseidon.library/psdEnumerateHardware +poseidon.library/psdFindDevice +poseidon.library/psdFreeDevice +poseidon.library/psdFreePipe +poseidon.library/psdFreeVec +poseidon.library/psdGetAttrs +poseidon.library/psdGetNextDevice +poseidon.library/psdGetPipeActual +poseidon.library/psdGetPipeError +poseidon.library/psdGetStringDescriptor +poseidon.library/psdLockReadDevice +poseidon.library/psdLockReadPBase +poseidon.library/psdLockWriteDevice +poseidon.library/psdLockWritePBase +poseidon.library/psdNumToStr +poseidon.library/psdPipeSetup +poseidon.library/psdReleaseAppBinding +poseidon.library/psdRemClass +poseidon.library/psdRemErrorMsg +poseidon.library/psdRemHardware +poseidon.library/psdSafeRawDoFmt +poseidon.library/psdSendPipe +poseidon.library/psdSetAltInterface +poseidon.library/psdSetAttrs +poseidon.library/psdSetDeviceConfig +poseidon.library/psdSpawnSubTask +poseidon.library/psdUnlockDevice +poseidon.library/psdUnlockPBase +poseidon.library/psdWaitPipe + +Need to be added: +psdAddEventHandler +psdRemEventHandler +psdSendEvent + +psdReleaseDevBinding +psdReleaseIfBinding + +psdReadCfg +psdWriteCfg +psdFindCfgForm +psdNextCfgForm +psdRemCfgForm + +psdAddCfgEntry +psdRemCfgChunk +psdGetCfgChunk +psdParseCfg +psdUnbindAll + +psdSetClsCfg +psdGetClsCfg +psdSetUsbDevCfg +psdGetUsbDevCfg + +psdFindInterface +psdFindEndpoint +psdCopyStrFmt +psdSetForcedBinding +psdGetForcedBinding + +psdCheckPipe + +/* V3 */ + +psdOpenStreamA +psdCloseStream +psdStreamRead +psdStreamWrite +psdStreamFlush +psdGetStreamError + +psdCalculatePower +psdLoadCfgFromDisk +psdSaveCfgToDisk + + + poseidon.library/psdReadCfg poseidon.library/psdReadCfg + + NAME + psdReadCfg -- read in a given form into an existing IFF context + + SYNOPSIS + success = psdReadCfg(pic, form); + D0 A0 A1 + + BOOL psdReadCfg(APTR, APTR); + + FUNCTION + Stores the given IFF form in the internal prefs structure at the + given Poseidon IFF context. + + The data given in the form must be of the same type (same ID) as the + IFF context, otherwise this function will fail. + + It will replace the previous contents of the form completely with + the new one. + + The pic parameter points to an internal Poseidon IFF context + structure. If pic is set to NULL, the root context is used. + + This function is considered to be semi-private, use with care. + + INPUTS + pic - pointer to a Poseidon IFF context structure or NULL for the + root context. This structure is private. + form - pointer to a valid IFF FORM. May not be NULL. + + RESULT + success - TRUE, if everything went okay, or FALSE, if there was + something wrong with the form. + + SEE ALSO + psdWriteCfg(), psdFindCfgForm(), psdRemCfgForm(), psdAddCfgEntry() + + + poseidon.library/psdWriteCfg poseidon.library/psdWriteCfg + + NAME + psdWriteCfg -- convert an IFF context into a serialized IFF form + + SYNOPSIS + form = psdWriteCfg(pic); + D0 A0 + + APTR psdWriteCfg(APTR); + + FUNCTION + psdWriteCfg() takes the given Poseidon IFF context and generates a + serialized IFF form out of it. The returned pointer is a buffer to + the IFF form data of the contexted given (including all subforms and + chunks). + + If the context is NULL, a complete configuration memory dump is + created, starting from the root context. The returned pointer then + contains the complete Poseidon prefs data. + + The buffer is allocated automatically and has to be freed using the + psdFreeVec() call after it is no longer required. + + The size of the buffer can be calculated by adding 8 to the second + longword (as it's a normal IFF structure). + + To read out a single chunk instead, use the psdGetCfgChunk() + function. + + INPUTS + pic - pointer to a Poseidon IFF context structure or NULL for the + root context. This structure is private. + + RESULT + form - pointer to the IFF FORM generated from the context or NULL, + if the function failed (e.g. out of memory). + + SEE ALSO + psdReadCfg(), psdFindCfgForm(), psdRemCfgForm(), psdAddCfgEntry(), + psdGetCfgChunk() + + + poseidon.library/psdFindCfgForm poseidon.library/psdFindCfgForm + + NAME + psdFindCfgForm -- search for a specific config form + + SYNOPSIS + subpic = psdFindCfgForm(pic, formid); + D0 A0 D0 + + APTR psdFindCfgForm(APTR, ULONG); + + FUNCTION + This function searches the internal configuration space given by the + Poseidon IFF context for a certain IFF FORM as given by the form ID. + + The result is a pointer to Poseidon IFF context representing the + form found, or NULL, if no such IFF FORM could be discovered. + + As there may be any number of IFF forms with the same ID, the + function psdNextCfgForm() can be used obtain any further forms with + the same ID. + + INPUTS + pic - pointer to a Poseidon IFF context structure or NULL for the + root context. This structure is private. + formid - longword containing the ID of the form to search. + + RESULT + subpic - pointer to the first Poseidon IFF context structure found, + or NULL, if no such form was found. + + SEE ALSO + psdNextCfgForm(), psdRemCfgForm(), psdGetCfgChunk() + + + poseidon.library/psdNextCfgForm poseidon.library/psdNextCfgForm + + NAME + psdNextCfgForm -- continue search for a specific config form + + SYNOPSIS + nextpic = psdNextCfgForm(pic); + D0 A0 + + APTR psdNextCfgForm(APTR); + + FUNCTION + psdNextCfgForm() searches for addition IFF FORMs within the same + parent Poseidon IFF context. + + The parameter pic given to psdNextCfgForm() should be the one + returned by psdFindCfgForm(). There is no need to supply the form ID + anymore, because the context already contains this. + + If another IFF form with the same ID is found, the Poseidon IFF + context pointer for it will be returned. Otherwise, nextpic will + contain NULL. + + INPUTS + pic - pointer to a Poseidon IFF context structure. + + RESULT + nextpic - pointer to the next Poseidon IFF context structure found, + or NULL, if no additional form could be retrieved. + + SEE ALSO + psdNextCfgForm(), psdRemCfgForm(), psdGetCfgChunk() + + + poseidon.library/psdRemCfgForm poseidon.library/psdRemCfgForm + + NAME + psdRemCfgForm -- remove a configuration form + + SYNOPSIS + psdRemCfgForm(pic); + A0 + + VOID psdRemCfgForm(APTR); + + FUNCTION + Removes the given Poseidon IFF context, including all its chunks and + subforms. + + To remove single chunks, use the psdRemCfgChunk() instead. + + INPUTS + pic - pointer to a Poseidon IFF context structure, or NULL for the + root context (for normal applications, DO NOT USE the NULL + pointer). + + SEE ALSO + psdFindCfgForm(), psdNextCfgForm(), psdRemCfgChunk() + + + poseidon.library/psdAddCfgEntry poseidon.library/psdAddCfgEntry + + NAME + psdAddCfgEntry -- add a chunk or a whole form to an IFF context + + SYNOPSIS + subpic = psdAddCfgEntry(pic, form); + D0 A0 A1 + + APTR psdAddCfgEntry(APTR, APTR); + + FUNCTION + Using this function you can add an IFF chunk or a complete FORM to + the given Poseidon IFF context. + + If the form parameter points to an IFF form buffer (NOT context), the + function performs the following: + - Adds the given form to the context. If such an form already + existed, it will still be added behind the existing one. + - Returns a pointer to the newly created Poseidon IFF context. + + If the form parameter points to an IFF chunk only, psdAddCfgEntry + does the following: + - If no chunk with the same ID exists, it adds it to the given + context. Otherwise, the existing chunk will be replaced by the + new one. + - Returns the previously given context pointer. + + subpic is set to NULL, if an error occurred during adding (e.g. + corrupt IFF FORM). + + INPUTS + pic - pointer to a Poseidon IFF context structure or NULL for the + root context. This structure is private. + form - a pointer to a buffer containing the IFF FORM or chunk data. + + RESULT + subpic - pointer to the Poseidon IFF context structure (see above) + or NULL, if the form or chunk could not be added. + + SEE ALSO + psdAddCfgForm(), psdRemCfgForm(), psdGetCfgChunk(), psdRemCfgChunk() + + + poseidon.library/psdRemCfgChunk poseidon.library/psdRemCfgChunk + + NAME + psdRemCfgChunk -- remove a chunk for a given context + + SYNOPSIS + success = psdRemCfgChunk(pic, chunkid); + D0 A0 D0 + + BOOL psdRemCfgChunk(APTR, ULONG); + + FUNCTION + psdRemCfgChunk() tries to remove a chunk from the given Poseidon IFF + context, which has the ID stored in parameter chunkid. + + If no chunk with that ID existed, it will return FALSE, otherwise the + return value will be TRUE to show the success of the removal. + + A special case is implemented by using a special chunkid of 0. This + will completely empty out the IFF context, by deleting every chunk + and form. This is not quite the same as psdRemCfgForm(), as it will + not delete the context itself. + + INPUTS + pic - pointer to a Poseidon IFF context structure or NULL for the + root context. This structure is private. + chunkid - the longword containing the ID of the chunk to remove, + or 0, to remove all chunks AND subforms. + + RESULT + success - TRUE, if the chunk was found and removed, FALSE otherwise. + + SEE ALSO + psdAddCfgForm(), psdRemCfgForm(), psdGetCfgChunk() + + + poseidon.library/psdGetCfgChunk poseidon.library/psdGetCfgChunk + + NAME + psdGetCfgChunk -- convert an IFF context into a serialized IFF form + + SYNOPSIS + chunk = psdGetCfgChunk(pic, chunkid); + D0 A0 D0 + + APTR psdGetCfgChunk(APTR, ULONG); + + FUNCTION + psdGetCfgChunk() searches and returns the chunk with the given ID + in chunkid inside the Poseidon IFF context pic. The returned pointer + is a buffer to the IFF chunk data. + + If the context is NULL, the root context is used. + + The buffer is allocated automatically and has to be freed using the + psdFreeVec() call after it is no longer required. + + The size of the buffer can be calculated by adding 8 to the second + longword (as it's a normal IFF structure). The actual data stored in + the chunk starts at the third longword (offset 8). + + To obtain a serialized version of an IFF context instead of a single + chunk, use the psdWriteCfg() function. + + INPUTS + pic - pointer to a Poseidon IFF context structure or NULL for the + root context. This structure is private. + chunkid - IFF id of the chunk to search. + + RESULT + chunk - pointer to the IFF chunk generated from the context or NULL, + if the function failed (e.g. out of memory). + + SEE ALSO + psdWriteCfg(), psdFindCfgForm(), psdRemCfgForm(), psdAddCfgEntry(), + psdGetCfgChunk() + + + poseidon.library/psdSetClsCfg poseidon.library/psdSetClsCfg + + NAME + psdSetClsCfg -- store the class configuration in the prefs + + SYNOPSIS + success = psdSetClsCfg(owner, form); + D0 A0 A1 + + BOOL psdSetClsCfg(STRPTR, APTR); + + FUNCTION + Stores the class configuration IFF form in the internal prefs + structure. This is normally USB device independent preference + information, or the default settings for a class. + + The owner parameter is usually the name of the class (but not limited + to it). The form parameter has to be a pointer to a valid IFF-FORM + with FORM-ID IFFFORM_CLASSDATA (see poseidon.h). + + If the form pointer is NULL, an existing configuration form will be + deleted. In any other case, any previously existing data will be + overwritten by the given form. + + After successfully calling psdSetClsCfg(), psdGetClsCfg() will return + a pointer to the IFF structure for you to parse (or return as a + whole). This can be used to incrementally add/replace chunks or whole + forms to the existing prefs container using the psdAddCfgEntry() or + psdReadCfg() functions. + + psdSetClsCfg() does not store the config to disk. User interaction is + normally required for this (Trident, PoPo, or a call to + psdSaveCfgToDisk()). + + INPUTS + owner - unique name string of the owner, usually the class name. + form - pointer to a valid IFF CLASSDATA FORM. If a NULL pointer is + given, a minimal config form will be created and previous data + will be overwritten. + + RESULT + success - TRUE, if everything went okay, or FALSE, if there was + something wrong with the form. + + SEE ALSO + psdGetClsCfg(), psdSetUsbDevCfg(), psdGetUsbDevCfg(), psdAddCfgEntry() + + + poseidon.library/psdGetClsCfg poseidon.library/psdGetClsCfg + + NAME + psdGetClsCfg -- obtain the class configuration from the prefs + + SYNOPSIS + pic = psdGetClsCfg(owner); + D0 A0 + + APTR psdGetClsCfg(STRPTR); + + FUNCTION + This call tries to obtain the previously stored class configuration + data. Class prefs can be saved in the internal configuration system + using the psdSetClsCfg() function. + + The owner parameter usually corresponds to the name of the class. + + If no configuration has been stored yet, a NULL pointer will be + returned. If there is at least a minimal configuration structure, + a pointer to this internal IFF context will be returned (this is not + a pointer to a FORM memory region!). This minimal configuration can + be generated using psdSetClsCfg(owner, NULL); + + INPUTS + owner - unique name string of the owner, usually the class name. + + RESULT + pic - pointer to a Poseidon IFF context structure. This structure is + private. Use the Poseidon configuration management functions to + access the data behind it. + + SEE ALSO + psdSetClsCfg(), psdSetUsbDevCfg(), psdGetUsbDevCfg(), + psdAddCfgEntry(), psdGetCfgChunk(), psdFindCfgForm(), psdWriteCfg() + + + poseidon.library/psdSetUsbDevCfg poseidon.library/psdSetUsbDevCfg + + NAME + psdSetUsbDevCfg -- store usb device specific settings in the prefs + + SYNOPSIS + success = psdSetUsbDevCfg(owner, devid, ifid, form); + D0 A0 A2 A3 A1 + + BOOL psdSetUsbDevCfg(STRPTR, STRPTR, STRPTR, APTR); + + FUNCTION + Stores the USB device specific configuration IFF form in the internal + prefs structure. This is normally device or interface specific + information, stored indivdually for each device attached. + + The usage is very similar to the psdSetClsCfg() function, hence only + the additional parameter devid and ifid are explained here. + + The devid parameter normally contains the DA_IDString identification + string as returned by psdGetAttrs(), which is unique to every USB + device connected to the stack. devid may NOT be NULL. + + If the class is bound to USB devices as a whole, and not to particular + interfaces, it can usually leave the ifid parameter to NULL. + Otherwise, ifid should point to the string returned by psdGetAttrs() + on the specific interface using IFA_IDString tag. + + The owner parameter is usually the name of the class (but not limited + to it). The form data must have ID IFFFORM_DEVCLSDATA, if the ifid is + NULL or IFFFORM_IFCLSDATA, if ifid is not NULL. Otherwise, the call + to this function will fail. + + If the form pointer is NULL, an existing configuration form will be + deleted. In any other case, any previously existing data will be + overwritten by the given form. + + After successfully calling psdSetUsbDevCfg(), psdGetUsbDevCfg() will + return a pointer to the IFF structure for you to parse (or return as + a whole). This can be used to incrementally add/replace chunks or + whole forms to the existing prefs container using the + psdAddCfgEntry() or psdReadCfg() functions. + + psdSetUsbDevCfg() does not store the config to disk. User interaction + is normally required for this (Trident, PoPo, or a call to + psdSaveCfgToDisk()). + + INPUTS + owner - unique name string of the owner, usually the class name. + devid - pointer to unique device ID string + ifid - pointer to unique interface ID string or NULL, if config is + to be stored for the whole device. + form - pointer to a valid IFF FORM. If a NULL pointer is given, a + minimal config form will be created and previous data will be + overwritten. + + RESULT + success - TRUE, if everything went okay, or FALSE, if there was + something wrong with the form. + + SEE ALSO + psdSetClsCfg(), psdGetClsCfg(), psdGetUsbDevCfg(), psdAddCfgEntry() + + + poseidon.library/psdGetUsbDevCfg poseidon.library/psdGetUsbDevCfg + + NAME + psdGetUsbDevCfg -- obtain the device specific settings from the prefs + + SYNOPSIS + pic = psdGetUsbDevCfg(owner, devid, ifid); + D0 A0 A2 A3 + + APTR psdGetUsbDevCfg(STRPTR, STRPTR, STRPTR); + + FUNCTION + This call tries to obtain the previously stored USB device specific + configuration data. This kind of prefs can be saved in the internal + configuration system using the psdSetUsbDevCfg() function. + + This call is very similar to psdGetClsCfg(), except for the devid and + ifid parameters, which are explained in detail for psdSetUsbDevCfg(). + + The owner parameter usually corresponds to the name of the class. + + If no configuration has been stored yet, a NULL pointer will be + returned. If there is at least a minimal configuration structure, + a pointer to this internal IFF context will be returned (this is not + a pointer to a FORM memory region!). This minimal configuration can + be generated using psdSetClsCfg(owner, NULL); + + INPUTS + owner - unique name string of the owner, usually the class name. + devid - pointer to unique device ID string + ifid - pointer to unique interface ID string or NULL, if config is + to be obtained for the whole device. + + RESULT + pic - pointer to a Poseidon IFF context structure. This structure is + private. Use the Poseidon configuration management functions to + access the data behind it. + + SEE ALSO + psdGetClsCfg(), psdSetClsCfg(), psdGetUsbDevCfg(), psdAddCfgEntry(), + psdGetCfgChunk(), psdFindCfgForm(), psdWriteCfg() + + + + poseidon.library/--background-- poseidon.library/--background-- + + PURPOSE + Poseidon is an USB protocol stack for the Amiga. It serves as a + manager and interface between the USB host controller drivers + (usbhardware.device) and the class drivers. + + This document is dated 28-Mar-02 19:53:03 + + OVERVIEW + Poseidon itself is a library. It has no own tasks except for the + tasks spawned for each hardware device mounted. The library functions + are fully re-entrant and all important structures are protected (or + can be protected), when access is to be shared. + + Poseidon uses the following levels of abstraction: + + PsdHardware - The usb hardware interface the devices are physically + (phw) connected to. There is no limit to the amount and + type of host controller hardware that can be added to + the stack. + A PsdHardware can have up to 127 PsdDevices. + + PsdDevice - A device mounted to a PsdHardware. Normally, this is + (pd) at least the root hub. + + A device can have multiple configurations, and a + maximum of one Device<->Class binding. + + PsdConfig - One or multiple configurations that the usb device + (pc) supports. USB allows only one configuration to be + active at a time. Each configuration must have at + least one interface. + + PsdInterface - Description of the interfaces, the device supports in + (pif) the chosen configuration. Each interface can have + 0 to 15 endpoints (endpoint 0 is always available). + + Each interface can have an Interface<->Class binding, + if no Device<->Class binding already exists. + + PsdEndpoint - An endpoint defines the destination port for a + (pep) transfer pipe. Endpoint 0, the default control + endpoint, is not explicitly defined. + + PsdPipe - A data transfer control pipe. You can allocate as + (pp) many pipes to an endpoint as you like, but each pipe + may be used for only one transfer at a time. + + PsdUsbClass - An usb class driver. There is hopefully no limitation + (puc) to what a class driver wants to do with an interface + or an device. + + PsdAppBinding - An application binding node. Whenever using a class + (pab) driver is not appropriate, application programmers + can use the AppBinding interface to claim an USB + device. + + PsdErrorMsg - Supportive structure for postponing an error message. + (pem) + + As all these structures are private (except for the information that + they all have a Node structure for linking) and subject to change, + the information can only be read (and in some cases written aswell) + by a call to psdGetAttrs() (and changed using psdSetAttrs()) which + use TagLists. This ensures future compatibilty with all extensions + and changes made. + + Class drivers are libraries aswell. Whenever a new device is detected + by the stack, all classes will be asked whether they want to + establish an interface or even the whole binding (that is, if they + know the interface protocol and therefore can add its features to the + system). In case they want to establish a binding, they normally + spawn a subtask with an instance of this binding. + + Device<->Class bindings allow full control over a device, all its + configurations and interfaces whereas Interface<->Class bindings are + limited to the interface they work on. They may, however, change the + interfaces' alternative setting. + + To support application programs, which need to talk to certain USB + devices with a vendor specific protocol, and which don't want to + through writing a class driver for just one protocol, there is also + the possibility to establish application bindings. This allows normal + programs to bypass the class interface to claim device bindings. Note + that his is not the preferred way to add functionality and should be + avoided, if you also could go through the class library interface + aswell. + + FILES + The poseidon.library itself resides in LIBS:, the USB hardware + devices should be in DEVS:USBHardware, and all class drivers should + be stored in SYS:Classes/USB. + + BUGS + The stack is not finished yet. Some features never have been tested. + There will be a lot of bugs hiding in all places. An event handler + (mainly for the use by the GUI) is going to be added, aswell as some + configuration and GUI hooks for the classes. + + This version is meant to be a working frame for developers to test + and add their hardware or for application programmers to add class + drivers. Be sure that some things WILL change, be sure to keep + contact to me, Chris Hodges . + + Also, bug reports, errors, feature requests are welcome and REQUIRED + for Poseidon to be a good product. + + + poseidon.library/psdAbortPipe poseidon.library/psdAbortPipe + + NAME + psdAbortPipe -- attempt to abort a pipe transaction + + SYNOPSIS + psdAbortPipe(pp); + A1 + + void psdAbortPipe(APTR); + + FUNCTION + Asks the hardware to abort the pipe request. The hardware may or may + not grant this and will return the request to you earlier than it + might have done. The ioerror code normally will be IOERR_ABORTED in + this case. + + NOTE + psdAbortPipe() does not Remove() the request from your message reply + port or even wait for it to complete. After psdAbortPipe() you must + normally wait for the reply message before actually reusing or + freeing the pipe using psdWaitPipe(). + + If a request is already completed, no action will be taken. + + INPUTS + pp - pointer to pipe to abort. + + SEE ALSO + psdSendPipe(), psdWaitPipe(), psdGetPipeError(), psdGetPipeActual() + + + poseidon.library/psdAddClass poseidon.library/psdAddClass + + NAME + psdAddClass -- add an usb class library to the stack + + SYNOPSIS + puc = psdAddClass(name, version); + D0 A1 D0 + + APTR psdAddClass(STRPTR, ULONG); + + FUNCTION + + psdAddClass() tries to open and add an usb class driver to the stack. + Be sure only to add libraries to the stack which are really Poseidon + compatible usb classes, else a crash is very probable. + + The opening the library succeeds, the class will be added to the + class list. + + Usually class libraries will be stored in SYS:Classes/USB. + + INPUTS + name - (file)name of the class to add. + version - version of library to request. + + RESULT + puc - pointer to the library base, or NULL if opening failed. + + SEE ALSO + psdRemClass(), psdClassScan() + + + poseidon.library/psdAddErrorMsg poseidon.library/psdAddErrorMsg + + NAME + psdAddErrorMsgA -- add an error or information message for the user + psdAddErrorMsg -- varargs stub for psdAddErrorMsgA + + SYNOPSIS + pem = psdAddErrorMsgA(level, origin, fmtstr, fmtdata); + D0 D0 A0 A1 A2 + + APTR psdAddErrorMsgA(UWORD, STRPTR, STRPTR, APTR); + + pem = psdAddErrorMsg(level, origin, fmtstr, ...); + + APTR psdAddErrorMsg(UWORD, STRPTR, STRPTR, ...); + + FUNCTION + Adds an error message for the user. This message will can be read in + the GUI or other logging tools. There are four different levels of + severity. + + NOTE + psdAddErrorMsg() uses a Forbid()/Permit() arbitration. The strings + can safely be of any length, but will be truncated at 256 characters. + + INPUTS + level - error level, either RETURN_OK (0) for information messages, + RETURN_WARN (5) for warnings, RETURN_ERROR (10) for error + messages and RETURN_FAIL (20) for fatal failure alerts. + origin - string of the module caused the error. + fmtstr - formatted string like in printf() or RawDoFmt() + fmtdata - format parameters + + RESULT + pem - pointer to an error message structure (private) or NULL on + failure. + + SEE ALSO + psdRemErrorMsg(), psdSafeRawDoFmt(), RawDoFmt() + + + poseidon.library/psdAddHardware poseidon.library/psdAddHardware + + NAME + psdAddHardware -- open and link a new usb hardware into the stack + + SYNOPSIS + phw = psdAddHardware(devname, unit); + D0 A0 D0 + + APTR psdAddHardware(STRPTR, ULONG); + + FUNCTION + psdAddHardware() is used for the stack manager to add a new hardware + device to the Poseidon USB stack. The hardware is initialized, but no + devices attached to the root hub are enumerated. To do this, just + call psdEnumerateHardware(). + + As a result a pointer to the internal hardware structure is returned. + The data of this structure is private! Do not touch! + + Moreover, the hardware is linked to the list of known hardware + devices and will be closed on the expunge of the library. + + This function returns NULL, if the hardware device could not be + opened or some other error occured. The user will find the reason in + the list of error messages. + + INPUTS + devname - pointer to usb hardware device name string + unit - unit number of usb hardware device + + RESULT + phw - internal hardware pointer. Do not touch (except for node + traversal). + + SEE ALSO + psdRemHardware(), psdEnumerateHardware() + + + poseidon.library/psdAllocDevice poseidon.library/psdAllocDevice + + NAME + psdAllocDevice -- allocate a device structure + + SYNOPSIS + pd = psdAllocDevice(phw); + D0 A0 + + APTR psdAllocDevice(APTR); + + FUNCTION + Creates a fresh device structure to be filled by the stack during + enumeration. + + The device will be linked into stack device list. psdLockWritePBase() + will be called to ensure that the list is protected from other tasks + during that phase. + + The hub class is probably the only class that will use this call and + then psdEnumerateDevice() to fill in the data. + + INPUTS + phw - pointer to a hardware structure. + + RESULT + pd - pointer to a device structure (private), + or NULL if the allocation failed. + + SEE ALSO + psdFreeDevice(), psdEnumerateDevice() + + + poseidon.library/psdAllocPipe poseidon.library/psdAllocPipe + + NAME + psdAllocPipe -- allocate a pipe for transfer requests + + SYNOPSIS + pp = psdAllocPipe(pd, mp, ep); + D0 A0 A1 A2 + + APTR psdAllocPipe(APTR, struct MsgPort *, APTR); + + FUNCTION + psdAllocPipe() is the main function to establish a transport pipe to + a device endpoint. + + After you have allocated a pipe, you can start sending or receiving + packets using psdDoPipe() or psdSendPipe(). If you do not need a pipe + anymore, use psdFreePipe() to get rid of it. + + Pipes allocated with this function are automatically assigned to the + given endpoint. If you want to establish a pipe to the default + control pipe, use an NULL pointer for ep. The settings of the pipe + will be read from the endpoint configuration. Additional flags like + PPA_NakTimeout can be changed using psdSetAttrs(). + + Note that there is no limit to the amount of pipes you can allocate + for an endpoint. This can be used to create asynchronous double + buffered transfers. + + INPUTS + pd - pointer to the device structure you want to allocate the pipe + at. + mp - pointer to a MsgPort that is used for sending the pipe messages. + Must not be NULL. + ep - pointer to an endpoint structure or NULL if you want to use the + default endpoint. + + RESULT + pp - pipe structure allocated or NULL if something failed. + + SEE ALSO + psdFreePipe(), psdDoPipe(), psdSendPipe() + + + poseidon.library/psdAllocVec poseidon.library/psdAllocVec + + NAME + psdAllocVec -- allocate memory for Poseidon system structures. + + SYNOPSIS + memptr = psdAllocVec(size); + D0 D0 + + APTR psdAllocVec(ULONG); + + FUNCTION + Allocates memory from the internal memory pool for Poseidon system + structures. The memory is of MEMF_PUBLIC|MEMF_CLEAR type. The memory + will be freed automatically on exit of Poseidon (or if linked to a + system structure, when the structure gets freed), so be sure that + this memory will not be needed somewhere else. Especially this memory + is NOT for internal use in your task! Use your own calls to the exec + memory functions instead. + + Memory allocated by this function MUST be freed using psdFreeVec() or + linked to a system structure that is known to free this memory on + removal. + + INPUTS + size - size in number of bytes for the to be allocated memory block. + + RESULT + memptr - pointer to the requested memory block or NULL on failure. + + SEE ALSO + psdFreeVec() + + + poseidon.library/psdClaimAppBinding poseidon.library/psdClaimAppBinding + + NAME + psdClaimAppBindingA -- try to establish a binding to an usb device + psdClaimAppBinding -- varargs stub for psdClaimAppBinding() + + SYNOPSIS + pab = psdClaimAppBindingA(taglist); + D0 A1 + + APTR psdClaimAppBindingA(struct TagList *); + + pab = psdClaimAppBinding(tag1, ...); + + APTR psdClaimAppBinding(Tag, ...); + + FUNCTION + This function tries to claim a device binding to a given device. + psdClaimAppBinding() is normally only used by applications, which + want to bypass the class modell for the bindings. + + The call will return a pointer to an internal AppBinding structure. + This chunk of data will be available only as long as the binding + exists. As soon as the device is unplugged, the structure will be + deallocated. To provide a simple notification mechanism, you MUST + pass a Hook structure using the TagList, which will be called just + BEFORE the structure gets freed. Normally your function should then + abort all running pipe transfers of your main program and shut down + further access to the device. + + As this abortion operation sometimes may be difficult to control with + the asynchronous hook call, the device structure will not be freed to + avoid crashes, IF AND ONLY IF there are still some pipes allocated + for this device. However, all further transactions will be denied + with an IOERR_ABORTED error code. A call to psdFreePipe(), closing + the last pipe will finally free the device data. Even if the device + is plugged in again, it will not be re-enabled (as there is no + reliable operation to return the device to its previous state and + ensure, that this is really the same one unplugged earlier). + + If you wish to terminate the binding yourself, just call + psdReleaseAppBinding() with the AppBinding context yourself. Be SURE + that the application binding still exists. This will also call your + hook. + + The whole acquiration process should be protected with + psdLockReadPBase() and psdUnlockPBase(). + + NOTE + You may not use devices directly, without adding an application + binding with psdClaimAppBinding(). This will provide you with a good + mechanism to find out if the device you are using gets unplugged and + will also ensure exclusive usage. + + INPUTS + taglist - pointer to TagItem list, terminated by TAG_END. + + TAGS + ABA_ReleaseHook (struct Hook *) - pointer to a function hook that + will be called if the binding must be terminated (e.g. when the + device has been unplugged). After this call the application + binding structure will be gone. The device will also be freed, if + there are no open pipes anymore. This hook also will be called + from psdReleaseAppBinding(). THIS TAG IS MANDATORY! + ABA_Device (APTR) - pointer to the device that should be bound. + THIS TAG IS MANDATORY! + ABA_UserData (ULONG) - pointer to auxillary data for your private + use. + + RESULT + pab - pointer to the internal AppBinding structure, if the binding + could be established, or NULL, if it failed. This pointer is + also available via the DA_Binding field of the device. + + SEE ALSO + psdReleaseAppBinding(), psdLockReadPBase(), psdUnlockPBase(), + psdFindDevice() + + + poseidon.library/psdClassScan poseidon.library/psdClassScan + + NAME + psdClassScan -- bind devices and interface to available classes + + SYNOPSIS + psdClassScan(); + + void psdClassScan(); + + FUNCTION + Traverses all devices currently available in the stack and tries to + establish bindings between those devices and its interfaces with usb + class drivers available, each at a time. + + SEE ALSO + psdAddClass(), psdRemClass() + + + poseidon.library/psdCopyStr poseidon.library/psdCopyStr + + NAME + psdCopyStr -- allocate memory for and copy a given string + + SYNOPSIS + newstrptr = psdCopyStr(strptr); + D0 A0 + + STRPTR psdCopyStr(STRPTR); + + FUNCTION + psdCopyStr() takes a NULL-terminated string and copies its contents + to a newly allocated buffer. The pointer to this buffer is returned + as result. + + The memory will be allocated from the internal memory pool and must + be freed using psdFreeVec(). DO NOT allocate memory this way if + you're not going to free the memory while you've got the + poseidon.library open. This memory CAN and WILL go away whenever the + library is expunged. + + This function returns NULL, if something went wrong. + + INPUTS + strptr - pointer to the string to be copied. + + RESULT + newstrptr - pointer to the copied string buffer or NULL on + failure. + + SEE ALSO + psdFreeVec() + + + poseidon.library/psdDelayMS poseidon.library/psdDelayMS + + NAME + psdDelayMS -- wait for a given amount of milliseconds + + SYNOPSIS + psdDelayMS(milli); + D0 + + void psdDelayMS(ULONG); + + FUNCTION + Delays the execution of the current task by the given amount of + milliseconds. The call is guaranteed to wait at least that amount of + milliseconds, but as usually in a multitasking environment, the call + could also take longer to return. + + INPUTS + milli - number of milliseconds to wait. + + + poseidon.library/psdDoPipe poseidon.library/psdDoPipe + + NAME + psdDoPipe -- synchronous transfer to endpoint + + SYNOPSIS + ioerr = psdDoPipe(pp, data, length); + D0 A1 A0 D0 + + LONG psdDoPipe(APTR, APTR, ULONG); + + FUNCTION + Start a transfer to an endpoint. Waits until the request is done and + then returns zero, if everything went okay, or an error code + otherwise. See devices/usbhardware.h for a list of errors. + + NOTE + The direction of the transfer is determined by the type of the + endpoint for bulk, interrupt and isochronous transfers. For control + transfers, however, this is given by the URTF_IN/URTF_OUT flags in + the bmRequestType field of the setup packet, which can be set by + psdPipeSetup(). For control transfers without data phase, using a + NULL pointer for data and zero for the length is permitted. Also, + the wLength field of the setup packet is filled automatically with + the correct length of your data transfer request. + + Note well that this call will hang until the request is answered. In + the case of interrupt transfers, this may never happen at all. Use + psdSendPipe() for those cases or enable the NAK timeout feature using + psdSetAttrs(). + + psdDoPipe() is just a call to psdSendPipe() followed by a + psdWaitPipe(). + + INPUTS + pp - pointer to pipe structure to send the request to. + data - pointer to the data buffer to send or receive. + length - number of bytes to transfer + + RESULT + ioerr - zero, if everthing went okay, else the IO error code. + + SEE ALSO + psdPipeSetup(), psdSendPipe(), psdAbortPipe(), psdWaitPipe() + + + poseidon.library/psdEnumerateDevice poseidon.library/psdEnumerateDevice + + NAME + psdEnumerateDevice -- start the enumeration process for a new device + + SYNOPSIS + pd = psdEnumerateDevice(pp); + D0 A1 + + APTR psdEnumerateDevice(APTR); + + FUNCTION + This function is used to enumerate a device that is still on the bus + without having a valid address and still unconfigured. It will be + called by the psdEnumerateHardware() function (for the root hub) and + the hub class for devices connected downstream. + + psdLockWriteDevice() will be called to ensure that the device is + protected from other tasks during that phase. + + INPUTS + pp - pointer to a default control pipe, allocated with psdAllocPipe() + on the freshly created device using psdAllocDevice() + + RESULT + pd - pointer to the device structure (private), or NULL if the + enumeration failed. + + SEE ALSO + psdAllocDevice(), psdFreeDevice(), psdEnumerateHardware(), + psdAllocPipe() + + + poseidon.library/psdEnumerateHardware poseidon.library/psdEnumerateHardware + + NAME + psdEnumerateHardware -- start enumeration of the root hub + + SYNOPSIS + pd = psdEnumerateHardware(phw); + D0 A0 + + APTR psdEnumerateHardware(APTR); + + FUNCTION + After the hardware has been allocated, the root device of the + hardware (normally the root hub) must be enumerated using + psdEnumerateHardware(). It adds the initial device to the device list + if it configures correctly. + + The next step then is just to call psdClassScan() which will do the + rest. + + INPUTS + phw - pointer to a previously allocated hardware. + + RESULT + pd - pointer to the root device, or NULL if configuration + failed. + + SEE ALSO + psdAllocHardware(), psdFreeHardware(), psdClassScan() + + + poseidon.library/psdFindDevice poseidon.library/psdFindDevice + + NAME + psdFindDeviceA -- find a specific device in the device list + psdFindDevice -- varargs stub for psdFindDeviceA() + + SYNOPSIS + pd = psdFindDeviceA(oldpd, taglist); + D0 A0 A1 + + APTR psdFindDeviceA(APTR, struct TagList *); + + pd = psdFindDevice(oldpd, tag1, ...); + + APTR psdFindDevice(APTR, Tag, ...); + + FUNCTION + Just like psdGetNextDevice(), psdFindDevice() is used to traverse the + list of all devices available to stack. The only difference is, that + you can give certain attributes that the device has to match ALL tags + to be returned by this function. The search will also cross all + mounted hardware devices. + + psdFindDevice() needs to be protected with a pair of + psdLockReadPBase() and psdUnlockPBase() during traversal. + + NOTE + You may not use devices directly, without adding an application + binding with psdClaimAppBinding(). This will provide you with a good + mechanism to find out if the device you are using gets unplugged and + will also ensure exclusive usage. + + INPUTS + oldpd - NULL for the first device or pointer to the last device + found. + taglist - pointer to TagItem list, terminated by TAG_END. Every given + tag must match to return the device. + + TAGS + Not all available tags are supported. Here's a list of what seemed + sensible to add: + + DA_Class (UWORD) - Class code to match. Note that most devices + use interface class codes instead of device class codes. + DA_SubClass (UWORD) - Subclass code to match. + DA_Protocol (UWORD) - Protocol code to match. + DA_VendorID (UWORD) - Vendor ID number. This is a + DA_ProductID (UWORD) - Vendor specific product ID. Only valid, if + DA_HasDevDesc is TRUE. + DA_Version (UWORD) - BCD number of device/product version. Only + valid, if DA_HasDevDesc is TRUE. + DA_Manufacturer (STRPTR) - pointer to a manufacturer string. If no + manufacturer string could be read from the device, Poseidon + will generate a string out of the vendor ID. Be sure to handle + a NULL pointer. Only valid, if DA_HasDevDesc is TRUE. + DA_ProductName (STRPTR) - pointer to the product name. If no product + name could be read from the device, Poseidon will generate one + out of the class, the vendor and the product ID. Be sure to + handle a NULL pointer. Only valid, if DA_HasDevDesc is TRUE. + DA_Binding (APTR) - normally used with an NULL pointer to ensure the + device has no binding already. + + RESULT + pd - pointer to the device found in the list, or NULL if there was no + device matching the criteria. + + SEE ALSO + psdLockReadPBase(), psdUnlockPBase(), psdGetNextDevice(), + psdClaimAppBinding(), psdReleaseAppBinding() + + + poseidon.library/psdFreeDevice poseidon.library/psdFreeDevice + + NAME + psdFreeDevice -- deallocate a device and free all bindings + + SYNOPSIS + psdFreeDevice(pd); + A0 + + void psdFreeDevice(APTR); + + FUNCTION + Removes and deallocates the given device from the system. All + previously allocated configuration structures and class bindings will + be freed aswell. The pointer becomes invalid right after. + + psdFreeDevice() will use the semaphore protection of + psdLockWritePBase(). + + INPUTS + pd - pointer to a device structure. + + SEE ALSO + psdAllocDevice() + + + poseidon.library/psdFreePipe poseidon.library/psdFreePipe + + NAME + psdFreePipe -- free a previously allocated pipe + + SYNOPSIS + psdFreePipe(pp); + A1 + + void psdFreePipe(APTR); + + FUNCTION + Deallocate a pipe created with psdAllocPipe() before. The pp pointer + becomes invalid right after this call. + + Be sure that there is no request pending for this pipe. If you ever + done asynchronous IO, you should call psdAbortPipe() and + psdWaitPipe() before psdFreePipe() to be on the safe side. + + INPUTS + pp - pointer to pipe structure to deallocate. + + SEE ALSO + psdAllocPipe(), psdSendPipe(), psdAbortPipe(), psdWaitPipe() + + + poseidon.library/psdFreeVec poseidon.library/psdFreeVec + + NAME + psdFreeVec -- free memory allocated by psdAllocVec() + + SYNOPSIS + psdFreeVec(memptr); + A1 + + void psdFreeVec(APTR); + + FUNCTION + Frees the memory allocated by psdAllocVec(). Do not pass any other + pointer to this function. Be sure that the given vector is not linked + to any internal structure or memory might be freed twice. + + INPUTS + memptr - pointer to the memory block allocated using psdAllocVec() + or NULL. + + SEE ALSO + psdAllocVec() + + + poseidon.library/psdGetAttrs poseidon.library/psdGetAttrs + + NAME + psdGetAttrsA -- get information from an internal stack structure + psdGetAttrs -- varargs stub for psdGetAttrsA() + + SYNOPSIS + num = psdGetAttrsA(type, psdstruct, taglist); + D0 D0 A0 A1 + + LONG psdGetAttrsA(ULONG, APTR, struct TagList *); + + num = psdGetAttrs(type, psdstruct, tag1, ...); + + LONG psdGetAttrs(ULONG, APTR, Tag, ...); + + FUNCTION + Acquires attribute information from an internal stack structure, + according to the attributes chosen in the tag list. For each entry in + the tag list, ti_Tag identifies the attribute and ti_Data is a + pointer to the long variable where you wish the result to be stored. + + There are currently a number of ten different system structures which + can be accessed in this way. To avoid adding multiple functions with + the same semantics, psdGetAttrs() requires the type of the structure + passed. + + INPUTS + type - describes the type of the structure passed. + See libraries/poseidon.h for details. + psdstruct - pointer to the system structure on which information + should be gathered. Can be NULL only for PGA_STACK. + taglist - pointer to TagItem list, terminated by TAG_END. + + TAGS + All tags are read-only, except stated otherwise. + + PGA_STACK: (read-only) + PA_HardwareList (struct List *) - pointer to the list of hardware in + the system. + PA_ClassList (struct List *) - pointer to the list of classes. + PA_ErrorMsgList (struct List *) - pointer to the list of error + messages, that have been encountered so far. The entries in this + list are only valid inside a Forbid()/Permit() clause. + + PGA_ERRORMSG: (read-only) + EMA_Level (UWORD) - level indicating the severeness of an error. + Normally corresponds to RETURN_OK, RETURN_WARN, RETURN_ERROR, and + RETURN_FAIL of dos/dos.h. + EMA_Origin (STRPTR) - points to the name of the module that caused + the error. + EMA_Msg (STRPTR) - a pointer to the error message itself. + + PGA_USBCLASS: (read-only) + UCA_ClassBase (struct Library *) - base pointer of the class library. + You should consider opening the library using OpenLibrary() and + UCA_ClassName, instead of using UCA_ClassBase directly. + UCA_ClassName (STRPTR) - pointer to the name string of the class. + UCA_UseCount (UWORD) - number of bindings active with this class. + + PGA_HARDWARE: (read-only) + HA_DeviceName (STRPTR) - pointer to the name string of the device + driver, opened by OpenDevice(). + HA_DeviceUnit (ULONG) - unit number of the hardware device. + HA_ProductName (STRPTR) - product name of the usb hardware board. + + PGA_DEVICE: (partially read/write) + DA_Address (UWORD) - device address on the usb bus. Only valid, if + DA_HasAddress is TRUE. + DA_NumConfigs (UWORD) - number of configs available for this device. + Only valid, if DA_HasDevDesc is TRUE. + DA_CurrConfig (UWORD) - id number of active configuration. + DA_HubDevice (APTR) - pointer to the hub device the device is + connected to or NULL for the root hub. May be changed, but is + only sensible of doing so by the hub class. + DA_UsbVersion (UWORD) - BCD number with the version of usb spec this + device follows. Only valid, if DA_HasDevDesc is TRUE. + DA_Class (UWORD) - Class code of the device. Note that most devices + use interface class codes instead of device class codes. Only + valid, if DA_HasDevDesc is TRUE. + DA_SubClass (UWORD) - Subclass code. Only valid, if DA_HasDevDesc is + TRUE. + DA_Protocol (UWORD) - Protocol code. Only valid, if DA_HasDevDesc is + TRUE. + DA_VendorID (UWORD) - Vendor ID number. Can be converted into a + string using PsdNumToStr(). Only valid, if DA_HasDevDesc is TRUE. + DA_ProductID (UWORD) - Vendor specific product ID. Only valid, if + DA_HasDevDesc is TRUE. + DA_Version (UWORD) - BCD number of device/product version. Only + valid, if DA_HasDevDesc is TRUE. + DA_Manufacturer (STRPTR) - pointer to a manufacturer string. If no + manufacturer string could be read from the device, Poseidon will + generate a string out of the vendor ID. Be sure to handle a NULL + pointer. Only valid, if DA_HasDevDesc is TRUE. + DA_ProductName (STRPTR) - pointer to the product name. If no product + name could be read from the device, Poseidon will generate one + out of the class, the vendor and the product ID. Be sure to + handle a NULL pointer. Only valid, if DA_HasDevDesc is TRUE. + DA_Hardware (APTR) - uplinking pointer to the hardware structure the + device is running on. + DA_LangIDArray (UWORD *) - pointer to a null terminated array of + languages the devices understands. If no such information could + be acquired, this will be a NULL pointer. The LangIDs can be + converted into readable strings using a call to psdNumToStr(). + DA_CurrLangID (UWORD) - ID of the language the device is using + currently. The stack will try to set a sensible value here + during enumeration. This value can also be modified, but will + only effect future calls to PsdGetStringDescriptor(), not prior + ones. + DA_Binding (APTR) - pointer to class private binding structure which + currently has a binding to the device or NULL, if no class + claimed it. If DA_HasAppBinding is TRUE, this is a pointer to the + AppBinding structure. + DA_BindingClass (struct Library *) - class currently having a device + binding. Only valid if DA_Binding is not NULL AND + DA_HasAppBinding is FALSE. + DA_IsLowspeed (BOOL) - Determines if the device is a lowspeed or full + speed device. Can be set, but this will probably ever used by the + hub class. + DA_IsConnected (BOOL) - is TRUE, if the device is still mounted to + the USB or FALSE, if it has been disconnected. This is normally + the first thing to check whenever your pipe requests come back + with UHIOERR_TIMEOUT. Hence, avoid transfers to unconnected + devices. + DA_HasAddress (BOOL) - is TRUE, if the device has been assigned an + address. Normally, no devices with DA_HasAddress set to FALSE + will remain in the system. + DA_HasDevDesc (BOOL) - TRUE, if the stack was able to read out the + device descriptor. this will yield information like product ID, + device class etc.. FALSE, if something went wrong. + DA_IsConfigured (BOOL) - yields TRUE, if there is an configuration to + work with. This means that you can look at the list of + configurations and may also expect interface and endpoint + descriptors. If something went wrong during the config probing + process, this returns FALSE. + DA_HasAppBinding (BOOL) - yields TRUE, if there is an application + binding. + DA_ConfigList (struct List *) - pointer to the list of + configurations available for this device. + + PGA_CONFIG: (read-only) + CA_ConfigNum (UWORD) - returns the internal number of the config + given. Can be used to set the config with psdSetDeviceConfig(). + CA_ConfigName (STRPTR) - gives back a name for the config. If no + specific name could be read out from the device, Poseidon + will generate a default string. + CA_MaxPower (UWORD) - returns the maximum power in mA the device + will use in this configuration. + CA_NumInterfaces (UWORD) - holds the number of interfaces available + in this configuration. + CA_Device (APTR) - uplinking pointer to the device the config is + attached to. + CA_InterfaceList (struct List *) - pointer to the list of interfaces + available for the config. + CA_Attrs (UWORD) - attributes for this config (see USB specs). + CA_SelfPowered (BOOL) - if the device is self-powered in this config, + this flag will return TRUE. On FALSE, device is in bus-powered + mode. + CA_RemoteWakeup (BOOL) - in the case the device supports the remote + wakeup feature, this field will be TRUE. + + PGA_INTERFACE: (read-only) + IFA_InterfaceNum (UWORD) - returns the interface number. + IFA_AlternateNum (UWORD) - if the interface has alternative settings, + this will be its number, otherwise just zero. + IFA_InterfaceName (STRPTR) - pointer to a string describing the + interface. Poseidon will generate a default string if no specific + name could be read from the device. + IFA_Class (UWORD) - class code of the interface. See devices/usb.h + for the list of known classes. psdNumToStr() may be used to + convert this number into human readable form. + IFA_SubClass (UWORD) - class dependant subclass code. Some subclasses + are defined in devices/usb.h. + IFA_Protocol (UWORD) - class specific protocol code. + IFA_NumEndpoints (UWORD) - number of endpoints available for this + interface, excluding the default control endpoint 0. + IFA_Binding (APTR) - pointer to a private binding structure, if the + interface has been claimed by a class or NULL, if no binding + exists. + IFA_BindingClass (struct Library *) - library pointer of the class + having a binding to this interface. Only valid if IFA_Binding is + not NULL. + IFA_Config (APTR) - uplinking pointer to the config the interface is + attached to. + IFA_EndpointList (struct List *) - pointer to the list of endpoints + available for this interface. + IFA_AlternateIfList (struct List *) - pointer to the list of + alternate settings available. The entries in this list are normal + interface structures except for the IFA_Binding and + IFA_BindingClass are not valid in the alternative setting. To + make this setting the active one, use psdSetAltInterface(). + + PGA_ENDPOINT: (read-only) + EA_EndpointNum (UWORD) - number of the endpoint. + EA_TransferType (UWORD) - transfer type, either USEAF_CONTROL, + USEAF_ISOCHRONOUS, USEAF_BULK or USAEF_INTERRUPT + (see devices/usb.h). + EA_MaxPktSize (UWORD) - returns the MaxPktSize for this endpoint. + EA_Interval (UWORD) - for interrupt endpoints, this field will + contain the interval in milliseconds before the request should be + retried. + EA_Interface (APTR) - uplinking pointer to the interface the endpoint + is attached to. + EA_IsIn (BOOL) - returns TRUE for IN (device to host) endpoints or + FALSE for OUT (host to device) endpoints. + + PGA_PIPE: (partially read/write) + PPA_Endpoint (APTR) - pointer to the endpoint the pipe is associated + with or NULL for default endpoint 0. Can be set by the user. + PPA_EndpointNum (UWORD) - number of target endpoint. This field can + be written for special 'hacking' purpose. + PPA_DeviceAddress (UWORD) - device address of the usb device. Can be + changed, but consider this hacking, that might disturb other + devices on the bus. + PPA_Error (BYTE) - returns the error code for the last transfer. See + devices/usbhardware.h for the list of possible errors. This error + code can also be converted to readable format using a call to + psdNumToStr(). + PPA_Actual (ULONG) - number of bytes actually transferred during last + pipe transfer. + PPA_MaxPktSize (UWORD) - returns the number of bytes allowed for one + packet. Can be changed (for good reasons only). + PPA_IORequest (struct UsbHWIOReq *) - pointer to the IO request used + by the pipe. Note that you will probably never wish to read or + change fields in this IORequest yourself. Use the tags instead. + PPA_NakTimeout (BOOL) - if set to TRUE, the pipe will be retired + after the time given with PPA_NakTimeoutTime, when the device + constantly replies with NAKs. This could be the case if no data + is available at the endpoint, or the usb device is broken in some + kind. Default is FALSE, which means that the pipe will never be + retired due to NAKs. Can be both read and written. + PPA_NakTimeoutTime (ULONG) - time to wait in milliseconds until the + request is retired due to NAK timeout (see above). This field can + and should be written, if PPA_NakTimeout is set to TRUE. + PPA_NoShortPackets (BOOL) - if set to TRUE, no short package (packet + with size shorter than MaxPktSize) will be generated on OUT + transfers, if this bit is set. This allows you to generate a + constant stream of data with multiple requests. To be effective, + the transfer size must be a multiple of MaxPktSize. + PPA_AllowRuntPackets (BOOL) - allow packets that are smaller than the + number of bytes specified without returning UHIOERR_RUNTPACKET. + You will have to read the PPA_Actual field (or use + psdGetPipeActual()) to get the actual amount of data transferred. + + PGA_APPBINDING: (read/write) + ABA_ReleaseHook (struct Hook *) - pointer to a function hook that + will be called if the binding must be terminated (e.g. when the + device has been unplugged). After this call the application + binding structure will be gone (see psdClaimAppBinding() for more + details). The device will also be freed, if there are no open + pipes anymore. This hook also will be called from + psdReleaseAppBinding(). + ABA_Device (APTR) - pointer to the device that is bound with this + binding. Do not change this while running. + ABA_UserData (ULONG) - pointer to auxillary data for your private + use. + + RESULT + num - number of tags actually read or -1, if the request was not + supported somehow. + + SEE ALSO + psdSetAttrs(), psdNumToStr() + + + poseidon.library/psdGetNextDevice poseidon.library/psdGetNextDevice + + NAME + psdGetNextDevice -- traverse the device list + + SYNOPSIS + pd = psdGetNextDevice(oldpd); + D0 A0 + + APTR psdGetNextDevice(APTR); + + FUNCTION + psdGetNextDevice() is used to traverse the list of all devices + available to stack. It will also cross all mounted hardware devices. + + psdGetNextDevice() needs to be protected with a pair of + psdLockReadPBase() and psdUnlockPBase() during traversal. + + INPUTS + oldpd - NULL for the first device, or pointer to the last device. + + RESULT + pd - pointer to the next device in the list, or NULL if there was no + further device. + + SEE ALSO + psdLockReadPBase(), psdUnlockPBase(), psdFindDevice() + + + poseidon.library/psdGetPipeActual poseidon.library/psdGetPipeActual + + NAME + psdGetPipeActual -- get amount of bytes transferred with a pipe + + SYNOPSIS + length = psdGetPipeActual(pp); + D0 A1 + + ULONG psdGetPipeActual(APTR); + + FUNCTION + psdGetPipeActual() is used to determine the amount of data + transferred during the last pipe transfer. This will be neccessary if + you allowed the reception of runt packets enabled with the + PPA_ALLOWRUNTPACKETS tag. + + NOTE + You can also use psdGetAttrs() to read the actual length. + + INPUTS + pp - pointer to pipe structure to send the request to. + + RESULT + length - number of bytes transferred during last pipe transaction. + + SEE ALSO + psdGetPipeError(), psdSendPipe(), psdAbortPipe(), psdGetAttrs() + + + poseidon.library/psdGetPipeError poseidon.library/psdGetPipeError + + NAME + psdGetPipeError -- get last IO error from a pipe + + SYNOPSIS + ioerr = psdGetPipeError(pp); + D0 A1 + + LONG psdGetPipeError(APTR); + + FUNCTION + Returns the IO error of the last transfer with the given pipe. + Whenever you are using asynchronous pipe transfers, you will have to + read the error code yourself from the pipe. + + NOTE + You can also use psdGetAttrs() to read the error code. + + Error codes can be converted into human readable strings using the + psdNumToStr() function. + + INPUTS + pp - pointer to pipe structure to send the request to. + + RESULT + ioerr - zero, if everthing went okay, else the IO error code. + + SEE ALSO + psdGetPipeActual(), psdSendPipe(), psdAbortPipe(), psdGetAttrs() + + + poseidon.library/psdGetStringDescriptor seidon.library/psdGetStringDescriptor + + NAME + psdGetStringDescriptor -- try to get a device string descriptor + + SYNOPSIS + str = psdGetStringDescriptor(pp, idx); + D0 A1 D0 + + STRPTR psdAddClass(APTR, UWORD); + + FUNCTION + Tries to read out a device string descriptor with the given index. + Automatically does the unicode to ascii conversion and allocates + enough memory to hold the final string. + + On the first invocation on a device, it also tries to acquire the + array of supported languages and sets the current language to a + reasonable value. + + The returned string buffer should be freed using psdFreeVec(), if it + is not linked to some stack internal structure. + + INPUTS + pp - pointer to the default control pipe of a device. + idx - index number of the string to fetch. + + RESULT + str - pointer to a newly created buffer with the string fetched, + or NULL if something failed. + + SEE ALSO + psdFreeVec() + + + poseidon.library/psdLockReadDevice poseidon.library/psdLockReadDevice + + NAME + psdLockReadDevice -- lock device for reading + + SYNOPSIS + psdLockReadDevice(pd); + A0 + + void psdLockReadDevice(APTR); + + FUNCTION + This function locks the access to the internal device structures for + reading. This can be used to ensure the data and pointers remain + valid during querying with GetAttrs(). + + psdLockReadDevice() calls nest. + + Be sure to unlock the device after the use or you will hang the stack + very quickly. + + Normal classes will probably not need to use this call, so it is + considered to be at least semi-private. + + WARNING + Be sure NOT to have locked the base for reading if you want to lock + the base for writing later. THIS WILL CAUSE A DEADLOCK! It is + possible to lock the base for reading AFTER having claimed a writing + lock, but not the other way round! + + SEE ALSO + psdUnlockPBase(), psdLockWritePBase(), psdGetNextDevice() + + + poseidon.library/psdLockReadPBase poseidon.library/psdLockReadPBase + + NAME + psdLockReadPBase -- lock access to internal data structures + + SYNOPSIS + psdLockReadPBase(); + + void psdLockReadPBase(void); + + FUNCTION + This function locks the access to internal data structures for + reading. This especially includes traversal of lists, like classes, + devices, and hardware (which could change at any time otherwise). + + psdLockReadPBase() calls nest. + + Be sure to unlock the base after the use or you will hang the stack + very quickly. Try to keep the locking stage as short as possible. + + Normal classes will probably not need to use this call, so it is + considered to be at least semi-private. + + WARNING + Be sure NOT to have locked the base for reading if you want to lock + the base for writing later. THIS WILL CAUSE A DEADLOCK! It is + possible to lock the base for reading AFTER having claimed a writing + lock, but not the other way round! + + SEE ALSO + psdUnlockPBase(), psdLockWritePBase(), psdGetNextDevice() + + + poseidon.library/psdLockWriteDevice poseidon.library/psdLockWriteDevice + + NAME + psdLockWriteDevice -- lock access for changing device structures + + SYNOPSIS + psdLockWriteDevice(pd); + A0 + + void psdLockWriteDevice(APTR); + + FUNCTION + This function locks the access to a device structure for writing. + This will only be neccessary if you change some linkages and + structures inside the device, which you will probably never do. + + Note that for some poseidon calls like psdEnumerateDevice(), the + locking and unlocking is done automatically. Refer to the docs for + that call. + + psdLockWriteDevice() calls nest. + + Be sure to unlock the base after the use or you will hang the stack + very quickly. + + Normal classes will probably not need to use this call, so it is + considered to be at least semi-private. + + WARNING + Be sure NOT to have locked the device for reading if you want to lock + the device for writing later. THIS WILL CAUSE A DEADLOCK! It is + possible to lock it for reading AFTER having claimed a writing lock, + but not the other way round! + + SEE ALSO + psdUnlockDevice(), psdLockReadDevice(), psdEnumerateDevice() + + + poseidon.library/psdLockWritePBase poseidon.library/psdLockWritePBase + + NAME + psdLockWritePBase -- lock access for changing structures + + SYNOPSIS + psdLockWritePBase(); + + void psdLockWritePBase(void); + + FUNCTION + This function locks the access to internal data structures for your + exclusive manipulation. The base must be locked whenever you are + going to add or remove internal nodes, link or unlike system + components. + + Note that for some poseidon calls like psdAllocDevice(), the locking + and unlocking is done automatically. Refer to the docs for that call. + + psdLockWritePBase() calls nest. + + Be sure to unlock the base after the use or you will hang the stack + very quickly. + + Normal classes will probably not need to use this call, so it is + considered to be at least semi-private. + + WARNING + Be sure NOT to have locked the base for reading if you want to lock + the base for writing later. THIS WILL CAUSE A DEADLOCK! It is + possible to lock the base for reading AFTER having claimed a writing + lock, but not the other way round! + + SEE ALSO + psdUnlockPBase(), psdLockReadPBase(), psdGetNextDevice() + + + poseidon.library/psdNumToStr poseidon.library/psdNumToStr + + NAME + psdNumToStr -- convert a value of certain meaning into a string + + SYNOPSIS + str = psdNumToStr(type, idx, defstr); + D0 D0 D1 A0 + + STRPTR psdNumToStr(UWORD, LONG, STRPTR); + + FUNCTION + psdNumToStr() is a support function which will convert IDs and other + codes of known type into a readable string. + + NOTE + This function adds about 36 KB to the library :) + + INPUTS + type - code/value type. Currently this is one of these: + NTS_IOERR - for io error codes + NTS_LANGID - for USB language IDs + NTS_TRANSTYPE - for transfer types + NTS_VENDORID - for the USB vendor IDs + NTS_CLASSCODE - for known class codes. + idx - ID, number or code to convert. + defstr - if no string is found in the database, this string will + be returned instead. + + RESULT + str - pointer to the string corresponding to the code or defstr, if + the code is unknown. + + + poseidon.library/psdPipeSetup poseidon.library/psdPipeSetup + + NAME + psdPipeSetup -- set request data for control pipes + + SYNOPSIS + psdPipeSetup(pp, rt, rq, val, idx); + A1 D0 D1 D2 D3 + + void psdPipeSetup(APTR, UWORD, UWORD, UWORD, UWORD); + + FUNCTION + This function is used to configure a control pipe request. It sets + the bmRequestType, bRequest, wValue and wIndex fields of the + eight-byte setup packet (see devices/usb.h for more information). It + also does the required big-endian to little-endian conversions on the + wValue and wIndex fields. + + The wLength field is set automatically on psdDoPipe() or + psdSendPipe(). + + INPUTS + pp - pointer to the control pipe allocated using psdAllocPipe() + rt - bmRequestType field. This is a bitmap with the following flags: + URTF_OUT - direction of the transfer is set to from host to + device (OUT). Normally, this is also used for control + transfers without data phase. + URTF_IN - data is going to be read in (device to host) during + the data phase. + URTF_STANDARD - this is a standard usb request. + URTF_CLASS - this is a class specific request. + URTF_VENDOR - this is a vendor specific request. + URTF_DEVICE - the request is aimed at the whole device. + URTF_INTERFACE - the request is targeted at an interface. For + standard usb requests, the interface number is given in the + wIndex field. + URTF_ENDPOINT - the request is targeted at an endpoint. For + standard usb requests, the endpoint number is given in the + wIndex field or'ed with URTF_IN, if the endpoint is an IN + endpoint. + URTF_OTHER - the request goes somewhere else. + rq - request number for bRequest. See devices/usb.h for some standard + requests. + val - wValue in big-endian format. This is request specific. + idx - wIndex in big-endian format. Also request specific. + + SEE ALSO + psdDoPipe(), psdSendPipe() + + + poseidon.library/psdReleaseAppBinding poseidon.library/psdReleaseAppBinding + + NAME + psdReleaseAppBinding -- release an application binding again + + SYNOPSIS + psdReleaseAppBinding(pab); + A0 + + void psdReleaseAppBinding(APTR); + + FUNCTION + If you want to terminate using a device, you must release the binding + previously acquired by psdClaimAppBinding(). This is done with a + corresponding call to psdReleaseAppBinding(). The function will call + the your Hook function to allow you take the correct actions to avoid + further calls to the device, as psdReleaseAppBinding() might also be + called by the stack itself, when the device gets unplugged. + + The hook will be called via utility.library/CallHookPkt() with the + hook structure itself in A0, the AppBinding as object in A2 and + the contents of the ABA_UserData field as message in A1. + + As this abortion operation sometimes may be difficult to control with + the asynchronous hook call, the device structure will not be freed to + avoid crashes, IF AND ONLY IF there are still some pipes allocated + for this device. However, all further transactions will be denied + with an IOERR_ABORTED error code. A call to psdFreePipe(), closing + the last pipe will finally free the device data. Even if the device + is plugged in again, it will not be re-enabled (as there is no + reliable operation to return the device to its previous state and + ensure, that this is really the same one unplugged earlier). + + This function will free the AppBinding context, rendering further + accesses to the pab pointer invalid. + + INPUTS + pab - pointer to the internal AppBinding structure returned by + psdClaimAppBinding() or psdGetAttrs() with the DA_Binding tag. + Using a NULL pointer is okay, and will just do nothing. + + SEE ALSO + psdClaimAppBinding(), psdFindDevice() + + + poseidon.library/psdRemClass poseidon.library/psdRemClass + + NAME + psdRemClass -- remove an usb class library from the stack + + SYNOPSIS + psdRemClass(puc); + A1 + + void psdRemClass(struct Library *); + + FUNCTION + psdRemClass() removes an class library from the stack. The puc + pointer will become invalid right after. + + NOTE + If any bindings to interfaces or devices still exist, this call will + try to remove all these bindings. If it does not succeed for + impossible reasons, this call will go into Wait(0L) state. + + INPUTS + puc - pointer to previously opened usb class. + + SEE ALSO + psdAddClass(), psdClassScan() + + + poseidon.library/psdRemHardware poseidon.library/psdRemHardware + + NAME + psdRemHardware -- close down an usb hardware + + SYNOPSIS + psdRemHardware(phw); + A0 + + void psdRemHardware(APTR); + + FUNCTION + This function may be used to close down a previously allocated USB + hardware using psdAllocHardware(). As all devices connected to the + hardware will be closed down aswell, none of these devices may still + have bindings. These bindings will be terminated aswell. For this + reason, this call might take some time to complete. + + Normally, there is no use calling this function except for the stack + manager (GUI) or the library expunge function. + + The phw hardware pointer becomes invalid right after. + + INPUTS + phw - internal usb hardware pointer. + + SEE ALSO + psdRemHardware(), psdEnumerateHardware() + + + poseidon.library/psdRemErrorMsg poseidon.library/psdRemErrorMsg + + NAME + psdRemErrorMsg -- free an error message + + SYNOPSIS + psdRemErrorMsg(pem); + A0 + + void psdRemErrorMsg(APTR); + + FUNCTION + Remove an error message from the list. This is a function which you + probably will never use. Note that the pem pointer gets invalid right + after this call. + + A pointer to the list of error messages can be acquired using + psdGetAttrs(), but is only valid inside a Forbid()/Permit() clause. + + INPUTS + pen - pointer to error message to deallocate. + + SEE ALSO + psdAddErrorMsg() + + + poseidon.library/psdSafeRawDoFmt poseidon.library/psdSafeRawDoFmt + + NAME + psdSafeRawDoFmtA -- add an error or information message for the user + psdSafeRawDoFmt -- varargs stub for psdSafeRawDoFmtA + + SYNOPSIS + psdSafeRawDoFmtA(buf, len, fmtstr, fmtdata); + A0 D0 A1 A2 + + void psdSafeRawDoFmtA(STRPTR, ULONG, STRPTR, APTR); + + psdSafeRawDoFmt(buf, len, fmtstr, ...); + + APTR psdSafeRawDoFmt(STRPTR, ULONG, STRPTR, ...); + + FUNCTION + Just like sprintf(), but avoid buffer overruns by truncating the + string to the maximum buffer size. + + INPUTS + buf - pointer to a buffer to store the formatted string in. + len - size of this buffer. + fmtstr - formatted string like in printf() or RawDoFmt() + fmtdata - format parameters + + SEE ALSO + RawDoFmt() + + + poseidon.library/psdSendPipe poseidon.library/psdSendPipe + + NAME + psdSendPipe -- initiate asynchronous pipe transfer + + SYNOPSIS + psdSendPipe(pp, data, length); + A1 A0 D0 + + void psdSendPipe(APTR, APTR, ULONG); + + FUNCTION + Asynchronously start a transfer to an endpoint. Immediately returns + from this call without waiting for it to terminate. You will get back + the pipe request at the message port you gave when allocating the + pipe when it is ready, triggering the MsgPort signal for you when it + arrives. + + You can also use psdWaitPipe() to wait for the arrival of the + message. + + It is illegal to reuse a pipe request while it is still pending! The + contents of the pipe may not be altered during this phase. The + restrictions are somewhat similar to the IORequests send by the exec + function SendIO(). + + If you don't want to wait for the termination of a transfer, you can + TRY to abort it using psdAbortPipe(), but you have still to wait for + it to arrive. + + To get the error message, you can use the psdGetPipeError() function. + + NOTE + The direction of the transfer is determined by the type of the + endpoint for bulk, interrupt and isochronous transfers. For control + transfers, however, this is given by the URTF_IN/URTF_OUT flags in + the bmRequestType field of the setup packet, which can be set by + psdPipeSetup(). For control transfers without data phase, using a + NULL pointer for data and zero for the length is permitted. Also, the + wLength field of the setup packet is filled automatically with the + correct length of your data transfer request. + + INPUTS + pp - pointer to pipe structure to send the request to. + data - pointer to the data buffer to send or receive. + length - number of bytes to transfer + + SEE ALSO + psdPipeSetup(), psdDoPipe(), psdAbortPipe(), psdWaitPipe(), + psdGetPipeError(), psdGetPipeActual() + + + poseidon.library/psdSetAltInterface poseidon.library/psdSetAltInterface + + NAME + psdSetAltInterface -- change an interface to an alternate setting + + SYNOPSIS + success = psdSetAltInterface(pp, pif); + D0 A1 A0 + + BOOL psdSetAltInterface(APTR, APTR); + + FUNCTION + + USB devices support to have alternate settings for an interface. + Whenever such alternate settings exist, you may want to switch + between them. psdSetAltInterface() changes the interface to its + alternate setting. These interfaces are not stored directly in the + list of interfaces but in a sublist for the active one. See + psdGetAttrs() for the IFA_AlterateIfList tag. + + This function does some internal magic for the given alternative + interface to become the active one. + + If the given interface is already active, this operation will do + nothing. + + NOTE + Bindings will be moved alltogether. Note that pointers to the + previously active interface will become obsolete for the + IFA_Binding and IFA_BindingClass calls. + + INPUTS + pp - pointer to the default control pipe of a device. + pif - pointer to the alternate interface setting to become active. + + RESULT + success - TRUE, if the modification was successful or FALSE, if the + interface could not be changed. + + SEE ALSO + psdGetAttrs() + + + poseidon.library/psdSetAttrs poseidon.library/psdSetAttrs + + NAME + psdSetAttrsA -- change fields of an internal stack structure + psdSetAttrs -- varargs stub for psdSetAttrsA() + + SYNOPSIS + num = psdSetAttrsA(type, psdstruct, taglist); + D0 D0 A0 A1 + + LONG psdSetAttrsA(ULONG, APTR, struct TagList *); + + num = psdSetAttrs(type, psdstruct, tag1, ...); + + LONG psdSetAttrs(ULONG, APTR, Tag, ...); + + FUNCTION + Changes the fields allowed to be written of an internal stack + structure according to the attributes chosen in the tag list. For + each entry in the tag list, ti_Tag identifies the attribute and + ti_Data is the long data you wish to change the value to. + + There are currently a number of ten different system structures + which can be accessed in this way. To avoid adding multiple functions + with the same semantics, psdSetAttrs() requires the type of the + structure passed. + + INPUTS + type - describes the type of the structure passed. + See libraries/poseidon.h for details. + psdstruct - pointer to the system structure on which information + should be changed. Can be NULL only for PGA_STACK. + taglist - pointer to TagItem list, terminated by TAG_END. + + TAGS + See psdGetAttrs() for the tags which can be changed. + + RESULT + num - number of tags actually read or -1, if the request was not + supported somehow. + + SEE ALSO + psdGetAttrs() + + + poseidon.library/psdSetDeviceConfig poseidon.library/psdSetDeviceConfig + + NAME + psdSetDeviceConfig -- change the config of a device + + SYNOPSIS + success = psdSetDeviceConfig(pp, cfgnum); + D0 A1 D0 + + BOOL psdSetDeviceConfig(APTR, UWORD); + + FUNCTION + Changes the configuration of the device to a new one. As only a few + devices support multiple configurations, and the stack automatically + handles this case, you will probably never call this function. + + Classes which want to call psdSetDeviceConfig() must have a device + binding. An interface binding is not enough and might conflict with + other classes having bindings to interfaces. + + INPUTS + pp - pointer to the default control pipe of a device. + cfgnum - configuration number as given in the configuration + descriptor. + + RESULT + success - TRUE, if the change was successful or FALSE, if the config + could not be altered. + + SEE ALSO + psdGetAttrs() + + + poseidon.library/psdSpawnSubTask poseidon.library/psdSpawnSubTask + + NAME + psdSpawnSubTask -- launch a subtask + + SYNOPSIS + task = psdSpawnSubTask(name, initpc, userdata); + D0 A0 A1 A2 + + struct Task * psdSpawnSubTask(STRPTR, APTR, APTR); + + FUNCTION + Simple function to lauch a subtask. The name will be copied and + automatically freed at the termination of the task, as will the 8KB + of stack allocated. + + The task will use a default priority of 5. + + NOTE + If these parameters don't suit you, just write your own code. Note + that this really creates a Task and not a DOS Process. + + INPUTS + name - name of the task + initpc - inital program counter to start the program at. + userdata - some data that will be entered in the tc_UserData field. + + RESULT + task - pointer to a task structure or NULL, if the task creation + failed. Note that the task pointer will become invalid as soon + as the tasks terminates. It's recommended that you do not use + it as a structure pointer, but a success indicator. + + BUGS + Should really use taglists. + + + poseidon.library/psdUnlockDevice poseidon.library/psdUnlockDevice + + NAME + psdUnlockDevice -- unlock access to a device + + SYNOPSIS + psdUnlockDevice(pd); + A0 + + void psdUnlockDevice(APTR); + + FUNCTION + After psdLockReadDevice() or psdLockWriteDevice() had been called to + lock the a device, psdUnlockDevice() must be used to unlock it again. + + Be sure to unlock the device after the use or you will hang the stack + very quickly. + + SEE ALSO + psdLockReadDevice(), psdLockWriteDevice() + + + poseidon.library/psdUnlockPBase poseidon.library/psdUnlockPBase + + NAME + psdUnlockPBase -- unlock access to internal data structures + + SYNOPSIS + psdUnlockPBase(); + + void psdUnlockPBase(void); + + FUNCTION + After psdLockReadPBase() or psdLockWritePBase() had been called to + lock the base, psdUnlockPBase() must be used to unlock the base + again. + + Be sure to unlock the base after the use or you will hang the stack + very quickly. + + SEE ALSO + psdLockReadPBase(), psdLockWritePBase(), psdGetNextDevice() + + + poseidon.library/psdWaitPipe poseidon.library/psdWaitPipe + + NAME + psdWaitPipe -- wait for the completion of a pipe transfer + + SYNOPSIS + ioerr = psdWaitPipe(pp); + D0 A1 + + LONG psdWaitPipe(APTR); + + FUNCTION + + After you have started a pipe or aborted a pipe, you might want to + wait for it to complete or terminate. psdWaitPipe() does this for + you: it waits for the pipe message to arrive, removes it from the + reply port queue and returns the IO error code. + + NOTE + If you don't want to wait for the termination of a transfer, you can + TRY to abort it using psdAbortPipe(), but you have still to wait for + it to arrive. + + INPUTS + pp - pointer to pending pipe to wait for. + + RESULT + ioerr - zero, if everthing went okay, else the IO error code. + + SEE ALSO + psdPipeSetup(), psdDoPipe(), psdAbortPipe(), psdWaitPipe(), + psdGetPipeError(), psdGetPipeActual() + + + diff --git a/rom/usb/poseidon/poseidon.library.c b/rom/usb/poseidon/poseidon.library.c new file mode 100644 index 000000000..f69fb7b16 --- /dev/null +++ b/rom/usb/poseidon/poseidon.library.c @@ -0,0 +1,9287 @@ +/**************************************************************************** + + __ __ V/\V. /\ + |" | |" | mMMnw, || [] + | | | | (o o)W () || || + |__|_|_"| | / |Mw || ||// + (" " \| \ -'_/mw \\||/ + \______) ~%%/WM" \|| + _____ ___ ______ _____ __ _____ ___ __ __/~~__ ~~\ _|| +|"(" \()/\" \ ()/"_ )|"(___) ) )|"(" \ ()/\" \(__)/" ) /" ) " \ /_)O +| ) )/" \ \ (_/"\__/ | )_ ( ( | )_ ) /" \ \ / /|/ / ·\ \/ ,|O +| (___/( (_\__) _\ \_ | (__) ) )| (__) |( (_\__)/ /"/ / |\ '_|O +| | _ \ / / /" \_/ ) | ")__ ( ( | )" ) \ / // /|/ / . .|/\__/ || +|__| (_) \/__/ (______/ |_(___) )_)|_(___/ . \/__/(__/ (__/ .:.:| || + _____ + |" __ \ Poseidon -- The divine USB stack for Amiga computers + | (__) ) + | __ ( Designed and written by + |"(__) ) Chris Hodges + |_____/ Copyright ©2002-2009 Chris Hodges. All rights reserved. + + ****************************************************************************/ + +/* + *---------------------------------------------------------------------------- + * Poseidon main library + *---------------------------------------------------------------------------- + * By Chris Hodges + */ + +#include "debug.h" + +#include "poseidon.library.h" + +#include "numtostr.h" + +#include +#include +#include +#include +#include + +#define NewList(list) NEWLIST(list) + +#define min(x,y) (((x) < (y)) ? (x) : (y)) +#define max(x,y) (((x) > (y)) ? (x) : (y)) + +extern const struct PsdWStringMap usbclasscodestr[]; +extern const struct PsdULStringMap usbcomboclasscodestr[]; +extern const struct PsdULStringMap usbdesctypestr[]; +extern const struct PsdWStringMap usbhwioerrstr[]; +extern const struct PsdUWStringMap usblangids[]; +extern const struct PsdUWStringMap usbvendorids[]; + +extern struct ExecBase *SysBase; + +/* Static data */ +const char libname[] = MOD_NAME_STRING; + +#define UsbClsBase puc->puc_ClassBase +#define DOSBase ps->ps_DosBase +#define TimerBase ps->ps_TimerIOReq.tr_node.io_Device + +/* LibInit */ +static int libInit(LIBBASETYPEPTR ps) +{ + KPRINTF(10, ("libInit ps: 0x%08lx SysBase: 0x%08lx\n", + ps, SysBase)); + + ps->ps_StackInit = FALSE; + ps->ps_UtilityBase = (struct UtilityBase *) OpenLibrary("utility.library", 39); + +#define UtilityBase ps->ps_UtilityBase + + if(UtilityBase) + { + NewList(&ps->ps_Hardware); + NewList(&ps->ps_Classes); + NewList(&ps->ps_ErrorMsgs); + NewList(&ps->ps_EventHooks); + ps->ps_EventReplyPort.mp_Flags = PA_IGNORE; + NewList(&ps->ps_EventReplyPort.mp_MsgList); + NewList(&ps->ps_ConfigRoot); + NewList(&ps->ps_AlienConfigs); + + NewList(&ps->ps_DeadlockDebug); + + InitSemaphore(&ps->ps_ReentrantLock); + InitSemaphore(&ps->ps_PoPoLock); + + if((ps->ps_MemPool = CreatePool(MEMF_CLEAR|MEMF_PUBLIC|MEMF_SEM_PROTECTED, 16384, 1024))) + { + if((ps->ps_SemaMemPool = CreatePool(MEMF_CLEAR|MEMF_PUBLIC, 16*sizeof(struct PsdReadLock), sizeof(struct PsdBorrowLock)))) + { + pInitSem(ps, &ps->ps_Lock, "PBase"); + pInitSem(ps, &ps->ps_ConfigLock, "ConfigLock"); + KPRINTF(20, ("libInit: Done!\n")); + return TRUE; + } + DeletePool(ps->ps_MemPool); + } else { + KPRINTF(20, ("libInit: CreatePool() failed!\n")); + } + CloseLibrary((struct Library *) UtilityBase); + } else { + KPRINTF(20, ("libInit: OpenLibrary(\"utility.library\", 39) failed!\n")); + } + return FALSE; +} + +/* LibOpen */ +static int libOpen(LIBBASETYPEPTR ps) +{ + struct PsdIFFContext *pic; + + KPRINTF(10, ("libOpen ps: 0x%08lx\n", ps)); + ObtainSemaphore(&ps->ps_ReentrantLock); + if(!ps->ps_StackInit) + { + ps->ps_TimerIOReq.tr_node.io_Message.mn_Node.ln_Type = NT_REPLYMSG; + ps->ps_TimerIOReq.tr_node.io_Message.mn_ReplyPort = NULL; + ps->ps_TimerIOReq.tr_node.io_Message.mn_Length = sizeof(struct timerequest); + if(!OpenDevice("timer.device", UNIT_MICROHZ, (struct IORequest *) &ps->ps_TimerIOReq, 0)) + { + ps->ps_TimerIOReq.tr_node.io_Message.mn_Node.ln_Name = "Poseidon"; + ps->ps_TimerIOReq.tr_node.io_Command = TR_ADDREQUEST; + + ps->ps_ReleaseVersion = RELEASEVERSION; + ps->ps_OSVersion = MAKE_ID('A','R','O','S'); + + pic = pAllocForm(ps, NULL, IFFFORM_PSDCFG); + if((ps->ps_GlobalCfg = psdAllocVec(sizeof(struct PsdGlobalCfg)))) + { + ps->ps_GlobalCfg->pgc_ChunkID = AROS_LONG2BE(IFFCHNK_GLOBALCFG); + ps->ps_GlobalCfg->pgc_Length = AROS_LONG2BE(sizeof(struct PsdGlobalCfg)-8); + ps->ps_GlobalCfg->pgc_LogInfo = TRUE; + ps->ps_GlobalCfg->pgc_LogWarning = TRUE; + ps->ps_GlobalCfg->pgc_LogError = TRUE; + ps->ps_GlobalCfg->pgc_LogFailure = TRUE; + ps->ps_GlobalCfg->pgc_BootDelay = 2; + ps->ps_GlobalCfg->pgc_SubTaskPri = 5; + ps->ps_GlobalCfg->pgc_PopupDeviceNew = PGCP_ISNEW; + ps->ps_GlobalCfg->pgc_PopupDeviceGone = TRUE; + ps->ps_GlobalCfg->pgc_PopupDeviceDeath = TRUE; + ps->ps_GlobalCfg->pgc_PopupCloseDelay = 5; + ps->ps_GlobalCfg->pgc_PopupActivateWin = FALSE; + ps->ps_GlobalCfg->pgc_PopupWinToFront = TRUE; + ps->ps_GlobalCfg->pgc_AutoDisableLP = FALSE; + ps->ps_GlobalCfg->pgc_AutoDisableDead = FALSE; + ps->ps_GlobalCfg->pgc_AutoRestartDead = TRUE; + ps->ps_GlobalCfg->pgc_PowerSaving = FALSE; + ps->ps_GlobalCfg->pgc_ForceSuspend = FALSE; + ps->ps_GlobalCfg->pgc_SuspendTimeout = 30; + + ps->ps_GlobalCfg->pgc_PrefsVersion = 0; // is updated on writing + ps->ps_ConfigRead = FALSE; + if(pic) + { + pic = pAllocForm(ps, pic, IFFFORM_STACKCFG); + if(pic) + { + pAddCfgChunk(ps, pic, ps->ps_GlobalCfg); + } + } + ps->ps_PoPo.po_InsertSndFile = psdCopyStr("SYS:Prefs/Presets/Poseidon/Connect.iff"); + ps->ps_PoPo.po_RemoveSndFile = psdCopyStr("SYS:Prefs/Presets/Poseidon/Disconnect.iff"); + + { + STRPTR tmpstr; + tmpstr = psdCopyStr((STRPTR) VERSION_STRING); + if(tmpstr) + { + tmpstr[strlen(tmpstr)-2] = 0; + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, "Welcome to %s (%08lx)!", tmpstr, ps->ps_ReleaseVersion); + psdFreeVec(tmpstr); + } else { + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, "Welcome to %s", VERSION_STRING); + } + } + + psdAddErrorMsg0(RETURN_OK, (STRPTR) libname, "This is the AROS port."); + + KPRINTF(10, ("libOpen: Ok\n")); + ps->ps_StackInit = TRUE; + ReleaseSemaphore(&ps->ps_ReentrantLock); + pStartEventHandler(ps); + + return TRUE; + } else { + KPRINTF(20, ("libOpen: No memory for cfg!\n")); + } + } else { + KPRINTF(20, ("libOpen: OpenDevice(timer.device) failed!\n")); + } + ReleaseSemaphore(&ps->ps_ReentrantLock); + return FALSE; + } + ReleaseSemaphore(&ps->ps_ReentrantLock); + KPRINTF(5, ("libOpen: openCnt = %ld\n", ps->ps_Library.lib_OpenCnt)); + return TRUE; +} + +int libExpunge(LIBBASETYPEPTR ps) +{ + struct PsdHardware *phw = (struct PsdHardware *) ps->ps_Hardware.lh_Head; + struct PsdUsbClass *puc = (struct PsdUsbClass *) ps->ps_Classes.lh_Head; + struct PsdErrorMsg *pem = (struct PsdErrorMsg *) ps->ps_ErrorMsgs.lh_Head; + struct PsdIFFContext *pic = (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head; + KPRINTF(10, ("libExpunge ps: 0x%08lx\n", ps)); + while(phw->phw_Node.ln_Succ) + { + psdRemHardware(phw); + phw = (struct PsdHardware *) ps->ps_Hardware.lh_Head; + } + while(puc->puc_Node.ln_Succ) + { + psdRemClass(puc); + puc = (struct PsdUsbClass *) ps->ps_Classes.lh_Head; + } + while(pem->pem_Node.ln_Succ) + { + psdRemErrorMsg(pem); + pem = (struct PsdErrorMsg *) ps->ps_ErrorMsgs.lh_Head; + } + + while(pic->pic_Node.ln_Succ) + { + pFreeForm(ps, pic); + pic = (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head; + } + + if(ps->ps_PoPo.po_Task) + { + ps->ps_PoPo.po_ReadySignal = SIGB_SINGLE; + ps->ps_PoPo.po_ReadySigTask = FindTask(NULL); + Signal(ps->ps_PoPo.po_Task, SIGBREAKF_CTRL_C); + while(ps->ps_PoPo.po_Task) + { + Wait(1L<ps_PoPo.po_ReadySignal); + } + ps->ps_PoPo.po_ReadySigTask = NULL; + //FreeSignal(ps->ps_PoPo.po_ReadySignal); + } + if(ps->ps_EventHandler.ph_Task) + { + ps->ps_EventHandler.ph_ReadySignal = SIGB_SINGLE; + ps->ps_EventHandler.ph_ReadySigTask = FindTask(NULL); + Signal(ps->ps_EventHandler.ph_Task, SIGBREAKF_CTRL_C); + while(ps->ps_EventHandler.ph_Task) + { + Wait(1L<ps_EventHandler.ph_ReadySignal); + } + ps->ps_EventHandler.ph_ReadySigTask = NULL; + //FreeSignal(ps->ps_EventHandler.ph_ReadySignal); + } + psdFreeVec(ps->ps_PoPo.po_InsertSndFile); + psdFreeVec(ps->ps_PoPo.po_RemoveSndFile); + pGarbageCollectEvents(ps); + + CloseDevice((struct IORequest *) &ps->ps_TimerIOReq); + DeletePool(ps->ps_SemaMemPool); + DeletePool(ps->ps_MemPool); + + KPRINTF(1, ("libExpunge: closelibrary utilitybase 0x%08lx\n", + UtilityBase)); + CloseLibrary((struct Library *) UtilityBase); + + CloseLibrary(DOSBase); + + KPRINTF(1, ("libExpunge: removing library node 0x%08lx\n", + &ps->ps_Library.lib_Node)); + Remove(&ps->ps_Library.lib_Node); + + return TRUE; +} +/* \\\ */ + +ADD2INITLIB(libInit, 0) +ADD2OPENLIB(libOpen, 0) +ADD2EXPUNGELIB(libExpunge, 0); + +/* + * *********************************************************************** + * * Library functions * + * *********************************************************************** + */ + +static const ULONG *PsdPTArray[PGA_LAST+1]; + +/* *** Memory *** */ + +/* /// "psdAllocVec()" */ +AROS_LH1(APTR, psdAllocVec, + AROS_LHA(ULONG, size, D0), + LIBBASETYPEPTR, ps, 5, psd) +{ + AROS_LIBFUNC_INIT + ULONG *pmem; + KPRINTF(1, ("psdAllocVec(%ld)\n", size)); +#ifndef MEMDEBUG + if((pmem = AllocPooled(ps->ps_MemPool, size + (1*sizeof(ULONG))))) + { +#else + if((pmem = AllocPooled(ps->ps_MemPool, size + (1*sizeof(ULONG)) + 1024))) + { + ULONG upos = size + (1*sizeof(ULONG)); + UWORD unum = 1024; + UBYTE *dbptr = (UBYTE *) pmem; + while(unum--) + { + dbptr[upos] = upos; + upos++; + } +#endif + //*pmem++ = MAKE_ID('H','U','R','Z'); + *pmem++ = size; + //*((ULONG *) (((UBYTE *) pmem) + size)) = MAKE_ID('N','A','R','F'); + ps->ps_MemAllocated += size; + return((APTR) pmem); + } + return(NULL); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdFreeVec()" */ +AROS_LH1(void, psdFreeVec, + AROS_LHA(APTR, pmem, A1), + LIBBASETYPEPTR, ps, 6, psd) +{ + AROS_LIBFUNC_INIT + ULONG size; + + KPRINTF(1, ("psdFreeVec(%08lx)\n", pmem)); + if(pmem) + { + size = ((ULONG *) pmem)[-1]; + //((ULONG *) pmem)[-2] = 0; + ps->ps_MemAllocated -= size; + +#ifdef MEMDEBUG + FreePooled(ps->ps_MemPool, &((ULONG *) pmem)[-1], size + (1*sizeof(ULONG)) + 1024); +#else + FreePooled(ps->ps_MemPool, &((ULONG *) pmem)[-1], size + (1*sizeof(ULONG))); +#endif + } + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* *** PBase *** */ + +/* /// "pInitSem()" */ +void pInitSem(LIBBASETYPEPTR ps, struct PsdLockSem *pls, STRPTR name) +{ + NewList(&pls->pls_WaitQueue); + NewList(&pls->pls_ReadLocks); + pls->pls_Node.ln_Name = name; + // struct should be nulled anyway + pls->pls_Owner = NULL; + pls->pls_ExclLockCount = 0; + pls->pls_SharedLockCount = 0; + pls->pls_Dead = FALSE; +} +/* \\\ */ + +/* /// "pDeleteSem()" */ +void pDeleteSem(LIBBASETYPEPTR ps, struct PsdLockSem *pls) +{ + // nothing to do here +} +/* \\\ */ + +/* /// "pLockSemExcl()" */ +void pLockSemExcl(LIBBASETYPEPTR ps, struct PsdLockSem *pls) +{ + struct PsdReadLock waitprl; + struct Task *thistask = FindTask(NULL); + + waitprl.prl_Task = thistask; + waitprl.prl_IsExcl = TRUE; + + Forbid(); // ObtainSemaphore(&ps->ps_SemaLock); + do + { + // it's already mine!! + if(thistask == pls->pls_Owner) + { + break; + } + if(!pls->pls_ExclLockCount) + { + // easy case: no shared locks, no exclusive locker + if(!pls->pls_SharedLockCount) + { + break; + } + // sole readlock promotion case + if((pls->pls_SharedLockCount == 1) && ((struct PsdReadLock *) pls->pls_ReadLocks.lh_Head)->prl_Task == thistask) + { + KPRINTF(1, ("Promoting read lock (%08lx) to write lock!\n", thistask)); + break; + } + } + + // okay, bad luck, we've got to wait somehow + AddHead(&pls->pls_WaitQueue, &waitprl.prl_Node); + thistask->tc_SigRecvd &= ~SIGF_SINGLE; + + //ReleaseSemaphore(&ps->ps_SemaLock); + Wait(SIGF_SINGLE); + //ObtainSemaphore(&ps->ps_SemaLock); + + Remove(&waitprl.prl_Node); + } while(TRUE); + pls->pls_Owner = thistask; + pls->pls_ExclLockCount++; + Permit(); //ReleaseSemaphore(&ps->ps_SemaLock); +} +/* \\\ */ + +/* /// "pLockSemShared()" */ +void pLockSemShared(LIBBASETYPEPTR ps, struct PsdLockSem *pls) +{ + struct PsdReadLock *prl; + struct Task *thistask = FindTask(NULL); + + Forbid(); //ObtainSemaphore(&ps->ps_SemaLock); + // is this already locked exclusively by me? + if(thistask == pls->pls_Owner) + { + // yes? then just increase exclusive lock count + pls->pls_ExclLockCount++; + Permit(); //ReleaseSemaphore(&ps->ps_SemaLock); + return; + } + + // find existing readlock + prl = (struct PsdReadLock *) pls->pls_ReadLocks.lh_Head; + while(prl->prl_Node.ln_Succ) + { + if(prl->prl_Task == thistask) + { + KPRINTF(1, ("Increasing ReadLock (%08lx) count to %ld\n", thistask, prl->prl_Count)); + prl->prl_Count++; + Permit(); // ReleaseSemaphore(&ps->ps_SemaLock); + return; + } + prl = (struct PsdReadLock *) prl->prl_Node.ln_Succ; + } + + // this is a new readlock, generate context + if(!(prl = (struct PsdReadLock *) AllocPooled(ps->ps_SemaMemPool, sizeof(struct PsdReadLock)))) + { + KPRINTF(20, ("No mem for shared lock! context (%08lx) on %08lx\n", thistask, pls)); + // try exclusive lock as fallback (needs no memory) + Permit(); // ReleaseSemaphore(&ps->ps_SemaLock); + pLockSemExcl(ps, pls); + return; + } + + KPRINTF(1, ("New ReadLockShared context (%08lx) on %08lx\n", thistask, pls)); + prl->prl_Task = thistask; + prl->prl_Count = 0; + prl->prl_IsExcl = FALSE; + + // if it's exclusively locked, wait for this lock to vanish + while(pls->pls_Owner) + { + AddTail(&pls->pls_WaitQueue, &prl->prl_Node); + thistask->tc_SigRecvd &= ~SIGF_SINGLE; + + //ReleaseSemaphore(&ps->ps_SemaLock); + Wait(SIGF_SINGLE); + //ObtainSemaphore(&ps->ps_SemaLock); + + Remove(&prl->prl_Node); + } + + if(prl->prl_IsExcl) + { + // we got promoted by BorrowLocks during the process! So we don't need the shared stuff anymore + FreePooled(ps->ps_SemaMemPool, prl, sizeof(struct PsdReadLock)); + pls->pls_Owner = thistask; + pls->pls_ExclLockCount++; + } else { + // got the lock! + AddHead(&pls->pls_ReadLocks, &prl->prl_Node); + prl->prl_Count++; + pls->pls_SharedLockCount++; + } + Permit(); //ReleaseSemaphore(&ps->ps_SemaLock); + return; +} +/* \\\ */ + +/* /// "pUnlockSem()" */ +void pUnlockSem(LIBBASETYPEPTR ps, struct PsdLockSem *pls) +{ + struct PsdReadLock *prl; + struct Task *thistask = FindTask(NULL); + BOOL gotit = FALSE; + + Forbid(); //ObtainSemaphore(&ps->ps_SemaLock); + if(pls->pls_Owner) + { + // exclusively locked, this means unlocking task must be owner + if(pls->pls_Owner != thistask) + { + Permit(); //ReleaseSemaphore(&ps->ps_SemaLock); + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "Attempt to unlock exclusive semaphore %08lx not owned by task %s!", + pls, thistask->tc_Node.ln_Name); + return; + + } + if(--pls->pls_ExclLockCount) + { + // still locked + Permit(); //ReleaseSemaphore(&ps->ps_SemaLock); + return; + } + pls->pls_Owner = NULL; + // otherwise drop through and notify + } else { + if(!pls->pls_SharedLockCount) + { + Permit(); //ReleaseSemaphore(&ps->ps_SemaLock); + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "Attempt to unlock (free) semaphore %08lx once too often by task %s!", + pls, thistask->tc_Node.ln_Name); + return; + } + // find readlock + prl = (struct PsdReadLock *) pls->pls_ReadLocks.lh_Head; + while(prl->prl_Node.ln_Succ) + { + if(prl->prl_Task == thistask) + { + if(--prl->prl_Count) + { + // can't be the last lock, so just reduce count and return + Permit(); //ReleaseSemaphore(&ps->ps_SemaLock); + return; + } + // remove read lock, it's no longer needed + KPRINTF(1, ("Removing read lock context (%08lx) on %08lx!\n", thistask, pls)); + Remove(&prl->prl_Node); + FreePooled(ps->ps_SemaMemPool, prl, sizeof(struct PsdReadLock)); + gotit = TRUE; + // losing a designated lock + pls->pls_SharedLockCount--; + break; + } + prl = (struct PsdReadLock *) prl->prl_Node.ln_Succ; + } + if(!gotit) + { + Permit(); //ReleaseSemaphore(&ps->ps_SemaLock); + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "Attempt to unlock (shared) semaphore %08lx once too often by task %s!", + pls, thistask->tc_Node.ln_Name); + return; + } + + // we need to notify anyway, because the waiter could already have a shared lock + // on the same semaphore, and if we only notified on LockCount reaching zero, + // the locker would wait forever. + } + + // notify waiting tasks + prl = (struct PsdReadLock *) pls->pls_WaitQueue.lh_Head; + while(prl->prl_Node.ln_Succ) + { + Signal(prl->prl_Task, SIGF_SINGLE); + prl = (struct PsdReadLock *) prl->prl_Node.ln_Succ; + } + Permit(); //ReleaseSemaphore(&ps->ps_SemaLock); +} +/* \\\ */ + +/* /// "psdLockReadPBase()" */ +AROS_LH0(void, psdLockReadPBase, + LIBBASETYPEPTR, ps, 8, psd) +{ + AROS_LIBFUNC_INIT + KPRINTF(2, ("psdLockReadPBase(%08lx)\n", FindTask(NULL))); + pLockSemShared(ps, &ps->ps_Lock); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdLockWritePBase()" */ +AROS_LH0(void, psdLockWritePBase, + LIBBASETYPEPTR, ps, 7, psd) +{ + AROS_LIBFUNC_INIT + KPRINTF(2, ("psdLockWritePBase(%08lx)\n", FindTask(NULL))); + pLockSemExcl(ps, &ps->ps_Lock); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdUnlockPBase()" */ +AROS_LH0(void, psdUnlockPBase, + LIBBASETYPEPTR, ps, 9, psd) +{ + AROS_LIBFUNC_INIT + KPRINTF(2, ("psdUnlockPBase(%08lx)\n", FindTask(NULL))); + pUnlockSem(ps, &ps->ps_Lock); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdBorrowLocksWait()" */ +AROS_LH2(ULONG, psdBorrowLocksWait, + AROS_LHA(struct Task *, task, A1), + AROS_LHA(ULONG, signals, D0), + LIBBASETYPEPTR, ps, 97, psd) +{ + AROS_LIBFUNC_INIT + struct Task *thistask = FindTask(NULL); + ULONG cnt = 0; + ULONG sigmask; + struct PsdSemaInfo *psi; + struct PsdLockSem *pls; + struct PsdReadLock *prl; + struct PsdBorrowLock *pbl; + struct List borrows; + struct List reclaims; + BOOL moveowner; + + XPRINTF(10, ("Borrowing locks from %08lx (%s) to %08lx (%s)!\n", + thistask, thistask->tc_Node.ln_Name, task, task->tc_Node.ln_Name)); + + Forbid(); + psi = (struct PsdSemaInfo *) ps->ps_DeadlockDebug.lh_Head; + while(psi->psi_Node.ln_Succ) + { + pls = psi->psi_LockSem; + if(pls->pls_Owner == thistask) + { + cnt++; + } + if(pls->pls_SharedLockCount) + { + struct PsdReadLock *prl = (struct PsdReadLock *) pls->pls_ReadLocks.lh_Head; + do + { + if(prl->prl_Task == thistask) + { + cnt++; + break; + } + } while((prl = (struct PsdReadLock *) prl->prl_Node.ln_Succ)->prl_Node.ln_Succ); + } + psi = (struct PsdSemaInfo *) psi->psi_Node.ln_Succ; + } + if(!cnt) + { + Permit(); + XPRINTF(10, ("Nothing to borrow!\n")); + return(Wait(signals)); + } + + NewList(&borrows); + NewList(&reclaims); + XPRINTF(10, ("Borrowing %ld locks\n", cnt)); + + psi = (struct PsdSemaInfo *) ps->ps_DeadlockDebug.lh_Head; + while(psi->psi_Node.ln_Succ) + { + moveowner = TRUE; + pls = psi->psi_LockSem; + if(pls->pls_Owner == thistask) + { + // check if the target task is already waiting for that lock + // in this case, we simply remove our exclusive lock and let + // the other task catch it + prl = (struct PsdReadLock *) pls->pls_WaitQueue.lh_Head; + while(prl->prl_Node.ln_Succ) + { + if(prl->prl_Task == task) + { + if(!prl->prl_IsExcl) + { + // if we hand over the excl lock, we have to make sure that the exclusiveness is kept + // and no other thread may catch it while it is shared. + // hence we will need set this lock exclusive aswell + // this no optimal solution, but it guarantees the same + // behaviour with pending lock and no pending lock + prl->prl_IsExcl = TRUE; + XPRINTF(10, ("Promo waiting lock to excl\n")); + } + // move shared lock to top of the list + Remove(&prl->prl_Node); + AddHead(&pls->pls_WaitQueue, &prl->prl_Node); + if((pbl = (struct PsdBorrowLock *) AllocPooled(ps->ps_SemaMemPool, sizeof(struct PsdBorrowLock)))) + { + pbl->pbl_LockSem = pls; + pbl->pbl_ExclLockCount = pls->pls_ExclLockCount; + AddTail(&reclaims, &pbl->pbl_Node); + + // unlock exclusive lock + pls->pls_ExclLockCount = 0; + pls->pls_Owner = NULL; + Signal(task, SIGF_SINGLE); + XPRINTF(10, ("Waiting lock %08lx transfer\n", pls)); + } + moveowner = FALSE; + break; + } + prl = (struct PsdReadLock *) prl->prl_Node.ln_Succ; + } + if(moveowner) + { + if((pbl = (struct PsdBorrowLock *) AllocPooled(ps->ps_SemaMemPool, sizeof(struct PsdBorrowLock)))) + { + pbl->pbl_LockSem = pls; + pbl->pbl_ExclLockCount = pls->pls_ExclLockCount; + AddTail(&borrows, &pbl->pbl_Node); + pls->pls_Owner = task; + XPRINTF(10, ("Lock %08lx transfer\n", pls)); + } + } + } + if(pls->pls_SharedLockCount) + { + prl = (struct PsdReadLock *) pls->pls_ReadLocks.lh_Head; + do + { + if(prl->prl_Task == thistask) + { + // check if target task is waiting for this task + struct PsdReadLock *prl2 = (struct PsdReadLock *) pls->pls_WaitQueue.lh_Head; + while(prl2->prl_Node.ln_Succ) + { + if(prl2->prl_Task == task) + { + // move lock to top of the list + Remove(&prl2->prl_Node); + AddHead(&pls->pls_WaitQueue, &prl2->prl_Node); + if((pbl = (struct PsdBorrowLock *) AllocPooled(ps->ps_SemaMemPool, sizeof(struct PsdBorrowLock)))) + { + pbl->pbl_LockSem = pls; + pbl->pbl_ReadLock = prl; + pbl->pbl_Count = prl->prl_Count; + AddHead(&reclaims, &pbl->pbl_Node); + + // unlock shared lock + Remove(&prl->prl_Node); + FreePooled(ps->ps_SemaMemPool, prl, sizeof(struct PsdReadLock)); + pls->pls_SharedLockCount--; + Signal(task, SIGF_SINGLE); + } + moveowner = FALSE; + XPRINTF(10, ("Waiting shared lock %08lx transfer\n", pls)); + break; + } + prl2 = (struct PsdReadLock *) prl2->prl_Node.ln_Succ; + } + if(moveowner) + { + // check if target task already has a shared lock on this + prl2 = (struct PsdReadLock *) pls->pls_ReadLocks.lh_Head; + do + { + if(prl2->prl_Task == task) + { + if((pbl = (struct PsdBorrowLock *) AllocPooled(ps->ps_SemaMemPool, sizeof(struct PsdBorrowLock)))) + { + // we redirect to this other lock + pbl->pbl_LockSem = pls; + pbl->pbl_ReadLock = prl2; + pbl->pbl_Count = prl->prl_Count; // save the old lock count + AddTail(&borrows, &pbl->pbl_Node); + + // unlock shared lock + Remove(&prl->prl_Node); + FreePooled(ps->ps_SemaMemPool, prl, sizeof(struct PsdReadLock)); + pls->pls_SharedLockCount--; + // just increase lockcount, so a split occurs automatically + prl2->prl_Count += pbl->pbl_Count; + } + XPRINTF(10, ("Already locked %08lx transfer\n", pls)); + moveowner = FALSE; + break; + } + } while((prl2 = (struct PsdReadLock *) prl2->prl_Node.ln_Succ)->prl_Node.ln_Succ); + } + if(moveowner) + { + if((pbl = (struct PsdBorrowLock *) AllocPooled(ps->ps_SemaMemPool, sizeof(struct PsdBorrowLock)))) + { + pbl->pbl_LockSem = pls; + pbl->pbl_ReadLock = prl; + pbl->pbl_Count = prl->prl_Count; + AddTail(&borrows, &pbl->pbl_Node); + prl->prl_Task = task; + XPRINTF(10, ("Std lock %08lx transfer\n", pls)); + } + } + break; + } + } while((prl = (struct PsdReadLock *) prl->prl_Node.ln_Succ)->prl_Node.ln_Succ); + } + psi = (struct PsdSemaInfo *) psi->psi_Node.ln_Succ; + } + + sigmask = Wait(signals); + + // try to get moved locks back first + pbl = (struct PsdBorrowLock *) borrows.lh_Head; + while(pbl->pbl_Node.ln_Succ) + { + Remove(&pbl->pbl_Node); + pls = pbl->pbl_LockSem; + if(pbl->pbl_ExclLockCount) + { + if(pbl->pbl_ExclLockCount == pls->pls_ExclLockCount) + { + // all fine, other task didn't use the locks or returned them already + pls->pls_Owner = thistask; + FreePooled(ps->ps_SemaMemPool, pbl, sizeof(struct PsdBorrowLock)); + } else { + // okay, bad thing, release lock and try to obtain it again -- eventually the other task should free the lock again + pls->pls_ExclLockCount -= pbl->pbl_ExclLockCount; + AddTail(&reclaims, &pbl->pbl_Node); + } + } else { + if(pls->pls_Owner == task) + { + // oh, damn. The other task converted our shared lock into an exclusive lock -- + // we cannot claim this back right now. This gets tricky now. + if(pbl->pbl_Count == pbl->pbl_ReadLock->prl_Count) + { + // luckily, the count didn't change, so we just release the shared lock and requeue us into the reclaim list + Remove(&pbl->pbl_ReadLock->prl_Node); + FreePooled(ps->ps_SemaMemPool, pbl->pbl_ReadLock, sizeof(struct PsdReadLock)); + pbl->pbl_ReadLock = NULL; + pls->pls_SharedLockCount--; // should turn to 0 + } else { + // can it get worse? obviously, the alien task also has added some read locks + // this means we need to split up! + // therefore we leave a few lock counts and requeue + pbl->pbl_ReadLock->prl_Count -= pbl->pbl_Count; + pbl->pbl_ReadLock = NULL; + } + AddHead(&reclaims, &pbl->pbl_Node); + } else { + if(pbl->pbl_Count == pbl->pbl_ReadLock->prl_Count) + { + // the count didn't change, just so just change owner + pbl->pbl_ReadLock->prl_Task = thistask; + FreePooled(ps->ps_SemaMemPool, pbl, sizeof(struct PsdBorrowLock)); + } else { + // the alien task still has some read locks + // this means we need to split up! + // therefore we leave a few lock counts and requeue + pbl->pbl_ReadLock->prl_Count -= pbl->pbl_Count; + pbl->pbl_ReadLock = NULL; + AddHead(&reclaims, &pbl->pbl_Node); + } + } + } + pbl = (struct PsdBorrowLock *) borrows.lh_Head; + } + + // try to reclaim released locks + pbl = (struct PsdBorrowLock *) reclaims.lh_Head; + while(pbl->pbl_Node.ln_Succ) + { + Remove(&pbl->pbl_Node); + pls = pbl->pbl_LockSem; + while(pbl->pbl_Count) + { + pLockSemShared(ps, pls); + --pbl->pbl_Count; + } + while(pbl->pbl_ExclLockCount) + { + pLockSemExcl(ps, pls); + --pbl->pbl_ExclLockCount; + } + FreePooled(ps->ps_SemaMemPool, pbl, sizeof(struct PsdBorrowLock)); + pbl = (struct PsdBorrowLock *) reclaims.lh_Head; + } + Permit(); + + return(sigmask); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* *** Support *** */ + +/* /// "psdCopyStr()" */ +AROS_LH1(STRPTR, psdCopyStr, + AROS_LHA(STRPTR, name, A0), + LIBBASETYPEPTR, ps, 10, psd) +{ + AROS_LIBFUNC_INIT + STRPTR rs = psdAllocVec((ULONG) strlen(name)+1); + KPRINTF(1, ("psdCopyStr(%s)\n", name)); + if(rs) + { + strcpy(rs, name); + } + return(rs); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdSafeRawDoFmtA()" */ +AROS_LH4(void, psdSafeRawDoFmtA, + AROS_LHA(STRPTR, buf, A0), + AROS_LHA(ULONG, len, D0), + AROS_LHA(STRPTR, fmtstr, A1), + AROS_LHA(IPTR *, fmtdata, A2), + LIBBASETYPEPTR, ps, 42, psd) +{ + AROS_LIBFUNC_INIT + struct PsdRawDoFmt rdf; + + if(len > 0) + { + rdf.rdf_Len = len; + rdf.rdf_Buf = buf; + RawDoFmt(fmtstr, fmtdata, (void (*)()) pPutChar, &rdf); + buf[len-1] = 0; + } + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "pPutChar()" */ +AROS_UFH2(void, pPutChar, + AROS_UFHA(char, ch, D0), + AROS_UFHA(struct PsdRawDoFmt *, rdf, A3)) +{ + AROS_USERFUNC_INIT + if(rdf->rdf_Len) + { + rdf->rdf_Len--; + *rdf->rdf_Buf++ = ch; + } + AROS_USERFUNC_EXIT +} +/* \\\ */ + +/* /// "psdCopyStrFmtA()" */ +AROS_LH2(STRPTR, psdCopyStrFmtA, + AROS_LHA(STRPTR, fmtstr, A0), + AROS_LHA(IPTR *, fmtdata, A1), + LIBBASETYPEPTR, ps, 68, psd) +{ + AROS_LIBFUNC_INIT + ULONG len = 0; + STRPTR buf; + + RawDoFmt(fmtstr, fmtdata, (void (*)()) pRawFmtLength, &len); + buf = psdAllocVec(len+1); + if(buf) + { + psdSafeRawDoFmtA(buf, len+1, fmtstr, fmtdata); + } + return(buf); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "pRawFmtLength()" */ +AROS_UFH2(void, pRawFmtLength, + AROS_UFHA(char, ch, D0), + AROS_UFHA(ULONG *, len, A3)) +{ + AROS_USERFUNC_INIT + (*len)++; + AROS_USERFUNC_EXIT +} +/* \\\ */ + +/* /// "psdDelayMS()" */ +AROS_LH1(void, psdDelayMS, + AROS_LHA(ULONG, milli, D0), + LIBBASETYPEPTR, ps, 11, psd) +{ + AROS_LIBFUNC_INIT + struct MsgPort mp; + struct timerequest tr; + + KPRINTF(1, ("psdDelayMS(%ld)\n", milli)); + mp.mp_Flags = PA_SIGNAL; + mp.mp_SigBit = SIGB_SINGLE; + mp.mp_SigTask = FindTask(NULL); + NewList(&mp.mp_MsgList); + CopyMem(&ps->ps_TimerIOReq, &tr, sizeof(tr)); + tr.tr_node.io_Message.mn_ReplyPort = ∓ + tr.tr_time.tv_secs = 0; + tr.tr_time.tv_micro = milli * 1000; + DoIO((struct IORequest *) &tr); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdGetAttrsA()" */ +AROS_LH3(LONG, psdGetAttrsA, + AROS_LHA(ULONG, type, D0), + AROS_LHA(APTR, psdstruct, A0), + AROS_LHA(struct TagItem *, tags, A1), + LIBBASETYPEPTR, ps, 22, psd) +{ + AROS_LIBFUNC_INIT + struct TagItem *ti; + ULONG count = 0; + ULONG *packtab = NULL; + + KPRINTF(1, ("psdGetAttrsA(%ld, %08lx, %08lx)\n", type, psdstruct, tags)); + + if(type <= PGA_LAST) + { + packtab = (ULONG *) PsdPTArray[type]; + } + + switch(type) + { + case PGA_STACK: + psdstruct = ps; + if((ti = FindTagItem(PA_HardwareList, tags))) + { + *((struct List **) ti->ti_Data) = &ps->ps_Hardware; + count++; + } + if((ti = FindTagItem(PA_ClassList, tags))) + { + *((struct List **) ti->ti_Data) = &ps->ps_Classes; + count++; + } + if((ti = FindTagItem(PA_ErrorMsgList, tags))) + { + *((struct List **) ti->ti_Data) = &ps->ps_ErrorMsgs; + count++; + } + break; + + case PGA_HARDWARE: + if((ti = FindTagItem(HA_DeviceList, tags))) + { + *((struct List **) ti->ti_Data) = &(((struct PsdHardware *) psdstruct)->phw_Devices); + count++; + } + break; + + case PGA_DEVICE: + if((ti = FindTagItem(DA_ConfigList, tags))) + { + *((struct List **) ti->ti_Data) = &(((struct PsdDevice *) psdstruct)->pd_Configs); + count++; + } + if((ti = FindTagItem(DA_DescriptorList, tags))) + { + *((struct List **) ti->ti_Data) = &(((struct PsdDevice *) psdstruct)->pd_Descriptors); + count++; + } + break; + + case PGA_CONFIG: + if((ti = FindTagItem(CA_InterfaceList, tags))) + { + *((struct List **) ti->ti_Data) = &(((struct PsdConfig *) psdstruct)->pc_Interfaces); + count++; + } + break; + + case PGA_INTERFACE: + if((ti = FindTagItem(IFA_EndpointList, tags))) + { + *((struct List **) ti->ti_Data) = &(((struct PsdInterface *) psdstruct)->pif_EPs); + count++; + } + if((ti = FindTagItem(IFA_AlternateIfList, tags))) + { + *((struct List **) ti->ti_Data) = &(((struct PsdInterface *) psdstruct)->pif_AlterIfs); + count++; + } + break; + + case PGA_ERRORMSG: + if((ti = FindTagItem(EMA_DateStamp, tags))) + { + *((struct DateStamp **) ti->ti_Data) = &(((struct PsdErrorMsg *) psdstruct)->pem_DateStamp); + count++; + } + break; + + case PGA_PIPE: + if((ti = FindTagItem(PPA_IORequest, tags))) + { + *((struct IOUsbHWReq **) ti->ti_Data) = &(((struct PsdPipe *) psdstruct)->pp_IOReq); + count++; + } + break; + + case PGA_STACKCFG: + if((ti = FindTagItem(GCA_InsertionSound, tags))) + { + count++; + *((STRPTR *) ti->ti_Data) = ps->ps_PoPo.po_InsertSndFile; + } + if((ti = FindTagItem(GCA_RemovalSound, tags))) + { + count++; + *((STRPTR *) ti->ti_Data) = ps->ps_PoPo.po_RemoveSndFile; + } + break; + } + if(packtab) + { + return((LONG) (UnpackStructureTags(psdstruct, (ULONG *) packtab, tags)+count)); + } else { + return(-1); + } + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdSetAttrsA()" */ +AROS_LH3(LONG, psdSetAttrsA, + AROS_LHA(ULONG, type, D0), + AROS_LHA(APTR, psdstruct, A0), + AROS_LHA(struct TagItem *, tags, A1), + LIBBASETYPEPTR, ps, 23, psd) +{ + AROS_LIBFUNC_INIT + struct TagItem *ti; + ULONG count = 0; + ULONG *packtab = NULL; + BOOL savepopocfg = FALSE; + BOOL checkcfgupdate = FALSE; + BOOL powercalc = FALSE; + LONG res; + + KPRINTF(1, ("psdSetAttrsA(%ld, %08lx, %08lx)\n", type, psdstruct, tags)); + + if(type <= PGA_LAST) + { + packtab = (ULONG *) PsdPTArray[type]; + } + + switch(type) + { + case PGA_DEVICE: + if(FindTagItem(DA_InhibitPopup, tags) || FindTagItem(DA_InhibitClassBind, tags)) + { + savepopocfg = TRUE; + } + if(FindTagItem(DA_OverridePowerInfo, tags)) + { + savepopocfg = TRUE; + powercalc = TRUE; + } + break; + + case PGA_STACK: + psdstruct = ps; + break; + + case PGA_STACKCFG: + if((ti = FindTagItem(GCA_InsertionSound, tags))) + { + count++; + if(strcmp(ps->ps_PoPo.po_InsertSndFile, (STRPTR) ti->ti_Data)) + { + psdFreeVec(ps->ps_PoPo.po_InsertSndFile); + ps->ps_PoPo.po_InsertSndFile = psdCopyStr((STRPTR) ti->ti_Data); + } + } + if((ti = FindTagItem(GCA_RemovalSound, tags))) + { + count++; + if(strcmp(ps->ps_PoPo.po_RemoveSndFile, (STRPTR) ti->ti_Data)) + { + psdFreeVec(ps->ps_PoPo.po_RemoveSndFile); + ps->ps_PoPo.po_RemoveSndFile = psdCopyStr((STRPTR) ti->ti_Data); + } + } + checkcfgupdate = TRUE; + break; + + case PGA_PIPESTREAM: + { + struct PsdPipeStream *pps = (struct PsdPipeStream *) psdstruct; + struct PsdPipe *pp; + ULONG oldbufsize = pps->pps_BufferSize; + ULONG oldnumpipes = pps->pps_NumPipes; + ULONG cnt; + + KPRINTF(1, ("SetAttrs PIPESTREAM\n")); + ObtainSemaphore(&pps->pps_AccessLock); + if((ti = FindTagItem(PSA_MessagePort, tags))) + { + count++; + if((pps->pps_Flags & PSFF_OWNMSGPORT) && pps->pps_MsgPort) + { + KPRINTF(1, ("Deleting old MsgPort\n")); + DeleteMsgPort(pps->pps_MsgPort); + pps->pps_MsgPort = NULL; + } + pps->pps_Flags &= ~PSFF_OWNMSGPORT; + } + count += PackStructureTags(psdstruct, packtab, tags); + KPRINTF(1, ("Pipes = %ld (old: %ld), BufferSize = %ld (old: %ld)\n", + pps->pps_NumPipes, oldnumpipes, pps->pps_BufferSize, oldbufsize)); + if(pps->pps_NumPipes < 1) + { + pps->pps_NumPipes = 1; /* minimal */ + } + if(pps->pps_BufferSize < pps->pps_Endpoint->pep_MaxPktSize) + { + pps->pps_BufferSize = pps->pps_Endpoint->pep_MaxPktSize; /* minimal */ + } + if(!pps->pps_MsgPort) + { + if((pps->pps_MsgPort = CreateMsgPort())) + { + KPRINTF(1, ("Creating MsgPort\n")); + pps->pps_Flags |= PSFF_OWNMSGPORT; + } + } + /* do we need to reallocate? */ + if((oldbufsize != pps->pps_BufferSize) || + (oldnumpipes != pps->pps_NumPipes) || + (!pps->pps_Pipes) || + (!pps->pps_Buffer)) + { + if(pps->pps_Pipes) + { + KPRINTF(1, ("freeing %ld old pipes\n", oldnumpipes)); + for(cnt = 0; cnt < oldnumpipes; cnt++) + { + pp = pps->pps_Pipes[cnt]; + //if(pp->pp_IOReq.iouh_Req.io_Message.mn_Node.ln_Type == NT_MESSAGE) + { + KPRINTF(1, ("Abort %ld\n", cnt)); + psdAbortPipe(pp); + KPRINTF(1, ("Wait %ld\n", cnt)); + psdWaitPipe(pp); + } + KPRINTF(1, ("Free %ld\n", cnt)); + psdFreePipe(pp); + } + psdFreeVec(pps->pps_Pipes); + } + psdFreeVec(pps->pps_Buffer); + /* reset stuff */ + NewList(&pps->pps_FreePipes); + NewList(&pps->pps_ReadyPipes); + pps->pps_Offset = 0; + pps->pps_BytesPending = 0; + pps->pps_ReqBytes = 0; + pps->pps_ActivePipe = NULL; + pps->pps_Buffer = psdAllocVec(pps->pps_NumPipes * pps->pps_BufferSize); + pps->pps_Pipes = psdAllocVec(pps->pps_NumPipes * sizeof(struct PsdPipe *)); + if(pps->pps_Pipes && pps->pps_Buffer) + { + KPRINTF(1, ("allocating %ld new pipes\n", pps->pps_NumPipes)); + for(cnt = 0; cnt < pps->pps_NumPipes; cnt++) + { + pp = psdAllocPipe(pps->pps_Device, pps->pps_MsgPort, pps->pps_Endpoint); + if((pps->pps_Pipes[cnt] = pp)) + { + pp->pp_Num = cnt; + if(pps->pps_Flags & PSFF_NOSHORTPKT) pp->pp_IOReq.iouh_Flags |= UHFF_NOSHORTPKT; + if(pps->pps_Flags & PSFF_NAKTIMEOUT) pp->pp_IOReq.iouh_Flags |= UHFF_NAKTIMEOUT; + if(pps->pps_Flags & PSFF_ALLOWRUNT) pp->pp_IOReq.iouh_Flags |= UHFF_ALLOWRUNTPKTS; + pp->pp_IOReq.iouh_NakTimeout = pps->pps_NakTimeoutTime; + AddTail(&pps->pps_FreePipes, &pp->pp_Msg.mn_Node); + } else { + KPRINTF(1, ("Allocating Pipe %ld failed!\n", cnt)); + } + } + } else { + KPRINTF(1, ("Allocating Pipe array failed!\n")); + psdFreeVec(pps->pps_Buffer); + pps->pps_Buffer = NULL; + psdFreeVec(pps->pps_Pipes); + pps->pps_Pipes = NULL; + } + } + ReleaseSemaphore(&pps->pps_AccessLock); + return((LONG) count); + } + } + + if(packtab) + { + res = (LONG) PackStructureTags(psdstruct, packtab, tags); + } else { + res = -1; + } + if(savepopocfg) + { + struct PsdDevice *pd = (struct PsdDevice *) psdstruct; + struct PsdIFFContext *pic; + + pic = psdGetUsbDevCfg("Trident", pd->pd_IDString, NULL); + if(!pic) + { + psdSetUsbDevCfg("Trident", pd->pd_IDString, NULL, NULL); + pic = psdGetUsbDevCfg("Trident", pd->pd_IDString, NULL); + } + if(pic) + { + pAddCfgChunk(ps, pic, &pd->pd_PoPoCfg); + checkcfgupdate = TRUE; + } + } + if(checkcfgupdate) + { + pUpdateGlobalCfg(ps, (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head); + pCheckCfgChanged(ps); + } + if(powercalc) + { + psdCalculatePower(((struct PsdDevice *) psdstruct)->pd_Hardware); + } + return(res); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdSpawnSubTask()" */ +AROS_LH3(struct Task *, psdSpawnSubTask, + AROS_LHA(STRPTR, name, A0), + AROS_LHA(APTR, initpc, A1), + AROS_LHA(APTR, userdata, A2), + LIBBASETYPEPTR, ps, 39, psd) +{ + AROS_LIBFUNC_INIT +#define SUBTASKSTACKSIZE 8192 + struct + { + struct MemList mrm_ml; + struct MemEntry mtm_me[2]; + } memlist; + + struct MemList *newmemlist; + struct Task *nt; + struct Process *subtask; + + if(!(name && initpc)) + { + return(NULL); + } + + /* If there's dos available, create a process instead of a task */ + if(pOpenDOS(ps)) + { + subtask = CreateNewProcTags(NP_Entry, (ULONG) initpc, + NP_StackSize, SUBTASKSTACKSIZE, + NP_Priority, ps->ps_GlobalCfg->pgc_SubTaskPri, + NP_Name, (ULONG) name, + NP_CopyVars, FALSE, + NP_UserData, (ULONG) userdata, + TAG_END); + return((struct Task *) subtask); + } + + /* Allocate memory of memlist */ + + memlist.mrm_ml.ml_Node.ln_Type = NT_MEMORY; + memlist.mrm_ml.ml_Node.ln_Pri = 0; + memlist.mrm_ml.ml_Node.ln_Name = NULL; + memlist.mrm_ml.ml_NumEntries = 3; + memlist.mrm_ml.ml_ME[1].me_Un.meu_Reqs = memlist.mrm_ml.ml_ME[0].me_Un.meu_Reqs = MEMF_CLEAR|MEMF_PUBLIC; + memlist.mrm_ml.ml_ME[0].me_Length = sizeof(struct Task); + memlist.mrm_ml.ml_ME[1].me_Length = SUBTASKSTACKSIZE; + memlist.mrm_ml.ml_ME[2].me_Un.meu_Reqs = MEMF_PUBLIC; + memlist.mrm_ml.ml_ME[2].me_Length = strlen(name) + 1; + + newmemlist = AllocEntry(&memlist.mrm_ml); + if((ULONG) newmemlist & 0x80000000) + { + return(NULL); + } + nt = newmemlist->ml_ME[0].me_Un.meu_Addr; + nt->tc_Node.ln_Name = newmemlist->ml_ME[2].me_Un.meu_Addr; + strcpy(nt->tc_Node.ln_Name, name); + nt->tc_Node.ln_Type = NT_TASK; + nt->tc_Node.ln_Pri = ps->ps_GlobalCfg->pgc_SubTaskPri; + nt->tc_SPLower = newmemlist->ml_ME[1].me_Un.meu_Addr; + nt->tc_SPUpper = nt->tc_SPReg = (APTR) ((ULONG) nt->tc_SPLower + SUBTASKSTACKSIZE); + nt->tc_UserData = userdata; + NewList(&nt->tc_MemEntry); + AddTail(&nt->tc_MemEntry, (struct Node *) newmemlist); + KPRINTF(1, ("TDNestCnt=%ld\n", SysBase->TDNestCnt)); + if((nt = AddTask(nt, initpc, NULL))) + { + XPRINTF(10, ("Started task %08lx (%s)\n", nt, name)); + return(nt); + } + FreeEntry(newmemlist); + return(NULL); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdNumToStr()" */ +AROS_LH3(STRPTR, psdNumToStr, + AROS_LHA(UWORD, type, D0), + AROS_LHA(LONG, idx, D1), + AROS_LHA(STRPTR, defstr, A0), + LIBBASETYPEPTR, ps, 38, psd) +{ + AROS_LIBFUNC_INIT + switch(type) + { + case NTS_IOERR: + { + const struct PsdWStringMap *psm = usbhwioerrstr; + while(psm->psm_ID) + { + if(psm->psm_ID == idx) + { + return(psm->psm_String); + } + psm++; + } + break; + } + + case NTS_LANGID: + { + const struct PsdUWStringMap *psm = usblangids; + while(psm->psm_ID) + { + if(psm->psm_ID == idx) + { + return(psm->psm_String); + } + psm++; + } + break; + } + + case NTS_TRANSTYPE: + switch(idx) + { + case USEAF_CONTROL: + return("control"); + case USEAF_ISOCHRONOUS: + return("isochronous"); + case USEAF_BULK: + return("bulk"); + case USEAF_INTERRUPT: + return("interrupt"); + } + break; + + case NTS_SYNCTYPE: + switch(idx) + { + case USEAF_NOSYNC: + return("no synchronization"); + case USEAF_ASYNC: + return("asynchronous"); + case USEAF_ADAPTIVE: + return("adaptive"); + case USEAF_SYNC: + return("synchronous"); + } + break; + + case NTS_USAGETYPE: + switch(idx) + { + case USEAF_DATA: + return("data"); + case USEAF_FEEDBACK: + return("feedback"); + case USEAF_IMPLFEEDBACK: + return("implicit feedback data"); + } + break; + + case NTS_VENDORID: + { + const struct PsdUWStringMap *psm = usbvendorids; + while(psm->psm_ID) + { + if(psm->psm_ID == idx) + { + return(psm->psm_String); + } + psm++; + } + break; + } + + case NTS_CLASSCODE: + { + const struct PsdWStringMap *psm = usbclasscodestr; + while(psm->psm_ID) + { + if(psm->psm_ID == idx) + { + return(psm->psm_String); + } + psm++; + } + break; + } + + case NTS_DESCRIPTOR: + { + const struct PsdULStringMap *psm = usbdesctypestr; + while(psm->psm_ID) + { + if(psm->psm_ID == idx) + { + return(psm->psm_String); + } + psm++; + } + break; + } + + case NTS_COMBOCLASS: + { + const struct PsdULStringMap *psm = usbcomboclasscodestr; + if(idx & (NTSCCF_CLASS|NTSCCF_SUBCLASS|NTSCCF_PROTO)) + { + while(psm->psm_ID) + { + BOOL take; + take = TRUE; + if(psm->psm_ID & NTSCCF_CLASS) + { + if((!(idx & NTSCCF_CLASS)) || ((idx & 0x0000ff) != (psm->psm_ID & 0x0000ff))) + { + take = FALSE; + } + } + if(psm->psm_ID & NTSCCF_SUBCLASS) + { + if((!(idx & NTSCCF_SUBCLASS)) || ((idx & 0x00ff00) != (psm->psm_ID & 0x00ff00))) + { + take = FALSE; + } + } + if(psm->psm_ID & NTSCCF_PROTO) + { + if((!(idx & NTSCCF_PROTO)) || ((idx & 0xff0000) != (psm->psm_ID & 0xff0000))) + { + take = FALSE; + } + } + if(take) + { + return(psm->psm_String); + } + psm++; + } + } + break; + } + } + return(defstr); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* *** Endpoint *** */ + +/* /// "pFreeEndpoint()" */ +void pFreeEndpoint(struct PsdEndpoint *pep) +{ + LIBBASETYPEPTR ps = pep->pep_Interface->pif_Config->pc_Device->pd_Hardware->phw_Base; + KPRINTF(2, (" FreeEndpoint()\n")); + Remove(&pep->pep_Node); + psdFreeVec(pep); +} +/* \\\ */ + +/* /// "pAllocEndpoint()" */ +struct PsdEndpoint * pAllocEndpoint(struct PsdInterface *pif) +{ + LIBBASETYPEPTR ps = pif->pif_Config->pc_Device->pd_Hardware->phw_Base; + struct PsdEndpoint *pep; + if((pep = psdAllocVec(sizeof(struct PsdEndpoint)))) + { + pep->pep_Interface = pif; + AddTail(&pif->pif_EPs, &pep->pep_Node); + return(pep); + } + return(NULL); +} +/* \\\ */ + +/* /// "psdFindEndpointA()" */ +AROS_LH3(struct PsdEndpoint *, psdFindEndpointA, + AROS_LHA(struct PsdInterface *, pif, A0), + AROS_LHA(struct PsdEndpoint *, pep, A2), + AROS_LHA(struct TagItem *, tags, A1), + LIBBASETYPEPTR, ps, 67, psd) +{ + AROS_LIBFUNC_INIT + struct TagItem *ti; + BOOL takeit; + + KPRINTF(2, ("psdFindEndpointA(%08lx, %08lx, %08lx)\n", pif, pep, tags)); + if(!pep) + { + pep = (struct PsdEndpoint *) pif->pif_EPs.lh_Head; + } else { + pep = (struct PsdEndpoint *) pep->pep_Node.ln_Succ; + } + while(pep->pep_Node.ln_Succ) + { + takeit = TRUE; + if((ti = FindTagItem(EA_IsIn, tags))) + { + if((ti->ti_Data && !pep->pep_Direction) || (!ti->ti_Data && pep->pep_Direction)) + { + takeit = FALSE; + } + } + if((ti = FindTagItem(EA_EndpointNum, tags))) + { + if(ti->ti_Data != pep->pep_EPNum) + { + takeit = FALSE; + } + } + if((ti = FindTagItem(EA_TransferType, tags))) + { + if(ti->ti_Data != pep->pep_TransType) + { + takeit = FALSE; + } + } + if((ti = FindTagItem(EA_MaxPktSize, tags))) + { + if(ti->ti_Data != pep->pep_MaxPktSize) + { + takeit = FALSE; + } + } + if((ti = FindTagItem(EA_Interval, tags))) + { + if(ti->ti_Data != pep->pep_Interval) + { + takeit = FALSE; + } + } + + if(takeit) + { + return(pep); + } + pep = (struct PsdEndpoint *) pep->pep_Node.ln_Succ; + } + return(NULL); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* *** Interface *** */ + +/* /// "pFreeInterface()" */ +void pFreeInterface(struct PsdInterface *pif) +{ + LIBBASETYPEPTR ps = pif->pif_Config->pc_Device->pd_Hardware->phw_Base; + struct PsdEndpoint *pep = (struct PsdEndpoint *) pif->pif_EPs.lh_Head; + struct PsdInterface *altif = (struct PsdInterface *) pif->pif_AlterIfs.lh_Head; + KPRINTF(2, (" FreeInterface()\n")); + /* Remove alternate interfaces */ + while(altif->pif_Node.ln_Succ) + { + pFreeInterface(altif); + altif = (struct PsdInterface *) pif->pif_AlterIfs.lh_Head; + } + /* Remove endpoints */ + while(pep->pep_Node.ln_Succ) + { + pFreeEndpoint(pep); + pep = (struct PsdEndpoint *) pif->pif_EPs.lh_Head; + } + psdFreeVec(pif->pif_IfStr); + psdFreeVec(pif->pif_IDString); + Remove(&pif->pif_Node); + psdFreeVec(pif); +} +/* \\\ */ + +/* /// "pAllocInterface()" */ +struct PsdInterface * pAllocInterface(struct PsdConfig *pc) +{ + LIBBASETYPEPTR ps = pc->pc_Device->pd_Hardware->phw_Base; + struct PsdInterface *pif; + if((pif = psdAllocVec(sizeof(struct PsdInterface)))) + { + pif->pif_Config = pc; + NewList(&pif->pif_EPs); + NewList(&pif->pif_AlterIfs); + AddTail(&pc->pc_Interfaces, &pif->pif_Node); + return(pif); + } + return(NULL); +} +/* \\\ */ + +/* /// "psdFindInterfaceA()" */ +AROS_LH3(struct PsdInterface *, psdFindInterfaceA, + AROS_LHA(struct PsdDevice *, pd, A0), + AROS_LHA(struct PsdInterface *, pif, A2), + AROS_LHA(struct TagItem *, tags, A1), + LIBBASETYPEPTR, ps, 66, psd) +{ + AROS_LIBFUNC_INIT + struct PsdConfig *pc; + struct TagItem *ti; + BOOL takeit; + BOOL searchalt = FALSE; + BOOL isalt = FALSE; + struct PsdInterface *oldpif = NULL; + + KPRINTF(2, ("psdFindInterfaceA(%08lx, %08lx, %08lx)\n", pd, pif, tags)); + if(!pif) + { + pc = pd->pd_CurrentConfig; + if(pc) + { + pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head; + } + if(!pif) + { + return(NULL); + } + } else { + if(FindTagItem(IFA_AlternateNum, tags)) + { + searchalt = TRUE; + } + if(pif->pif_ParentIf) + { + // special case: we are in an alternate interface right now + searchalt = TRUE; + if(pif->pif_Node.ln_Succ) + { + isalt = TRUE; + oldpif = pif->pif_ParentIf; + pif = (struct PsdInterface *) pif->pif_Node.ln_Succ; + } else { + pif = (struct PsdInterface *) pif->pif_ParentIf->pif_Node.ln_Succ; + } + } else { + // go into alt interfaces + if(searchalt && pif->pif_AlterIfs.lh_Head->ln_Succ) + { + isalt = TRUE; + oldpif = pif; + pif = (struct PsdInterface *) pif->pif_AlterIfs.lh_Head; + } else { + pif = (struct PsdInterface *) pif->pif_Node.ln_Succ; + } + } + } + + while(pif->pif_Node.ln_Succ) + { + takeit = TRUE; + if((ti = FindTagItem(IFA_InterfaceNum, tags))) + { + if(ti->ti_Data != pif->pif_IfNum) + { + takeit = FALSE; + } + } + if((ti = FindTagItem(IFA_AlternateNum, tags))) + { + searchalt = TRUE; + if(ti->ti_Data <= 0xff) // if alternate number is greater than 0xff, don't check compliance, but just enable alternate interface searching + { + if(ti->ti_Data != pif->pif_Alternate) + { + takeit = FALSE; + } + } + } + if((ti = FindTagItem(IFA_NumEndpoints, tags))) + { + if(ti->ti_Data != pif->pif_NumEPs) + { + takeit = FALSE; + } + } + if((ti = FindTagItem(IFA_Class, tags))) + { + if(ti->ti_Data != pif->pif_IfClass) + { + takeit = FALSE; + } + } + if((ti = FindTagItem(IFA_SubClass, tags))) + { + if(ti->ti_Data != pif->pif_IfSubClass) + { + takeit = FALSE; + } + } + if((ti = FindTagItem(IFA_Protocol, tags))) + { + if(ti->ti_Data != pif->pif_IfProto) + { + takeit = FALSE; + } + } + if((ti = FindTagItem(IFA_Binding, tags))) + { + if((APTR) ti->ti_Data != pif->pif_IfBinding) + { + takeit = FALSE; + } + } + if((ti = FindTagItem(IFA_InterfaceName, tags))) + { + if(strcmp((STRPTR) ti->ti_Data, pif->pif_IfStr)) + { + takeit = FALSE; + } + } + if((ti = FindTagItem(IFA_IDString, tags))) + { + if(strcmp((STRPTR) ti->ti_Data, pif->pif_IDString)) + { + takeit = FALSE; + } + } + + if(takeit) + { + return(pif); + } + if(searchalt) + { + if(isalt) + { + pif = (struct PsdInterface *) pif->pif_Node.ln_Succ; + if(!pif->pif_Node.ln_Succ) + { + pif = (struct PsdInterface *) oldpif->pif_Node.ln_Succ; + isalt = FALSE; + } + } else { + oldpif = pif; + pif = (struct PsdInterface *) pif->pif_AlterIfs.lh_Head; + if(!pif->pif_Node.ln_Succ) + { + pif = (struct PsdInterface *) oldpif->pif_Node.ln_Succ; + } else { + isalt = TRUE; + } + } + } else { + pif = (struct PsdInterface *) pif->pif_Node.ln_Succ; + } + } + return(NULL); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* *** Config *** */ + +/* /// "pFreeConfig()" */ +void pFreeConfig(struct PsdConfig *pc) +{ + LIBBASETYPEPTR ps = pc->pc_Device->pd_Hardware->phw_Base; + struct PsdInterface *pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head; + KPRINTF(2, (" FreeConfig()\n")); + while(pif->pif_Node.ln_Succ) + { + psdReleaseIfBinding(pif); + pFreeInterface(pif); + pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head; + } + psdFreeVec(pc->pc_CfgStr); + Remove(&pc->pc_Node); + psdFreeVec(pc); +} +/* \\\ */ + +/* /// "pAllocConfig()" */ +struct PsdConfig * pAllocConfig(struct PsdDevice *pd) +{ + LIBBASETYPEPTR ps = pd->pd_Hardware->phw_Base; + struct PsdConfig *pc; + KPRINTF(2, (" AllocConfig()\n")); + if((pc = psdAllocVec(sizeof(struct PsdConfig)))) + { + pc->pc_Device = pd; + NewList(&pc->pc_Interfaces); + AddTail(&pd->pd_Configs, &pc->pc_Node); + return(pc); + } + return(NULL); +} +/* \\\ */ + +/* *** Descriptors *** */ + +/* /// "pFreeDescriptor()" */ +void pFreeDescriptor(struct PsdDescriptor *pdd) +{ + LIBBASETYPEPTR ps = pdd->pdd_Device->pd_Hardware->phw_Base; + KPRINTF(2, (" FreeDescriptor()\n")); + //psdFreeVec(pdd->pdd_Data); // part of the structure alloc + Remove(&pdd->pdd_Node); + psdFreeVec(pdd); +} +/* \\\ */ + +/* /// "pAllocDescriptor()" */ +struct PsdDescriptor * pAllocDescriptor(struct PsdDevice *pd, UBYTE *buf) +{ + LIBBASETYPEPTR ps = pd->pd_Hardware->phw_Base; + struct PsdDescriptor *pdd; + + KPRINTF(2, (" AllocDescriptor()\n")); + if((pdd = psdAllocVec(sizeof(struct PsdDescriptor) + (ULONG) buf[0]))) + { + pdd->pdd_Device = pd; + pdd->pdd_Data = ((UBYTE *) pdd) + sizeof(struct PsdDescriptor); + pdd->pdd_Length = buf[0]; + pdd->pdd_Type = buf[1]; + if((pdd->pdd_Type >= UDT_CS_UNDEFINED) && (pdd->pdd_Type <= UDT_CS_ENDPOINT)) + { + pdd->pdd_CSSubType = buf[2]; + } + pdd->pdd_Name = psdNumToStr(NTS_DESCRIPTOR, (LONG) pdd->pdd_Type, ""); + CopyMem(buf, pdd->pdd_Data, (ULONG) buf[0]); + AddTail(&pd->pd_Descriptors, &pdd->pdd_Node); + return(pdd); + } + return(NULL); +} +/* \\\ */ + +/* /// "psdFindDescriptorA()" */ +AROS_LH3(struct PsdDescriptor *, psdFindDescriptorA, + AROS_LHA(struct PsdDevice *, pd, A0), + AROS_LHA(struct PsdDescriptor *, pdd, A2), + AROS_LHA(struct TagItem *, tags, A1), + LIBBASETYPEPTR, ps, 91, psd) +{ + AROS_LIBFUNC_INIT + struct PsdConfig *pc = pd->pd_CurrentConfig; + struct TagItem *ti; + BOOL takeit; + + KPRINTF(2, ("psdFindDescriptorA(%08lx, %08lx, %08lx)\n", pd, pdd, tags)); + if(!pdd) + { + pdd = (struct PsdDescriptor *) pd->pd_Descriptors.lh_Head; + } else { + pdd = (struct PsdDescriptor *) pdd->pdd_Node.ln_Succ; + } + + while(pdd->pdd_Node.ln_Succ) + { + takeit = TRUE; + + if((ti = FindTagItem(DDA_Config, tags))) + { + // special case to workaround default: with NULL given, all configs are matched + if(ti->ti_Data && (((struct PsdConfig *) ti->ti_Data) != pdd->pdd_Config)) + { + takeit = FALSE; + } + } else { + // only take descriptors from the current configuration by default + if(pc != pdd->pdd_Config) + { + takeit = FALSE; + } + } + if((ti = FindTagItem(DDA_Interface, tags))) + { + if(((struct PsdInterface *) ti->ti_Data) != pdd->pdd_Interface) + { + takeit = FALSE; + } + } + if((ti = FindTagItem(DDA_Endpoint, tags))) + { + if(((struct PsdEndpoint *) ti->ti_Data) != pdd->pdd_Endpoint) + { + takeit = FALSE; + } + } + if((ti = FindTagItem(DDA_DescriptorType, tags))) + { + if(ti->ti_Data != pdd->pdd_Type) + { + takeit = FALSE; + } + } + if((ti = FindTagItem(DDA_CS_SubType, tags))) + { + if(ti->ti_Data != pdd->pdd_CSSubType) + { + takeit = FALSE; + } + } + if((ti = FindTagItem(DDA_DescriptorLength, tags))) + { + if(ti->ti_Data != pdd->pdd_Length) + { + takeit = FALSE; + } + } + + if(takeit) + { + return(pdd); + } + pdd = (struct PsdDescriptor *) pdd->pdd_Node.ln_Succ; + } + return(NULL); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* *** Device *** */ + +/* /// "pFreeBindings()" */ +void pFreeBindings(LIBBASETYPEPTR ps, struct PsdDevice *pd) +{ + struct PsdHardware *phw = pd->pd_Hardware; + struct PsdConfig *pc; + struct PsdInterface *pif; + KPRINTF(3, (" FreeBindings(%08lx)\n", pd)); + + /* move device to list of dead devices first + This caused a lot of trouble as it could + happen that a device got into class scan + right after the bindings had been released. */ + psdLockWritePBase(); + Remove(&pd->pd_Node); + AddTail(&phw->phw_DeadDevices, &pd->pd_Node); + psdUnlockPBase(); + + /* If there are bindings, get rid of them. */ + psdLockWriteDevice(pd); + psdReleaseDevBinding(pd); + + pc = (struct PsdConfig *) pd->pd_Configs.lh_Head; + while(pc->pc_Node.ln_Succ) + { + pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head; + while(pif->pif_Node.ln_Succ) + { + psdReleaseIfBinding(pif); + pif = (struct PsdInterface *) pif->pif_Node.ln_Succ; + } + pc = (struct PsdConfig *) pc->pc_Node.ln_Succ; + } + psdUnlockDevice(pd); +} +/* \\\ */ + +/* /// "pFreeDevice()" */ +void pFreeDevice(LIBBASETYPEPTR ps, struct PsdDevice *pd) +{ + struct PsdHardware *phw = pd->pd_Hardware; + struct PsdConfig *pc; + struct PsdDescriptor *pdd; + + psdCalculatePower(phw); + psdLockWriteDevice(pd); + if(pd->pd_UseCnt) + { + KPRINTF(20, ("Couldn't free device, use cnt %ld\n", pd->pd_UseCnt)); + pd->pd_Flags &= ~PDFF_CONNECTED; + pd->pd_Flags |= PDFF_DELEXPUNGE; + psdUnlockDevice(pd); + } else { + pc = (struct PsdConfig *) pd->pd_Configs.lh_Head; + while(pc->pc_Node.ln_Succ) + { + pFreeConfig(pc); + pc = (struct PsdConfig *) pd->pd_Configs.lh_Head; + } + + pdd = (struct PsdDescriptor *) pd->pd_Descriptors.lh_Head; + while(pdd->pdd_Node.ln_Succ) + { + pFreeDescriptor(pdd); + pdd = (struct PsdDescriptor *) pd->pd_Descriptors.lh_Head; + } + + psdFreeVec(pd->pd_LangIDArray); + pd->pd_LangIDArray = NULL; + psdFreeVec(pd->pd_MnfctrStr); + pd->pd_MnfctrStr = NULL; + /*if(!ps->ps_PoPo.po_Task) // keep name at least + { + psdFreeVec(pd->pd_ProductStr); + pd->pd_ProductStr = NULL; + }*/ + psdFreeVec(pd->pd_OldProductStr); + pd->pd_OldProductStr = NULL; + psdFreeVec(pd->pd_SerNumStr); + pd->pd_SerNumStr = NULL; + psdFreeVec(pd->pd_IDString); + pd->pd_IDString = NULL; + if(pd->pd_DevAddr) + { + KPRINTF(5,("Released DevAddr %ld\n", pd->pd_DevAddr)); + phw->phw_DevArray[pd->pd_DevAddr] = NULL; + } + psdUnlockDevice(pd); + psdLockWritePBase(); + Remove(&pd->pd_Node); + psdUnlockPBase(); + pDeleteSem(ps, &pd->pd_Lock); + /* cannot free this vector -- tasks might still call LockDevice */ + //psdFreeVec(pd); + } + KPRINTF(3, ("FreeDevice done\n")); +} +/* \\\ */ + +/* /// "psdFreeDevice()" */ +AROS_LH1(void, psdFreeDevice, + AROS_LHA(struct PsdDevice *, pd, A0), + LIBBASETYPEPTR, ps, 16, psd) +{ + AROS_LIBFUNC_INIT + struct PsdHardware *phw = pd->pd_Hardware; + struct PsdConfig *pc; + struct PsdInterface *pif; + struct PsdRTIsoHandler *prt; + struct PsdRTIsoHandler *nextprt; + + KPRINTF(3, (" FreeDevice(%08lx)\n", pd)); + + /* move device to list of dead devices first + This caused a lot of trouble as it could + happen that a device got into class scan + right after the bindings had been released. */ + psdLockWritePBase(); + Remove(&pd->pd_Node); + AddTail(&phw->phw_DeadDevices, &pd->pd_Node); + pd->pd_Flags &= ~PDFF_DELEXPUNGE; + psdUnlockPBase(); + + psdLockWriteDevice(pd); + + /* Inform all ISO handlers about the device going offline */ + prt = (struct PsdRTIsoHandler *) pd->pd_RTIsoHandlers.lh_Head; + while((nextprt = (struct PsdRTIsoHandler *) prt->prt_Node.ln_Succ)) + { + if(prt->prt_ReleaseHook) + { + CallHookPkt(prt->prt_ReleaseHook, prt, NULL); + } + prt = nextprt; + } + + /* If there are bindings, get rid of them. */ + psdHubReleaseDevBinding(pd); + + pc = (struct PsdConfig *) pd->pd_Configs.lh_Head; + while(pc->pc_Node.ln_Succ) + { + pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head; + while(pif->pif_Node.ln_Succ) + { + psdHubReleaseIfBinding(pif); + pif = (struct PsdInterface *) pif->pif_Node.ln_Succ; + } + pc = (struct PsdConfig *) pc->pc_Node.ln_Succ; + } + psdUnlockDevice(pd); + + pFreeDevice(ps, pd); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdAllocDevice()" */ +AROS_LH1(struct PsdDevice *, psdAllocDevice, + AROS_LHA(struct PsdHardware *, phw, A0), + LIBBASETYPEPTR, ps, 15, psd) +{ + AROS_LIBFUNC_INIT + struct PsdDevice *pd; + KPRINTF(2, ("psdAllocDevice(%08lx)\n", phw)); + if((pd = psdAllocVec(sizeof(struct PsdDevice)))) + { + pd->pd_Hardware = phw; + pd->pd_Hub = NULL; + pd->pd_MaxPktSize0 = 8; + + pInitSem(ps, &pd->pd_Lock, "Device"); + + NewList(&pd->pd_Configs); + NewList(&pd->pd_Descriptors); + NewList(&pd->pd_RTIsoHandlers); + + // init prefs + pd->pd_PoPoCfg.poc_ChunkID = AROS_LONG2BE(IFFCHNK_POPUP); + pd->pd_PoPoCfg.poc_Length = AROS_LONG2BE(sizeof(struct PsdPoPoCfg) - 8); + pd->pd_PoPoCfg.poc_InhibitPopup = FALSE; + pd->pd_PoPoCfg.poc_NoClassBind = FALSE; + pd->pd_PoPoCfg.poc_OverridePowerInfo = POCP_TRUST_DEVICE; + + psdLockWritePBase(); + AddTail(&phw->phw_Devices, &pd->pd_Node); + psdUnlockPBase(); + return(pd); + } else { + KPRINTF(20, ("psdAllocDevice(): out of memory!\n")); + } + return(NULL); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdLockReadDevice()" */ +AROS_LH1(void, psdLockReadDevice, + AROS_LHA(struct PsdDevice *, pd, A0), + LIBBASETYPEPTR, ps, 17, psd) +{ + AROS_LIBFUNC_INIT + KPRINTF(2, ("psdLockReadDevice(%08lx, %08lx)\n", pd, FindTask(NULL))); + pLockSemShared(ps, &pd->pd_Lock); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdLockWriteDevice()" */ +AROS_LH1(void, psdLockWriteDevice, + AROS_LHA(struct PsdDevice *, pd, A0), + LIBBASETYPEPTR, ps, 18, psd) +{ + AROS_LIBFUNC_INIT + KPRINTF(2, ("psdLockWriteDevice(%08lx, %08lx)\n", pd, FindTask(NULL))); + pLockSemExcl(ps, &pd->pd_Lock); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdUnlockDevice()" */ +AROS_LH1(void, psdUnlockDevice, + AROS_LHA(struct PsdDevice *, pd, A0), + LIBBASETYPEPTR, ps, 19, psd) +{ + AROS_LIBFUNC_INIT + KPRINTF(2, ("psdUnlockDevice(%08lx, %08lx)\n", pd, FindTask(NULL))); + pUnlockSem(ps, &pd->pd_Lock); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "pAllocDevAddr()" */ +UWORD pAllocDevAddr(struct PsdDevice *pd) +{ + struct PsdHardware *phw = pd->pd_Hardware; + UWORD da; + if(pd->pd_DevAddr) + { + return(pd->pd_DevAddr); + } + for(da = 1; da < 128; da++) + { + if(!phw->phw_DevArray[da]) + { + phw->phw_DevArray[da] = pd; + pd->pd_DevAddr = da; + return(da); + } + } + return(0); +} +/* \\\ */ + +/* /// "psdGetStringDescriptor()" */ +AROS_LH2(STRPTR, psdGetStringDescriptor, + AROS_LHA(struct PsdPipe *, pp, A1), + AROS_LHA(UWORD, idx, D0), + LIBBASETYPEPTR, ps, 33, psd) +{ + AROS_LIBFUNC_INIT + struct PsdDevice *pd = pp->pp_Device; + ULONG len; + UBYTE buf[256]; + UWORD *tmpptr; + UWORD *tmpbuf; + STRPTR rs; + STRPTR cbuf; + LONG ioerr; + UWORD widechar; + KPRINTF(1, ("psdGetStringDescriptor(%08lx, %ld)\n", pp, idx)); + + buf[0] = 0; + if(!pd->pd_LangIDArray) + { + KPRINTF(10,("Trying to get language array...\n")); + psdPipeSetup(pp, URTF_IN|URTF_STANDARD|URTF_DEVICE, + USR_GET_DESCRIPTOR, UDT_STRING<<8, 0); + ioerr = psdDoPipe(pp, buf, 2); + if(ioerr == UHIOERR_OVERFLOW) + { + ioerr = 0; + psdAddErrorMsg0(RETURN_WARN, (STRPTR) libname, "Language array overflow."); + } + if(ioerr) + { + ioerr = psdDoPipe(pp, buf, 256); + if(ioerr == UHIOERR_RUNTPACKET) + { + ioerr = 0; + } + } + if(!ioerr) + { + len = buf[0]; + if((pd->pd_LangIDArray = psdAllocVec(max(len, 4)))) + { + tmpbuf = tmpptr = pd->pd_LangIDArray; + KPRINTF(1, ("Getting LangID Array length %ld\n", len)); + // generate minimal sized array + if(len < 4) + { + len = 4; + *tmpbuf++ = 0; + *tmpbuf = AROS_WORD2LE(0x0409); + /*psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "Language array descriptor too small (len %ld), using dummy.", + len);*/ + ioerr = 0; + } else { + ioerr = psdDoPipe(pp, tmpbuf++, len); + } + if(!ioerr) + { + len >>= 1; + while(--len) + { + KPRINTF(1, ("LangID: %04lx\n", AROS_WORD2LE(*tmpbuf))); + *tmpptr++ = AROS_WORD2LE(*tmpbuf); + tmpbuf++; + } + *tmpptr = 0; + tmpptr = pd->pd_LangIDArray; + pd->pd_CurrLangID = *tmpptr; + while(*tmpptr) + { + if(*tmpptr == 0x0409) + { + pd->pd_CurrLangID = *tmpptr; + break; + } + tmpptr++; + } + } else { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "Reading language array descriptor (len %ld) failed: %s (%ld)", + len, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + KPRINTF(15, ("Error reading lang array descriptor (%ld) failed %ld\n", len, ioerr)); + *tmpptr = 0; + } + } else { + KPRINTF(20, ("No langid array memory!\n")); + } + } else { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "Reading language array descriptor (len %ld) failed: %s (%ld)", + 2, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + KPRINTF(15, ("Error reading lang array descriptor (2) failed %ld\n", ioerr)); + /* Create empty array */ + if((pd->pd_LangIDArray = psdAllocVec(2))) + { + *pd->pd_LangIDArray = 0; + } + } + } + buf[0] = 0; + psdPipeSetup(pp, URTF_IN|URTF_STANDARD|URTF_DEVICE, + USR_GET_DESCRIPTOR, (UDT_STRING<<8)|idx, pd->pd_CurrLangID); + ioerr = psdDoPipe(pp, buf, 2); + if(ioerr == UHIOERR_OVERFLOW) + { + ioerr = 0; + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, "String %ld overflow.", idx); + } + if(ioerr) + { + ioerr = psdDoPipe(pp, buf, 256); + } + if(!ioerr) + { + len = buf[0]; + if(len > 2) + { + tmpptr = (UWORD *) buf; + KPRINTF(1, ("Getting String Descriptor %ld, length %ld\n", idx, len)); + ioerr = psdDoPipe(pp, tmpptr++, len); + if(ioerr == UHIOERR_RUNTPACKET) + { + len = pp->pp_IOReq.iouh_Actual; + if(len > 3) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "String descriptor %ld truncated to %ld, requested %ld", + idx, len, buf[0]); + ioerr = 0; + } + } + else if(ioerr) + { + ioerr = psdDoPipe(pp, buf, 256); + } + if(!ioerr) + { + if((cbuf = rs = psdAllocVec(len>>1))) + { + len >>= 1; + while(--len) + { + widechar = *tmpptr++; + widechar = AROS_WORD2LE(widechar); + if((widechar < 0x20) || (widechar > 255)) + { + *cbuf++ = '?'; + } else { + *cbuf++ = widechar; + } + } + *cbuf = 0; + KPRINTF(1, ("String \"%s\"\n", rs)); + if(*rs) + { + return(rs); + } else { + psdFreeVec(rs); + return(NULL); + } + } else { + KPRINTF(20, ("No memory for string!\n")); + } + } else { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "Reading string descriptor %ld (len %ld) failed: %s (%ld)", + idx, len, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + KPRINTF(15, ("Error reading string descriptor %ld (%ld) failed %ld\n", + idx, len, ioerr)); + } + } else { + KPRINTF(5, ("Empty string\n")); + return(psdCopyStr("")); + } + } else { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "Reading string descriptor %ld (len %ld) failed: %s (%ld)", + idx, 2, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + KPRINTF(15, ("Error reading string descriptor %ld (2) failed %ld\n", idx, ioerr)); + } + return(NULL); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdSetDeviceConfig()" */ +AROS_LH2(BOOL, psdSetDeviceConfig, + AROS_LHA(struct PsdPipe *, pp, A1), + AROS_LHA(UWORD, cfgnum, D0), + LIBBASETYPEPTR, ps, 34, psd) +{ + AROS_LIBFUNC_INIT + struct PsdConfig *pc; + struct PsdDevice *pd = pp->pp_Device; + //UBYTE buf[8]; // VIA babble bug safety buffer (8 instead of 2) + LONG ioerr; + BOOL res = FALSE; + + KPRINTF(2, ("Setting configuration to %ld...\n", cfgnum)); + psdPipeSetup(pp, URTF_STANDARD|URTF_DEVICE, + USR_SET_CONFIGURATION, cfgnum, 0); + ioerr = psdDoPipe(pp, NULL, 0); + if(!ioerr) + { +#if 0 // MacOS X does not verify the configuration set. And as we don't check the results anyway, don't obtain current configuration to avoid bad devices breaking down + psdPipeSetup(pp, URTF_IN|URTF_STANDARD|URTF_DEVICE, + USR_GET_CONFIGURATION, 0, 0); + ioerr = psdDoPipe(pp, buf, 1); + if(!ioerr) + { + pd->pd_CurrCfg = buf[0]; + if(cfgnum != buf[0]) + { + pd->pd_CurrCfg = cfgnum; + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "Broken: SetConfig/GetConfig mismatch (%ld != %ld) for %s!", + cfgnum, buf[0], pp->pp_Device->pd_ProductStr); + } + res = TRUE; + } else { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "GET_CONFIGURATION failed: %s (%ld)", + psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + pd->pd_CurrCfg = cfgnum; + KPRINTF(15, ("GET_CONFIGURATION failed %ld!\n", ioerr)); + } +#else + pd->pd_CurrCfg = cfgnum; + res = TRUE; +#endif + } else { + psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname, + "SET_CONFIGURATION failed: %s (%ld)", + psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + KPRINTF(15, ("SET_CONFIGURATION failed %ld!\n", ioerr)); + } + // update direct link + Forbid(); + pd->pd_CurrentConfig = NULL; + pc = (struct PsdConfig *) pd->pd_Configs.lh_Head; + while(pc->pc_Node.ln_Succ) + { + if(pc->pc_CfgNum == pd->pd_CurrCfg) + { + pd->pd_CurrentConfig = pc; + break; + } + pc = (struct PsdConfig *) pc->pc_Node.ln_Succ; + } + Permit(); + if(!pd->pd_CurrentConfig) + { + psdAddErrorMsg0(RETURN_ERROR, (STRPTR) libname, "No current configuration, huh?"); + } else { + UWORD status = 0; + // power saving stuff + if(ps->ps_GlobalCfg->pgc_PowerSaving && (pd->pd_CurrentConfig->pc_Attr & USCAF_REMOTE_WAKEUP)) + { + psdPipeSetup(pp, URTF_STANDARD|URTF_DEVICE, + USR_SET_FEATURE, UFS_DEVICE_REMOTE_WAKEUP, 0); + ioerr = psdDoPipe(pp, NULL, 0); + if(ioerr) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "SET_DEVICE_REMOTE_WAKEUP failed: %s (%ld)", + psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + KPRINTF(15, ("SET_DEVICE_REMOTE_WAKEUP failed %ld!\n", ioerr)); + } + psdPipeSetup(pp, URTF_IN|URTF_STANDARD|URTF_DEVICE, USR_GET_STATUS, 0, 0); + ioerr = psdDoPipe(pp, &status, 2); + if(!ioerr) + { + if(status & U_GSF_REMOTE_WAKEUP) + { + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, + "Enabled remote wakeup feature for '%s'.", + pd->pd_ProductStr); + } else { + pd->pd_CurrentConfig->pc_Attr &= ~USCAF_REMOTE_WAKEUP; + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "Remote wakeup feature for '%s' could not be enabled.", + pd->pd_ProductStr); + } + } else { + /*psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "GET_STATUS failed: %s (%ld)", + psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);*/ + KPRINTF(15, ("GET_STATUS failed %ld!\n", ioerr)); + } + } else { + psdPipeSetup(pp, URTF_IN|URTF_STANDARD|URTF_DEVICE, USR_GET_STATUS, 0, 0); + ioerr = psdDoPipe(pp, &status, 2); + } + if(!ioerr) + { + if((status & U_GSF_SELF_POWERED) && (!(pd->pd_CurrentConfig->pc_Attr & USCAF_SELF_POWERED))) + { + pd->pd_CurrentConfig->pc_Attr |= USCAF_SELF_POWERED; + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, + "Device '%s' says it is currently self-powered. Fixing config.", + pd->pd_ProductStr); + } + else if((!(status & U_GSF_SELF_POWERED)) && (pd->pd_CurrentConfig->pc_Attr & USCAF_SELF_POWERED)) + { + pd->pd_CurrentConfig->pc_Attr &= ~USCAF_SELF_POWERED; + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, + "Device '%s' says it is currently bus-powered. Fixing config.", + pd->pd_ProductStr); + } + } else { + /*psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "GET_STATUS failed: %s (%ld)", + psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);*/ + KPRINTF(15, ("GET_STATUS failed %ld!\n", ioerr)); + } + } + + return(res); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdSetAltInterface()" */ +AROS_LH2(BOOL, psdSetAltInterface, + AROS_LHA(struct PsdPipe *, pp, A1), + AROS_LHA(struct PsdInterface *, pif, A0), + LIBBASETYPEPTR, ps, 43, psd) +{ + AROS_LIBFUNC_INIT + struct PsdConfig *pc = pif->pif_Config; + struct PsdInterface *curif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head; + struct PsdInterface *tmpif; + struct PsdDevice *pd = pc->pc_Device; + UBYTE buf[8]; // VIA babble bug safety buffer (8 instead of 2) + LONG ioerr; + UWORD ifnum = pif->pif_IfNum; + UWORD altnum = pif->pif_Alternate; + + KPRINTF(2, ("Setting interface %ld to alt %ld...\n", ifnum, altnum)); + psdLockWriteDevice(pd); + + /* Find root config structure */ + while(curif->pif_Node.ln_Succ) + { + if(curif->pif_IfNum == ifnum) + { + break; + } + curif = (struct PsdInterface *) curif->pif_Node.ln_Succ; + } + if(!curif->pif_Node.ln_Succ) + { + KPRINTF(20, ("Where did you get that fucking interface from?!?")); + psdUnlockDevice(pd); + return(FALSE); + } + if(curif == pif) /* Is already the current alternate setting */ + { + psdUnlockDevice(pd); + return(TRUE); + } + KPRINTF(1, ("really setting interface...\n")); + if(pp) + { + psdPipeSetup(pp, URTF_STANDARD|URTF_INTERFACE, + USR_SET_INTERFACE, altnum, ifnum); + ioerr = psdDoPipe(pp, NULL, 0); + } else { + ioerr = 0; + } + if((!ioerr) || (ioerr == UHIOERR_STALL)) + { + if(pp) + { + psdPipeSetup(pp, URTF_IN|URTF_STANDARD|URTF_INTERFACE, + USR_GET_INTERFACE, 0, ifnum); + ioerr = psdDoPipe(pp, buf, 1); + } else { + buf[0] = altnum; + } + if(!ioerr) + { + if(altnum == buf[0]) + { + KPRINTF(1, ("resorting list...")); + /*psdAddErrorMsg(RETURN_OK, (STRPTR) libname, + "Changed to alt %ld", + altnum);*/ + Forbid(); + /* Remove pif from alt list */ + Remove(&pif->pif_Node); + pif->pif_ParentIf = NULL; + /* Now move bindings */ + pif->pif_ClsBinding = curif->pif_ClsBinding; + pif->pif_IfBinding = curif->pif_IfBinding; + curif->pif_IfBinding = NULL; + curif->pif_ClsBinding = NULL; + /* Insert it after root interface */ + Insert(&pc->pc_Interfaces, (struct Node *) &pif->pif_Node, (struct Node *) &curif->pif_Node); + /* Unlink root interface */ + Remove(&curif->pif_Node); + /* Now move all remaining alt interfaces to the new root interface */ + tmpif = (struct PsdInterface *) curif->pif_AlterIfs.lh_Head; + while(tmpif->pif_Node.ln_Succ) + { + Remove(&tmpif->pif_Node); + AddTail(&pif->pif_AlterIfs, &tmpif->pif_Node); + tmpif->pif_ParentIf = pif; + tmpif = (struct PsdInterface *) curif->pif_AlterIfs.lh_Head; + } + /* Add old root to the end of the alt list */ + AddTail(&pif->pif_AlterIfs, &curif->pif_Node); + curif->pif_ParentIf = pif; + Permit(); + psdUnlockDevice(pd); + return(TRUE); + } else { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "Attempt to change interface %ld to alt %ld remained at alt %ld.", + ifnum, altnum, buf[0]); + } + } else { + psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname, + "GET_INTERFACE(%ld) failed: %s (%ld)", + ifnum, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + KPRINTF(15, ("GET_INTERFACE failed %ld!\n", ioerr)); + } + } else { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "SET_INTERFACE(%ld)=%ld failed: %s (%ld)", + ifnum, altnum, + psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + KPRINTF(15, ("SET_INTERFACE failed %ld!\n", ioerr)); + } + psdUnlockDevice(pd); + return(FALSE); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdEnumerateDevice()" */ +AROS_LH1(struct PsdDevice *, psdEnumerateDevice, + AROS_LHA(struct PsdPipe *, pp, A1), + LIBBASETYPEPTR, ps, 20, psd) +{ + AROS_LIBFUNC_INIT + struct PsdDevice *pd = pp->pp_Device; + struct PsdDevice *itpd = pp->pp_Device; + struct PsdConfig *pc; + struct PsdInterface *pif; + struct UsbStdDevDesc usdd; + UWORD oldflags; + ULONG oldnaktimeout; + LONG ioerr; + STRPTR classname; + STRPTR vendorname; + ULONG devclass; + BOOL hasprodname; + BOOL haspopupinhibit; + UWORD cfgnum; + struct PsdIFFContext *pic; + ULONG *chnk; + UBYTE dummybuf[8]; + + KPRINTF(2, ("psdEnumerateDevice(%08lx)\n", pp)); + + psdLockWriteDevice(pd); + if(pAllocDevAddr(pd)) + { + oldflags = pp->pp_IOReq.iouh_Flags; + oldnaktimeout = pp->pp_IOReq.iouh_NakTimeout; + pp->pp_IOReq.iouh_Flags |= UHFF_NAKTIMEOUT; + pp->pp_IOReq.iouh_NakTimeout = 1000; + pp->pp_IOReq.iouh_DevAddr = 0; + + psdPipeSetup(pp, URTF_IN|URTF_STANDARD|URTF_DEVICE, + USR_GET_DESCRIPTOR, UDT_DEVICE<<8, 0); + ioerr = psdDoPipe(pp, dummybuf, 8); + if(ioerr && (ioerr != UHIOERR_RUNTPACKET)) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "GET_DESCRIPTOR (len %ld) failed: %s (%ld)", + 8, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + KPRINTF(15, ("GET_DESCRIPTOR (8) failed %ld!\n", ioerr)); + } + KPRINTF(1, ("Setting DevAddr %ld...\n", pd->pd_DevAddr)); + psdPipeSetup(pp, URTF_STANDARD|URTF_DEVICE, + USR_SET_ADDRESS, pd->pd_DevAddr, 0); + ioerr = psdDoPipe(pp, NULL, 0); + /* This is tricky: Maybe the device has accepted the command, + but failed to send an ACK. Now, every resend trial will + go to the wrong address! */ + if((ioerr == UHIOERR_TIMEOUT) || (ioerr == UHIOERR_STALL)) + { + KPRINTF(1, ("First attempt failed, retrying new address\n")); + /*pp->pp_IOReq.iouh_DevAddr = pd->pd_DevAddr;*/ + psdDelayMS(250); + ioerr = psdDoPipe(pp, NULL, 0); + /*pp->pp_IOReq.iouh_DevAddr = 0;*/ + } + if(!ioerr) + { + pd->pd_Flags |= PDFF_HASDEVADDR|PDFF_CONNECTED; + pp->pp_IOReq.iouh_DevAddr = pd->pd_DevAddr; + + psdDelayMS(50); /* Allowed time to settle */ + + KPRINTF(1, ("Getting MaxPktSize0...\n")); + psdPipeSetup(pp, URTF_IN|URTF_STANDARD|URTF_DEVICE, + USR_GET_DESCRIPTOR, UDT_DEVICE<<8, 0); + ioerr = psdDoPipe(pp, &usdd, 8); + if(!ioerr) + { + switch(usdd.bMaxPacketSize0) + { + case 8: + case 16: + case 32: + case 64: + pp->pp_IOReq.iouh_MaxPktSize = pd->pd_MaxPktSize0 = usdd.bMaxPacketSize0; + break; + default: + psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname, + "Illegal MaxPktSize0=%ld for endpoint 0", + (ULONG) usdd.bMaxPacketSize0); + KPRINTF(2, ("Illegal MaxPktSize0=%ld!\n", usdd.bMaxPacketSize0)); + //pp->pp_IOReq.iouh_MaxPktSize = pd->pd_MaxPktSize0 = 8; + ioerr = UHIOERR_CRCERROR; + break; + } + } + if(!ioerr) + { + KPRINTF(1, (" MaxPktSize0 = %ld\n", pd->pd_MaxPktSize0)); + KPRINTF(1, ("Getting full descriptor...\n")); + ioerr = psdDoPipe(pp, &usdd, sizeof(struct UsbStdDevDesc)); + if(!ioerr) + { + pAllocDescriptor(pd, (UBYTE *) &usdd); + pd->pd_Flags |= PDFF_HASDEVDESC; + pd->pd_USBVers = AROS_WORD2LE(usdd.bcdUSB); + pd->pd_DevClass = usdd.bDeviceClass; + pd->pd_DevSubClass = usdd.bDeviceSubClass; + pd->pd_DevProto = usdd.bDeviceProtocol; + pd->pd_VendorID = AROS_WORD2LE(usdd.idVendor); + pd->pd_ProductID = AROS_WORD2LE(usdd.idProduct); + pd->pd_DevVers = AROS_WORD2LE(usdd.bcdDevice); + vendorname = psdNumToStr(NTS_VENDORID, (LONG) pd->pd_VendorID, NULL); + + // patch to early determine highspeed roothubs + if((!pd->pd_Hub) && (pd->pd_USBVers >= 0x200)) + { + pd->pd_Flags |= PDFF_HIGHSPEED; + } + + if(usdd.iManufacturer) + { + pd->pd_MnfctrStr = psdGetStringDescriptor(pp, usdd.iManufacturer); + } + if(usdd.iProduct) + { + pd->pd_ProductStr = psdGetStringDescriptor(pp, usdd.iProduct); + } + if(usdd.iSerialNumber) + { + pd->pd_SerNumStr = psdGetStringDescriptor(pp, usdd.iSerialNumber); + } + if(!pd->pd_MnfctrStr) + { + pd->pd_MnfctrStr = psdCopyStr(vendorname ? vendorname : (STRPTR) "n/a"); + } + if(!pd->pd_ProductStr) + { + hasprodname = FALSE; + classname = psdNumToStr(NTS_CLASSCODE, (LONG) pd->pd_DevClass, NULL); + if(classname) + { + pd->pd_ProductStr = psdCopyStrFmt("%s: Vdr=%04lx/PID=%04lx", + classname, pd->pd_VendorID, pd->pd_ProductID); + } else { + pd->pd_ProductStr = psdCopyStrFmt("Cls=%ld/Vdr=%04lx/PID=%04lx", + pd->pd_DevClass, pd->pd_VendorID, pd->pd_ProductID); + } + } else { + hasprodname = TRUE; + } + if(!pd->pd_SerNumStr) + { + pd->pd_SerNumStr = psdCopyStr("n/a"); + } + + KPRINTF(2, ("Product : %s\n" + "Manufacturer: %s\n" + "SerialNumber: %s\n", + pd->pd_ProductStr, pd->pd_MnfctrStr, pd->pd_SerNumStr)); + KPRINTF(2, ("USBVersion: %04lx\n" + "Class : %ld\n" + "SubClass : %ld\n" + "DevProto : %ld\n" + "VendorID : %ld\n" + "ProductID : %ld\n" + "DevVers : %04lx\n", + pd->pd_USBVers, pd->pd_DevClass, pd->pd_DevSubClass, pd->pd_DevProto, + pd->pd_VendorID, pd->pd_ProductID, pd->pd_DevVers)); + + /* check for clones */ + itpd = NULL; + while((itpd = psdGetNextDevice(itpd))) + { + if(itpd != pd) + { + if((itpd->pd_ProductID == pd->pd_ProductID) && + (itpd->pd_VendorID == pd->pd_VendorID) && + (!strcmp(itpd->pd_SerNumStr, pd->pd_SerNumStr)) && + (itpd->pd_CloneCount == pd->pd_CloneCount)) + { + pd->pd_CloneCount++; + itpd = NULL; + } + } + } + + pd->pd_IDString = psdCopyStrFmt("%s-%04lx-%04lx-%s-%02lx", pd->pd_ProductStr, pd->pd_VendorID, pd->pd_ProductID, pd->pd_SerNumStr, pd->pd_CloneCount); + + pStripString(ps, pd->pd_MnfctrStr); + pStripString(ps, pd->pd_ProductStr); + pStripString(ps, pd->pd_SerNumStr); + + /* get custom name of device */ + pLockSemExcl(ps, &ps->ps_ConfigLock); // Exclusive lock to avoid deadlock situation when promoting read to write + pd->pd_OldProductStr = pd->pd_ProductStr; + pd->pd_ProductStr = NULL; + haspopupinhibit = FALSE; + pic = psdGetUsbDevCfg("Trident", pd->pd_IDString, NULL); + if(pic) + { + pd->pd_IsNewToMe = FALSE; + if((pd->pd_ProductStr = pGetStringChunk(ps, pic, IFFCHNK_NAME))) + { + hasprodname = TRUE; + } + if((chnk = pFindCfgChunk(ps, pic, IFFCHNK_POPUP))) + { + struct PsdPoPoCfg *poc = (struct PsdPoPoCfg *) chnk; + CopyMem(((UBYTE *) poc) + 8, ((UBYTE *) &pd->pd_PoPoCfg) + 8, min(AROS_LONG2BE(poc->poc_Length), AROS_LONG2BE(pd->pd_PoPoCfg.poc_Length))); + haspopupinhibit = TRUE; + } + } else { + pd->pd_IsNewToMe = TRUE; + psdSetUsbDevCfg("Trident", pd->pd_IDString, NULL, NULL); + } + if(!pd->pd_ProductStr) + { + pd->pd_ProductStr = psdCopyStr(pd->pd_OldProductStr); + } + if(!haspopupinhibit) + { + if(pd->pd_DevClass == HUB_CLASSCODE) // hubs default to true + { + pd->pd_PoPoCfg.poc_InhibitPopup = TRUE; + } + } + pUnlockSem(ps, &ps->ps_ConfigLock); + + pd->pd_NumCfgs = usdd.bNumConfigurations; + KPRINTF(10, ("Device has %ld different configurations\n", pd->pd_NumCfgs)); + + if(pGetDevConfig(pp)) + { + cfgnum = 1; + if(pd->pd_Configs.lh_Head->ln_Succ) + { + cfgnum = ((struct PsdConfig *) pd->pd_Configs.lh_Head)->pc_CfgNum; + } + psdSetDeviceConfig(pp, cfgnum); /* *** FIXME *** Workaround for USB2.0 devices */ + { + if(!hasprodname) + { + devclass = pd->pd_DevClass; + pc = (struct PsdConfig *) pd->pd_Configs.lh_Head; + while(pc->pc_Node.ln_Succ) + { + pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head; + while(pif->pif_Node.ln_Succ) + { + if(pif->pif_IfClass) + { + if(!devclass) + { + devclass = pif->pif_IfClass; + } else { + if(devclass != pif->pif_IfClass) + { + devclass = 0; + break; + } + } + } + pif = (struct PsdInterface *) pif->pif_Node.ln_Succ; + } + pc = (struct PsdConfig *) pc->pc_Node.ln_Succ; + } + if(devclass) + { + classname = psdNumToStr(NTS_CLASSCODE, (LONG) devclass, NULL); + if(classname) + { + psdFreeVec(pd->pd_ProductStr); + if(vendorname) + { + pd->pd_ProductStr = psdCopyStrFmt("%s (%s/%04lx)", + classname, vendorname, pd->pd_ProductID); + } else { + pd->pd_ProductStr = psdCopyStrFmt("%s (%04lx/%04lx)", + classname, pd->pd_VendorID, pd->pd_ProductID); + } + } + } + } + pFixBrokenConfig(pp); + pp->pp_IOReq.iouh_Flags = oldflags; + pp->pp_IOReq.iouh_NakTimeout = oldnaktimeout; + psdUnlockDevice(pd); + psdCalculatePower(pd->pd_Hardware); + return(pd); + } /*else { + KPRINTF(15, ("SetDeviceConfig(1) failed\n")); + }*/ + } else { + psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname, + "Could not acquire device configuration for %s", + pd->pd_ProductStr ? pd->pd_ProductStr : (STRPTR) "new device"); + KPRINTF(15, ("GetDevConfig() failed\n")); + } + /* Although the device failed to configure fully, maybe + some firmware will able to use this device anyway? */ + pp->pp_IOReq.iouh_Flags = oldflags; + pp->pp_IOReq.iouh_NakTimeout = oldnaktimeout; + + psdUnlockDevice(pd); + return(pd); + } else { + psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname, + "GET_DESCRIPTOR (len %ld) failed: %s (%ld)", + 18, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + KPRINTF(15, ("GET_DESCRIPTOR (18) failed %ld!\n", ioerr)); + } + } else { + psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname, + "GET_DESCRIPTOR (len %ld) failed: %s (%ld)", + 8, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + KPRINTF(15, ("GET_DESCRIPTOR (8) failed %ld!\n", ioerr)); + } + } else { + psdAddErrorMsg(RETURN_FAIL, (STRPTR) libname, + "SET_ADDRESS failed: %s (%ld)", + psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + KPRINTF(15, ("SET_ADDRESS failed %ld!\n", ioerr)); + + } + pp->pp_IOReq.iouh_Flags = oldflags; + pp->pp_IOReq.iouh_NakTimeout = oldnaktimeout; + } else { + psdAddErrorMsg0(RETURN_FAIL, (STRPTR) libname, "This cannot happen! More than 127 devices on the bus???"); + KPRINTF(20, ("out of addresses???\n")); + } + psdAddErrorMsg0(RETURN_FAIL, (STRPTR) libname, "Device enumeration failed, sorry."); + psdUnlockDevice(pd); + return(NULL); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdGetNextDevice()" */ +AROS_LH1(struct PsdDevice *, psdGetNextDevice, + AROS_LHA(struct PsdDevice *, pd, A0), + LIBBASETYPEPTR, ps, 21, psd) +{ + AROS_LIBFUNC_INIT + struct PsdHardware *phw; + + KPRINTF(1, ("psdGetNextDevice(%08lx)\n", pd)); + if(pd) + { + /* Is there another device node in the current hardware? */ + if(pd->pd_Node.ln_Succ->ln_Succ) + { + return((struct PsdDevice *) pd->pd_Node.ln_Succ); + } + /* No, then check if there's another hardware to scan */ + phw = (struct PsdHardware *) pd->pd_Hardware->phw_Node.ln_Succ; + } else { + /* No context, start with first hardware */ + phw = (struct PsdHardware *) ps->ps_Hardware.lh_Head; + } + while(phw->phw_Node.ln_Succ) + { + pd = (struct PsdDevice *) phw->phw_Devices.lh_Head; + /* Is this an valid entry, or is the list empty? */ + if(pd->pd_Node.ln_Succ) + { + return(pd); + } + phw = (struct PsdHardware *) phw->phw_Node.ln_Succ; + } + /* End of list reached */ + return(NULL); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdSuspendBindings()" */ +AROS_LH1(BOOL, psdSuspendBindings, + AROS_LHA(struct PsdDevice *, pd, A0), + LIBBASETYPEPTR, ps, 100, psd) +{ + AROS_LIBFUNC_INIT + struct PsdUsbClass *puc; + struct PsdConfig *pc; + struct PsdInterface *pif; + BOOL res = FALSE; + IPTR suspendable; + BOOL force = FALSE; + + KPRINTF(5, ("psdSuspendBindings(%08lx)\n", pd)); + if(pd) + { + if(ps->ps_GlobalCfg->pgc_ForceSuspend && (pd->pd_CurrentConfig->pc_Attr & USCAF_REMOTE_WAKEUP)) + { + force = TRUE; + } + // ask existing bindings to go to suspend first -- if they don't support it, break off + if(pd->pd_DevBinding) + { + if(pd->pd_Flags & PDFF_APPBINDING) + { + if(!force) + { + // can't suspend application binding devices + psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname, + "Cannot suspend with application binding on '%s'.", + pd->pd_ProductStr); + return FALSE; + } + psdReleaseDevBinding(pd); + } + if((puc = pd->pd_ClsBinding)) + { + suspendable = 0; + usbGetAttrs(UGA_CLASS, NULL, UCCA_SupportsSuspend, &suspendable, TAG_END); + if(suspendable) + { + res = usbDoMethod(UCM_AttemptSuspendDevice, pd->pd_DevBinding); + if(!res) + { + // didn't want to suspend + psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname, + "Class '%s' failed to suspend device '%s'.", + puc->puc_Node.ln_Name, pd->pd_ProductStr); + return FALSE; + } + } else { + if(pd->pd_IOBusyCount) + { + if(!force) + { + psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname, + "Class '%s' does not support suspending.", + puc->puc_Node.ln_Name); + return FALSE; + } else { + psdReleaseDevBinding(pd); + } + } else { + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, + "Class '%s' does not support suspending, but has no active IO. Suspending anyway.", + puc->puc_Node.ln_Name); + } + } + } + } + pc = pd->pd_CurrentConfig; + pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head; + while(pif->pif_Node.ln_Succ) + { + if(pif->pif_IfBinding) + { + if((puc = pif->pif_ClsBinding)) + { + suspendable = 0; + usbGetAttrs(UGA_CLASS, NULL, UCCA_SupportsSuspend, &suspendable, TAG_END); + if(suspendable) + { + res = usbDoMethod(UCM_AttemptSuspendDevice, pif->pif_IfBinding); + if(!res) + { + // didn't want to suspend + psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname, + "%s failed to suspend device '%s'.", + puc->puc_Node.ln_Name, pd->pd_ProductStr); + return FALSE; + } + } else { + if(pd->pd_IOBusyCount) + { + if(!force) + { + + psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname, + "%s does not support suspending.", + puc->puc_Node.ln_Name); + return FALSE; + } else { + psdReleaseIfBinding(pif); + } + } else { + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, + "%s does not support suspending, but has no active IO. Suspending anyway.", + puc->puc_Node.ln_Name); + } + } + } + } + pif = (struct PsdInterface *) pif->pif_Node.ln_Succ; + } + return TRUE; + } + return FALSE; + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdSuspendDevice()" */ +AROS_LH1(BOOL, psdSuspendDevice, + AROS_LHA(struct PsdDevice *, pd, A0), + LIBBASETYPEPTR, ps, 98, psd) +{ + AROS_LIBFUNC_INIT + struct PsdUsbClass *puc; + struct PsdDevice *hubpd; + APTR binding; + BOOL res = FALSE; + + KPRINTF(5, ("psdSuspendDevice(%08lx)\n", pd)); + if(pd) + { + if(pd->pd_Flags & PDFF_SUSPENDED) + { + return TRUE; + } + hubpd = pd->pd_Hub; + if(!hubpd) // suspend root hub + { + // suspend whole USB, using the HCI UHCMD_USBSUSPEND command + // FIXME currently unsupported! + psdAddErrorMsg0(RETURN_ERROR, (STRPTR) libname, "Suspending of root hub currently not supported."); + return FALSE; + } + + psdLockWriteDevice(pd); + res = psdSuspendBindings(pd); + psdUnlockDevice(pd); + if(res) + { + psdLockReadDevice(pd); + if((binding = hubpd->pd_DevBinding) && (puc = hubpd->pd_ClsBinding)) + { + res = usbDoMethod(UCM_HubSuspendDevice, binding, pd); + } + psdUnlockDevice(pd); + } + } + if(!res) + { + psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname, + "Suspending of device '%s' failed.", + pd->pd_ProductStr); + } + return(res); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdResumeBindings()" */ +AROS_LH1(BOOL, psdResumeBindings, + AROS_LHA(struct PsdDevice *, pd, A0), + LIBBASETYPEPTR, ps, 101, psd) +{ + AROS_LIBFUNC_INIT + struct PsdUsbClass *puc; + struct PsdConfig *pc; + struct PsdInterface *pif; + BOOL res = FALSE; + BOOL rescan = FALSE; + + KPRINTF(5, ("psdResumeBindings(%08lx)\n", pd)); + if(pd) + { + // ask existing bindings to resume -- if they don't support it, rebind + if(pd->pd_DevBinding) + { + if(!(pd->pd_Flags & PDFF_APPBINDING)) + { + if((puc = pd->pd_ClsBinding)) + { + res = usbDoMethod(UCM_AttemptResumeDevice, pd->pd_DevBinding); + if(!res) + { + // if the device couldn't resume, better get rid of the binding + psdReleaseDevBinding(pd); + rescan = TRUE; + } + } + } + } + pc = pd->pd_CurrentConfig; + pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head; + while(pif->pif_Node.ln_Succ) + { + if(pif->pif_IfBinding) + { + if((puc = pif->pif_ClsBinding)) + { + res = usbDoMethod(UCM_AttemptResumeDevice, pif->pif_IfBinding); + if(!res) + { + // didn't want to suspend + psdReleaseIfBinding(pif); + rescan = TRUE; + } + } + break; + } + pif = (struct PsdInterface *) pif->pif_Node.ln_Succ; + } + if(rescan) + { + psdClassScan(); + } + } + return(TRUE); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdResumeDevice()" */ +AROS_LH1(BOOL, psdResumeDevice, + AROS_LHA(struct PsdDevice *, pd, A0), + LIBBASETYPEPTR, ps, 99, psd) +{ + AROS_LIBFUNC_INIT + struct PsdUsbClass *puc; + struct PsdDevice *hubpd; + APTR binding; + BOOL res = FALSE; + + KPRINTF(5, ("psdResumeDevice(%08lx)\n", pd)); + if(pd) + { + if(!(pd->pd_Flags & PDFF_SUSPENDED)) + { + return(TRUE); + } + hubpd = pd->pd_Hub; + if(!hubpd) // resume root hub + { + // resume whole USB, using the HCI UHCMD_USBRESUME command + // FIXME currently unsupported! + return(FALSE); + } + psdLockWriteDevice(pd); + if((binding = hubpd->pd_DevBinding) && (puc = hubpd->pd_ClsBinding)) + { + res = usbDoMethod(UCM_HubResumeDevice, binding, pd); + } + psdUnlockDevice(pd); + + if(res) + { + psdResumeBindings(pd); + } + } + + return(res); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdFindDeviceA()" */ +AROS_LH2(struct PsdDevice *, psdFindDeviceA, + AROS_LHA(struct PsdDevice *, pd, A0), + AROS_LHA(struct TagItem *, tags, A1), + LIBBASETYPEPTR, ps, 44, psd) +{ + AROS_LIBFUNC_INIT + struct TagItem *ti; + BOOL takeit; + KPRINTF(2, ("psdFindDeviceA(%08lx, %08lx)\n", pd, tags)); + while((pd = psdGetNextDevice(pd))) + { + takeit = TRUE; + if((ti = FindTagItem(DA_ProductID, tags))) + { + if(ti->ti_Data != pd->pd_ProductID) + { + takeit = FALSE; + } + } + if((ti = FindTagItem(DA_VendorID, tags))) + { + if(ti->ti_Data != pd->pd_VendorID) + { + takeit = FALSE; + } + } + if((ti = FindTagItem(DA_Class, tags))) + { + if(ti->ti_Data != pd->pd_DevClass) + { + takeit = FALSE; + } + } + if((ti = FindTagItem(DA_SubClass, tags))) + { + if(ti->ti_Data != pd->pd_DevSubClass) + { + takeit = FALSE; + } + } + if((ti = FindTagItem(DA_Protocol, tags))) + { + if(ti->ti_Data != pd->pd_DevProto) + { + takeit = FALSE; + } + } + if((ti = FindTagItem(DA_Version, tags))) + { + if(ti->ti_Data != pd->pd_DevVers) + { + takeit = FALSE; + } + } + if((ti = FindTagItem(DA_SerialNumber, tags))) + { + if(strcmp((STRPTR) ti->ti_Data, pd->pd_SerNumStr)) + { + takeit = FALSE; + } + } + if((ti = FindTagItem(DA_ProductName, tags))) + { + if(strcmp((STRPTR) ti->ti_Data, pd->pd_ProductStr)) + { + takeit = FALSE; + } + } + if((ti = FindTagItem(DA_Manufacturer, tags))) + { + if(strcmp((STRPTR) ti->ti_Data, pd->pd_MnfctrStr)) + { + takeit = FALSE; + } + } + if((ti = FindTagItem(DA_IDString, tags))) + { + if(strcmp((STRPTR) ti->ti_Data, pd->pd_IDString)) + { + takeit = FALSE; + } + } + if((ti = FindTagItem(DA_Binding, tags))) + { + if(ti->ti_Data != (ULONG) pd->pd_DevBinding) + { + takeit = FALSE; + } + } + if((ti = FindTagItem(DA_HubDevice, tags))) + { + if(ti->ti_Data != (ULONG) pd->pd_Hub) + { + takeit = FALSE; + } + } + + if(takeit) + { + return(pd); + } + } + return(NULL); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* *** Hardware *** */ + +/* /// "pFindHardware()" */ +struct PsdHardware * pFindHardware(LIBBASETYPEPTR ps, STRPTR name, ULONG unit) +{ + struct PsdHardware *phw; + Forbid(); + while(*name) + { + phw = (struct PsdHardware *) ps->ps_Hardware.lh_Head; + while(phw->phw_Node.ln_Succ) + { + if((phw->phw_Unit == unit) && (!strcmp(phw->phw_DevName, name))) + { + Permit(); + return(phw); + } + phw = (struct PsdHardware *) phw->phw_Node.ln_Succ; + } + do + { + if((*name == '/') || (*name == ':')) + { + ++name; + break; + } + } while(*(++name)); + } + Permit(); + return(NULL); +} +/* \\\ */ + +/* /// "psdEnumerateHardware()" */ +AROS_LH1(struct PsdDevice *, psdEnumerateHardware, + AROS_LHA(struct PsdHardware *, phw, A0), + LIBBASETYPEPTR, ps, 14, psd) +{ + AROS_LIBFUNC_INIT + struct PsdDevice *pd = NULL; + struct PsdPipe *pp; + struct MsgPort *mp; + KPRINTF(2, ("psdEnumerateHardware(%08lx)\n", phw)); + + if((mp = CreateMsgPort())) + { + Forbid(); + if((pd = psdAllocDevice(phw))) + { + Permit(); + if((pp = psdAllocPipe(pd, mp, NULL))) + { + //pp->pp_IOReq.iouh_Flags |= UHFF_NAKTIMEOUT; + //pp->pp_IOReq.iouh_NakTimeout = 1000; + pd->pd_Flags |= PDFF_CONNECTED; + pp->pp_IOReq.iouh_Req.io_Command = UHCMD_USBRESET; + psdDoPipe(pp, NULL, 0); + pp->pp_IOReq.iouh_Req.io_Command = UHCMD_CONTROLXFER; + psdDelayMS(100); // wait for root hub to settle + if(psdEnumerateDevice(pp)) + { + KPRINTF(1, ("Enumeration finished!\n")); + psdAddErrorMsg0(RETURN_OK, (STRPTR) libname, "Root hub has been enumerated."); + psdFreePipe(pp); + DeleteMsgPort(mp); + phw->phw_RootDevice = pd; + psdSendEvent(EHMB_ADDDEVICE, pd, NULL); + return(pd); + } + psdFreePipe(pp); + } + pFreeBindings(ps, pd); + pFreeDevice(ps, pd); + } else { + Permit(); + } + DeleteMsgPort(mp); + } + psdAddErrorMsg0(RETURN_FAIL, (STRPTR) libname, "Root hub enumeration failed. Blame your hardware driver programmer."); + return(NULL); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdRemHardware()" */ +AROS_LH1(void, psdRemHardware, + AROS_LHA(struct PsdHardware *, phw, A0), + LIBBASETYPEPTR, ps, 13, psd) +{ + AROS_LIBFUNC_INIT + struct PsdDevice *pd; + ULONG cnt; + + KPRINTF(5, ("FreeHardware(%08lx)\n", phw)); + + pd = (struct PsdDevice *) phw->phw_Devices.lh_Head; + while(pd->pd_Node.ln_Succ) + { + pFreeBindings(ps, pd); + pFreeDevice(ps, pd); + psdSendEvent(EHMB_REMDEVICE, pd, NULL); + pd = (struct PsdDevice *) phw->phw_Devices.lh_Head; + } + cnt = 0; + pd = (struct PsdDevice *) phw->phw_DeadDevices.lh_Head; + while(pd->pd_Node.ln_Succ) + { + if(pd->pd_UseCnt) + { + KPRINTF(20, ("Can't remove device, usecnt %ld\n", pd->pd_UseCnt)); + if(++cnt == 5) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "Can't remove device '%s', there are still %ld pipes in use...", + pd->pd_ProductStr, pd->pd_UseCnt); + } + if(++cnt == 30) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "Okay, going down with device '%s' anyway, maybe the driver crashed?", + pd->pd_ProductStr); + pd->pd_UseCnt = 0; + cnt--; + } else { + psdDelayMS(1000); + } + } else { + pFreeDevice(ps, pd); + //psdSendEvent(EHMB_REMDEVICE, pd, NULL); + } + pd = (struct PsdDevice *) phw->phw_DeadDevices.lh_Head; + } + + Forbid(); + /* Note that the subtask unlinks the hardware! */ + phw->phw_ReadySignal = SIGB_SINGLE; + phw->phw_ReadySigTask = FindTask(NULL); + if(phw->phw_Task) + { + Signal(phw->phw_Task, SIGBREAKF_CTRL_C); + } + Permit(); + while(phw->phw_Task) + { + Wait(1L<phw_ReadySignal); + } + //FreeSignal(phw->phw_ReadySignal); + KPRINTF(1, ("FreeHardware(%08lx) freevec name\n", phw)); + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, + "Removed hardware %s/%ld. Bye bye!", + phw->phw_DevName, phw->phw_Unit); + psdFreeVec(phw->phw_DevName); + psdFreeVec(phw->phw_ProductName); + psdFreeVec(phw->phw_Manufacturer); + psdFreeVec(phw->phw_Description); + psdFreeVec(phw->phw_Copyright); + psdFreeVec(phw); + psdSendEvent(EHMB_REMHARDWARE, phw, NULL); + KPRINTF(1, ("FreeHardware(%08lx) done\n", phw)); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdAddHardware()" */ +AROS_LH2(struct PsdHardware *,psdAddHardware, + AROS_LHA(STRPTR, name, A0), + AROS_LHA(ULONG, unit, D0), + LIBBASETYPEPTR, ps, 12, psd) +{ + AROS_LIBFUNC_INIT + struct PsdHardware *phw; + char buf[64]; + struct Task *tmptask; + KPRINTF(5, ("psdAddHardware(%s, %ld)\n", name, unit)); + + if((phw = psdAllocVec(sizeof(struct PsdHardware)))) + { + NewList(&phw->phw_Devices); + NewList(&phw->phw_DeadDevices); + phw->phw_Unit = unit; + phw->phw_Base = ps; + if((phw->phw_Node.ln_Name = phw->phw_DevName = psdCopyStr(name))) + { + psdSafeRawDoFmt(buf, 64, "usbhw<%s/%ld>", name, unit); + phw->phw_ReadySignal = SIGB_SINGLE; + phw->phw_ReadySigTask = FindTask(NULL); + SetSignal(0, SIGF_SINGLE); // clear single bit + if((tmptask = psdSpawnSubTask(buf, pDeviceTask, phw))) + { + psdBorrowLocksWait(tmptask, 1UL<phw_ReadySignal); + if(phw->phw_Task) + { + phw->phw_ReadySigTask = NULL; + //FreeSignal(phw->phw_ReadySignal); + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, + "New hardware %s/%ld added (%s).", + phw->phw_DevName, + phw->phw_Unit, + phw->phw_ProductName); + psdSendEvent(EHMB_ADDHARDWARE, phw, NULL); + return(phw); + } + } + phw->phw_ReadySigTask = NULL; + //FreeSignal(phw->phw_ReadySignal); + psdFreeVec(phw->phw_DevName); + } + psdFreeVec(phw); + } + return(NULL); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdCalculatePower()" */ +AROS_LH1(void, psdCalculatePower, + AROS_LHA(struct PsdHardware *, phw, A0), + LIBBASETYPEPTR, ps, 78, psd) +{ + AROS_LIBFUNC_INIT + struct PsdDevice *roothub = NULL; + struct PsdDevice *pd; + + psdLockReadPBase(); + /* goto root */ + pd = (struct PsdDevice *) phw->phw_Devices.lh_Head; + while(pd->pd_Node.ln_Succ) + { + if(!pd->pd_Hub) + { + roothub = pd; + break; + } + pd = (struct PsdDevice *) pd->pd_Node.ln_Succ; + } + if(!roothub) + { + psdUnlockPBase(); + return; + } + roothub->pd_PowerDrain = 0; + roothub->pd_PowerSupply = 500; + + /* calculate drain */ + pPowerRecurseDrain(ps, roothub); + + /* calculate supply */ + pPowerRecurseSupply(ps, roothub); + psdUnlockPBase(); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* *** Pipes *** */ + +/* /// "psdAllocPipe()" */ +AROS_LH3(struct PsdPipe *, psdAllocPipe, + AROS_LHA(struct PsdDevice *, pd, A0), + AROS_LHA(struct MsgPort *, mp, A1), + AROS_LHA(struct PsdEndpoint *, pep, A2), + LIBBASETYPEPTR, ps, 24, psd) +{ + AROS_LIBFUNC_INIT + struct PsdPipe *pp; + struct PsdDevice *hubpd; + + KPRINTF(2, ("psdAllocPipe(%08lx, %08lx, %08lx)\n", pd, mp, pep)); + if(!mp || !pd) + { + return(NULL); + } + if(pep && (pep->pep_TransType == USEAF_ISOCHRONOUS) && (!(pep->pep_Interface->pif_Config->pc_Device->pd_Hardware->phw_Capabilities & UHCF_ISO))) + { + psdAddErrorMsg0(RETURN_FAIL, (STRPTR) libname, "Your HW controller driver does not support iso transfers. Sorry."); + return(NULL); + } + + if((pp = psdAllocVec(sizeof(struct PsdPipe)))) + { + pp->pp_Msg.mn_Node.ln_Type = NT_FREEMSG; + pp->pp_MsgPort = pp->pp_Msg.mn_ReplyPort = mp; + pp->pp_Msg.mn_Length = sizeof(struct PsdPipe); + pp->pp_Device = pd; + pp->pp_Endpoint = pep; + pp->pp_IOReq = *(pd->pd_Hardware->phw_RootIOReq); + pp->pp_IOReq.iouh_DevAddr = pd->pd_DevAddr; + if(pd->pd_Flags & PDFF_LOWSPEED) + { + pp->pp_IOReq.iouh_Flags |= UHFF_LOWSPEED; + } + if(pd->pd_Flags & PDFF_HIGHSPEED) + { + pp->pp_IOReq.iouh_Flags |= UHFF_HIGHSPEED; + if(pep) + { + switch(pep->pep_NumTransMuFr) + { + case 2: + pp->pp_IOReq.iouh_Flags |= UHFF_MULTI_2; + break; + case 3: + pp->pp_IOReq.iouh_Flags |= UHFF_MULTI_3; + break; + + default: + pp->pp_IOReq.iouh_Flags |= UHFF_MULTI_1; + } + } else { + pp->pp_IOReq.iouh_Flags |= UHFF_MULTI_1; + } + } + if(pd->pd_Flags & PDFF_NEEDSSPLIT) + { + /* USB1.1 device connected to a USB2.0 hub */ + pp->pp_IOReq.iouh_Flags |= UHFF_SPLITTRANS; + hubpd = pd->pd_Hub; + pp->pp_IOReq.iouh_SplitHubPort = pd->pd_HubPort; + // find the root USB 2.0 hub in the tree + while(hubpd && !(hubpd->pd_Flags & PDFF_HIGHSPEED)) + { + pp->pp_IOReq.iouh_SplitHubPort = hubpd->pd_HubPort; + hubpd = hubpd->pd_Hub; + } + if(!hubpd) + { + psdAddErrorMsg0(RETURN_ERROR, (STRPTR) libname, "Internal error obtaining split transaction hub!"); + psdFreeVec(pp); + return(NULL); + } + pp->pp_IOReq.iouh_Flags |= (hubpd->pd_HubThinkTime<pp_IOReq.iouh_SplitHubAddr = hubpd->pd_DevAddr; + } + if(pep) + { + switch(pep->pep_TransType) + { + case USEAF_CONTROL: + pp->pp_IOReq.iouh_Req.io_Command = UHCMD_CONTROLXFER; + break; + case USEAF_ISOCHRONOUS: + pp->pp_IOReq.iouh_Req.io_Command = UHCMD_ISOXFER; + break; + case USEAF_BULK: + pp->pp_IOReq.iouh_Req.io_Command = UHCMD_BULKXFER; + break; + case USEAF_INTERRUPT: + pp->pp_IOReq.iouh_Req.io_Command = UHCMD_INTXFER; + break; + default: + psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname, + "AllocPipe(): Illegal transfer type %ld", + pep->pep_TransType); + KPRINTF(20, ("Illegal transfer type for endpoint!")); + psdFreeVec(pp); + return(NULL); + + } + pp->pp_IOReq.iouh_Dir = (pep->pep_Direction ? UHDIR_IN : UHDIR_OUT); + pp->pp_IOReq.iouh_Endpoint = pep->pep_EPNum; + pp->pp_IOReq.iouh_MaxPktSize = pep->pep_MaxPktSize; + pp->pp_IOReq.iouh_Interval = pep->pep_Interval; + } else { + pp->pp_IOReq.iouh_Req.io_Command = UHCMD_CONTROLXFER; + pp->pp_IOReq.iouh_Dir = UHDIR_SETUP; + pp->pp_IOReq.iouh_Endpoint = 0; + pp->pp_IOReq.iouh_MaxPktSize = pd->pd_MaxPktSize0; + } + pd->pd_UseCnt++; + return(pp); + } + return(NULL); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdFreePipe()" */ +AROS_LH1(void, psdFreePipe, + AROS_LHA(struct PsdPipe *, pp, A1), + LIBBASETYPEPTR, ps, 25, psd) +{ + AROS_LIBFUNC_INIT + struct PsdDevice *pd; + if(!pp) + { + return; + } + KPRINTF(2, ("psdFreePipe(%08lx)\n", pp)); + pd = pp->pp_Device; + + if(pp->pp_Msg.mn_Node.ln_Type == NT_MESSAGE) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "Tried to free pipe on %s that was still pending!", pd->pd_ProductStr); + psdAbortPipe(pp); + psdWaitPipe(pp); + } + + if(!(--pd->pd_UseCnt) && (pd->pd_Flags & PDFF_DELEXPUNGE)) + { + KPRINTF(20, ("Finally getting rid of device %s\n", pd->pd_ProductStr)); + pFreeDevice(ps, pd); + //psdSendEvent(EHMB_REMDEVICE, pd, NULL); + } + + psdFreeVec(pp); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdPipeSetup()" */ +AROS_LH5(void, psdPipeSetup, + AROS_LHA(struct PsdPipe *, pp, A1), + AROS_LHA(UWORD, rt, D0), + AROS_LHA(UWORD, rq, D1), + AROS_LHA(UWORD, val, D2), + AROS_LHA(UWORD, idx, D3), + LIBBASETYPEPTR, ps, 26, psd) +{ + AROS_LIBFUNC_INIT + struct UsbSetupData *usd = &pp->pp_IOReq.iouh_SetupData; + + KPRINTF(1, ("psdSetupPipe(%08lx, (%02lx %02lx %04lx %04lx))\n", + pp, rt, rq, val, idx)); + usd->bmRequestType = rt; + usd->bRequest = rq; + usd->wValue = AROS_WORD2LE(val); + usd->wIndex = AROS_WORD2LE(idx); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdDoPipe()" */ +AROS_LH3(LONG, psdDoPipe, + AROS_LHA(struct PsdPipe *, pp, A1), + AROS_LHA(APTR, data, A0), + AROS_LHA(ULONG, len, D0), + LIBBASETYPEPTR, ps, 27, psd) +{ + AROS_LIBFUNC_INIT + struct PsdDevice *pd = pp->pp_Device; + KPRINTF(200, ("psdDoPipe(%08lx, %08lx, %ld)\n", pp, data, len)); + + if(pd->pd_Flags & PDFF_CONNECTED) + { + if(pd->pd_Flags & PDFF_SUSPENDED) + { + // make sure the device is up and running before trying to send a new pipe + psdResumeDevice(pd); + } + + pp->pp_IOReq.iouh_Data = data; + pp->pp_IOReq.iouh_Length = len; + if(!pp->pp_Endpoint) + { + pp->pp_IOReq.iouh_SetupData.wLength = AROS_WORD2LE(len); + } + PutMsg(&pd->pd_Hardware->phw_TaskMsgPort, &pp->pp_Msg); + ++pd->pd_IOBusyCount; + GetSysTime((APTR) &pd->pd_LastActivity); + return(psdWaitPipe(pp)); + } else { + psdDelayMS(50); + pp->pp_IOReq.iouh_Actual = 0; + pp->pp_Msg.mn_Node.ln_Type = NT_FREEMSG; + return(pp->pp_IOReq.iouh_Req.io_Error = UHIOERR_TIMEOUT); + } + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdSendPipe()" */ +AROS_LH3(void, psdSendPipe, + AROS_LHA(struct PsdPipe *, pp, A1), + AROS_LHA(APTR, data, A0), + AROS_LHA(ULONG, len, D0), + LIBBASETYPEPTR, ps, 28, psd) +{ + AROS_LIBFUNC_INIT + struct PsdDevice *pd = pp->pp_Device; + KPRINTF(200, ("psdSendPipe(%08lx, %08lx, %ld)\n", pp, data, len)); + if(pd->pd_Flags & PDFF_CONNECTED) + { + if(pd->pd_Flags & PDFF_SUSPENDED) + { + // make sure the device is up and running before trying to send a new pipe + psdResumeDevice(pd); + } + + pp->pp_IOReq.iouh_Data = data; + pp->pp_IOReq.iouh_Length = len; + if(!pp->pp_Endpoint) + { + pp->pp_IOReq.iouh_SetupData.wLength = AROS_WORD2LE(len); + } + PutMsg(&pd->pd_Hardware->phw_TaskMsgPort, &pp->pp_Msg); + GetSysTime((APTR) &pd->pd_LastActivity); + ++pd->pd_IOBusyCount; + } else { + psdDelayMS(50); + pp->pp_IOReq.iouh_Actual = 0; + //pp->pp_Msg.mn_Node.ln_Type = NT_REPLYMSG; + pp->pp_IOReq.iouh_Req.io_Error = UHIOERR_TIMEOUT; + ReplyMsg(&pp->pp_Msg); + ++pd->pd_IOBusyCount; + } + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdAbortPipe()" */ +AROS_LH1(void, psdAbortPipe, + AROS_LHA(struct PsdPipe *, pp, A1), + LIBBASETYPEPTR, ps, 29, psd) +{ + AROS_LIBFUNC_INIT + struct PsdPipe *npp; + + KPRINTF(5, ("psdAbortPipe(%08lx)\n", pp)); + if(pp->pp_Msg.mn_Node.ln_Type != NT_MESSAGE) + { + KPRINTF(5, ("Nothing to abort %02lx\n", pp->pp_IOReq.iouh_Req.io_Message.mn_Node.ln_Type)); + return; + } + if((npp = psdAllocVec(sizeof(struct PsdPipe)))) + { + //npp->pp_Msg.mn_Node.ln_Type = NT_MESSAGE; + npp->pp_Device = pp->pp_Device; + npp->pp_MsgPort = npp->pp_Msg.mn_ReplyPort = pp->pp_MsgPort; + npp->pp_Msg.mn_Length = sizeof(struct PsdPipe); + + npp->pp_AbortPipe = pp; + PutMsg(&pp->pp_Device->pd_Hardware->phw_TaskMsgPort, &npp->pp_Msg); + psdWaitPipe(npp); + psdFreeVec(npp); + } + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdWaitPipe()" */ +AROS_LH1(LONG, psdWaitPipe, + AROS_LHA(struct PsdPipe *, pp, A1), + LIBBASETYPEPTR, ps, 30, psd) +{ + AROS_LIBFUNC_INIT + ULONG sigs = 0; + struct PsdDevice *pd = pp->pp_Device; + LONG ioerr; + KPRINTF(5, ("psdWaitPipe(%08lx)\n", pp)); + while(pp->pp_Msg.mn_Node.ln_Type == NT_MESSAGE) + { + KPRINTF(5, ("ln_Type = %02lx\n", pp->pp_Msg.mn_Node.ln_Type)); + sigs |= Wait(1L<pp_MsgPort->mp_SigBit); + KPRINTF(5, ("sigs = %08lx\n", sigs)); + } +#if 1 // broken? + Forbid(); + if(pp->pp_Msg.mn_Node.ln_Type == NT_REPLYMSG) + { + pp->pp_Msg.mn_Node.ln_Type = NT_FREEMSG; + Remove(&pp->pp_Msg.mn_Node); + } + //if(pp->pp_MsgPort->mp_MsgList.lh_Head->ln_Succ) + { + // avoid signals getting lost for other messages arriving. + SetSignal(sigs, sigs); + } + Permit(); +#else + Forbid(); + Remove(&pp->pp_Msg.mn_Node); + Permit(); +#endif + ioerr = pp->pp_IOReq.iouh_Req.io_Error; + switch(ioerr) + { + case UHIOERR_TIMEOUT: + pd->pd_DeadCount++; + // fall through + case UHIOERR_NAKTIMEOUT: + pd->pd_DeadCount++; + case UHIOERR_CRCERROR: + pd->pd_DeadCount++; + break; + case UHIOERR_RUNTPACKET: + default: + if(pd->pd_DeadCount) + { + pd->pd_DeadCount >>= 1; + /*psdAddErrorMsg(RETURN_OK, (STRPTR) libname, + "Device %s starts recovering with %s (%ld)!", + pd->pd_ProductStr, + psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);*/ + } + } + KPRINTF(200, ("psdWaitPipe(%08lx)=%ld\n", pp, ioerr)); + --pd->pd_IOBusyCount; + GetSysTime((APTR) &pd->pd_LastActivity); + + if((pd->pd_DeadCount > 19) || ((pd->pd_DeadCount > 14) && (pd->pd_Flags & (PDFF_HASDEVADDR|PDFF_HASDEVDESC)))) + { + if(!(pd->pd_Flags & PDFF_DEAD)) + { + pd->pd_Flags |= PDFF_DEAD; + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "Device %s probably dropped dead!", pd->pd_ProductStr); + + psdSendEvent(EHMB_DEVICEDEAD, pp->pp_Device, NULL); + } + } else { + if((!pd->pd_DeadCount) && ((pd->pd_Flags & (PDFF_DEAD|PDFF_CONNECTED)) == (PDFF_DEAD|PDFF_CONNECTED))) + { + pd->pd_Flags &= ~PDFF_DEAD; + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, + "Uuuhuuuhh, the zombie %s returned from the dead!", pd->pd_ProductStr); + } + } + return(ioerr); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdCheckPipe()" */ +AROS_LH1(struct PsdPipe *, psdCheckPipe, + AROS_LHA(struct PsdPipe *, pp, A1), + LIBBASETYPEPTR, ps, 71, psd) +{ + AROS_LIBFUNC_INIT + KPRINTF(5, ("psdCheckPipe(%08lx)\n", pp)); + if(pp->pp_Msg.mn_Node.ln_Type == NT_MESSAGE) + { + return(NULL); + } + return(pp); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdGetPipeActual()" */ +AROS_LH1(ULONG, psdGetPipeActual, + AROS_LHA(struct PsdPipe *, pp, A1), + LIBBASETYPEPTR, ps, 31, psd) +{ + AROS_LIBFUNC_INIT + KPRINTF(1, ("psdGetPipeActual(%08lx)\n", pp)); + return(pp->pp_IOReq.iouh_Actual); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdGetPipeError()" */ +AROS_LH1(LONG, psdGetPipeError, + AROS_LHA(struct PsdPipe *, pp, A1), + LIBBASETYPEPTR, ps, 32, psd) +{ + AROS_LIBFUNC_INIT + KPRINTF(1, ("psdGetPipeError(%08lx)\n", pp)); + return((LONG) pp->pp_IOReq.iouh_Req.io_Error); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* *** Streams *** */ + +/* /// "psdOpenStreamA()" */ +AROS_LH2(struct PsdPipeStream *, psdOpenStreamA, + AROS_LHA(struct PsdEndpoint *, pep, A0), + AROS_LHA(struct TagItem *, tags, A1), + LIBBASETYPEPTR, ps, 72, psd) +{ + AROS_LIBFUNC_INIT + struct PsdPipeStream *pps; + + KPRINTF(2, ("psdOpenStream(%08lx, %08lx)\n", pep, tags)); + if(!pep) + { + return(NULL); + } + if((pps = psdAllocVec(sizeof(struct PsdPipeStream)))) + { + pps->pps_Device = pep->pep_Interface->pif_Config->pc_Device; + pps->pps_Endpoint = pep; + NewList(&pps->pps_FreePipes); + NewList(&pps->pps_ReadyPipes); + InitSemaphore(&pps->pps_AccessLock); + pps->pps_NakTimeoutTime = 5000; + if(pep->pep_Direction) + { + /* Defaults for IN */ + pps->pps_NumPipes = 4; + pps->pps_Flags = PSFF_READAHEAD|PSFF_BUFFERREAD|PSFF_ALLOWRUNT; + pps->pps_BufferSize = 32*pps->pps_Endpoint->pep_MaxPktSize; + } else { + /* Defaults for OUT */ + pps->pps_NumPipes = 4; + pps->pps_Flags = PSFF_NOSHORTPKT; + pps->pps_BufferSize = 4*pps->pps_Endpoint->pep_MaxPktSize; + } + + psdSetAttrsA(PGA_PIPESTREAM, pps, tags); + if(!pps->pps_Pipes) + { + psdCloseStream(pps); + pps = NULL; + } + return(pps); + } + return(NULL); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdCloseStream()" */ +AROS_LH1(void, psdCloseStream, + AROS_LHA(struct PsdPipeStream *, pps, A1), + LIBBASETYPEPTR, ps, 73, psd) +{ + AROS_LIBFUNC_INIT + struct PsdPipe *pp; + ULONG cnt; + + KPRINTF(2, ("psdCloseStream(%08lx)\n", pps)); + if(!pps) + { + return; + } + psdStreamFlush(pps); + ObtainSemaphore(&pps->pps_AccessLock); + if(pps->pps_Pipes) + { + for(cnt = 0; cnt < pps->pps_NumPipes; cnt++) + { + pp = pps->pps_Pipes[cnt]; + //if(pp->pp_IOReq.iouh_Req.io_Message.mn_Node.ln_Type == NT_MESSAGE) + { + KPRINTF(1, ("Abort %ld\n", cnt)); + psdAbortPipe(pp); + KPRINTF(1, ("Wait %ld\n", cnt)); + psdWaitPipe(pp); + } + KPRINTF(1, ("Free %ld\n", cnt)); + psdFreePipe(pp); + } + psdFreeVec(pps->pps_Pipes); + if((pps->pps_Flags & PSFF_OWNMSGPORT) && pps->pps_MsgPort) + { + DeleteMsgPort(pps->pps_MsgPort); + } + } + psdFreeVec(pps->pps_Buffer); + ReleaseSemaphore(&pps->pps_AccessLock); + psdFreeVec(pps); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdStreamRead()" */ +AROS_LH3(LONG, psdStreamRead, + AROS_LHA(struct PsdPipeStream *, pps, A1), + AROS_LHA(UBYTE *, buffer, A0), + AROS_LHA(LONG, length, D0), + LIBBASETYPEPTR, ps, 74, psd) +{ + AROS_LIBFUNC_INIT + struct PsdPipe *pp; + ULONG cnt; + LONG ioerr; + LONG remlen; + BOOL term = FALSE; + LONG actual = 0; + ULONG sigmask; + + UBYTE *bufptr; + UBYTE *srcptr; + UBYTE *tarrptr; + ULONG tcnt; + UBYTE cchar; + + KPRINTF(2, ("psdStreamRead(%08lx, %08lx, %ld)\n", pps, buffer, length)); + if(!pps) + { + return(-1); + } + ObtainSemaphore(&pps->pps_AccessLock); + KPRINTF(2, ("Sema\n")); + pps->pps_Error = 0; + if((!pps->pps_Pipes) || (!pps->pps_Endpoint->pep_Direction)) + { + KPRINTF(2, ("Wrong direction!\n")); + pps->pps_Error = UHIOERR_BADPARAMS; + ReleaseSemaphore(&pps->pps_AccessLock); + return(-1); + } + if(!(pps->pps_Flags & PSFF_ASYNCIO)) + { + if(pps->pps_Flags & PSFF_BUFFERREAD) + { + /* buffered reading */ + do + { + /* check for incoming packets */ + while((pp = (struct PsdPipe *) GetMsg(pps->pps_MsgPort))) + { + KPRINTF(1, ("PktBack(%08lx, %08lx, %ld/%ld)=%ld\n", + pp, pp->pp_IOReq.iouh_Data, pp->pp_IOReq.iouh_Actual, + pp->pp_IOReq.iouh_Length, pp->pp_IOReq.iouh_Req.io_Error)); + + pps->pps_ReqBytes -= pp->pp_IOReq.iouh_Length; + ioerr = pp->pp_IOReq.iouh_Req.io_Error; + if((ioerr == UHIOERR_NAKTIMEOUT) && pp->pp_IOReq.iouh_Actual) + { + ioerr = 0; + } + + if(ioerr) + { + pps->pps_Error = ioerr; + term = TRUE; + if(ioerr != UHIOERR_TIMEOUT) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) "StreamRead", + "Packet(%s) failed: %s (%ld)", (STRPTR) "b", + psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + } + /* stop automatic queueing */ + pps->pps_Flags &= ~PSFF_READAHEAD; + AddTail(&pps->pps_FreePipes, &pp->pp_Msg.mn_Node); + } else { + /* successfully received packet */ + pps->pps_BytesPending += pp->pp_IOReq.iouh_Actual; + AddTail(&pps->pps_ReadyPipes, &pp->pp_Msg.mn_Node); + } + } + if(length == -1) /* get all that's there (STRONGLY DISCOURAGED! Might cause buffer overflows) */ + { + length = pps->pps_BytesPending; + } + /* check for buffered data */ + while(length && pps->pps_BytesPending) + { + pp = (struct PsdPipe *) pps->pps_ReadyPipes.lh_Head; + if(!pp->pp_Msg.mn_Node.ln_Succ) /* debug */ + { + psdAddErrorMsg0(RETURN_FAIL, (STRPTR) "StreamRead", "Readqueue empty!"); + ReleaseSemaphore(&pps->pps_AccessLock); + return(-1); + } + if(pp->pp_IOReq.iouh_Actual < pps->pps_Offset) + { + psdAddErrorMsg(RETURN_FAIL, (STRPTR) "StreamRead", + "Actual %ld < offset %ld!", pp->pp_IOReq.iouh_Actual, pps->pps_Offset); + ReleaseSemaphore(&pps->pps_AccessLock); + return(-1); + } + remlen = pp->pp_IOReq.iouh_Actual - pps->pps_Offset; + if(length < remlen) + { + KPRINTF(1, ("PktBit(%08lx, %08lx, %ld)\n", pp, buffer, length)); + remlen = length; + } else { + KPRINTF(1, ("PktRem(%08lx, %08lx, %ld)\n", pp, buffer, remlen)); + } + /* copy packet */ + if(pp->pp_Flags & PFF_INPLACE) + { + KPRINTF(1, ("PktRemIP(%08lx, %08lx, %ld)\n", pp, buffer, remlen)); + } else { + if(pps->pps_TermArray) + { + /* EOF Mode */ + KPRINTF(1, ("PktCpyEOF(%08lx, %08lx, %ld)\n", pp, buffer, remlen)); + bufptr = buffer; + srcptr = &(((UBYTE *) pp->pp_IOReq.iouh_Data)[pps->pps_Offset]); + tarrptr = pps->pps_TermArray; + cnt = remlen; + remlen = 0; + if(cnt) + { + do + { + cchar = *bufptr++ = *srcptr++; + remlen++; + tcnt = 0; + do + { + if(cchar < tarrptr[tcnt]) + { + break; + } + else if(cchar == tarrptr[tcnt]) + { + cnt = 1; + term = TRUE; + KPRINTF(2, ("EOF char %02lx found, length = %ld\n", cchar, remlen)); + break; + } + if(tcnt < 7) + { + if(tarrptr[tcnt] == tarrptr[tcnt+1]) + { + break; + } + } + } while(++tcnt < 8); + } while(--cnt); + } + } else { + KPRINTF(1, ("PktCpy(%08lx, %08lx, %ld)\n", pp, buffer, remlen)); + /* quick non-eof mode */ + CopyMem(&(((UBYTE *) pp->pp_IOReq.iouh_Data)[pps->pps_Offset]), buffer, remlen); + } + } + actual += remlen; + length -= remlen; + buffer += remlen; + pps->pps_BytesPending -= remlen; + pps->pps_Offset += remlen; + /* end of packet reached? */ + if(pps->pps_Offset == pp->pp_IOReq.iouh_Actual) + { + pps->pps_Offset = 0; + Remove(&pp->pp_Msg.mn_Node); + AddTail(&pps->pps_FreePipes, &pp->pp_Msg.mn_Node); + /* check for short packet */ + if((pps->pps_Flags & PSFF_SHORTTERM) && (pp->pp_IOReq.iouh_Actual % pp->pp_IOReq.iouh_MaxPktSize)) + { + term = TRUE; + } + } + if(term) + { + break; + } + } + /* start sending out requests */ + remlen = length; + pp = (struct PsdPipe *) pps->pps_FreePipes.lh_Head; + if(!(pps->pps_BytesPending || pps->pps_ReqBytes || pps->pps_TermArray || (length < pps->pps_BufferSize))) + { + /* faster non-buffered mode */ + if(pp->pp_Msg.mn_Node.ln_Succ) + { + pp->pp_Flags |= PFF_INPLACE; + Remove(&pp->pp_Msg.mn_Node); + remlen = length - (length % pp->pp_IOReq.iouh_MaxPktSize); + KPRINTF(1, ("OutFast(%08lx, %08lx, %ld/%ld)\n", + pp, buffer, remlen, length)); + psdSendPipe(pp, buffer, remlen); + pps->pps_ReqBytes += remlen; + pp = (struct PsdPipe *) pps->pps_FreePipes.lh_Head; + } + } + /* slower buffered mode */ + while(pp->pp_Msg.mn_Node.ln_Succ && ((remlen > pps->pps_ReqBytes) || (pps->pps_Flags & PSFF_READAHEAD))) + { + pp->pp_Flags &= ~PFF_INPLACE; + Remove(&pp->pp_Msg.mn_Node); + if((pps->pps_Flags & PSFF_READAHEAD) || (remlen % pp->pp_IOReq.iouh_MaxPktSize)) + { + KPRINTF(1, ("OutSlow(%08lx, %08lx, %ld)\n", + pp, &pps->pps_Buffer[pp->pp_Num * pps->pps_BufferSize], pps->pps_BufferSize)); + remlen = pps->pps_BufferSize; + } else { + KPRINTF(1, ("OutExact(%08lx, %08lx, %ld)\n", + pp, &pps->pps_Buffer[pp->pp_Num * pps->pps_BufferSize], remlen)); + } + psdSendPipe(pp, &pps->pps_Buffer[pp->pp_Num * pps->pps_BufferSize], remlen); + pps->pps_ReqBytes += remlen; + pp = (struct PsdPipe *) pps->pps_FreePipes.lh_Head; + } + if((!length) || (pps->pps_Flags & PSFF_DONOTWAIT)) + { + term = TRUE; + } + if(!term) + { + sigmask = (1UL<pps_MsgPort->mp_SigBit)|pps->pps_AbortSigMask; + KPRINTF(1, ("WaitPort (%08lx)\n", sigmask)); + sigmask = Wait(sigmask); + KPRINTF(1, ("Wait back (%08lx)\n", sigmask)); + if(sigmask & pps->pps_AbortSigMask) + { + KPRINTF(1, ("Aborted!\n")); + term = TRUE; + Signal(FindTask(NULL), pps->pps_AbortSigMask & sigmask); + } + } + } while(!term); + } else { + /* plain reading (might lose data) */ + if(pps->pps_TermArray || (pps->pps_Flags & PSFF_READAHEAD)) + { + psdAddErrorMsg0(RETURN_WARN, (STRPTR) "StreamRead", "This mode combination for the stream is not supported!"); + } + /* start sending out requests */ + pp = (struct PsdPipe *) pps->pps_FreePipes.lh_Head; + if(pp->pp_Msg.mn_Node.ln_Succ && length) + { + ioerr = psdDoPipe(pp, buffer, length); + if(ioerr) + { + pps->pps_Error = ioerr; + if(ioerr != UHIOERR_TIMEOUT) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) "StreamRead", + "Packet(%s) failed: %s (%ld)", (STRPTR) "u", + psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + } + } + actual = pp->pp_IOReq.iouh_Actual; + } + } + } + ReleaseSemaphore(&pps->pps_AccessLock); + return(actual); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdStreamWrite()" */ +AROS_LH3(LONG, psdStreamWrite, + AROS_LHA(struct PsdPipeStream *, pps, A1), + AROS_LHA(UBYTE *, buffer, A0), + AROS_LHA(LONG, length, D0), + LIBBASETYPEPTR, ps, 75, psd) +{ + AROS_LIBFUNC_INIT + struct PsdPipe *pp; + struct PsdPipe *newpp; + ULONG cnt; + LONG ioerr; + LONG remlen; + LONG actual = 0; + ULONG sigmask; + + UBYTE *bufptr; + UBYTE *srcptr; + UBYTE *tarrptr; + ULONG tcnt; + UBYTE cchar; + + KPRINTF(2, ("psdStreamWrite(%08lx, %08lx, %ld)\n", pps, buffer, length)); + if(!pps) + { + return(-1); + } + ObtainSemaphore(&pps->pps_AccessLock); + pps->pps_Error = 0; + if((!pps->pps_Pipes) || pps->pps_Endpoint->pep_Direction) + { + KPRINTF(2, ("Wrong direction!\n")); + pps->pps_Error = UHIOERR_BADPARAMS; + ReleaseSemaphore(&pps->pps_AccessLock); + return(-1); + } + if(length == -1) /* null terminated string mode */ + { + KPRINTF(2, ("EOL mode!\n")); + length = strlen(buffer); + } + if((tarrptr = pps->pps_TermArray)) /* EOF Mode */ + { + KPRINTF(1, ("EOFSearch(%08lx, %ld)\n", buffer, length)); + srcptr = buffer; + cnt = length; + length = 0; + if(cnt) + { + do + { + cchar = *srcptr++; + length++; + tcnt = 0; + do + { + if(cchar < tarrptr[tcnt]) + { + break; + } + else if(cchar == tarrptr[tcnt]) + { + cnt = 1; + KPRINTF(2, ("EOF char %02lx found, length = %ld\n", cchar, length)); + break; + } + if(tcnt) + { + if(tarrptr[tcnt] == tarrptr[tcnt+1]) + { + break; + } + } + } while(++tcnt < 8); + } while(--cnt); + } + } + if(!(pps->pps_Flags & PSFF_ASYNCIO)) + { + pp = (struct PsdPipe *) pps->pps_FreePipes.lh_Head; + if(pp->pp_Msg.mn_Node.ln_Succ && length) + { + if(pps->pps_Flags & PSFF_BUFFERWRITE) + { + /* buffered writing */ + if(pps->pps_BytesPending) + { + remlen = pps->pps_BytesPending % pp->pp_IOReq.iouh_MaxPktSize; + /* align to packet boundary */ + if(remlen + length >= pp->pp_IOReq.iouh_MaxPktSize) + { + /* new data crosses at least on packet size */ + if(pps->pps_BytesPending + length <= pps->pps_BufferSize) + { + /* copy everything up to the last (!) boundary */ + remlen = pps->pps_BytesPending + length; + remlen = remlen - (remlen % pp->pp_IOReq.iouh_MaxPktSize); + remlen -= pps->pps_BytesPending; + KPRINTF(1, ("PendOptCpy(%08lx, %ld+%ld/%ld)\n", buffer, pps->pps_BytesPending, remlen, length)); + } else { + /* just calculate amount to copy to the next boundary */ + remlen = pp->pp_IOReq.iouh_MaxPktSize - remlen; + KPRINTF(1, ("PendOneCpy(%08lx, %ld+%ld/%ld)\n", buffer, pps->pps_BytesPending, remlen, length)); + } + CopyMem(buffer, &pps->pps_Buffer[pps->pps_BytesPending], remlen); + pps->pps_BytesPending += remlen; + actual += remlen; + buffer += remlen; + length -= remlen; + } else { + KPRINTF(1, ("PendAdd(%08lx, %ld+%ld)\n", buffer, pps->pps_BytesPending, length)); + /* only a few bytes, see if we can fit them */ + CopyMem(buffer, &pps->pps_Buffer[pps->pps_BytesPending], length); + pps->pps_BytesPending += length; + actual += length; + //buffer += length; /* not needed */ + length = 0; + } + /* flush some buffers */ + if((length >= pp->pp_IOReq.iouh_MaxPktSize) || + ((pps->pps_BytesPending >= (pps->pps_BufferSize>>1)) && (pps->pps_BytesPending >= pp->pp_IOReq.iouh_MaxPktSize))) + { + remlen = pps->pps_BytesPending - (pps->pps_BytesPending % pp->pp_IOReq.iouh_MaxPktSize); + KPRINTF(1, ("PendFlush(%ld/%ld)\n", remlen, pps->pps_BytesPending)); + Remove(&pp->pp_Msg.mn_Node); + psdSendPipe(pp, pps->pps_Buffer, remlen); + pps->pps_ActivePipe = pp; + while(!(newpp = (struct PsdPipe *) GetMsg(pps->pps_MsgPort))) + { + sigmask = (1UL<pps_MsgPort->mp_SigBit)|pps->pps_AbortSigMask; + sigmask = Wait(sigmask); + if(sigmask & pps->pps_AbortSigMask) + { + KPRINTF(1, ("Kill signal detected!\n")); + Signal(FindTask(NULL), pps->pps_AbortSigMask & sigmask); + break; + } + } + if(!newpp) + { + psdAbortPipe(pp); + } + ioerr = psdWaitPipe(pp); + pps->pps_ActivePipe = NULL; + AddTail(&pps->pps_FreePipes, &pp->pp_Msg.mn_Node); + + /* move end of buffer */ + cnt = pps->pps_BytesPending; + tcnt = pp->pp_IOReq.iouh_Actual; + pps->pps_BytesPending -= tcnt; + bufptr = pps->pps_Buffer; + srcptr = bufptr + tcnt; + cnt -= tcnt; + if(cnt) + { + do + { + *bufptr++ = *srcptr++; + } while(--cnt); + } + if(ioerr) + { + pps->pps_Error = ioerr; + if(ioerr != UHIOERR_TIMEOUT) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) "StreamWrite", + "Packet(%s) failed: %s (%ld)", (STRPTR) "b", + psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + } + ReleaseSemaphore(&pps->pps_AccessLock); + return(actual); + } + } + } + /* send out large chunk (avoid copying) */ + if(length >= pp->pp_IOReq.iouh_MaxPktSize) + { + remlen = length - (length % pp->pp_IOReq.iouh_MaxPktSize); + KPRINTF(1, ("BulkFlush(%08lx, %ld/%ld)\n", buffer, remlen, length)); + Remove(&pp->pp_Msg.mn_Node); + psdSendPipe(pp, buffer, remlen); + pps->pps_ActivePipe = pp; + while(!(newpp = (struct PsdPipe *) GetMsg(pps->pps_MsgPort))) + { + sigmask = (1UL<pps_MsgPort->mp_SigBit)|pps->pps_AbortSigMask; + sigmask = Wait(sigmask); + if(sigmask & pps->pps_AbortSigMask) + { + KPRINTF(1, ("Kill signal detected!\n")); + Signal(FindTask(NULL), pps->pps_AbortSigMask & sigmask); + break; + } + } + if(!newpp) + { + psdAbortPipe(pp); + } + ioerr = psdWaitPipe(pp); + pps->pps_ActivePipe = NULL; + AddTail(&pps->pps_FreePipes, &pp->pp_Msg.mn_Node); + + actual += pp->pp_IOReq.iouh_Actual; + buffer += pp->pp_IOReq.iouh_Actual; + length -= pp->pp_IOReq.iouh_Actual; + if(ioerr) + { + pps->pps_Error = ioerr; + if(ioerr != UHIOERR_TIMEOUT) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) "StreamWrite", + "Packet(%s) failed: %s (%ld)", (STRPTR) "c", + psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + } + ReleaseSemaphore(&pps->pps_AccessLock); + return(actual); + } + } + /* buffer remaining bytes */ + if(length) + { + KPRINTF(1, ("BufAdd(%08lx, %ld)\n", buffer, length)); + /* only a few bytes left, so lets buffer them */ + CopyMem(buffer, &pps->pps_Buffer[pps->pps_BytesPending], length); + pps->pps_BytesPending += length; + actual += length; + } + } else { + /* plain writing */ + /* start sending out requests */ + KPRINTF(1, ("PlainWrite(%08lx, %ld)\n", buffer, length)); + Remove(&pp->pp_Msg.mn_Node); + psdSendPipe(pp, buffer, length); + pps->pps_ActivePipe = pp; + while(!(newpp = (struct PsdPipe *) GetMsg(pps->pps_MsgPort))) + { + sigmask = (1UL<pps_MsgPort->mp_SigBit)|pps->pps_AbortSigMask; + sigmask = Wait(sigmask); + if(sigmask & pps->pps_AbortSigMask) + { + KPRINTF(1, ("Kill signal detected!\n")); + Signal(FindTask(NULL), pps->pps_AbortSigMask & sigmask); + break; + } + } + if(!newpp) + { + psdAbortPipe(pp); + } + ioerr = psdWaitPipe(pp); + pps->pps_ActivePipe = NULL; + AddTail(&pps->pps_FreePipes, &pp->pp_Msg.mn_Node); + if(ioerr) + { + pps->pps_Error = ioerr; + if(ioerr != UHIOERR_TIMEOUT) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) "StreamWrite", + "Packet(%s) failed: %s (%ld)", (STRPTR) "u", + psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + } + } + actual = pp->pp_IOReq.iouh_Actual; + } + } else { + KPRINTF(2, ("No free pipe!\n")); + } + } + ReleaseSemaphore(&pps->pps_AccessLock); + return(actual); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdStreamFlush()" */ +AROS_LH1(LONG, psdStreamFlush, + AROS_LHA(struct PsdPipeStream *, pps, A1), + LIBBASETYPEPTR, ps, 76, psd) +{ + AROS_LIBFUNC_INIT + struct PsdPipe *pp; + ULONG cnt; + LONG ioerr; + LONG ret = FALSE; + + KPRINTF(2, ("psdStreamFlush(%08lx)\n", pps)); + if(!pps) + { + return(-1); + } + ObtainSemaphore(&pps->pps_AccessLock); + pps->pps_Error = 0; + if(pps->pps_Endpoint->pep_Direction) + { + /* IN */ + KPRINTF(2, ("Flushing in...\n")); + for(cnt = 0; cnt < pps->pps_NumPipes; cnt++) + { + psdAbortPipe(pps->pps_Pipes[cnt]); + } + for(cnt = 0; cnt < pps->pps_NumPipes; cnt++) + { + psdWaitPipe(pps->pps_Pipes[cnt]); + } + pp = (struct PsdPipe *) pps->pps_ReadyPipes.lh_Head; + while(pp->pp_Msg.mn_Node.ln_Succ) + { + Remove(&pp->pp_Msg.mn_Node); + AddTail(&pps->pps_FreePipes, &pp->pp_Msg.mn_Node); + pp = (struct PsdPipe *) pps->pps_ReadyPipes.lh_Head; + } + while((pp = (struct PsdPipe *) GetMsg(pps->pps_MsgPort))) + { + AddTail(&pps->pps_FreePipes, &pp->pp_Msg.mn_Node); + } + pps->pps_ReqBytes = 0; + pps->pps_BytesPending = 0; + pps->pps_Offset = 0; + ret = TRUE; + } else { + /* OUT */ + pp = (struct PsdPipe *) pps->pps_FreePipes.lh_Head; + if(pp->pp_Msg.mn_Node.ln_Succ) + { + ret = TRUE; + if(pps->pps_BytesPending) + { + KPRINTF(2, ("Flushing out %ld...\n", pps->pps_BytesPending)); + Remove(&pp->pp_Msg.mn_Node); + ioerr = psdDoPipe(pp, pps->pps_Buffer, pps->pps_BytesPending); + AddTail(&pps->pps_FreePipes, &pp->pp_Msg.mn_Node); + pps->pps_BytesPending = 0; + if(ioerr) + { + pps->pps_Error = ioerr; + psdAddErrorMsg(RETURN_WARN, (STRPTR) "StreamFlush", + "Packet(%s) failed: %s (%ld)", (STRPTR) "f", + psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + ret = FALSE; + } + } else { + KPRINTF(2, ("Nothing to flush\n")); + } + } + } + ReleaseSemaphore(&pps->pps_AccessLock); + return(ret); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdGetStreamError()" */ +AROS_LH1(LONG, psdGetStreamError, + AROS_LHA(struct PsdPipeStream *, pps, A1), + LIBBASETYPEPTR, ps, 77, psd) +{ + AROS_LIBFUNC_INIT + KPRINTF(1, ("psdGetStreamError(%08lx)\n", pps)); + if(pps) + { + return((LONG) pps->pps_Error); + } else { + return(-1); + } + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* *** Realtime Iso */ + +/* /// "psdAllocRTIsoHandler()" */ +AROS_LH2(struct PsdRTIsoHandler *, psdAllocRTIsoHandlerA, + AROS_LHA(struct PsdEndpoint *, pep, A0), + AROS_LHA(struct TagItem *, tags, A1), + LIBBASETYPEPTR, ps, 93, psd) +{ + AROS_LIBFUNC_INIT + struct PsdRTIsoHandler *prt; + struct PsdPipe *pp; + LONG ioerr; + + KPRINTF(2, ("psdAllocRTIso(%08lx, %08lx)\n", pep, tags)); + if(!pep) + { + return(NULL); + } + if(pep->pep_TransType != USEAF_ISOCHRONOUS) + { + return(NULL); + } + if(!(pep->pep_Interface->pif_Config->pc_Device->pd_Hardware->phw_Capabilities & UHCF_RT_ISO)) + { + psdAddErrorMsg0(RETURN_FAIL, (STRPTR) libname, "Your HW controller driver does not support realtime iso transfers. Sorry."); + return(NULL); + } + if((prt = psdAllocVec(sizeof(struct PsdRTIsoHandler)))) + { + prt->prt_Device = pep->pep_Interface->pif_Config->pc_Device; + prt->prt_Endpoint = pep; + prt->prt_RTIso.urti_OutPrefetch = 2048; + if((pp = prt->prt_Pipe = psdAllocPipe(prt->prt_Device, (struct MsgPort *) 0xffffffff, pep))) + { + pp->pp_MsgPort = pp->pp_Msg.mn_ReplyPort = NULL; + psdSetAttrsA(PGA_RTISO, prt, tags); + pp->pp_IOReq.iouh_Req.io_Command = UHCMD_ADDISOHANDLER; + pp->pp_IOReq.iouh_Data = &prt->prt_RTIso; + // hardware must support quick IO for this to work! + ioerr = DoIO((struct IORequest *) &pp->pp_IOReq); + if(!ioerr) + { + Forbid(); + AddTail(&prt->prt_Device->pd_RTIsoHandlers, &prt->prt_Node); + Permit(); + return(prt); + } else { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "Adding RT Iso Handler failed: %s (%ld)", + psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + } + psdFreePipe(prt->prt_Pipe); + } + psdFreeVec(prt); + } + return(NULL); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdFreeRTIsoHandler()" */ +AROS_LH1(void, psdFreeRTIsoHandler, + AROS_LHA(struct PsdRTIsoHandler *, prt, A1), + LIBBASETYPEPTR, ps, 94, psd) +{ + AROS_LIBFUNC_INIT + struct PsdPipe *pp; + + if(!prt) + { + return; + } + Forbid(); + Remove(&prt->prt_Node); + Permit(); + pp = prt->prt_Pipe; + pp->pp_IOReq.iouh_Req.io_Command = UHCMD_REMISOHANDLER; + DoIO((struct IORequest *) &pp->pp_IOReq); + psdFreePipe(pp); + psdFreeVec(prt); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdStartRTIso()" */ +AROS_LH1(LONG, psdStartRTIso, + AROS_LHA(struct PsdRTIsoHandler *, prt, A1), + LIBBASETYPEPTR, ps, 95, psd) +{ + AROS_LIBFUNC_INIT + struct PsdPipe *pp; + LONG ioerr; + + if(!prt) + { + return UHIOERR_BADPARAMS; + } + pp = prt->prt_Pipe; + if(pp->pp_Device->pd_Flags & PDFF_SUSPENDED) + { + // make sure the device is up and running before trying to send a new pipe + psdResumeDevice(pp->pp_Device); + } + pp->pp_IOReq.iouh_Req.io_Command = UHCMD_STARTRTISO; + ioerr = DoIO((struct IORequest *) &pp->pp_IOReq); + if(!ioerr) + { + ++pp->pp_Device->pd_IOBusyCount; + } + return(ioerr); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdStopRTIso()" */ +AROS_LH1(LONG, psdStopRTIso, + AROS_LHA(struct PsdRTIsoHandler *, prt, A1), + LIBBASETYPEPTR, ps, 96, psd) +{ + AROS_LIBFUNC_INIT + struct PsdPipe *pp; + LONG ioerr; + + if(!prt) + { + return UHIOERR_BADPARAMS; + } + pp = prt->prt_Pipe; + pp->pp_IOReq.iouh_Req.io_Command = UHCMD_STOPRTISO; + ioerr = DoIO((struct IORequest *) &pp->pp_IOReq); + if(!ioerr) + { + --pp->pp_Device->pd_IOBusyCount; + } + return(ioerr); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* *** Classes *** */ + +/* /// "psdAddClass()" */ +AROS_LH2(struct PsdUsbClass *,psdAddClass, + AROS_LHA(STRPTR, name, A1), + AROS_LHA(ULONG, vers, D0), + LIBBASETYPEPTR, ps, 35, psd) +{ + AROS_LIBFUNC_INIT + struct Library *cls = NULL; + struct PsdUsbClass *puc; + IPTR pri = 0; + STRPTR desc; + UWORD msgoff; + STRPTR origname = name; + STRPTR evilmsg[8] = { "Say hello to %s V%ld.%ld (%s).", + "Whoah! %s V%ld.%ld surprised as %s.", + "The door bell rang for %s V%ld.%ld (%s).", + "Welcome %s V%ld.%ld (%s) to the party.", + + "Don't laugh at %s V%ld.%ld for %s.", + "Time has come for %s V%ld.%ld (%s) to join the show.", + "Start blaming %s V%ld.%ld for helping at %s.", + "Ain't %s V%ld.%ld useful for %s?" }; + + KPRINTF(5, ("psdAddClass(%s, %ld)\n", name, vers)); + + while(*name) + { + if((cls = OpenLibrary(name, vers))) + { + break; + } + do + { + if((*name == '/') || (*name == ':')) + { + ++name; + break; + } + } while(*(++name)); + } + if(cls) + { + Forbid(); + if(FindName(&ps->ps_Classes, cls->lib_Node.ln_Name)) + { + Permit(); + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "Attempted to add class %s twice. Nothing is good enough for people like you.", + name); + KPRINTF(20, ("attempt to add class twice!\n")); + CloseLibrary(cls); + return(NULL); + } + Permit(); + if((puc = psdAllocVec(sizeof(struct PsdUsbClass)))) + { + puc->puc_Base = ps; + puc->puc_ClassBase = cls; + puc->puc_Node.ln_Name = puc->puc_ClassName = psdCopyStr(cls->lib_Node.ln_Name); + puc->puc_FullPath = psdCopyStr(origname); + + usbGetAttrs(UGA_CLASS, NULL, + UCCA_Priority, &pri, + UCCA_Description, &desc, + TAG_END); + + puc->puc_Node.ln_Pri = pri; + psdLockWritePBase(); + Enqueue(&ps->ps_Classes, &puc->puc_Node); + psdUnlockPBase(); + msgoff = ps->ps_FunnyCount++ & 7; + + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, + evilmsg[msgoff], + cls->lib_Node.ln_Name, cls->lib_Version, cls->lib_Revision, desc); + psdSendEvent(EHMB_ADDCLASS, puc, NULL); + return(puc); + } + CloseLibrary(cls); + } + return(NULL); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdRemClass()" */ +AROS_LH1(void, psdRemClass, + AROS_LHA(struct PsdUsbClass *, puc, A1), + LIBBASETYPEPTR, ps, 36, psd) +{ + AROS_LIBFUNC_INIT + KPRINTF(5, ("psdRemClass(%08lx)\n", puc)); + psdLockWritePBase(); + Remove(&puc->puc_Node); + psdUnlockPBase(); + + /* Check if there are still bindings remaining */ + while(puc->puc_UseCnt) + { + struct PsdDevice *pd; + struct PsdConfig *pc; + struct PsdInterface *pif; + + KPRINTF(20, ("This should never happen: Class %s still in use (%ld), can't close!\n", + puc->puc_ClassBase->lib_Node.ln_Name, puc->puc_UseCnt)); + + /* Well, try to release the open bindings in a best effort attempt */ + psdLockReadPBase(); + pd = NULL; + while((pd = psdGetNextDevice(pd))) + { + if(pd->pd_DevBinding && (pd->pd_ClsBinding == puc) && (!(pd->pd_Flags & PDFF_APPBINDING))) + { + psdUnlockPBase(); + psdReleaseDevBinding(pd); + psdLockReadPBase(); + pd = NULL; /* restart */ + continue; + } + pc = (struct PsdConfig *) pd->pd_Configs.lh_Head; + while(pc->pc_Node.ln_Succ) + { + pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head; + while(pif->pif_Node.ln_Succ) + { + if(pif->pif_IfBinding && (pif->pif_ClsBinding == puc)) + { + psdUnlockPBase(); + psdReleaseIfBinding(pif); + psdLockReadPBase(); + pd = NULL; /* restart */ + continue; + } + pif = (struct PsdInterface *) pif->pif_Node.ln_Succ; + } + pc = (struct PsdConfig *) pc->pc_Node.ln_Succ; + } + } + psdUnlockPBase(); + if(puc->puc_UseCnt) + { + psdAddErrorMsg(RETURN_FAIL, (STRPTR) libname, + "This should never happen! Class %s still in use (cnt=%ld). Could not get rid of it! Sorry, we're broke.", + puc->puc_ClassBase->lib_Node.ln_Name, puc->puc_UseCnt); + Wait(0L); + /*psdDelayMS(2000);*/ + } + } + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, + "I shot class %s, but I didn't kill the deputy.", + puc->puc_ClassBase->lib_Node.ln_Name); + CloseLibrary(puc->puc_ClassBase); + psdFreeVec(puc->puc_ClassName); + psdFreeVec(puc->puc_FullPath); + psdFreeVec(puc); + psdSendEvent(EHMB_REMCLASS, puc, NULL); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* *** Error Msgs *** */ + +/* /// "psdAddErrorMsgA()" */ +AROS_LH4(struct PsdErrorMsg *, psdAddErrorMsgA, + AROS_LHA(UWORD, level, D0), + AROS_LHA(STRPTR, origin, A0), + AROS_LHA(STRPTR, fmtstr, A1), + AROS_LHA(IPTR *, fmtdata, A2), + LIBBASETYPEPTR, ps, 40, psd) +{ + AROS_LIBFUNC_INIT + struct PsdErrorMsg *pem; + if(((!ps->ps_GlobalCfg->pgc_LogInfo) && (level < RETURN_WARN)) || + ((!ps->ps_GlobalCfg->pgc_LogWarning) && (level >= RETURN_WARN) && (level < RETURN_ERROR)) || + ((!ps->ps_GlobalCfg->pgc_LogError) && (level >= RETURN_ERROR) && (level < RETURN_FAIL)) || + ((!ps->ps_GlobalCfg->pgc_LogFailure) && (level >= RETURN_FAIL))) + { + return(NULL); + } + if((pem = psdAllocVec(sizeof(struct PsdErrorMsg)))) + { + pem->pem_Base = ps; + pem->pem_Level = level; + if((pem->pem_Origin = psdCopyStr(origin))) + { + if((pem->pem_Msg = psdCopyStrFmtA(fmtstr, fmtdata))) + { + if(pOpenDOS(ps)) + { + DateStamp(&pem->pem_DateStamp); + } else { + struct timerequest tr = ps->ps_TimerIOReq; + tr.tr_node.io_Command = TR_GETSYSTIME; + DoIO((struct IORequest *) &tr); + pem->pem_DateStamp.ds_Days = tr.tr_time.tv_secs / (24*60*60); + pem->pem_DateStamp.ds_Minute = (tr.tr_time.tv_secs / 60) % 60; + pem->pem_DateStamp.ds_Tick = (tr.tr_time.tv_secs % 60) * 50; + } + Forbid(); + AddTail(&ps->ps_ErrorMsgs, &pem->pem_Node); + Permit(); + psdSendEvent(EHMB_ADDERRORMSG, pem, NULL); + return(pem); + } + psdFreeVec(pem->pem_Origin); + } + psdFreeVec(pem); + } + return(NULL); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdRemErrorMsg()" */ +AROS_LH1(void, psdRemErrorMsg, + AROS_LHA(struct PsdErrorMsg *, pem, A0), + LIBBASETYPEPTR, ps, 41, psd) +{ + AROS_LIBFUNC_INIT + KPRINTF(1, ("psdRemErrorMsg()\n")); + Forbid(); + Remove(&pem->pem_Node); + Permit(); + psdFreeVec(pem->pem_Origin); + psdFreeVec(pem->pem_Msg); + psdFreeVec(pem); + psdSendEvent(EHMB_REMERRORMSG, pem, NULL); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* *** Bindings *** */ + +/* /// "psdClassScan()" */ +AROS_LH0(void, psdClassScan, + LIBBASETYPEPTR, ps, 37, psd) +{ + AROS_LIBFUNC_INIT + struct PsdHardware *phw; + struct PsdDevice *pd; + struct PsdUsbClass *puc; + + psdLockReadPBase(); + + if((FindTask(NULL)->tc_Node.ln_Type != NT_PROCESS) && (!ps->ps_ConfigRead)) + { + // it's the first time we were reading the config and DOS was not available + ps->ps_StartedAsTask = TRUE; + } + + puc = (struct PsdUsbClass *) ps->ps_Classes.lh_Head; + if(!puc->puc_Node.ln_Succ) + { + psdAddErrorMsg0(RETURN_WARN, (STRPTR) libname, "ClassScan attempted with no classes installed!"); + psdUnlockPBase(); + return; + } + + phw = (struct PsdHardware *) ps->ps_Hardware.lh_Head; + while(phw->phw_Node.ln_Succ) + { + if((pd = phw->phw_RootDevice)) + { + // for the root, do it ourselves, the rest is done by each hub task + psdHubClassScan(pd); + } + phw = (struct PsdHardware *) phw->phw_Node.ln_Succ; + } + psdUnlockPBase(); + //psdSendEvent(EHMB_CLSSCANRDY, NULL, NULL); + KPRINTF(5, ("************ Scanning finished!\n")); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdDoHubMethodA()" */ +AROS_LH3(LONG, psdDoHubMethodA, + AROS_LHA(struct PsdDevice *, pd, A0), + AROS_LHA(ULONG, methodid, D0), + AROS_LHA(APTR, methoddata, A1), + LIBBASETYPEPTR, ps, 92, psd) +{ + AROS_LIBFUNC_INIT + struct PsdUsbClass *puc; + KPRINTF(2, ("psdDoHubMethodA(%08lx)\n", pd)); + + if(pd) + { + if(pd->pd_Hub) + { + if((pd->pd_Hub->pd_DevBinding) && (puc = pd->pd_Hub->pd_ClsBinding)) + { + return(usbDoMethodA(methodid, methoddata)); + } + } + } + return 0; + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdClaimAppBindingA()" */ +AROS_LH1(struct PsdAppBinding *, psdClaimAppBindingA, + AROS_LHA(struct TagItem *, tags, A1), + LIBBASETYPEPTR, ps, 45, psd) +{ + AROS_LIBFUNC_INIT + struct PsdDevice *pd; + struct PsdConfig *pc; + struct PsdInterface *pif; + struct PsdDevice *hubpd; + struct PsdAppBinding tmppab; + struct PsdAppBinding *pab = NULL; + struct PsdUsbClass *puc; + + APTR binding; + + KPRINTF(2, ("psdClaimAppBindingA(%08lx)\n", tags)); + + tmppab.pab_Device = NULL; + tmppab.pab_ReleaseHook = NULL; + tmppab.pab_Task = NULL; + tmppab.pab_ForceRelease = FALSE; + psdSetAttrsA(PGA_APPBINDING, &tmppab, tags); + if(tmppab.pab_Device && tmppab.pab_ReleaseHook) + { + pd = tmppab.pab_Device; + + // force release of other bindings first + if(tmppab.pab_ForceRelease) + { + /* If there are bindings, get rid of them. */ + if(pd->pd_DevBinding) + { + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, + "%s really wants to bind to %s, so I'm letting the old binding go.", + FindTask(NULL)->tc_Node.ln_Name, + pd->pd_ProductStr); + + psdReleaseDevBinding(pd); + } else { + pc = (struct PsdConfig *) pd->pd_Configs.lh_Head; + while(pc->pc_Node.ln_Succ) + { + pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head; + while(pif->pif_Node.ln_Succ) + { + if(pif->pif_IfBinding) + { + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, + "%s really wants to bind to %s, so I'm letting the old binding go.", + FindTask(NULL)->tc_Node.ln_Name, + pd->pd_ProductStr); + psdReleaseIfBinding(pif); + } + pif = (struct PsdInterface *) pif->pif_Node.ln_Succ; + } + pc = (struct PsdConfig *) pc->pc_Node.ln_Succ; + } + } + } + hubpd = pd->pd_Hub; + if(!hubpd) // claim app binding at the root hub -- improbable, but possible. + { + pab = psdHubClaimAppBindingA(tags); + } else { + if((binding = hubpd->pd_DevBinding) && (puc = hubpd->pd_ClsBinding)) + { + pab = (struct PsdAppBinding *) usbDoMethod(UCM_HubClaimAppBinding, binding, tags); + } + } + if(pab) + { + // fill in task names + pab->pab_Task = FindTask(NULL); + pab->pab_Node.ln_Name = pab->pab_Task->tc_Node.ln_Name; + psdSendEvent(EHMB_ADDBINDING, pd, NULL); + return(pab); + } + } + return(NULL); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdReleaseAppBinding()" */ +AROS_LH1(void, psdReleaseAppBinding, + AROS_LHA(struct PsdAppBinding *, pab, A0), + LIBBASETYPEPTR, ps, 46, psd) +{ + AROS_LIBFUNC_INIT + struct PsdDevice *pd; + struct PsdDevice *hubpd; + struct PsdUsbClass *puc; + APTR binding; + + KPRINTF(2, ("psdReleaseAppBinding(%08lx)\n", pab)); + + if(pab) + { + pd = pab->pab_Device; + hubpd = pd->pd_Hub; + if(!hubpd) // release binding of hub (improbable) + { + psdHubReleaseDevBinding(pd); + return; + } + if((binding = hubpd->pd_DevBinding) && (puc = hubpd->pd_ClsBinding)) + { + usbDoMethod(UCM_HubReleaseDevBinding, binding, pd); + } + } + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdReleaseDevBinding()" */ +AROS_LH1(void, psdReleaseDevBinding, + AROS_LHA(struct PsdDevice *, pd, A0), + LIBBASETYPEPTR, ps, 50, psd) +{ + AROS_LIBFUNC_INIT + struct PsdUsbClass *puc; + struct PsdDevice *hubpd; + APTR binding; + + KPRINTF(5, ("psdReleaseDevBinding(%08lx)\n", pd)); + if(pd->pd_DevBinding) + { + hubpd = pd->pd_Hub; + if(!hubpd) // release binding of hub + { + psdHubReleaseDevBinding(pd); + return; + } + if((binding = hubpd->pd_DevBinding) && (puc = hubpd->pd_ClsBinding)) + { + usbDoMethod(UCM_HubReleaseDevBinding, binding, pd); + } + } + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdReleaseIfBinding()" */ +AROS_LH1(void, psdReleaseIfBinding, + AROS_LHA(struct PsdInterface *, pif, A0), + LIBBASETYPEPTR, ps, 51, psd) +{ + AROS_LIBFUNC_INIT + struct PsdUsbClass *puc; + struct PsdDevice *hubpd; + APTR binding; + + KPRINTF(5, ("psdReleaseIfBinding(%08lx)\n", pif)); + if(pif->pif_IfBinding && pif->pif_ClsBinding) + { + hubpd = pif->pif_Config->pc_Device->pd_Hub; + if(!hubpd) // release binding of hub (improbable) + { + psdHubReleaseIfBinding(pif); + return; + } + if((binding = hubpd->pd_DevBinding) && (puc = hubpd->pd_ClsBinding)) + { + usbDoMethod(UCM_HubReleaseIfBinding, binding, pif); + } + } + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdUnbindAll()" */ +AROS_LH0(void, psdUnbindAll, + LIBBASETYPEPTR, ps, 61, psd) +{ + AROS_LIBFUNC_INIT + struct PsdHardware *phw; + struct PsdDevice *pd; + struct PsdConfig *pc; + struct PsdInterface *pif; + BOOL restart; + + KPRINTF(10, ("pUnbindAll()\n")); + /* FIXME What happens if devices or hardware gets removed during the process? Need notify semaphore */ + psdLockReadPBase(); + do + { + restart = FALSE; + phw = (struct PsdHardware *) ps->ps_Hardware.lh_Head; + while(phw->phw_Node.ln_Succ) + { + pd = (struct PsdDevice *) phw->phw_Devices.lh_Head; + while(pd->pd_Node.ln_Succ) + { + /* If there are bindings, get rid of them. */ + if(pd->pd_DevBinding) + { + psdUnlockPBase(); + psdReleaseDevBinding(pd); + psdLockReadPBase(); + restart = TRUE; + break; + } + pc = (struct PsdConfig *) pd->pd_Configs.lh_Head; + while(pc->pc_Node.ln_Succ) + { + pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head; + while(pif->pif_Node.ln_Succ) + { + if(pif->pif_IfBinding) + { + psdUnlockPBase(); + psdReleaseIfBinding(pif); + psdLockReadPBase(); + restart = TRUE; + break; + } + pif = (struct PsdInterface *) pif->pif_Node.ln_Succ; + } + if(restart) + { + break; + } + pc = (struct PsdConfig *) pc->pc_Node.ln_Succ; + } + if(restart) + { + break; + } + pd = (struct PsdDevice *) pd->pd_Node.ln_Succ; + } + if(restart) + { + break; + } + phw = (struct PsdHardware *) phw->phw_Node.ln_Succ; + } + } while(restart); + psdUnlockPBase(); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdHubClassScan()" */ +AROS_LH1(void, psdHubClassScan, + AROS_LHA(struct PsdDevice *, pd, A0), + LIBBASETYPEPTR, ps, 82, psd) +{ + AROS_LIBFUNC_INIT + struct PsdUsbClass *puc; + struct PsdConfig *pc; + struct PsdInterface *pif; + struct PsdInterface *firstpif; + struct PsdPipe *pp = NULL; + struct MsgPort *mp; + APTR binding; + UWORD hasifbinding; + BOOL mainif; + STRPTR owner; + + KPRINTF(5, ("psdClassScan()\n")); + + if(!(mp = CreateMsgPort())) + { + return; + } + psdLockReadPBase(); + psdLockWriteDevice(pd); + while(!(pd->pd_PoPoCfg.poc_NoClassBind || pd->pd_DevBinding)) + { + if(!(pp = psdAllocPipe(pd, mp, NULL))) + { + break; + } + KPRINTF(5, ("Doing ClassScan on Device: %s\n", pd->pd_ProductStr)); + hasifbinding = 0; + /* First look if there is any interface binding. We may not change + the current config in this case! */ + pc = (struct PsdConfig *) pd->pd_Configs.lh_Head; + while(pc->pc_Node.ln_Succ) + { + pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head; + + while(pif->pif_Node.ln_Succ) + { + if(pif->pif_IfBinding) + { + hasifbinding = pc->pc_CfgNum; + break; + } + pif = (struct PsdInterface *) pif->pif_Node.ln_Succ; + } + pc = (struct PsdConfig *) pc->pc_Node.ln_Succ; + } + + owner = psdGetForcedBinding(pd->pd_IDString, NULL); + if((!hasifbinding) && owner) + { + puc = (struct PsdUsbClass *) ps->ps_Classes.lh_Head; + while(puc->puc_Node.ln_Succ) + { + if(!strcmp(owner, puc->puc_ClassName)) + { + if((pd->pd_DevBinding = (APTR) usbDoMethod(UCM_ForceDeviceBinding, pd))) + { + pd->pd_ClsBinding = puc; + puc->puc_UseCnt++; + psdSendEvent(EHMB_ADDBINDING, pd, NULL); + } else { + psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname, + "Forced device binding of %s to %s failed.", pd->pd_ProductStr, owner); + } + break; + } + puc = (struct PsdUsbClass *) puc->puc_Node.ln_Succ; + } + /* no more scanning required, abort here */ + break; + } + + /* Second attempt */ + pc = (struct PsdConfig *) pd->pd_Configs.lh_Head; + while(pc->pc_Node.ln_Succ) + { + if((!hasifbinding) || (hasifbinding == pc->pc_CfgNum)) + { + /* If the current config is not the one selected, change it */ + if(pd->pd_CurrCfg != pc->pc_CfgNum) + { + psdSetDeviceConfig(pp, pc->pc_CfgNum); + } + KPRINTF(5, (" Config %ld\n", pc->pc_CfgNum)); + /* If something went wrong above, we must exclude this config */ + if(pd->pd_CurrCfg == pc->pc_CfgNum) + { + pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head; + while(pif->pif_Node.ln_Succ) + { + KPRINTF(5, (" Interface %ld\n", pif->pif_IfNum)); + firstpif = pif; + mainif = TRUE; + if(!pif->pif_IfBinding) + { + binding = NULL; + do + { + if(!psdSetAltInterface(pp, pif)) + { + pif->pif_IfBinding = NULL; + /* Okay, this alternate setting failed. Try to get next one */ + if(!mainif) + { + pif = (struct PsdInterface *) pif->pif_Node.ln_Succ; + if(pif->pif_Node.ln_Succ) + { + KPRINTF(5, ("CONT!\n")); + continue; + } else { + KPRINTF(5, ("BREAK!\n")); + pif = firstpif; + break; + } + } + } + owner = psdGetForcedBinding(pd->pd_IDString, pif->pif_IDString); + puc = (struct PsdUsbClass *) ps->ps_Classes.lh_Head; + while(puc->puc_Node.ln_Succ) + { + KPRINTF(5, (">>>PING %s!\n", puc->puc_ClassName)); + if(owner) + { + if(!strcmp(owner, puc->puc_ClassName)) + { + binding = (APTR) usbDoMethod(UCM_ForceInterfaceBinding, pif); + if(!binding) + { + psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname, + "Forced interface binding of %s to %s failed.", pd->pd_ProductStr, owner); + } + } + if(!binding) + { + puc = (struct PsdUsbClass *) puc->puc_Node.ln_Succ; + continue; + } + } else { + binding = (APTR) usbDoMethod(UCM_AttemptInterfaceBinding, pif); + } + Forbid(); + KPRINTF(5, ("<<pc_Interfaces.lh_Head; + while(pif->pif_Node.ln_Succ) + { + if(pif->pif_IfNum == firstpif->pif_IfNum) + { + break; + } + pif = (struct PsdInterface *) pif->pif_Node.ln_Succ; + } + if(!pif->pif_Node.ln_Succ) + { + KPRINTF(5, ("Fucked it up!\n")); + psdAddErrorMsg0(RETURN_FAIL, (STRPTR) libname, "Something incredibly stupid happend. I've given up."); + Permit(); + break; + } + pif->pif_IfBinding = binding; + pif->pif_ClsBinding = puc; + hasifbinding = pc->pc_CfgNum; + puc->puc_UseCnt++; + psdSendEvent(EHMB_ADDBINDING, pd, NULL); + Permit(); + break; + } + Permit(); + puc = (struct PsdUsbClass *) puc->puc_Node.ln_Succ; + } + if(binding) + { + break; + } + //break; /* FIXME: DISABLED ALTSCANNING */ + /* Check alternate setting */ + if(pif->pif_AlterIfs.lh_Head->ln_Succ) + { + /* There are some alternative interfaces, start at top */ + pif = (struct PsdInterface *) pif->pif_AlterIfs.lh_Head; + mainif = FALSE; + } + } while(pif != firstpif); + //pif->pif_IfBinding = binding; + if(!binding) + { + psdSetAltInterface(pp, pif); + } + /* Hohum, search current main interface then */ + pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head; + while(pif->pif_Node.ln_Succ) + { + if(pif->pif_IfNum == firstpif->pif_IfNum) + { + break; + } + pif = (struct PsdInterface *) pif->pif_Node.ln_Succ; + } + } + pif = (struct PsdInterface *) pif->pif_Node.ln_Succ; + } + } + } + KPRINTF(5, ("End, next ConfigCheck!\n")); + pc = (struct PsdConfig *) pc->pc_Node.ln_Succ; + } + /* Could not establish interface binding, try device binding then */ + //psdUnlockPBase(); + if(!hasifbinding) + { + //pd->pd_DevBinding = (APTR) ~0UL; + binding = NULL; + owner = psdGetForcedBinding(pd->pd_IDString, NULL); + puc = (struct PsdUsbClass *) ps->ps_Classes.lh_Head; + while(puc->puc_Node.ln_Succ) + { + binding = NULL; + if(owner) + { + if(!strcmp(owner, puc->puc_ClassName)) + { + binding = (APTR) usbDoMethod(UCM_ForceDeviceBinding, pd, TAG_END); + if(!binding) + { + psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname, + "Forced device binding of %s to %s failed.", pd->pd_ProductStr, owner); + } + } + if(!binding) + { + puc = (struct PsdUsbClass *) puc->puc_Node.ln_Succ; + continue; + } + } else { + binding = (APTR) usbDoMethod(UCM_AttemptDeviceBinding, pd); + } + if(binding) + { + pd->pd_DevBinding = binding; + pd->pd_ClsBinding = puc; + puc->puc_UseCnt++; + psdSendEvent(EHMB_ADDBINDING, pd, NULL); + break; + } + puc = (struct PsdUsbClass *) puc->puc_Node.ln_Succ; + } + pd->pd_DevBinding = binding; + } + break; + } + if(pp) + { + psdFreePipe(pp); + } + // call hub class scan code + if((binding = pd->pd_DevBinding) && (puc = pd->pd_ClsBinding)) + { + usbDoMethod(UCM_HubClassScan, binding); + } + psdUnlockDevice(pd); + psdUnlockPBase(); + DeleteMsgPort(mp); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdHubClaimAppBindingA()" */ +AROS_LH1(struct PsdAppBinding *, psdHubClaimAppBindingA, + AROS_LHA(struct TagItem *, tags, A1), + LIBBASETYPEPTR, ps, 83, psd) +{ + AROS_LIBFUNC_INIT + struct PsdDevice *pd; + struct PsdAppBinding *pab; + struct PsdConfig *pc; + struct PsdInterface *pif; + + BOOL hasbinding = FALSE; + KPRINTF(2, ("psdHubClaimAppBindingA(%08lx)\n", tags)); + + if((pab = psdAllocVec(sizeof(struct PsdAppBinding)))) + { + psdSetAttrsA(PGA_APPBINDING, pab, tags); + if(pab->pab_Device && pab->pab_ReleaseHook) + { + pd = pab->pab_Device; + if(pd->pd_DevBinding) + { + hasbinding = TRUE; + } else { + pc = (struct PsdConfig *) pd->pd_Configs.lh_Head; + while(pc->pc_Node.ln_Succ) + { + pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head; + + while(pif->pif_Node.ln_Succ) + { + if(pif->pif_IfBinding) + { + hasbinding = TRUE; + break; + } + pif = (struct PsdInterface *) pif->pif_Node.ln_Succ; + } + pc = (struct PsdConfig *) pc->pc_Node.ln_Succ; + } + } + if(!hasbinding) + { + pd->pd_Flags |= PDFF_APPBINDING; + pd->pd_DevBinding = pab; + pd->pd_ClsBinding = NULL; + return(pab); + } + } + psdFreeVec(pab); + } + return(NULL); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdHubReleaseDevBinding()" */ +AROS_LH1(void, psdHubReleaseDevBinding, + AROS_LHA(struct PsdDevice *, pd, A0), + LIBBASETYPEPTR, ps, 84, psd) +{ + AROS_LIBFUNC_INIT + struct PsdUsbClass *puc; + APTR binding; + struct PsdAppBinding *pab; + + KPRINTF(5, ("psdHubReleaseDevBinding(%08lx)\n", pd)); + if(pd) + { + psdLockWriteDevice(pd); + if((binding = pd->pd_DevBinding)) + { + pd->pd_DevBinding = NULL; + if(pd->pd_Flags & PDFF_APPBINDING) + { + pab = (struct PsdAppBinding *) binding; + CallHookPkt(pab->pab_ReleaseHook, pab, (APTR) pab->pab_UserData); + pd->pd_ClsBinding = NULL; + pd->pd_Flags &= ~PDFF_APPBINDING; + psdFreeVec(pab); + psdSendEvent(EHMB_REMBINDING, pd, NULL); + } else { + puc = pd->pd_ClsBinding; + if(puc) + { + pd->pd_ClsBinding = NULL; + usbDoMethod(UCM_ReleaseDeviceBinding, binding); + puc->puc_UseCnt--; + psdSendEvent(EHMB_REMBINDING, pd, NULL); + } + } + } + psdUnlockDevice(pd); + } + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdHubReleaseIfBinding()" */ +AROS_LH1(void, psdHubReleaseIfBinding, + AROS_LHA(struct PsdInterface *, pif, A0), + LIBBASETYPEPTR, ps, 85, psd) +{ + AROS_LIBFUNC_INIT + struct PsdUsbClass *puc; + struct PsdDevice *pd; + APTR binding; + + KPRINTF(5, ("psdHubReleaseIfBinding(%08lx)\n", pif)); + + if(pif) + { + pd = pif->pif_Config->pc_Device; + psdLockWriteDevice(pd); + if((binding = pif->pif_IfBinding)) + { + pif->pif_IfBinding = NULL; + puc = pif->pif_ClsBinding; + if(puc) + { + pif->pif_ClsBinding = NULL; + usbDoMethod(UCM_AttemptInterfaceBinding, binding); + puc->puc_UseCnt--; + } + psdSendEvent(EHMB_REMBINDING, pd, NULL); + } + psdUnlockDevice(pd); + } + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* *** Events *** */ + +/* /// "psdAddEventHandler()" */ +AROS_LH2(struct PsdEventHook *, psdAddEventHandler, + AROS_LHA(struct MsgPort *, mp, A1), + AROS_LHA(ULONG, msgmask, D0), + LIBBASETYPEPTR, ps, 47, psd) +{ + AROS_LIBFUNC_INIT + struct PsdEventHook *peh = NULL; + + KPRINTF(5, ("psdAddEventHandler(%08lx, %08lx)\n", mp, msgmask)); + + if(mp) + { + ObtainSemaphore(&ps->ps_ReentrantLock); + if((peh = psdAllocVec(sizeof(struct PsdEventHook)))) + { + peh->peh_MsgPort = mp; + peh->peh_MsgMask = msgmask; + AddTail(&ps->ps_EventHooks, &peh->peh_Node); + } + ReleaseSemaphore(&ps->ps_ReentrantLock); + } + return(peh); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdRemEventHandler()" */ +AROS_LH1(void, psdRemEventHandler, + AROS_LHA(struct PsdEventHook *, peh, A0), + LIBBASETYPEPTR, ps, 48, psd) +{ + AROS_LIBFUNC_INIT + struct Message *msg; + + KPRINTF(5, ("psdRemEventHandler(%08lx)\n", peh)); + if(!peh) + { + return; + } + ObtainSemaphore(&ps->ps_ReentrantLock); + Remove(&peh->peh_Node); + while((msg = GetMsg(peh->peh_MsgPort))) + { + ReplyMsg(msg); + } + ReleaseSemaphore(&ps->ps_ReentrantLock); + pGarbageCollectEvents(ps); + psdFreeVec(peh); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdSendEvent()" */ +AROS_LH3(void, psdSendEvent, + AROS_LHA(ULONG, ehmt, D0), + AROS_LHA(APTR, param1, A0), + AROS_LHA(APTR, param2, A1), + LIBBASETYPEPTR, ps, 49, psd) +{ + AROS_LIBFUNC_INIT + struct PsdEventNote *pen; + struct PsdEventHook *peh; + ULONG msgmask = (1L<ps_ReentrantLock); + peh = (struct PsdEventHook *) ps->ps_EventHooks.lh_Head; + while(peh->peh_Node.ln_Succ) + { + if(peh->peh_MsgMask & msgmask) + { + if((pen = psdAllocVec(sizeof(struct PsdEventNote)))) + { + pen->pen_Msg.mn_ReplyPort = &ps->ps_EventReplyPort; + pen->pen_Msg.mn_Length = sizeof(struct PsdEventNote); + pen->pen_Event = ehmt; + pen->pen_Param1 = param1; + pen->pen_Param2 = param2; + PutMsg(peh->peh_MsgPort, &pen->pen_Msg); + } + } + peh = (struct PsdEventHook *) peh->peh_Node.ln_Succ; + } + ReleaseSemaphore(&ps->ps_ReentrantLock); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* *** Configuration *** */ + +/* /// "psdReadCfg()" */ +AROS_LH2(BOOL, psdReadCfg, + AROS_LHA(struct PsdIFFContext *, pic, A0), + AROS_LHA(APTR, formdata, A1), + LIBBASETYPEPTR, ps, 52, psd) +{ + AROS_LIBFUNC_INIT + struct PsdIFFContext *subpic; + LONG len; + ULONG chlen; + ULONG *buf = formdata; + BOOL res = TRUE; + KPRINTF(10, ("psdReadCfg(%08lx, %08lx)\n", pic, formdata)); + + pLockSemExcl(ps, &ps->ps_ConfigLock); + if(!pic) + { + pic = (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head; + if(!(pic->pic_Node.ln_Succ)) + { + pUnlockSem(ps, &ps->ps_ConfigLock); + return(FALSE); + } + } + if((AROS_LONG2BE(*buf) != ID_FORM) || (AROS_LONG2BE(buf[2]) != pic->pic_FormID)) + { + psdAddErrorMsg0(RETURN_FAIL, (STRPTR) libname, "Tried to replace a cfg form with a chunk or with an alien form!"); + pUnlockSem(ps, &ps->ps_ConfigLock); + return(FALSE); + } + subpic = (struct PsdIFFContext *) pic->pic_SubForms.lh_Head; + while(subpic->pic_Node.ln_Succ) + { + pFreeForm(ps, subpic); + subpic = (struct PsdIFFContext *) pic->pic_SubForms.lh_Head; + } + pic->pic_ChunksLen = 0; + len = (AROS_LONG2BE(buf[1]) - 3) & ~1UL; + buf += 3; + while(len >= 8) + { + if(!(pAddCfgChunk(ps, pic, buf))) + { + break; + } + chlen = (AROS_LONG2BE(buf[1]) + 9) & ~1UL; + len -= chlen; + buf = (ULONG *) (((UBYTE *) buf) + chlen); + } + if(len) + { + psdAddErrorMsg0(RETURN_FAIL, (STRPTR) libname, "Tried to add a nasty corrupted FORM chunk! Configuration is probably b0rken!"); + res = 0; + } + + pUnlockSem(ps, &ps->ps_ConfigLock); + ps->ps_CheckConfigReq = TRUE; + return(res); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdLoadCfgFromDisk()" */ +AROS_LH1(BOOL, psdLoadCfgFromDisk, + AROS_LHA(STRPTR, filename, A1), + LIBBASETYPEPTR, ps, 79, psd) +{ + AROS_LIBFUNC_INIT + ULONG *buf; + BOOL loaded = FALSE; + BPTR filehandle; + ULONG formhead[3]; + ULONG formlen; + + if(!filename) + { + loaded = psdLoadCfgFromDisk("ENV:Sys/poseidon.prefs"); + if(loaded) + { + return(TRUE); + } + + loaded = psdLoadCfgFromDisk("ENVARC:Sys/poseidon.prefs"); + + return(loaded); + } + + if(!pOpenDOS(ps)) + { + return(FALSE); + } + filehandle = Open(filename, MODE_OLDFILE); + if(filehandle) + { + if(Read(filehandle, formhead, 12) == 12) + { + if((AROS_LONG2BE(formhead[0]) == ID_FORM) && (AROS_LONG2BE(formhead[2]) == IFFFORM_PSDCFG)) + { + formlen = AROS_LONG2BE(formhead[1]); + buf = (ULONG *) psdAllocVec(formlen + 8); + if(buf) + { + buf[0] = formhead[0]; + buf[1] = formhead[1]; + buf[2] = formhead[2]; + if(Read(filehandle, &buf[3], formlen - 4) == formlen - 4) + { + psdReadCfg(NULL, buf); + psdParseCfg(); + loaded = TRUE; + } + psdFreeVec(buf); + } + } + } + Close(filehandle); + } else { + psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname, + "Failed to load config from '%s'!", + filename); + } + if(loaded) + { + ps->ps_SavedConfigHash = ps->ps_ConfigHash; + } + return(loaded); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdSaveCfgToDisk()" */ +AROS_LH2(BOOL, psdSaveCfgToDisk, + AROS_LHA(STRPTR, filename, A1), + AROS_LHA(BOOL, executable, D0), + LIBBASETYPEPTR, ps, 80, psd) +{ + AROS_LIBFUNC_INIT + ULONG *buf; + BOOL saved = FALSE; + BPTR filehandle; + + if(!filename) + { + saved &= psdSaveCfgToDisk("ENVARC:Sys/poseidon.prefs", FALSE); + saved &= psdSaveCfgToDisk("ENV:Sys/poseidon.prefs", FALSE); + return(saved); + } + + if(!pOpenDOS(ps)) + { + return(FALSE); + } + pLockSemShared(ps, &ps->ps_ConfigLock); + + buf = (ULONG *) psdWriteCfg(NULL); + if(buf) + { + /* Write file */ + filehandle = Open(filename, MODE_NEWFILE); + if(filehandle) + { + Write(filehandle, buf, (AROS_LONG2BE(buf[1])+9) & ~1UL); + Close(filehandle); + saved = TRUE; + } else { + psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname, + "Failed to write config to '%s'!", + filename); + } + psdFreeVec(buf); + } + pUnlockSem(ps, &ps->ps_ConfigLock); + if(saved) + { + ps->ps_SavedConfigHash = ps->ps_ConfigHash; + } + return(saved); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdWriteCfg()" */ +AROS_LH1(APTR, psdWriteCfg, + AROS_LHA(struct PsdIFFContext *, pic, A0), + LIBBASETYPEPTR, ps, 53, psd) +{ + AROS_LIBFUNC_INIT + ULONG len; + APTR buf = NULL; + + KPRINTF(10, ("psdWriteCfg(%08lx)\n", pic)); + + pLockSemShared(ps, &ps->ps_ConfigLock); + if(!pic) + { + pic = (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head; + if(!(pic->pic_Node.ln_Succ)) + { + pUnlockSem(ps, &ps->ps_ConfigLock); + return(NULL); + } + } + pUpdateGlobalCfg(ps, pic); + ps->ps_CheckConfigReq = TRUE; + len = pGetFormLength(pic); + if((buf = psdAllocVec(len))) + { + pInternalWriteForm(pic, buf); + } + pUnlockSem(ps, &ps->ps_ConfigLock); + return(buf); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdFindCfgForm()" */ +AROS_LH2(struct PsdIFFContext *, psdFindCfgForm, + AROS_LHA(struct PsdIFFContext *, pic, A0), + AROS_LHA(ULONG, formid, D0), + LIBBASETYPEPTR, ps, 54, psd) +{ + AROS_LIBFUNC_INIT + struct PsdIFFContext *subpic; + + KPRINTF(160, ("psdFindCfgForm(%08lx, %08lx)\n", pic, formid)); + pLockSemShared(ps, &ps->ps_ConfigLock); + if(!pic) + { + pic = (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head; + if(!(pic->pic_Node.ln_Succ)) + { + pUnlockSem(ps, &ps->ps_ConfigLock); + return(NULL); + } + } + subpic = (struct PsdIFFContext *) pic->pic_SubForms.lh_Head; + while(subpic->pic_Node.ln_Succ) + { + if(subpic->pic_FormID == formid) + { + pUnlockSem(ps, &ps->ps_ConfigLock); + return(subpic); + } + subpic = (struct PsdIFFContext *) subpic->pic_Node.ln_Succ; + } + pUnlockSem(ps, &ps->ps_ConfigLock); + return(NULL); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdNextCfgForm()" */ +AROS_LH1(struct PsdIFFContext *, psdNextCfgForm, + AROS_LHA(struct PsdIFFContext *, pic, A0), + LIBBASETYPEPTR, ps, 55, psd) +{ + AROS_LIBFUNC_INIT + ULONG formid; + KPRINTF(160, ("psdNextCfgForm(%08lx)\n", pic)); + + if(!pic) + { + return(NULL); + } + pLockSemShared(ps, &ps->ps_ConfigLock); + formid = pic->pic_FormID; + pic = (struct PsdIFFContext *) pic->pic_Node.ln_Succ; + while(pic->pic_Node.ln_Succ) + { + if(pic->pic_FormID == formid) + { + pUnlockSem(ps, &ps->ps_ConfigLock); + return(pic); + } + pic = (struct PsdIFFContext *) pic->pic_Node.ln_Succ; + } + pUnlockSem(ps, &ps->ps_ConfigLock); + return(NULL); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdAllocCfgForm()" */ +AROS_LH1(struct PsdIFFContext *, psdAllocCfgForm, + AROS_LHA(ULONG, formid, D0), + LIBBASETYPEPTR, ps, 86, psd) +{ + AROS_LIBFUNC_INIT + struct PsdIFFContext *pic; + KPRINTF(10, ("psdAllocCfgForm(%08lx)\n", formid)); + if((pic = psdAllocVec(sizeof(struct PsdIFFContext)))) + { + NewList(&pic->pic_SubForms); + //pic->pic_Parent = parent; + pic->pic_FormID = formid; + pic->pic_FormLength = 4; + pic->pic_Chunks = NULL; + pic->pic_ChunksLen = 0; + pic->pic_BufferLen = 0; + Forbid(); + AddTail(&ps->ps_AlienConfigs, &pic->pic_Node); + Permit(); + } + return(pic); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdRemCfgForm()" */ +AROS_LH1(void, psdRemCfgForm, + AROS_LHA(struct PsdIFFContext *, pic, A0), + LIBBASETYPEPTR, ps, 56, psd) +{ + AROS_LIBFUNC_INIT + KPRINTF(10, ("psdRemCfgForm(%08lx)\n", pic)); + + pLockSemExcl(ps, &ps->ps_ConfigLock); + if(!pic) + { + pic = (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head; + if(!(pic->pic_Node.ln_Succ)) + { + pUnlockSem(ps, &ps->ps_ConfigLock); + return; + } + } + pFreeForm(ps, pic); + pUnlockSem(ps, &ps->ps_ConfigLock); + ps->ps_CheckConfigReq = TRUE; + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdAddCfgEntry()" */ +AROS_LH2(struct PsdIFFContext *, psdAddCfgEntry, + AROS_LHA(struct PsdIFFContext *, pic, A0), + AROS_LHA(APTR, formdata, A1), + LIBBASETYPEPTR, ps, 57, psd) +{ + AROS_LIBFUNC_INIT + struct PsdIFFContext *res; + + KPRINTF(10, ("psdAddCfgEntry(%08lx, %08lx)\n", pic, formdata)); + pLockSemExcl(ps, &ps->ps_ConfigLock); + if(!pic) + { + pic = (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head; + if(!(pic->pic_Node.ln_Succ)) + { + pUnlockSem(ps, &ps->ps_ConfigLock); + return(NULL); + } + } + res = pAddCfgChunk(ps, pic, formdata); + pUnlockSem(ps, &ps->ps_ConfigLock); + ps->ps_CheckConfigReq = TRUE; + return(res); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdRemCfgChunk()" */ +AROS_LH2(BOOL, psdRemCfgChunk, + AROS_LHA(struct PsdIFFContext *, pic, A0), + AROS_LHA(ULONG, chnkid, D0), + LIBBASETYPEPTR, ps, 58, psd) +{ + AROS_LIBFUNC_INIT + BOOL res = FALSE; + + KPRINTF(10, ("psdRemCfgChunk(%08lx, %08lx)\n", pic, chnkid)); + pLockSemExcl(ps, &ps->ps_ConfigLock); + if(!pic) + { + pic = (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head; + if(!(pic->pic_Node.ln_Succ)) + { + pUnlockSem(ps, &ps->ps_ConfigLock); + return(FALSE); + } + } + if(chnkid) + { + res = pRemCfgChunk(ps, pic, chnkid); + } else { + struct PsdIFFContext *subpic = (struct PsdIFFContext *) pic->pic_SubForms.lh_Head; + while(subpic->pic_Node.ln_Succ) + { + pFreeForm(ps, subpic); + res = TRUE; + subpic = (struct PsdIFFContext *) pic->pic_SubForms.lh_Head; + } + if(pic->pic_ChunksLen) + { + res = TRUE; + } + pic->pic_ChunksLen = 0; + pic->pic_FormLength = 4; + } + + pUnlockSem(ps, &ps->ps_ConfigLock); + ps->ps_CheckConfigReq = TRUE; + return(res); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdGetCfgChunk()" */ +AROS_LH2(APTR, psdGetCfgChunk, + AROS_LHA(struct PsdIFFContext *, pic, A0), + AROS_LHA(ULONG, chnkid, D0), + LIBBASETYPEPTR, ps, 59, psd) +{ + AROS_LIBFUNC_INIT + ULONG *chnk; + ULONG *res = NULL; + + KPRINTF(10, ("psdGetCfgChunk(%08lx, %08lx)\n", pic, chnkid)); + + pLockSemShared(ps, &ps->ps_ConfigLock); + if(!pic) + { + pic = (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head; + if(!(pic->pic_Node.ln_Succ)) + { + pUnlockSem(ps, &ps->ps_ConfigLock); + return(NULL); + } + } + pUpdateGlobalCfg(ps, pic); + chnk = pFindCfgChunk(ps, pic, chnkid); + if(chnk) + { + res = psdAllocVec(AROS_LONG2BE(chnk[1]+8)); + if(res) + { + memcpy(res, chnk, AROS_LONG2BE((size_t) chnk[1]+8)); + } + } + pUnlockSem(ps, &ps->ps_ConfigLock); + return(res); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdParseCfg()" */ +AROS_LH0(void, psdParseCfg, + LIBBASETYPEPTR, ps, 60, psd) +{ + AROS_LIBFUNC_INIT + struct PsdIFFContext *pic; + struct PsdIFFContext *subpic; + ULONG *chnk; + STRPTR name; + ULONG unit; + struct PsdHardware *phw; + struct PsdUsbClass *puc; + BOOL removeall = TRUE; + BOOL nodos = (FindTask(NULL)->tc_Node.ln_Type != NT_PROCESS); + IPTR restartme; + + KPRINTF(10, ("psdParseCfg()\n")); + + pLockSemShared(ps, &ps->ps_ConfigLock); + pCheckCfgChanged(ps); + pic = psdFindCfgForm(NULL, IFFFORM_STACKCFG); + if(!pic) + { + pUnlockSem(ps, &ps->ps_ConfigLock); + return; + } + + // if no config for hardware is found, we don't remove the devices, + // because this could render the system useless (no USB mice or + // keyboards to configure the hardware!) + if(!psdFindCfgForm(pic, IFFFORM_UHWDEVICE)) + { + removeall = FALSE; + } + + psdLockReadPBase(); + + /* select all hardware devices for removal */ + phw = (struct PsdHardware *) ps->ps_Hardware.lh_Head; + while(phw->phw_Node.ln_Succ) + { + phw->phw_RemoveMe = removeall; + phw = (struct PsdHardware *) phw->phw_Node.ln_Succ; + } + + /* select all classes for removal */ + puc = (struct PsdUsbClass *) ps->ps_Classes.lh_Head; + while(puc->puc_Node.ln_Succ) + { + puc->puc_RemoveMe = TRUE; + puc = (struct PsdUsbClass *) puc->puc_Node.ln_Succ; + } + + psdUnlockPBase(); + + /* Get Hardware config */ + subpic = psdFindCfgForm(pic, IFFFORM_UHWDEVICE); + while(subpic) + { + chnk = pFindCfgChunk(ps, subpic, IFFCHNK_NAME); + if(chnk) + { + name = (STRPTR) &chnk[2]; + unit = 0; + chnk = pFindCfgChunk(ps, subpic, IFFCHNK_UNIT); + if(chnk) + { + unit = chnk[2]; + } + if(!pFindCfgChunk(ps, subpic, IFFCHNK_OFFLINE)) + { + phw = pFindHardware(ps, name, unit); + if(phw) + { + phw->phw_RemoveMe = FALSE; + } + } + } + subpic = psdNextCfgForm(subpic); + } + + /* Get Class config */ + subpic = psdFindCfgForm(pic, IFFFORM_USBCLASS); + while(subpic) + { + chnk = pFindCfgChunk(ps, subpic, IFFCHNK_NAME); + if(chnk) + { + name = (STRPTR) &chnk[2]; + puc = (struct PsdUsbClass *) pFindName(ps, &ps->ps_Classes, name); + if(puc) + { + puc->puc_RemoveMe = FALSE; + } + } + subpic = psdNextCfgForm(subpic); + } + + // unlock config while removing to avoid deadlocks. + pUnlockSem(ps, &ps->ps_ConfigLock); + + /* now remove remaining classes not found in the config */ + puc = (struct PsdUsbClass *) ps->ps_Classes.lh_Head; + while(puc->puc_Node.ln_Succ) + { + if(puc->puc_RemoveMe) + { + psdRemClass(puc); + puc = (struct PsdUsbClass *) ps->ps_Classes.lh_Head; + } else { + puc = (struct PsdUsbClass *) puc->puc_Node.ln_Succ; + } + } + + /* now remove all remaining hardware not found in the config */ + phw = (struct PsdHardware *) ps->ps_Hardware.lh_Head; + while(phw->phw_Node.ln_Succ) + { + if(phw->phw_RemoveMe) + { + psdRemHardware(phw); + phw = (struct PsdHardware *) ps->ps_Hardware.lh_Head; + } else { + phw = (struct PsdHardware *) phw->phw_Node.ln_Succ; + } + } + + pLockSemShared(ps, &ps->ps_ConfigLock); + pic = psdFindCfgForm(NULL, IFFFORM_STACKCFG); + if(!pic) + { + pUnlockSem(ps, &ps->ps_ConfigLock); + // oops! + return; + } + + /* Add missing Classes */ + subpic = psdFindCfgForm(pic, IFFFORM_USBCLASS); + while(subpic) + { + chnk = pFindCfgChunk(ps, subpic, IFFCHNK_NAME); + if(chnk) + { + /* *** FIXME *** POSSIBLE DEADLOCK WHEN CLASS TRIES TO DO CONFIG STUFF IN + AN EXTERNAL TASK INSIDE LIBOPEN CODE */ + name = (STRPTR) &chnk[2]; + puc = (struct PsdUsbClass *) pFindName(ps, &ps->ps_Classes, name); + if(!puc) + { + psdAddClass(name, 0); + } + } + subpic = psdNextCfgForm(subpic); + } + + /* Now really mount Hardware found in config */ + subpic = psdFindCfgForm(pic, IFFFORM_UHWDEVICE); + while(subpic) + { + chnk = pFindCfgChunk(ps, subpic, IFFCHNK_NAME); + if(chnk) + { + name = (STRPTR) &chnk[2]; + unit = 0; + chnk = pFindCfgChunk(ps, subpic, IFFCHNK_UNIT); + if(chnk) + { + unit = chnk[2]; + } + if(!pFindCfgChunk(ps, subpic, IFFCHNK_OFFLINE)) + { + phw = pFindHardware(ps, name, unit); + if(!phw) + { + phw = psdAddHardware(name, unit); + if(phw) + { + psdEnumerateHardware(phw); + } + } + } + } + subpic = psdNextCfgForm(subpic); + } + pUnlockSem(ps, &ps->ps_ConfigLock); + + if(!nodos && ps->ps_StartedAsTask) + { + // last time we were reading the config before DOS, so maybe we need to + // unbind some classes that need to be overruled by newly available classes, + // such as hid.class overruling bootmouse & bootkeyboard. + // so unbind those classes that promote themselves as AfterDOS + + psdLockReadPBase(); + psdAddErrorMsg0(RETURN_OK, (STRPTR) libname, "Checking AfterDOS..."); + puc = (struct PsdUsbClass *) ps->ps_Classes.lh_Head; + while(puc->puc_Node.ln_Succ) + { + restartme = FALSE; + usbGetAttrs(UGA_CLASS, NULL, + UCCA_AfterDOSRestart, &restartme, + TAG_END); + + if(restartme && puc->puc_UseCnt) + { + struct PsdDevice *pd; + struct PsdConfig *pc; + struct PsdInterface *pif; + + /* Well, try to release the open bindings in a best effort attempt */ + pd = NULL; + while((pd = psdGetNextDevice(pd))) + { + if(pd->pd_DevBinding && (pd->pd_ClsBinding == puc) && (!(pd->pd_Flags & PDFF_APPBINDING))) + { + psdUnlockPBase(); + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, + "AfterDOS: Temporarily releasing %s %s binding to %s.", + puc->puc_ClassName, "device", pd->pd_ProductStr); + psdReleaseDevBinding(pd); + psdLockReadPBase(); + pd = NULL; /* restart */ + continue; + } + pc = (struct PsdConfig *) pd->pd_Configs.lh_Head; + while(pc->pc_Node.ln_Succ) + { + pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head; + while(pif->pif_Node.ln_Succ) + { + if(pif->pif_IfBinding && (pif->pif_ClsBinding == puc)) + { + psdUnlockPBase(); + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, + "AfterDOS: Temporarily releasing %s %s binding to %s.", + puc->puc_ClassName, "interface", pd->pd_ProductStr); + psdReleaseIfBinding(pif); + psdLockReadPBase(); + pd = NULL; /* restart */ + continue; + } + pif = (struct PsdInterface *) pif->pif_Node.ln_Succ; + } + pc = (struct PsdConfig *) pc->pc_Node.ln_Succ; + } + } + } + usbDoMethodA(UCM_DOSAvailableEvent, NULL); + puc = (struct PsdUsbClass *) puc->puc_Node.ln_Succ; + } + ps->ps_StartedAsTask = FALSE; + psdUnlockPBase(); + } + + if(nodos && (!ps->ps_ConfigRead)) + { + // it's the first time we were reading the config and DOS was not available + ps->ps_StartedAsTask = TRUE; + } + ps->ps_ConfigRead = TRUE; + ps->ps_SavedConfigHash = ps->ps_ConfigHash; // update saved hash + + /* do a class scan */ + psdClassScan(); + + if(nodos && ps->ps_GlobalCfg->pgc_BootDelay) + { + // wait for hubs to settle + psdDelayMS(1000); + puc = (struct PsdUsbClass *) FindName(&ps->ps_Classes, "massstorage.class"); + if(puc && puc->puc_UseCnt) + { + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, + "Delaying further execution by %ld second(s) (boot delay).", + ps->ps_GlobalCfg->pgc_BootDelay); + if(ps->ps_GlobalCfg->pgc_BootDelay >= 1); + { + psdDelayMS((ps->ps_GlobalCfg->pgc_BootDelay-1)*1000); + } + } else { + psdAddErrorMsg0(RETURN_OK, (STRPTR) libname, "Boot delay skipped, no mass storage devices found."); + } + } + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdSetClsCfg()" */ +AROS_LH2(BOOL, psdSetClsCfg, + AROS_LHA(STRPTR, owner, A0), + AROS_LHA(APTR, form, A1), + LIBBASETYPEPTR, ps, 62, psd) +{ + AROS_LIBFUNC_INIT + struct PsdIFFContext *pic; + BOOL result = FALSE; + + KPRINTF(10, ("psdSetClsCfg(%s, %08lx)\n", owner, form)); + pLockSemExcl(ps, &ps->ps_ConfigLock); + pic = psdFindCfgForm(NULL, IFFFORM_CLASSCFG); + while(pic) + { + if(pMatchStringChunk(ps, pic, IFFCHNK_OWNER, owner)) + { + pic = psdFindCfgForm(pic, IFFFORM_CLASSDATA); + if(pic) + { + if(form) + { + result = psdReadCfg(pic, form); + } else { + psdRemCfgChunk(pic, 0); + result = TRUE; + } + break; + } else { + break; + } + } + pic = psdNextCfgForm(pic); + } + if(result) + { + pUnlockSem(ps, &ps->ps_ConfigLock); + pCheckCfgChanged(ps); + return(result); + } + pic = (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head; + if(pic->pic_Node.ln_Succ) + { + pic = pAllocForm(ps, pic, IFFFORM_CLASSCFG); + if(pic) + { + if(pAddStringChunk(ps, pic, IFFCHNK_OWNER, owner)) + { + if(form) + { + if(pAddCfgChunk(ps, pic, form)) + { + pUnlockSem(ps, &ps->ps_ConfigLock); + pCheckCfgChanged(ps); + return(TRUE); + } + } else { + ULONG buf[3]; + buf[0] = AROS_LONG2BE(ID_FORM); + buf[1] = AROS_LONG2BE(4); + buf[2] = AROS_LONG2BE(IFFFORM_CLASSDATA); + if(pAddCfgChunk(ps, pic, buf)) + { + pUnlockSem(ps, &ps->ps_ConfigLock); + pCheckCfgChanged(ps); + return(TRUE); + } + } + } + } + } + pUnlockSem(ps, &ps->ps_ConfigLock); + pCheckCfgChanged(ps); + return(FALSE); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdGetClsCfg()" */ +AROS_LH1(struct PsdIFFContext *, psdGetClsCfg, + AROS_LHA(STRPTR, owner, A0), + LIBBASETYPEPTR, ps, 63, psd) +{ + AROS_LIBFUNC_INIT + struct PsdIFFContext *pic; + + KPRINTF(10, ("psdGetClsCfg(%s)\n", owner)); + pic = psdFindCfgForm(NULL, IFFFORM_CLASSCFG); + while(pic) + { + if(pMatchStringChunk(ps, pic, IFFCHNK_OWNER, owner)) + { + return(psdFindCfgForm(pic, IFFFORM_CLASSDATA)); + } + pic = psdNextCfgForm(pic); + } + return(NULL); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdSetUsbDevCfg()" */ +AROS_LH4(BOOL, psdSetUsbDevCfg, + AROS_LHA(STRPTR, owner, A0), + AROS_LHA(STRPTR, devid, A2), + AROS_LHA(STRPTR, ifid, A3), + AROS_LHA(APTR, form, A1), + LIBBASETYPEPTR, ps, 64, psd) +{ + AROS_LIBFUNC_INIT + struct PsdIFFContext *pic; + struct PsdIFFContext *cpic = NULL; + struct PsdIFFContext *mpic = NULL; + ULONG ilen = 0; + BOOL result = FALSE; + + KPRINTF(10, ("psdSetUsbDevCfg(%s, %s, %s, %08lx)\n", owner, devid, ifid, form)); + if(ifid) + { + ilen = strlen(ifid); + } + pLockSemExcl(ps, &ps->ps_ConfigLock); + /* Find device config form. It contains all device config data */ + pic = psdFindCfgForm(NULL, IFFFORM_DEVICECFG); + while(pic) + { + /* Find DEVID-Chunk. Check if it matches our device id */ + if(pMatchStringChunk(ps, pic, IFFCHNK_DEVID, devid)) + { + cpic = NULL; + /* We found the correct device. Now if we need to store interface data, find the interface first */ + if(ifid) + { + /* Search interface config form */ + mpic = psdFindCfgForm(pic, IFFFORM_IFCFGDATA); + while(mpic) + { + /* Found the form. Find the the ID String for the interface */ + if(pMatchStringChunk(ps, mpic, IFFCHNK_IFID, ifid)) + { + /* ID did match, now check for owner */ + if(pMatchStringChunk(ps, mpic, IFFCHNK_OWNER, owner)) + { + /* found it! So there is already a config saved in there. Search for dev config data form */ + cpic = psdFindCfgForm(mpic, IFFFORM_IFCLSDATA); + if(!cpic) + { + /* not found, generate it */ + cpic = pAllocForm(ps, mpic, IFFFORM_IFCLSDATA); + } + break; + } + } + mpic = psdNextCfgForm(mpic); + } + if(!cpic) + { + if((mpic = pAllocForm(ps, pic, IFFFORM_IFCFGDATA))) + { + if(pAddStringChunk(ps, mpic, IFFCHNK_OWNER, owner)) + { + if(pAddStringChunk(ps, mpic, IFFCHNK_IFID, ifid)) + { + cpic = pAllocForm(ps, mpic, IFFFORM_IFCLSDATA); + } + } + } + } + } else { + /* Search for device config */ + mpic = psdFindCfgForm(pic, IFFFORM_DEVCFGDATA); + while(mpic) + { + /* search for the right owner */ + if(pMatchStringChunk(ps, mpic, IFFCHNK_OWNER, owner)) + { + /* found it! So there is already a config saved in there. Search for dev config data form */ + cpic = psdFindCfgForm(mpic, IFFFORM_DEVCLSDATA); + if(!cpic) + { + /* not found, generate it */ + cpic = pAllocForm(ps, mpic, IFFFORM_DEVCLSDATA); + } + break; + } + mpic = psdNextCfgForm(mpic); + } + if(!cpic) /* no device config form */ + { + if((mpic = pAllocForm(ps, pic, IFFFORM_DEVCFGDATA))) + { + if(pAddStringChunk(ps, mpic, IFFCHNK_OWNER, owner)) + { + cpic = pAllocForm(ps, mpic, IFFFORM_DEVCLSDATA); + } + } + } + } + if(cpic) + { + if(form) + { + result = psdReadCfg(cpic, form); + } else { + psdRemCfgChunk(cpic, 0); + result = TRUE; + } + break; + } + } + pic = psdNextCfgForm(pic); + } + if(result) + { + pUnlockSem(ps, &ps->ps_ConfigLock); + pCheckCfgChanged(ps); + return(result); + } + cpic = NULL; + pic = (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head; + if(pic->pic_Node.ln_Succ) + { + pic = pAllocForm(ps, pic, IFFFORM_DEVICECFG); + if(pic) + { + if(pAddStringChunk(ps, pic, IFFCHNK_DEVID, devid)) + { + if(ifid) + { + if((mpic = pAllocForm(ps, pic, IFFFORM_IFCFGDATA))) + { + if(pAddStringChunk(ps, mpic, IFFCHNK_OWNER, owner)) + { + if(pAddStringChunk(ps, mpic, IFFCHNK_IFID, ifid)) + { + cpic = pAllocForm(ps, mpic, IFFFORM_IFCLSDATA); + } + } + } + } else { + if((mpic = pAllocForm(ps, pic, IFFFORM_DEVCFGDATA))) + { + if(pAddStringChunk(ps, mpic, IFFCHNK_OWNER, owner)) + { + cpic = pAllocForm(ps, mpic, IFFFORM_DEVCLSDATA); + } + } + } + if(cpic) + { + if(form) + { + result = psdReadCfg(cpic, form); + } else { + psdRemCfgChunk(cpic, 0); + result = TRUE; + } + } + } + } + } + pUnlockSem(ps, &ps->ps_ConfigLock); + pCheckCfgChanged(ps); + return(result); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdGetUsbDevCfg()" */ +AROS_LH3(struct PsdIFFContext *, psdGetUsbDevCfg, + AROS_LHA(STRPTR, owner, A0), + AROS_LHA(STRPTR, devid, A2), + AROS_LHA(STRPTR, ifid, A3), + LIBBASETYPEPTR, ps, 65, psd) +{ + AROS_LIBFUNC_INIT + struct PsdIFFContext *pic; + struct PsdIFFContext *cpic = NULL; + struct PsdIFFContext *mpic = NULL; + ULONG ilen = 0; + + KPRINTF(10, ("psdGetUsbDevCfg(%s, %s, %s)\n", owner, devid, ifid)); + if(ifid) + { + ilen = strlen(ifid); + } + pLockSemShared(ps, &ps->ps_ConfigLock); + /* Find device config form. It contains all device config data */ + pic = psdFindCfgForm(NULL, IFFFORM_DEVICECFG); + while(pic) + { + /* Find DEVID-Chunk. Check if it matches our device id */ + if(pMatchStringChunk(ps, pic, IFFCHNK_DEVID, devid)) + { + cpic = NULL; + /* We found the correct device. Now if we need to store interface data, find the interface first */ + if(ifid) + { + /* Search interface config form */ + mpic = psdFindCfgForm(pic, IFFFORM_IFCFGDATA); + while(mpic) + { + /* Found the form. Find the the ID String for the interface */ + if(pMatchStringChunk(ps, mpic, IFFCHNK_IFID, ifid)) + { + /* ID did match, now check for owner */ + if(pMatchStringChunk(ps, mpic, IFFCHNK_OWNER, owner)) + { + /* found it! So there is already a config saved in there. Search for dev config data form */ + cpic = psdFindCfgForm(mpic, IFFFORM_IFCLSDATA); + break; + } + } + mpic = psdNextCfgForm(mpic); + } + } else { + /* Search for device config */ + mpic = psdFindCfgForm(pic, IFFFORM_DEVCFGDATA); + while(mpic) + { + /* search for the right owner */ + if(pMatchStringChunk(ps, mpic, IFFCHNK_OWNER, owner)) + { + /* found it! So there is already a config saved in there. Search for dev config data form */ + cpic = psdFindCfgForm(mpic, IFFFORM_DEVCLSDATA); + break; + } + mpic = psdNextCfgForm(mpic); + } + } + break; + } + pic = psdNextCfgForm(pic); + } + pUnlockSem(ps, &ps->ps_ConfigLock); + KPRINTF(1, ("Result %08lx\n", cpic)); + return(cpic); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdSetForcedBinding()" */ +AROS_LH3(BOOL, psdSetForcedBinding, + AROS_LHA(STRPTR, owner, A2), + AROS_LHA(STRPTR, devid, A0), + AROS_LHA(STRPTR, ifid, A1), + LIBBASETYPEPTR, ps, 69, psd) +{ + AROS_LIBFUNC_INIT + struct PsdIFFContext *pic; + struct PsdIFFContext *cpic = NULL; + struct PsdIFFContext *mpic = NULL; + ULONG olen = 0; + ULONG ilen = 0; + BOOL result = FALSE; + if(ifid) + { + ilen = strlen(ifid); + } + if(owner) + { + olen = strlen(owner); + } + pLockSemExcl(ps, &ps->ps_ConfigLock); + /* Find device config form. It contains all device config data */ + pic = psdFindCfgForm(NULL, IFFFORM_DEVICECFG); + while(pic) + { + /* Find DEVID-Chunk. Check if it matches our device id */ + if(pMatchStringChunk(ps, pic, IFFCHNK_DEVID, devid)) + { + cpic = NULL; + /* We found the correct device. Now if we need to store interface data, find the interface first */ + if(ifid) + { + /* Search interface config form */ + mpic = psdFindCfgForm(pic, IFFFORM_IFCFGDATA); + while(mpic) + { + /* Found the form. Find the the ID String for the interface */ + if(pMatchStringChunk(ps, mpic, IFFCHNK_IFID, ifid)) + { + /* ID did match, insert/replace forced binding */ + if(olen) + { + if(pAddStringChunk(ps, mpic, IFFCHNK_FORCEDBIND, owner)) + { + result = TRUE; + } + } else { + pRemCfgChunk(ps, mpic, IFFCHNK_FORCEDBIND); + result = TRUE; + } + } + mpic = psdNextCfgForm(mpic); + } + if(!olen) + { + result = TRUE; + } + if((!result) && olen) + { + if((mpic = pAllocForm(ps, pic, IFFFORM_IFCFGDATA))) + { + if(pAddStringChunk(ps, mpic, IFFCHNK_OWNER, owner)) + { + if(pAddStringChunk(ps, mpic, IFFCHNK_FORCEDBIND, owner)) + { + if(pAddStringChunk(ps, mpic, IFFCHNK_IFID, ifid)) + { + result = TRUE; + } + } + } + } + } + } else { + /* Add FBND chunk */ + if(olen) + { + if(pAddStringChunk(ps, pic, IFFCHNK_FORCEDBIND, owner)) + { + result = TRUE; + } + } else { + pRemCfgChunk(ps, pic, IFFCHNK_FORCEDBIND); + result = TRUE; + } + } + break; + } + pic = psdNextCfgForm(pic); + } + if(!olen) + { + result = TRUE; + } + if(result) + { + pUnlockSem(ps, &ps->ps_ConfigLock); + pCheckCfgChanged(ps); + return(result); + } + pic = (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head; + if(pic->pic_Node.ln_Succ) + { + pic = pAllocForm(ps, pic, IFFFORM_DEVICECFG); + if(pic) + { + if(pAddStringChunk(ps, pic, IFFCHNK_DEVID, devid)) + { + if(ifid) + { + if((mpic = pAllocForm(ps, pic, IFFFORM_IFCFGDATA))) + { + if(pAddStringChunk(ps, mpic, IFFCHNK_OWNER, owner)) + { + if(pAddStringChunk(ps, mpic, IFFCHNK_FORCEDBIND, owner)) + { + if(pAddStringChunk(ps, mpic, IFFCHNK_IFID, ifid)) + { + result = TRUE; + } + } + } + } + } else { + /* Add FBND chunk */ + if(pAddStringChunk(ps, pic, IFFCHNK_FORCEDBIND, owner)) + { + result = TRUE; + } + } + } + } + } + pUnlockSem(ps, &ps->ps_ConfigLock); + pCheckCfgChanged(ps); + return(result); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdGetForcedBinding()" */ +AROS_LH2(STRPTR, psdGetForcedBinding, + AROS_LHA(STRPTR, devid, A0), + AROS_LHA(STRPTR, ifid, A1), + LIBBASETYPEPTR, ps, 70, psd) +{ + AROS_LIBFUNC_INIT + struct PsdIFFContext *pic; + struct PsdIFFContext *mpic = NULL; + ULONG *chunk; + ULONG ilen = 0; + STRPTR owner = NULL; + + if(ifid) + { + ilen = strlen(ifid); + } + pLockSemShared(ps, &ps->ps_ConfigLock); + /* Find device config form. It contains all device config data */ + pic = psdFindCfgForm(NULL, IFFFORM_DEVICECFG); + while(pic) + { + /* Find DEVID-Chunk. Check if it matches our device id */ + if(pMatchStringChunk(ps, pic, IFFCHNK_DEVID, devid)) + { + /* We found the correct device. Now if we need to store interface data, find the interface first */ + if(ifid) + { + /* Search interface config form */ + mpic = psdFindCfgForm(pic, IFFFORM_IFCFGDATA); + while(mpic) + { + /* Found the form. Find the the ID String for the interface */ + if(pMatchStringChunk(ps, mpic, IFFCHNK_IFID, ifid)) + { + /* ID did match, now check for forced binding */ + chunk = pFindCfgChunk(ps, mpic, IFFCHNK_FORCEDBIND); + if(chunk) + { + owner = (STRPTR) &chunk[2]; + break; + } + } + mpic = psdNextCfgForm(mpic); + } + } else { + /* Search for device forced binding */ + chunk = pFindCfgChunk(ps, pic, IFFCHNK_FORCEDBIND); + if(chunk) + { + owner = (STRPTR) &chunk[2]; + break; + } + } + break; + } + pic = psdNextCfgForm(pic); + } + pUnlockSem(ps, &ps->ps_ConfigLock); + return(owner); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdAddStringChunk()" */ +AROS_LH3(BOOL, psdAddStringChunk, + AROS_LHA(struct PsdIFFContext *, pic, A0), + AROS_LHA(ULONG, chunkid, D0), + AROS_LHA(STRPTR, str, A1), + LIBBASETYPEPTR, ps, 87, psd) +{ + AROS_LIBFUNC_INIT + BOOL res; + KPRINTF(10, ("psdAddStringChunk(%08lx, %08lx, %s)\n", pic, chunkid, str)); + pLockSemExcl(ps, &ps->ps_ConfigLock); + res = pAddStringChunk(ps, pic, chunkid, str); + pUnlockSem(ps, &ps->ps_ConfigLock); + return(res); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdMatchStringChunk()" */ +AROS_LH3(BOOL, psdMatchStringChunk, + AROS_LHA(struct PsdIFFContext *, pic, A0), + AROS_LHA(ULONG, chunkid, D0), + AROS_LHA(STRPTR, str, A1), + LIBBASETYPEPTR, ps, 88, psd) +{ + AROS_LIBFUNC_INIT + BOOL res; + KPRINTF(10, ("psdMatchStringChunk(%08lx, %08lx, %s)\n", pic, chunkid, str)); + pLockSemShared(ps, &ps->ps_ConfigLock); + res = pMatchStringChunk(ps, pic, chunkid, str); + pUnlockSem(ps, &ps->ps_ConfigLock); + return(res); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* /// "psdGetStringChunk()" */ +AROS_LH2(STRPTR, psdGetStringChunk, + AROS_LHA(struct PsdIFFContext *, pic, A0), + AROS_LHA(ULONG, chunkid, D0), + LIBBASETYPEPTR, ps, 89, psd) +{ + AROS_LIBFUNC_INIT + STRPTR str; + KPRINTF(10, ("psdGetStringChunk(%08lx, %08lx)\n", pic, chunkid)); + pLockSemShared(ps, &ps->ps_ConfigLock); + str = pGetStringChunk(ps, pic, chunkid); + pUnlockSem(ps, &ps->ps_ConfigLock); + return(str); + AROS_LIBFUNC_EXIT +} +/* \\\ */ + +/* *** Configuration (non-library subroutines) *** */ + +/* /// "pAllocForm()" */ +struct PsdIFFContext * pAllocForm(LIBBASETYPEPTR ps, struct PsdIFFContext *parent, ULONG formid) +{ + struct PsdIFFContext *pic; + KPRINTF(10, ("pAllocForm(%08lx, %08lx)\n", parent, formid)); + if((pic = psdAllocVec(sizeof(struct PsdIFFContext)))) + { + NewList(&pic->pic_SubForms); + //pic->pic_Parent = parent; + pic->pic_FormID = formid; + pic->pic_FormLength = 4; + pic->pic_Chunks = NULL; + pic->pic_ChunksLen = 0; + pic->pic_BufferLen = 0; + Forbid(); + if(parent) + { + AddTail(&parent->pic_SubForms, &pic->pic_Node); + } else { + AddTail(&ps->ps_ConfigRoot, &pic->pic_Node); + } + Permit(); + } + return(pic); +} +/* \\\ */ + +/* /// "pFreeForm()" */ +void pFreeForm(LIBBASETYPEPTR ps, struct PsdIFFContext *pic) +{ + struct PsdIFFContext *subpic = (struct PsdIFFContext *) pic->pic_SubForms.lh_Head; + KPRINTF(10, ("pFreeForm(%08lx)\n", pic)); + Remove(&pic->pic_Node); + while(subpic->pic_Node.ln_Succ) + { + pFreeForm(ps, subpic); + subpic = (struct PsdIFFContext *) pic->pic_SubForms.lh_Head; + } + psdFreeVec(pic->pic_Chunks); + psdFreeVec(pic); +} +/* \\\ */ + +/* /// "pGetFormLength()" */ +ULONG pGetFormLength(struct PsdIFFContext *pic) +{ + ULONG len = (5 + pic->pic_ChunksLen) & ~1UL; + struct PsdIFFContext *subpic = (struct PsdIFFContext *) pic->pic_SubForms.lh_Head; + //KPRINTF(10, ("pGetFormLength(%08lx)\n", pic)); + while(subpic->pic_Node.ln_Succ) + { + len += pGetFormLength(subpic); + subpic = (struct PsdIFFContext *) subpic->pic_Node.ln_Succ; + } + pic->pic_FormLength = len; + //KPRINTF(10, ("FormLen=%ld\n", len+8)); + return(len + 8); +} +/* \\\ */ + +/* /// "pFindCfgChunk()" */ +APTR pFindCfgChunk(LIBBASETYPEPTR ps, struct PsdIFFContext *pic, ULONG chnkid) +{ + ULONG *buf = pic->pic_Chunks; + ULONG len = pic->pic_ChunksLen; + ULONG chlen; + KPRINTF(10, ("pFindCfgChunk(%08lx, %08lx)\n", pic, chnkid)); + + while(len) + { + if(AROS_LONG2BE(*buf) == chnkid) + { + KPRINTF(10, ("Found at %08lx\n", buf)); + return(buf); + } + chlen = (AROS_LONG2BE(buf[1]) + 9) & ~1UL; + len -= chlen; + buf = (ULONG *) (((UBYTE *) buf) + chlen); + } + KPRINTF(10, ("Not found!\n")); + return(NULL); +} +/* \\\ */ + +/* /// "pRemCfgChunk()" */ +BOOL pRemCfgChunk(LIBBASETYPEPTR ps, struct PsdIFFContext *pic, ULONG chnkid) +{ + ULONG *buf = pic->pic_Chunks; + ULONG len = pic->pic_ChunksLen; + ULONG chlen; + KPRINTF(10, ("pRemCfgChunk(%08lx, %08lx)\n", pic, chnkid)); + + while(len) + { + chlen = ((AROS_LONG2BE(buf[1])) + 9) & ~1UL; + if(AROS_LONG2BE(*buf) == chnkid) + { + len -= chlen; + if(len) + { + memcpy(buf, &((UBYTE *) buf)[chlen], (size_t) len); + } + pic->pic_ChunksLen -= chlen; + KPRINTF(10, ("Deleted %ld bytes to %ld chunk len\n", chlen, pic->pic_ChunksLen)); + return(TRUE); + } + len -= chlen; + buf = (ULONG *) (((UBYTE *) buf) + chlen); + } + KPRINTF(10, ("Not found!\n")); + return(FALSE); +} +/* \\\ */ + +/* /// "pAddCfgChunk()" */ +struct PsdIFFContext * pAddCfgChunk(LIBBASETYPEPTR ps, struct PsdIFFContext *pic, APTR chunk) +{ + LONG len; + LONG chlen; + ULONG *buf = chunk; + ULONG *newbuf; + struct PsdIFFContext *subpic; + KPRINTF(10, ("pAddCfgChunk(%08lx, %08lx)\n", pic, chunk)); + if(AROS_LONG2BE(*buf) == ID_FORM) + { + buf++; + len = ((AROS_LONG2BE(*buf)) - 3) & ~1UL; + buf++; + if((subpic = pAllocForm(ps, pic, AROS_LONG2BE(*buf)))) + { + buf++; + while(len >= 8) + { + if(!(pAddCfgChunk(ps, subpic, buf))) + { + break; + } + chlen = (AROS_LONG2BE(buf[1]) + 9) & ~1UL; + len -= chlen; + buf = (ULONG *) (((UBYTE *) buf) + chlen); + } + if(len) + { + psdAddErrorMsg0(RETURN_FAIL, (STRPTR) libname, "Tried to add a nasty corrupted FORM chunk! Configuration is probably b0rken!"); + return(NULL); + } + } else { + return(NULL); + } + return(subpic); + } else { + pRemCfgChunk(ps, pic, AROS_LONG2BE(*buf)); + len = (AROS_LONG2BE(buf[1]) + 9) & ~1UL; + if(pic->pic_ChunksLen+len > pic->pic_BufferLen) + { + KPRINTF(10, ("expanding buffer from %ld to %ld to fit %ld bytes\n", pic->pic_BufferLen, (pic->pic_ChunksLen+len)<<1, pic->pic_ChunksLen+len)); + + /* Expand buffer */ + if((newbuf = psdAllocVec((pic->pic_ChunksLen+len)<<1))) + { + if(pic->pic_ChunksLen) + { + memcpy(newbuf, pic->pic_Chunks, (size_t) pic->pic_ChunksLen); + psdFreeVec(pic->pic_Chunks); + } + pic->pic_Chunks = newbuf; + pic->pic_BufferLen = (pic->pic_ChunksLen+len)<<1; + } else { + return(NULL); + } + } + memcpy(&(((UBYTE *) pic->pic_Chunks)[pic->pic_ChunksLen]), chunk, (size_t) len); + pic->pic_ChunksLen += len; + return(pic); + } +} +/* \\\ */ + +/* /// "pInternalWriteForm()" */ +ULONG * pInternalWriteForm(struct PsdIFFContext *pic, ULONG *buf) +{ + struct PsdIFFContext *subpic = (struct PsdIFFContext *) pic->pic_SubForms.lh_Head; + //KPRINTF(10, ("pInternalWriteForm(%08lx, %08lx)", pic, buf)); + *buf++ = AROS_LONG2BE(ID_FORM); + *buf++ = AROS_LONG2BE(pic->pic_FormLength); + *buf++ = AROS_LONG2BE(pic->pic_FormID); + if(pic->pic_ChunksLen) + { + memcpy(buf, pic->pic_Chunks, (size_t) pic->pic_ChunksLen); + buf = (ULONG *) (((UBYTE *) buf) + pic->pic_ChunksLen); + } + while(subpic->pic_Node.ln_Succ) + { + buf = pInternalWriteForm(subpic, buf); + subpic = (struct PsdIFFContext *) subpic->pic_Node.ln_Succ; + } + return(buf); +} +/* \\\ */ + +/* /// "pCalcCfgCRC()" */ +ULONG pCalcCfgCRC(struct PsdIFFContext *pic) +{ + struct PsdIFFContext *subpic = (struct PsdIFFContext *) pic->pic_SubForms.lh_Head; + ULONG len; + ULONG crc = pic->pic_FormID; + UWORD *ptr; + + //KPRINTF(10, ("pInternalWriteForm(%08lx, %08lx)", pic, buf)); + if(pic->pic_ChunksLen) + { + len = pic->pic_ChunksLen>>1; + if(len) + { + ptr = (UWORD *) pic->pic_Chunks; + do + { + crc = ((crc<<1)|(crc>>31))^(*ptr++); + } while(--len); + } + } + while(subpic->pic_Node.ln_Succ) + { + crc ^= pCalcCfgCRC(subpic); + subpic = (struct PsdIFFContext *) subpic->pic_Node.ln_Succ; + } + return(crc); +} +/* \\\ */ + +/* /// "pCheckCfgChanged()" */ +BOOL pCheckCfgChanged(LIBBASETYPEPTR ps) +{ + ULONG crc; + struct PsdIFFContext *pic; + struct PsdIFFContext *subpic; + STRPTR tmpstr; + + pLockSemShared(ps, &ps->ps_ConfigLock); + ps->ps_CheckConfigReq = FALSE; + pic = (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head; + if(!(pic->pic_Node.ln_Succ)) + { + pUnlockSem(ps, &ps->ps_ConfigLock); + return(FALSE); + } + crc = pCalcCfgCRC(pic); + if(crc != ps->ps_ConfigHash) + { + ULONG *chnk; + ps->ps_ConfigHash = crc; + /* Get Global config */ + if((subpic = psdFindCfgForm(pic, IFFFORM_STACKCFG))) + { + if((chnk = pFindCfgChunk(ps, subpic, IFFCHNK_GLOBALCFG))) + { + CopyMem(&chnk[2], ((UBYTE *) ps->ps_GlobalCfg) + 8, min(AROS_LONG2BE(chnk[1]), AROS_LONG2BE(ps->ps_GlobalCfg->pgc_Length))); + } + if(!pMatchStringChunk(ps, subpic, IFFCHNK_INSERTSND, ps->ps_PoPo.po_InsertSndFile)) + { + if((tmpstr = pGetStringChunk(ps, subpic, IFFCHNK_INSERTSND))) + { + psdFreeVec(ps->ps_PoPo.po_InsertSndFile); + ps->ps_PoPo.po_InsertSndFile = tmpstr; + } + } + if(!pMatchStringChunk(ps, subpic, IFFCHNK_REMOVESND, ps->ps_PoPo.po_RemoveSndFile)) + { + if((tmpstr = pGetStringChunk(ps, subpic, IFFCHNK_REMOVESND))) + { + psdFreeVec(ps->ps_PoPo.po_RemoveSndFile); + ps->ps_PoPo.po_RemoveSndFile = tmpstr; + } + } + } + pUnlockSem(ps, &ps->ps_ConfigLock); + psdSendEvent(EHMB_CONFIGCHG, NULL, NULL); + return(TRUE); + } + pUnlockSem(ps, &ps->ps_ConfigLock); + return(FALSE); +} +/* \\\ */ + +/* /// "pAddStringChunk()" */ +BOOL pAddStringChunk(LIBBASETYPEPTR ps, struct PsdIFFContext *pic, ULONG chunkid, STRPTR str) +{ + BOOL res = FALSE; + ULONG len = strlen(str); + ULONG *chnk = (ULONG *) psdAllocVec((ULONG) len+8+2); + if(chnk) + { + chnk[0] = AROS_LONG2BE(chunkid); + chnk[1] = AROS_LONG2BE(len+1); + strcpy((STRPTR) &chnk[2], str); + if(pAddCfgChunk(ps, pic, chnk)) + { + res = TRUE; + } + psdFreeVec(chnk); + } + return(res); +} +/* \\\ */ + +/* /// "pMatchStringChunk()" */ +BOOL pMatchStringChunk(LIBBASETYPEPTR ps, struct PsdIFFContext *pic, ULONG chunkid, STRPTR str) +{ + ULONG *chunk; + ULONG len; + STRPTR srcptr; + if((chunk = pFindCfgChunk(ps, pic, chunkid))) + { + srcptr = (STRPTR) &chunk[2]; + len = AROS_LONG2BE(chunk[1]); + while(len-- && *srcptr) + { + if(*str++ != *srcptr++) + { + return(FALSE); + } + } + if(!*str) + { + return(TRUE); + } + } + return(FALSE); +} +/* \\\ */ + +/* /// "pGetStringChunk()" */ +STRPTR pGetStringChunk(LIBBASETYPEPTR ps, struct PsdIFFContext *pic, ULONG chunkid) +{ + ULONG *chunk; + STRPTR str; + if((chunk = pFindCfgChunk(ps, pic, chunkid))) + { + if((str = (STRPTR) psdAllocVec(AROS_LONG2BE(chunk[1] + 1)))) + { + memcpy(str, &chunk[2], (size_t) AROS_LONG2BE(chunk[1])); + return(str); + } + } + return(NULL); +} +/* \\\ */ + +/* /// "pUpdateGlobalCfg()" */ +void pUpdateGlobalCfg(LIBBASETYPEPTR ps, struct PsdIFFContext *pic) +{ + struct PsdIFFContext *tmppic; + /* Set Global config */ + if(pic == (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head) + { + if((tmppic = psdFindCfgForm(NULL, IFFFORM_STACKCFG))) + { + pAddCfgChunk(ps, tmppic, ps->ps_GlobalCfg); + pAddStringChunk(ps, tmppic, IFFCHNK_INSERTSND, ps->ps_PoPo.po_InsertSndFile); + pAddStringChunk(ps, tmppic, IFFCHNK_REMOVESND, ps->ps_PoPo.po_RemoveSndFile); + } + } +} +/* \\\ */ + +/* *** Misc (non library functions) ***/ + +/* /// "pGetDevConfig()" */ +BOOL pGetDevConfig(struct PsdPipe *pp) +{ + struct PsdDevice *pd = pp->pp_Device; + LIBBASETYPEPTR ps = pd->pd_Hardware->phw_Base; + UBYTE *tempbuf; + struct UsbStdCfgDesc uscd; + ULONG len; + LONG ioerr; + STRPTR classname; + UWORD curcfg = 0; + + KPRINTF(1, ("Getting configuration descriptor...\n")); + psdLockWriteDevice(pd); + while(curcfg < pd->pd_NumCfgs) + { + psdPipeSetup(pp, URTF_IN|URTF_STANDARD|URTF_DEVICE, + USR_GET_DESCRIPTOR, (UDT_CONFIGURATION<<8)|curcfg, 0); + + /*tempbuf = psdAllocVec(256); + ioerr = psdDoPipe(pp, tempbuf, 34); + if(ioerr == UHIOERR_RUNTPACKET) + { + ioerr = 0; + } + memcpy(&uscd, tempbuf, 9);*/ + ioerr = psdDoPipe(pp, &uscd, 9);//sizeof(struct UsbStdCfgDesc)); + if(!ioerr) + { + KPRINTF(1, ("Config type: %ld\n", (ULONG) uscd.bDescriptorType)); + len = (ULONG) AROS_WORD2LE(uscd.wTotalLength); + KPRINTF(1, ("Configsize %ld, total size %ld\n", (ULONG) uscd.bLength, len)); + if((tempbuf = psdAllocVec(len))) + //if(1) + { + KPRINTF(1, ("Getting whole configuration descriptor...\n")); + ioerr = psdDoPipe(pp, tempbuf, len); + if(!ioerr) + { + struct PsdConfig *pc = NULL; + struct PsdInterface *pif = NULL; + struct PsdInterface *altif = NULL; + struct PsdEndpoint *pep = NULL; + struct PsdDescriptor *pdd = NULL; + UBYTE *dbuf = tempbuf; + UBYTE *bufend; + ULONG dlen; + bufend = &dbuf[len]; + while(dbuf < bufend) + { + dlen = dbuf[0]; /* bLength */ + if(dlen < 2) + { + break; + } + if(&dbuf[dlen] > bufend) + { + psdAddErrorMsg0(RETURN_ERROR, (STRPTR) libname, "End of descriptor past buffer!"); + } + switch(dbuf[1]) /* bDescriptorType */ + { + case UDT_CONFIGURATION: + { + struct UsbStdCfgDesc *usc = (struct UsbStdCfgDesc *) dbuf; + pif = NULL; + altif = NULL; + pep = NULL; + if((pc = pAllocConfig(pd))) + { + pd->pd_Flags |= PDFF_CONFIGURED; + pc->pc_NumIfs = usc->bNumInterfaces; + pc->pc_CfgNum = usc->bConfigurationValue; + pc->pc_Attr = usc->bmAttributes; + pc->pc_MaxPower = usc->bMaxPower<<1; + + KPRINTF(1, (" Config %ld\n", pc->pc_CfgNum)); + if(usc->iConfiguration) + { + pc->pc_CfgStr = psdGetStringDescriptor(pp, usc->iConfiguration); + } + if(!pc->pc_CfgStr) + { + pc->pc_CfgStr = psdCopyStrFmt("Configuration %ld", pc->pc_CfgNum); + } + } else { + KPRINTF(20, (" Config allocation failed\n")); + } + break; + } + + case UDT_INTERFACE: + { + struct UsbStdIfDesc *usif = (struct UsbStdIfDesc *) dbuf; + pep = NULL; + if(pc) + { + if((altif = pAllocInterface(pc))) + { + altif->pif_IfNum = usif->bInterfaceNumber; + altif->pif_Alternate = usif->bAlternateSetting; + altif->pif_NumEPs = usif->bNumEndpoints; + altif->pif_IfClass = usif->bInterfaceClass; + altif->pif_IfSubClass = usif->bInterfaceSubClass; + altif->pif_IfProto = usif->bInterfaceProtocol; + KPRINTF(2, (" Interface %ld\n", altif->pif_IfNum)); + if(usif->iInterface) + { + altif->pif_IfStr = psdGetStringDescriptor(pp, usif->iInterface); + } + if(!altif->pif_IfStr) + { + classname = psdNumToStr(NTS_CLASSCODE, (LONG) altif->pif_IfClass, NULL); + if(classname) + { + altif->pif_IfStr = psdCopyStrFmt("%s interface (%ld)", classname, altif->pif_IfNum); + } else { + altif->pif_IfStr = psdCopyStrFmt("Interface %ld", altif->pif_IfNum); + } + } + KPRINTF(2, (" IfName : %s\n" + " Alternate : %ld\n" + " NumEPs : %ld\n" + " IfClass : %ld\n" + " IfSubClass: %ld\n" + " IfProto : %ld\n", + altif->pif_IfStr, altif->pif_Alternate, + altif->pif_NumEPs, + altif->pif_IfClass, + altif->pif_IfSubClass, altif->pif_IfProto)); + if(pc->pc_CfgNum == 1) + { + altif->pif_IDString = psdCopyStrFmt("%02lx-%02lx-%02lx-%02lx-%02lx", + altif->pif_IfNum, altif->pif_Alternate, + altif->pif_IfClass, altif->pif_IfSubClass, + altif->pif_IfProto); + } else { + // for more than one config, add config number (retain backwards compatibility with most devices) + altif->pif_IDString = psdCopyStrFmt("%02lx-%02lx-%02lx-%02lx-%02lx-%02lx", + pc->pc_CfgNum, + altif->pif_IfNum, altif->pif_Alternate, + altif->pif_IfClass, altif->pif_IfSubClass, + altif->pif_IfProto); + } + + /* Move the interface to the alternatives if possible */ + if(altif->pif_Alternate) + { + if(!pif) + { + psdAddErrorMsg0(RETURN_ERROR, (STRPTR) libname, "Alternate interface without prior main interface!"); + KPRINTF(20, (" Alternate interface without prior main interface\n")); + pif = altif; + } else { + Remove(&altif->pif_Node); + AddTail(&pif->pif_AlterIfs, &altif->pif_Node); + altif->pif_ParentIf = pif; + } + } else { + altif->pif_ParentIf = NULL; + pif = altif; + } + } else { + KPRINTF(20, (" Interface allocation failed\n")); + } + } else { + psdAddErrorMsg0(RETURN_ERROR, (STRPTR) libname, "Interface without prior config descriptor!"); + KPRINTF(20, (" Interface descriptor without Config\n")); + } + break; + } + + case UDT_ENDPOINT: + { + struct UsbStdEPDesc *usep = (struct UsbStdEPDesc *) dbuf; + if(altif) + { + if((pep = pAllocEndpoint(altif))) + { + STRPTR eptype; + pep->pep_EPNum = usep->bEndpointAddress & 0x0f; + pep->pep_Direction = usep->bEndpointAddress>>7; + pep->pep_TransType = usep->bmAttributes & 0x03; + pep->pep_SyncType = (usep->bmAttributes>>2) & 0x03; + pep->pep_UsageType = (usep->bmAttributes>>4) & 0x03; + eptype = (pep->pep_TransType == USEAF_INTERRUPT) ? "int" : "iso"; + + pep->pep_MaxPktSize = AROS_WORD2LE(usep->wMaxPacketSize) & 0x07ff; + pep->pep_NumTransMuFr = ((AROS_WORD2LE(usep->wMaxPacketSize)>>11) & 3) + 1; + if(pep->pep_NumTransMuFr == 4) + { + psdAddErrorMsg0(RETURN_WARN, (STRPTR) libname, "Endpoint contains illegal Num Trans µFrame value!"); + pep->pep_NumTransMuFr = 1; + } + + pep->pep_Interval = usep->bInterval; + if(pd->pd_Flags & PDFF_HIGHSPEED) + { + switch(pep->pep_TransType) + { + case USEAF_CONTROL: + case USEAF_BULK: + //pep->pep_Interval = 0; // no use here, NAK rate not of interest + break; + + case USEAF_ISOCHRONOUS: + if(pep->pep_MaxPktSize > 1024) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "Endpoint contains %s (%ld) MaxPktSize value!", + (STRPTR) "too high", pep->pep_MaxPktSize); + pep->pep_MaxPktSize = 1024; + } + + case USEAF_INTERRUPT: + if(!pep->pep_Interval) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "%sspeed %s endpoint contains %s interval value! Fixing.", + (STRPTR) "High", eptype, (STRPTR) "zero"); + pep->pep_Interval = 1; + } + else if(pep->pep_Interval > 16) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "%sspeed %s endpoint contains %s interval value! Fixing.", + (STRPTR) "High", eptype, (STRPTR) "too high"); + pep->pep_Interval = 16; + } + pep->pep_Interval = 1<<(pep->pep_Interval-1); + break; + } + } + else if(pd->pd_Flags & PDFF_LOWSPEED) + { + switch(pep->pep_TransType) + { + case USEAF_INTERRUPT: + if(pep->pep_Interval < 8) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, "%sspeed %s endpoint contains %s interval value! Fixing.", + (STRPTR) "Low", eptype, (STRPTR) "too low"); + pep->pep_Interval = 8; + } + break; + + case USEAF_CONTROL: + case USEAF_BULK: + pep->pep_Interval = 0; // no use here + break; + + case USEAF_ISOCHRONOUS: + psdAddErrorMsg0(RETURN_ERROR, (STRPTR) libname, "Lowspeed devices cannot have isochronous endpoints!"); + break; + } + } else { + switch(pep->pep_TransType) + { + case USEAF_INTERRUPT: + if(!pep->pep_Interval) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, "%sspeed %s endpoint contains %s interval value! Fixing.", + (STRPTR) "Full", eptype, (STRPTR) "zero"); + pep->pep_Interval = 1; + } + break; + + case USEAF_CONTROL: + case USEAF_BULK: + pep->pep_Interval = 0; // no use here + break; + + case USEAF_ISOCHRONOUS: + if(pep->pep_MaxPktSize > 1023) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, "Endpoint contains too high (%ld) MaxPktSize value! Fixing.", pep->pep_MaxPktSize); + pep->pep_MaxPktSize = 1023; + } + if(!pep->pep_Interval) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, "%sspeed %s endpoint contains %s interval value! Fixing.", + (STRPTR) "Full", eptype, (STRPTR) "zero"); + pep->pep_Interval = 1; + } + else if(pep->pep_Interval > 16) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, "%sspeed %s endpoint contains %s interval value! Fixing.", + (STRPTR) "Full", eptype, (STRPTR) "too high"); + pep->pep_Interval = 16; + } + pep->pep_Interval = 1<<(pep->pep_Interval-1); + break; + } + } + + KPRINTF(2, (" Endpoint %ld\n", pep->pep_EPNum)); + KPRINTF(2, (" Direction : %s\n" + " TransType : %ld\n" + " MaxPktSize: %ld\n" + " Interval : %ld\n", + (pep->pep_Direction ? "IN" : "OUT"), + pep->pep_TransType, pep->pep_MaxPktSize, + pep->pep_Interval)); + + } else { + KPRINTF(20, (" Endpoint allocation failed\n")); + } + } else { + psdAddErrorMsg0(RETURN_WARN, (STRPTR) libname, "Endpoint without prior interface descriptor!"); + KPRINTF(20, (" Endpoint descriptor without Interface\n")); + } + break; + } + + case UDT_DEVICE: + case UDT_HUB: + case UDT_HID: + case UDT_REPORT: + case UDT_PHYSICAL: + case UDT_CS_INTERFACE: + case UDT_CS_ENDPOINT: + case UDT_DEVICE_QUALIFIER: + case UDT_OTHERSPEED_QUALIFIER: + case UDT_INTERFACE_POWER: + case UDT_OTG: + //psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, "Skipping descriptor %02lx (pc=%08lx, pif=%08lx altpif=%08lx).", dbuf[1], pc, pif, altif); + KPRINTF(1, ("Skipping unknown descriptor %ld.\n", dbuf[1])); + break; + + default: + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, "Skipping unknown descriptor %02lx.", dbuf[1]); + KPRINTF(1, ("Skipping unknown descriptor %ld.\n", dbuf[1])); + break; + } + // add descriptor to device + pdd = pAllocDescriptor(pd, dbuf); + if(pdd) + { + STRPTR descname = NULL; + + pdd->pdd_Config = pc; + pdd->pdd_Interface = altif; + pdd->pdd_Endpoint = pep; + if(pdd->pdd_Interface) + { + if((pdd->pdd_Type >= UDT_CS_UNDEFINED) && (pdd->pdd_Type <= UDT_CS_ENDPOINT)) + { + descname = psdNumToStr(NTS_DESCRIPTOR, (LONG) (pdd->pdd_CSSubType<<24)|(pif->pif_IfSubClass<<16)|(pif->pif_IfClass<<8)|pdd->pdd_Type, NULL); + if(!descname) + { + descname = psdNumToStr(NTS_DESCRIPTOR, (LONG) (pdd->pdd_CSSubType<<24)|(pif->pif_IfClass<<8)|pdd->pdd_Type, NULL); + } + } + if(!descname) + { + descname = psdNumToStr(NTS_DESCRIPTOR, (LONG) (pif->pif_IfSubClass<<16)|(pif->pif_IfClass<<8)|pdd->pdd_Type, NULL); + } + if(!descname) + { + descname = psdNumToStr(NTS_DESCRIPTOR, (LONG) (pif->pif_IfClass<<8)|pdd->pdd_Type, NULL); + } + } + if(descname) + { + pdd->pdd_Name = descname; + } + } + dbuf += dlen; + } + KPRINTF(1, ("Configuration acquired!\n")); + psdFreeVec(tempbuf); + curcfg++; + continue; + //psdUnlockDevice(pd); + //return(TRUE); + } else { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "GET_DESCRIPTOR (len %ld) failed: %s (%ld)", + len, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + KPRINTF(15, ("GET_DESCRIPTOR failed %ld!\n", ioerr)); + } + psdFreeVec(tempbuf); + } else { + KPRINTF(20, ("No memory for %ld bytes config temp buffer!\n", len)); + } + } else { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "GET_DESCRIPTOR (len %ld) failed: %s (%ld)", + 9, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + KPRINTF(15, ("GET_DESCRIPTOR (9) failed %ld!\n", ioerr)); + } + psdUnlockDevice(pd); + return(FALSE); + } + psdUnlockDevice(pd); + return(TRUE); +} +/* \\\ */ + +/* /// "pPowerRecurseDrain()" */ +ULONG pPowerRecurseDrain(LIBBASETYPEPTR ps, struct PsdDevice *pd) +{ + struct PsdDevice *nextpd; + struct PsdConfig *pc; + UWORD maxdrain = 666; + UWORD childdrain; + BOOL selfpwd = TRUE; + pd->pd_PowerDrain = 0; + + /* look at config */ + if((pc = pd->pd_CurrentConfig)) + { + + /* if suspended, no more than 500µA are drained */ + if(pd->pd_Flags & PDFF_SUSPENDED) + { + pd->pd_PowerDrain = (pc->pc_MaxPower >= 100) ? 3 : 1; + return(pd->pd_PowerDrain); + } + selfpwd = ((pc->pc_Attr & USCAF_SELF_POWERED) && (pd->pd_PoPoCfg.poc_OverridePowerInfo != POCP_BUS_POWERED)) || + (pd->pd_PoPoCfg.poc_OverridePowerInfo == POCP_SELF_POWERED); + maxdrain = selfpwd ? 500 : 100; + } + + /* examine children */ + nextpd = (struct PsdDevice *) pd->pd_Hardware->phw_Devices.lh_Head; + while(nextpd->pd_Node.ln_Succ) + { + if(nextpd->pd_Hub == pd) + { + childdrain = pPowerRecurseDrain(ps, nextpd); + // limit the drain to the maximum power suckage + pd->pd_PowerDrain += (childdrain > maxdrain) ? maxdrain : childdrain; + } + nextpd = (struct PsdDevice *) nextpd->pd_Node.ln_Succ; + } + + /* look at config */ + if(selfpwd) + { + pd->pd_PowerDrain = 0; + } else { + pd->pd_PowerDrain += pc->pc_MaxPower; + } + return(pd->pd_PowerDrain); +} +/* \\\ */ + +/* /// "pPowerRecurseSupply()" */ +void pPowerRecurseSupply(LIBBASETYPEPTR ps, struct PsdDevice *pd) +{ + struct PsdDevice *nextpd; + struct PsdConfig *pc; + UWORD ports = 0; + UWORD supply = 666; + BOOL selfpwd = TRUE; + + /* look at config */ + if((pc = pd->pd_CurrentConfig)) + { + selfpwd = ((pc->pc_Attr & USCAF_SELF_POWERED) && (pd->pd_PoPoCfg.poc_OverridePowerInfo != POCP_BUS_POWERED)) || + (pd->pd_PoPoCfg.poc_OverridePowerInfo == POCP_SELF_POWERED); + } + + /* count children */ + nextpd = (struct PsdDevice *) pd->pd_Hardware->phw_Devices.lh_Head; + while(nextpd->pd_Node.ln_Succ) + { + if(nextpd->pd_Hub == pd) // this device is a child of us (we're a hub!) + { + ports++; + } + nextpd = (struct PsdDevice *) nextpd->pd_Node.ln_Succ; + } + + /* look at config */ + if(selfpwd) + { + if(pc) + { + pd->pd_PowerSupply = ports ? 500*ports + pc->pc_MaxPower : pc->pc_MaxPower; + } + supply = 500; // each downstream port gets the full monty + } else { + // the parent hub has already set the amount of supply for this port + if(pd->pd_PowerSupply >= pc->pc_MaxPower) + { + // the downstream ports get the remaining divided attention + if(ports) + { + // avoid division by zero + supply = (pd->pd_PowerSupply - pc->pc_MaxPower) / ports; + if(supply > 100) + { + // limit to 100 mA per port + supply = 100; + } + } + } else { + supply = 1; // bad luck, out of power + } + } + + /* set supply */ + if(ports) /* needs to be a hub */ + { + // propagate supply down to the children + nextpd = (struct PsdDevice *) pd->pd_Hardware->phw_Devices.lh_Head; + while(nextpd->pd_Node.ln_Succ) + { + if(nextpd->pd_Hub == pd) + { + nextpd->pd_PowerSupply = supply; + pPowerRecurseSupply(ps, nextpd); + } + nextpd = (struct PsdDevice *) nextpd->pd_Node.ln_Succ; + } + } + if(pd->pd_PowerDrain > pd->pd_PowerSupply) + { + if(!(pd->pd_Flags & PDFF_LOWPOWER)) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "Detected low power condition for '%s'.", pd->pd_ProductStr); + pd->pd_Flags |= PDFF_LOWPOWER; + psdSendEvent(EHMB_DEVICELOWPW, pd, NULL); + } + } else { + if(pd->pd_Flags & PDFF_LOWPOWER) + { + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, + "Low power condition resolved for '%s'.", pd->pd_ProductStr); + pd->pd_Flags &= ~PDFF_LOWPOWER; + } + } +} +/* \\\ */ + +/* /// "pGarbageCollectEvents()" */ +void pGarbageCollectEvents(LIBBASETYPEPTR ps) +{ + struct PsdEventNote *pen; + while((pen = (struct PsdEventNote *) GetMsg(&ps->ps_EventReplyPort))) + { + psdFreeVec(pen); + } +} +/* \\\ */ + +/* /// "pFindName()" */ +struct Node * pFindName(LIBBASETYPEPTR ps, struct List *list, STRPTR name) +{ + struct Node *res = NULL; + + Forbid(); + while(*name) + { + res = FindName(list, name); + if(res) + { + break; + } + do + { + if((*name == '/') || (*name == ':')) + { + ++name; + break; + } + } while(*(++name)); + } + Permit(); + return(res); +} +/* \\\ */ + +/* /// "pStripString()" */ +void pStripString(LIBBASETYPEPTR ps, STRPTR str) +{ + STRPTR srcptr = str; + STRPTR tarptr = str; + STRPTR lastgoodchar = str; + BOOL leadingspaces = TRUE; + UBYTE ch; + ULONG len = 0; + + while((ch = *srcptr++)) + { + len++; + if(ch == ' ') + { + if(!leadingspaces) + { + *tarptr++ = ch; + } + } else { + *tarptr++ = ch; + lastgoodchar = tarptr; + leadingspaces = FALSE; + } + } + *lastgoodchar = 0; + // empty string? + if((str == lastgoodchar) && (len > 6)) + { + strcpy(str, ""); + } +} +/* \\\ */ + +/* /// "pFixBrokenConfig()" */ +BOOL pFixBrokenConfig(struct PsdPipe *pp) +{ + struct PsdDevice *pd = pp->pp_Device; + LIBBASETYPEPTR ps = pd->pd_Hardware->phw_Base; + struct PsdConfig *pc; + struct PsdInterface *pif; + BOOL fixed = FALSE; + + switch(pd->pd_VendorID) + { + case 0x03eb: /* Atmel */ + if(pd->pd_ProductID == 0x3312) + { + psdFreeVec(pd->pd_ProductStr); + pd->pd_ProductStr = psdCopyStr("Highway/Subway Root Hub"); + } + break; + + case 0x04e6: /* E-Shuttle */ + if(pd->pd_ProductID == 0x0001) /* LS120 */ + { + pc = (struct PsdConfig *) pd->pd_Configs.lh_Head; + /* Get msd interface and fix it */ + pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head; + if(pif->pif_IfClass != MASSSTORE_CLASSCODE) + { + fixed = TRUE; + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, "Fixing broken %s interface descriptor!", (STRPTR) "E-Shuttle LS120"); + pif->pif_IfClass = MASSSTORE_CLASSCODE; + pif->pif_IfSubClass = MS_ATAPI_SUBCLASS; + pif->pif_IfProto = MS_PROTO_CB; + } + } + break; + + case 0x054C: /* Sony */ + if((pd->pd_ProductID == 0x002E) || (pd->pd_ProductID == 0x0010)) /* Handycam */ + { + fixed = TRUE; + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, "Fixing broken %s interface descriptor!", (STRPTR) "Sony MSD"); + pc = (struct PsdConfig *) pd->pd_Configs.lh_Head; + /* Get msd interface and fix it */ + pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head; + pif->pif_IfSubClass = MS_RBC_SUBCLASS; + } + break; + + case 0x057b: /* Y-E Data */ + if(pd->pd_ProductID == 0x0000) /* Flashbuster U */ + { + pc = (struct PsdConfig *) pd->pd_Configs.lh_Head; + /* Get msd interface and fix it */ + pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head; + if(pif->pif_IfClass != MASSSTORE_CLASSCODE) + { + fixed = TRUE; + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, "Fixing broken %s interface descriptor!", (STRPTR) "Y-E Data USB Floppy"); + pif->pif_IfClass = MASSSTORE_CLASSCODE; + pif->pif_IfSubClass = MS_UFI_SUBCLASS; + pif->pif_IfProto = (pd->pd_DevVers < 0x0300) ? MS_PROTO_CB : MS_PROTO_CBI; + } + } + break; + + case 0x04ce: /* ScanLogic */ + if(pd->pd_ProductID == 0x0002) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, "Fixing broken %s interface descriptor!", (STRPTR) "ScanLogic"); + pc = (struct PsdConfig *) pd->pd_Configs.lh_Head; + /* Get msd interface and fix it */ + pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head; + fixed = TRUE; + pif->pif_IfSubClass = MS_SCSI_SUBCLASS; + } + break; + + case 0x0584: /* Ratoc cardreader */ + if(pd->pd_ProductID == 0x0008) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, "Fixing broken %s interface descriptor!", (STRPTR) "RATOC"); + pc = (struct PsdConfig *) pd->pd_Configs.lh_Head; + /* Get msd interface and fix it */ + pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head; + fixed = TRUE; + pif->pif_IfClass = MASSSTORE_CLASSCODE; + pif->pif_IfSubClass = MS_SCSI_SUBCLASS; + pif->pif_IfProto = MS_PROTO_BULK; + } + break; + + case 0x04b8: /* Epson */ + if(pd->pd_ProductID == 0x0602) /* EPX Storage device (Card slot in Printer) */ + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, "Fixing broken %s interface descriptor!", (STRPTR) "Epson storage"); + pc = (struct PsdConfig *) pd->pd_Configs.lh_Head; + /* Get msd interface and fix it */ + pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head; + fixed = TRUE; + pif->pif_IfClass = MASSSTORE_CLASSCODE; + pif->pif_IfSubClass = MS_SCSI_SUBCLASS; + pif->pif_IfProto = MS_PROTO_BULK; + } + break; + + default: + break; + } + return(fixed); +} +/* \\\ */ + +/* /// "pOpenDOS()" */ +BOOL pOpenDOS(LIBBASETYPEPTR ps) +{ + if(DOSBase) + { + return TRUE; + } + if((DOSBase = OpenLibrary("dos.library", 39))) + { + return TRUE; + } + return FALSE; +} +/* \\\ */ + +/* *** Class Scan Task *** */ + +/* /// "pStartEventHandler()" */ +BOOL pStartEventHandler(LIBBASETYPEPTR ps) +{ + struct PsdHandlerTask *ph = &ps->ps_EventHandler; + + ObtainSemaphore(&ps->ps_PoPoLock); + if(ph->ph_Task) + { + ReleaseSemaphore(&ps->ps_PoPoLock); + return(TRUE); + } + ph->ph_ReadySignal = SIGB_SINGLE; + ph->ph_ReadySigTask = FindTask(NULL); + SetSignal(0, SIGF_SINGLE); // clear single bit + if(psdSpawnSubTask("Poseidon Event Broadcast", pEventHandlerTask, ps)) + { + Wait(1UL<ph_ReadySignal); + } + ph->ph_ReadySigTask = NULL; + //FreeSignal(ph->ph_ReadySignal); + if(ph->ph_Task) + { + ReleaseSemaphore(&ps->ps_PoPoLock); + psdAddErrorMsg0(RETURN_OK, (STRPTR) libname, "Event broadcaster started."); + return(TRUE); + } + ReleaseSemaphore(&ps->ps_PoPoLock); + return(FALSE); +} +/* \\\ */ + +/* *** Hardware Driver Task *** */ + +/* /// "pQuickForwardRequest()" */ +AROS_UFH1(void, pQuickForwardRequest, + AROS_UFHA(struct MsgPort *, msgport, A1)) +{ + AROS_USERFUNC_INIT + struct PsdHardware *phw = (struct PsdHardware *) msgport->mp_Node.ln_Name; + struct PsdPipe *pp; + + while((pp = (struct PsdPipe *) RemHead(&msgport->mp_MsgList))) + { + if(pp->pp_AbortPipe) + { + KPRINTF(2, ("Abort pipe %08lx\n", pp->pp_AbortPipe)); + AbortIO((struct IORequest *) &pp->pp_AbortPipe->pp_IOReq); + ReplyMsg(&pp->pp_Msg); + KPRINTF(2, ("Replying evil pipe %08lx\n", pp)); + } else { + KPRINTF(1, ("Forwarding pipe %08lx\n", pp)); + pp->pp_IOReq.iouh_UserData = pp; + SendIO((struct IORequest *) &pp->pp_IOReq); + ++phw->phw_MsgCount; + } + } + AROS_USERFUNC_EXIT +} +/* \\\ */ + +/* /// "pQuickReplyRequest()" */ +AROS_UFH1(void, pQuickReplyRequest, + AROS_UFHA(struct MsgPort *, msgport, A1)) +{ + AROS_USERFUNC_INIT + struct PsdHardware *phw = (struct PsdHardware *) msgport->mp_Node.ln_Name; + struct IOUsbHWReq *ioreq; + + while((ioreq = (struct IOUsbHWReq *) RemHead(&msgport->mp_MsgList))) + { + KPRINTF(1, ("Replying pipe %08lx\n", ioreq->iouh_UserData)); + ReplyMsg(&((struct PsdPipe *) ioreq->iouh_UserData)->pp_Msg); + --phw->phw_MsgCount; + } + AROS_USERFUNC_EXIT +} +/* \\\ */ + +/* /// "pDeviceTask()" */ +AROS_UFH0(void, pDeviceTask) +{ + AROS_USERFUNC_INIT + LIBBASETYPEPTR ps; + struct PsdHardware *phw; + struct Task *thistask; + ULONG sigs; + ULONG sigmask; + LONG ioerr; + struct TagItem taglist[11]; + struct TagItem *tag; + struct PsdPipe *pp; + struct IOUsbHWReq *ioreq; + + STRPTR prodname = NULL; + STRPTR manufacturer = NULL; + STRPTR description = NULL; + STRPTR copyright = NULL; + ULONG version = 0; + ULONG revision = 0; + ULONG driververs = 0x0100; + ULONG caps = UHCF_ISO; + STRPTR devname; + ULONG cnt; + + if(!(ps = (LIBBASETYPEPTR ) OpenLibrary("poseidon.library", 3))) + { + Alert(AG_OpenLib); + return; + } + thistask = FindTask(NULL); + SetTaskPri(thistask, 21); + phw = thistask->tc_UserData; + +#ifndef PA_CALLBACK // undocumented exec feature +#define PA_CALLBACK 3 +#endif + + phw->phw_TaskMsgPort.mp_Node.ln_Type = NT_MSGPORT; + phw->phw_TaskMsgPort.mp_Node.ln_Name = (APTR) phw; + phw->phw_TaskMsgPort.mp_Flags = PA_SIGNAL; + phw->phw_TaskMsgPort.mp_SigTask = thistask; + phw->phw_TaskMsgPort.mp_SigBit = AllocSignal(-1L); + NewList(&phw->phw_TaskMsgPort.mp_MsgList); + + phw->phw_DevMsgPort.mp_Node.ln_Type = NT_MSGPORT; + phw->phw_DevMsgPort.mp_Node.ln_Name = (APTR) phw; + phw->phw_DevMsgPort.mp_Flags = PA_SIGNAL; + phw->phw_DevMsgPort.mp_SigTask = thistask; + phw->phw_DevMsgPort.mp_SigBit = AllocSignal(-1L); + NewList(&phw->phw_DevMsgPort.mp_MsgList); + + if((phw->phw_RootIOReq = (struct IOUsbHWReq *) CreateIORequest(&phw->phw_DevMsgPort, sizeof(struct IOUsbHWReq)))) + { + devname = phw->phw_DevName; + ioerr = -1; + while(*devname) + { + if(!(ioerr = OpenDevice(devname, phw->phw_Unit, (struct IORequest *) phw->phw_RootIOReq, 0))) + { + break; + } + do + { + if((*devname == '/') || (*devname == ':')) + { + ++devname; + break; + } + } while(*(++devname)); + } + + if(!ioerr) + { + phw->phw_Node.ln_Name = phw->phw_RootIOReq->iouh_Req.io_Device->dd_Library.lib_Node.ln_Name; + tag = taglist; + tag->ti_Tag = UHA_ProductName; + tag->ti_Data = (ULONG) &prodname; + ++tag; + tag->ti_Tag = UHA_Manufacturer; + tag->ti_Data = (ULONG) &manufacturer; + ++tag; + tag->ti_Tag = UHA_Description; + tag->ti_Data = (ULONG) &description; + ++tag; + tag->ti_Tag = UHA_Version; + tag->ti_Data = (ULONG) &version; + ++tag; + tag->ti_Tag = UHA_Revision; + tag->ti_Data = (ULONG) &revision; + ++tag; + tag->ti_Tag = UHA_Copyright; + tag->ti_Data = (ULONG) ©right; + ++tag; + tag->ti_Tag = UHA_DriverVersion; + tag->ti_Data = (ULONG) &driververs; + ++tag; + tag->ti_Tag = UHA_Capabilities; + tag->ti_Data = (ULONG) ∩︀ + ++tag; + tag->ti_Tag = TAG_END; + phw->phw_RootIOReq->iouh_Data = taglist; + phw->phw_RootIOReq->iouh_Req.io_Command = UHCMD_QUERYDEVICE; + DoIO((struct IORequest *) phw->phw_RootIOReq); + + phw->phw_ProductName = psdCopyStr(prodname ? prodname : (STRPTR) "n/a"); + phw->phw_Manufacturer = psdCopyStr(manufacturer ? manufacturer : (STRPTR) "n/a"); + phw->phw_Description = psdCopyStr(description ? description : (STRPTR) "n/a"); + phw->phw_Copyright = psdCopyStr(copyright ? copyright : (STRPTR) "n/a"); + phw->phw_Version = version; + phw->phw_Revision = revision; + phw->phw_DriverVers = driververs; + phw->phw_Capabilities = caps; + + sigmask = SIGBREAKF_CTRL_C; + if(caps & UHCF_QUICKIO) + { + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, "Enabling QuickIO for %s.", prodname); + phw->phw_TaskMsgPort.mp_Flags = PA_CALLBACK; + phw->phw_TaskMsgPort.mp_SigTask = (APTR) pQuickForwardRequest; + + phw->phw_DevMsgPort.mp_Flags = PA_CALLBACK; + phw->phw_DevMsgPort.mp_SigTask = (APTR) pQuickReplyRequest; + } else { + sigmask |= (1UL<phw_DevMsgPort.mp_SigBit)|(1UL<phw_TaskMsgPort.mp_SigBit); + } + + KPRINTF(10, ("%s ready!\n", thistask->tc_Node.ln_Name)); + phw->phw_Task = thistask; + + psdLockWritePBase(); + AddTail(&ps->ps_Hardware, &phw->phw_Node); + psdUnlockPBase(); + + Forbid(); + if(phw->phw_ReadySigTask) + { + Signal(phw->phw_ReadySigTask, 1L<phw_ReadySignal); + } + Permit(); + do + { + KPRINTF(1, ("Main loop wait.\n")); + while((pp = (struct PsdPipe *) GetMsg(&phw->phw_TaskMsgPort))) + { + if(pp->pp_AbortPipe) + { + KPRINTF(2, ("Abort pipe %08lx\n", pp->pp_AbortPipe)); + AbortIO((struct IORequest *) &pp->pp_AbortPipe->pp_IOReq); + ReplyMsg(&pp->pp_Msg); + KPRINTF(2, ("Replying evil pipe %08lx\n", pp)); + } else { + KPRINTF(1, ("Forwarding pipe %08lx\n", pp)); + pp->pp_IOReq.iouh_UserData = pp; + SendIO((struct IORequest *) &pp->pp_IOReq); + ++phw->phw_MsgCount; + } + } + while((ioreq = (struct IOUsbHWReq *) GetMsg(&phw->phw_DevMsgPort))) + { + KPRINTF(1, ("Replying pipe %08lx\n", ioreq->iouh_UserData)); + ReplyMsg(&((struct PsdPipe *) ioreq->iouh_UserData)->pp_Msg); + --phw->phw_MsgCount; + } + sigs = Wait(sigmask); + } while(!(sigs & SIGBREAKF_CTRL_C)); + /* Flush all pending IO Requests */ + phw->phw_RootIOReq->iouh_Req.io_Command = CMD_FLUSH; + DoIO((struct IORequest *) phw->phw_RootIOReq); + cnt = 0; + while(phw->phw_MsgCount) + { + KPRINTF(20, ("Still %ld iorequests pending!\n", msgcount)); + psdDelayMS(100); + if(++cnt == 50) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "There are still %ld IORequests pending, before unit can go down. Driver buggy?", + phw->phw_MsgCount); + } + if(cnt == 300) + { + psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, + "Okay, I've waited long enough, sod these %ld IORequests.", + phw->phw_MsgCount); + phw->phw_MsgCount = 0; + break; + } + while((ioreq = (struct IOUsbHWReq *) GetMsg(&phw->phw_DevMsgPort))) + { + KPRINTF(1, ("Replying pipe %08lx\n", ioreq->iouh_UserData)); + ReplyMsg(&((struct PsdPipe *) ioreq->iouh_UserData)->pp_Msg); + --phw->phw_MsgCount; + } + } + psdLockWritePBase(); + Remove(&phw->phw_Node); + psdUnlockPBase(); + CloseDevice((struct IORequest *) phw->phw_RootIOReq); + } else { + psdAddErrorMsg(RETURN_FAIL, (STRPTR) libname, + "Opening %s unit %ld failed %s (%ld).", + phw->phw_DevName, phw->phw_Unit, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr); + } + DeleteIORequest((struct IORequest *) phw->phw_RootIOReq); + phw->phw_RootIOReq = NULL; + } + FreeSignal((LONG) phw->phw_TaskMsgPort.mp_SigBit); + FreeSignal((LONG) phw->phw_DevMsgPort.mp_SigBit); + + CloseLibrary((struct Library *) ps); + phw->phw_Task = NULL; + + Forbid(); + if(phw->phw_ReadySigTask) + { + Signal(phw->phw_ReadySigTask, 1L<phw_ReadySignal); + } + AROS_USERFUNC_EXIT +} +/* \\\ */ + +/* /// "pEventHandlerTask()" */ +AROS_UFH0(void, pEventHandlerTask) +{ + AROS_USERFUNC_INIT + LIBBASETYPEPTR ps; + struct Task *thistask; + struct timeval currtime; + ULONG sigs; + ULONG sigmask; + struct PsdUsbClass *puc; + struct PsdHandlerTask *ph; + struct PsdEventNote *pen; + ULONG counter; + ULONG cfgchanged; + + thistask = FindTask(NULL); + ps = thistask->tc_UserData; + ph = &ps->ps_EventHandler; + SetTaskPri(thistask, 0); + + if((ph->ph_MsgPort = CreateMsgPort())) + { + if((ph->ph_TimerMsgPort = CreateMsgPort())) + { + if((ph->ph_TimerIOReq = (struct timerequest *) CreateIORequest(ph->ph_TimerMsgPort, sizeof(struct timerequest)))) + { + if(!(OpenDevice("timer.device", UNIT_VBLANK, (struct IORequest *) ph->ph_TimerIOReq, 0))) + { + ph->ph_TimerIOReq->tr_node.io_Message.mn_Node.ln_Type = NT_REPLYMSG; + ph->ph_TimerIOReq->tr_node.io_Message.mn_Node.ln_Name = "EventHandler"; + ph->ph_TimerIOReq->tr_node.io_Command = TR_ADDREQUEST; + + ph->ph_EventHandler = psdAddEventHandler(ph->ph_MsgPort, EHMF_CONFIGCHG); + if(ph->ph_EventHandler) + { + ph->ph_Task = thistask; + Forbid(); + if(ph->ph_ReadySigTask) + { + Signal(ph->ph_ReadySigTask, 1L<ph_ReadySignal); + } + Permit(); + + ph->ph_TimerIOReq->tr_time.tv_micro = 500*1000; + SendIO(&ph->ph_TimerIOReq->tr_node); + sigmask = (1UL<ph_MsgPort->mp_SigBit)|(1UL<ph_TimerMsgPort->mp_SigBit)|SIGBREAKF_CTRL_C; + counter = 0; + cfgchanged = 0; + do + { + if(ps->ps_CheckConfigReq) + { + pCheckCfgChanged(ps); + } + while((pen = (struct PsdEventNote *) GetMsg(ph->ph_MsgPort))) + { + switch(pen->pen_Event) + { + case EHMB_CONFIGCHG: + if(!cfgchanged) + { + cfgchanged = counter; + } + break; + + } + ReplyMsg(&pen->pen_Msg); + } + if(CheckIO(&ph->ph_TimerIOReq->tr_node)) + { + BOOL startpopo; + WaitIO(&ph->ph_TimerIOReq->tr_node); + ph->ph_TimerIOReq->tr_time.tv_micro = 500*1000; + SendIO(&ph->ph_TimerIOReq->tr_node); + counter++; + startpopo = !((counter & 3) || ps->ps_PoPo.po_Task); + if((ps->ps_GlobalCfg->pgc_PopupDeviceNew == PGCP_NEVER) && + (!ps->ps_GlobalCfg->pgc_PopupDeviceDeath) && + (!ps->ps_GlobalCfg->pgc_PopupDeviceGone)) + { + startpopo = FALSE; // no need to start popo, no windows wanted + } + if(startpopo) + { + struct PsdPoPo *po = &ps->ps_PoPo; + + po->po_ReadySignal = SIGB_SINGLE; + po->po_ReadySigTask = FindTask(NULL); + SetSignal(0, SIGF_SINGLE); // clear single bit + if(psdSpawnSubTask("PoPo (Poseidon Popups)", pPoPoGUITask, ps)) + { + Wait(1UL<po_ReadySignal); + } + po->po_ReadySigTask = NULL; + //FreeSignal(po->po_ReadySignal); + if(po->po_Task) + { + psdAddErrorMsg0(RETURN_OK, (STRPTR) libname, "PoPo kicks ass."); + } + } + if((cfgchanged + 2) == counter) + { + KPRINTF(10, ("Sending information about config changed to all classes.\n")); + /* Inform all classes */ + psdLockReadPBase(); + puc = (struct PsdUsbClass *) ps->ps_Classes.lh_Head; + while(puc->puc_Node.ln_Succ) + { + usbDoMethod(UCM_ConfigChangedEvent); + puc = (struct PsdUsbClass *) puc->puc_Node.ln_Succ; + } + psdUnlockPBase(); + cfgchanged = 0; + } + // power saving stuff, check every second + if((counter & 1) && ps->ps_GlobalCfg->pgc_PowerSaving) + { + struct PsdDevice *pd = NULL; + struct PsdInterface *pif; + GetSysTime((APTR) &currtime); + while((pd = psdGetNextDevice(pd))) + { + if((pd->pd_DevClass != HUB_CLASSCODE) && + ((pd->pd_Flags & (PDFF_CONFIGURED|PDFF_DEAD|PDFF_SUSPENDED|PDFF_APPBINDING|PDFF_DELEXPUNGE)) == PDFF_CONFIGURED)) + { + if(pd->pd_LastActivity.tv_secs && ((currtime.tv_secs - pd->pd_LastActivity.tv_secs) > ps->ps_GlobalCfg->pgc_SuspendTimeout)) + { + BOOL doit = TRUE; + IPTR suspendable; + if(!((pd->pd_CurrentConfig->pc_Attr & USCAF_REMOTE_WAKEUP) && ps->ps_GlobalCfg->pgc_ForceSuspend)) + { + if(pd->pd_DevBinding && ((puc = pd->pd_ClsBinding))) + { + suspendable = 0; + usbGetAttrs(UGA_CLASS, NULL, UCCA_SupportsSuspend, &suspendable, TAG_END); + if(!suspendable) + { + doit = FALSE; + } + } + pif = (struct PsdInterface *) pd->pd_CurrentConfig->pc_Interfaces.lh_Head; + while(pif->pif_Node.ln_Succ) + { + if(pif->pif_IfBinding && ((puc = pif->pif_ClsBinding))) + { + suspendable = 0; + usbGetAttrs(UGA_CLASS, NULL, UCCA_SupportsSuspend, &suspendable, TAG_END); + if(!suspendable) + { + doit = FALSE; + break; + } + } + pif = (struct PsdInterface *) pif->pif_Node.ln_Succ; + } + } + if(doit) + { + psdAddErrorMsg(RETURN_OK, (STRPTR) libname, "Suspending '%s'.", pd->pd_ProductStr); + psdSuspendDevice(pd); + } + pd->pd_LastActivity.tv_secs = 0; + } + } + } + } + } + sigs = Wait(sigmask); + } while(!(sigs & SIGBREAKF_CTRL_C)); + psdRemEventHandler(ph->ph_EventHandler); + ph->ph_EventHandler = NULL; + AbortIO(&ph->ph_TimerIOReq->tr_node); + WaitIO(&ph->ph_TimerIOReq->tr_node); + } + CloseDevice((struct IORequest *) ph->ph_TimerIOReq); + } + DeleteIORequest((struct IORequest *) ph->ph_TimerIOReq); + } + DeleteMsgPort(ph->ph_TimerMsgPort); + } + DeleteMsgPort(ph->ph_MsgPort); + ph->ph_MsgPort = NULL; + } + Forbid(); + ph->ph_Task = NULL; + if(ph->ph_ReadySigTask) + { + Signal(ph->ph_ReadySigTask, 1L<ph_ReadySignal); + } + AROS_USERFUNC_EXIT +} +/* \\\ */ + +/*****************************************************************/ + +/* /// "Packtables for psdGetAttrs() and psdSetAttrs() " */ +/* Pack table for PsdBase */ +static const ULONG PsdBasePT[] = +{ + PACK_STARTTABLE(PA_Dummy), + PACK_ENTRY(PA_Dummy, PA_ConfigRead, PsdBase, ps_ConfigRead, PKCTRL_UWORD|PKCTRL_PACKUNPACK), + PACK_ENTRY(PA_Dummy, PA_GlobalConfig, PsdBase, ps_GlobalCfg, PKCTRL_ULONG|PKCTRL_UNPACKONLY), + PACK_ENTRY(PA_Dummy, PA_MemPoolUsage, PsdBase, ps_MemAllocated, PKCTRL_ULONG|PKCTRL_UNPACKONLY), + PACK_ENTRY(PA_Dummy, PA_CurrConfigHash, PsdBase, ps_ConfigHash, PKCTRL_ULONG|PKCTRL_UNPACKONLY), + PACK_ENTRY(PA_Dummy, PA_SavedConfigHash, PsdBase, ps_SavedConfigHash, PKCTRL_ULONG|PKCTRL_PACKUNPACK), + PACK_ENTRY(PA_Dummy, PA_ReleaseVersion, PsdBase, ps_ReleaseVersion, PKCTRL_ULONG|PKCTRL_UNPACKONLY), + PACK_ENTRY(PA_Dummy, PA_OSVersion, PsdBase, ps_OSVersion, PKCTRL_ULONG|PKCTRL_UNPACKONLY), + PACK_ENDTABLE +}; + +/* Pack table for PsdErrorMsg */ +static const ULONG PsdErrorMsgPT[] = +{ + PACK_STARTTABLE(EMA_Dummy), + PACK_ENTRY(EMA_Dummy, EMA_Level, PsdErrorMsg, pem_Level, PKCTRL_UWORD|PKCTRL_UNPACKONLY), + PACK_ENTRY(EMA_Dummy, EMA_Origin, PsdErrorMsg, pem_Origin, PKCTRL_ULONG|PKCTRL_UNPACKONLY), + PACK_ENTRY(EMA_Dummy, EMA_Msg, PsdErrorMsg, pem_Msg, PKCTRL_ULONG|PKCTRL_UNPACKONLY), + PACK_ENDTABLE +}; + +/* Pack table for PsdUsbClass */ +static const ULONG PsdUsbClassPT[] = +{ + PACK_STARTTABLE(UCA_Dummy), + PACK_ENTRY(UCA_Dummy, UCA_ClassBase, PsdUsbClass, puc_ClassBase, PKCTRL_ULONG|PKCTRL_UNPACKONLY), + PACK_ENTRY(UCA_Dummy, UCA_ClassName, PsdUsbClass, puc_ClassName, PKCTRL_ULONG|PKCTRL_UNPACKONLY), + PACK_ENTRY(UCA_Dummy, UCA_FullPath, PsdUsbClass, puc_FullPath, PKCTRL_ULONG|PKCTRL_UNPACKONLY), + PACK_ENTRY(UCA_Dummy, UCA_UseCount, PsdUsbClass, puc_UseCnt, PKCTRL_UWORD|PKCTRL_UNPACKONLY), + PACK_ENDTABLE +}; + +/* Pack table for PsdHardware */ +static const ULONG PsdHardwarePT[] = +{ + PACK_STARTTABLE(HA_Dummy), + PACK_ENTRY(HA_Dummy, HA_DeviceName, PsdHardware, phw_DevName, PKCTRL_ULONG|PKCTRL_UNPACKONLY), + PACK_ENTRY(HA_Dummy, HA_DeviceUnit, PsdHardware, phw_Unit, PKCTRL_ULONG|PKCTRL_UNPACKONLY), + PACK_ENTRY(HA_Dummy, HA_ProductName, PsdHardware, phw_ProductName, PKCTRL_ULONG|PKCTRL_UNPACKONLY), + PACK_ENTRY(HA_Dummy, HA_Manufacturer, PsdHardware, phw_Manufacturer, PKCTRL_ULONG|PKCTRL_UNPACKONLY), + PACK_ENTRY(HA_Dummy, HA_Description, PsdHardware, phw_Description, PKCTRL_ULONG|PKCTRL_UNPACKONLY), + PACK_ENTRY(HA_Dummy, HA_Copyright, PsdHardware, phw_Copyright, PKCTRL_ULONG|PKCTRL_UNPACKONLY), + PACK_ENTRY(HA_Dummy, HA_Version, PsdHardware, phw_Version, PKCTRL_UWORD|PKCTRL_UNPACKONLY), + PACK_ENTRY(HA_Dummy, HA_Revision, PsdHardware, phw_Revision, PKCTRL_UWORD|PKCTRL_UNPACKONLY), + PACK_ENTRY(HA_Dummy, HA_DriverVersion, PsdHardware, phw_DriverVers, PKCTRL_UWORD|PKCTRL_UNPACKONLY), + PACK_ENDTABLE +}; + +/* Pack table for PsdDevice */ +static const ULONG PsdDevicePT[] = +{ + PACK_STARTTABLE(DA_Dummy), + PACK_ENTRY(DA_Dummy, DA_Address, PsdDevice, pd_DevAddr, PKCTRL_UWORD|PKCTRL_UNPACKONLY), + PACK_ENTRY(DA_Dummy, DA_NumConfigs, PsdDevice, pd_NumCfgs, PKCTRL_UWORD|PKCTRL_UNPACKONLY), + PACK_ENTRY(DA_Dummy, DA_CurrConfig, PsdDevice, pd_CurrCfg, PKCTRL_UWORD|PKCTRL_UNPACKONLY), + PACK_ENTRY(DA_Dummy, DA_Config, PsdDevice, pd_CurrentConfig, PKCTRL_ULONG|PKCTRL_UNPACKONLY), + PACK_ENTRY(DA_Dummy, DA_HubDevice, PsdDevice, pd_Hub, PKCTRL_ULONG|PKCTRL_PACKUNPACK), + PACK_ENTRY(DA_Dummy, DA_UsbVersion, PsdDevice, pd_USBVers, PKCTRL_UWORD|PKCTRL_UNPACKONLY), + PACK_ENTRY(DA_Dummy, DA_Class, PsdDevice, pd_DevClass, PKCTRL_WORD|PKCTRL_UNPACKONLY), + PACK_ENTRY(DA_Dummy, DA_SubClass, PsdDevice, pd_DevSubClass, PKCTRL_WORD|PKCTRL_UNPACKONLY), + PACK_ENTRY(DA_Dummy, DA_Protocol, PsdDevice, pd_DevProto, PKCTRL_UWORD|PKCTRL_UNPACKONLY), + PACK_ENTRY(DA_Dummy, DA_VendorID, PsdDevice, pd_VendorID, PKCTRL_UWORD|PKCTRL_UNPACKONLY), + PACK_ENTRY(DA_Dummy, DA_MaxPktSize0, PsdDevice, pd_MaxPktSize0, PKCTRL_UWORD|PKCTRL_UNPACKONLY), + PACK_ENTRY(DA_Dummy, DA_ProductID, PsdDevice, pd_ProductID, PKCTRL_UWORD|PKCTRL_UNPACKONLY), + PACK_ENTRY(DA_Dummy, DA_Version, PsdDevice, pd_DevVers, PKCTRL_UWORD|PKCTRL_UNPACKONLY), + PACK_ENTRY(DA_Dummy, DA_Manufacturer, PsdDevice, pd_MnfctrStr, PKCTRL_ULONG|PKCTRL_UNPACKONLY), + PACK_ENTRY(DA_Dummy, DA_ProductName, PsdDevice, pd_ProductStr, PKCTRL_ULONG|PKCTRL_PACKUNPACK), + PACK_ENTRY(DA_Dummy, DA_OrigProductName, PsdDevice, pd_OldProductStr, PKCTRL_ULONG|PKCTRL_UNPACKONLY), + PACK_ENTRY(DA_Dummy, DA_SerialNumber, PsdDevice, pd_SerNumStr, PKCTRL_ULONG|PKCTRL_UNPACKONLY), + PACK_ENTRY(DA_Dummy, DA_Hardware, PsdDevice, pd_Hardware, PKCTRL_ULONG|PKCTRL_UNPACKONLY), + PACK_ENTRY(DA_Dummy, DA_Binding, PsdDevice, pd_DevBinding, PKCTRL_ULONG|PKCTRL_PACKUNPACK), + PACK_ENTRY(DA_Dummy, DA_BindingClass, PsdDevice, pd_ClsBinding, PKCTRL_ULONG|PKCTRL_PACKUNPACK), + PACK_ENTRY(DA_Dummy, DA_LangIDArray, PsdDevice, pd_LangIDArray, PKCTRL_ULONG|PKCTRL_UNPACKONLY), + PACK_ENTRY(DA_Dummy, DA_CurrLangID, PsdDevice, pd_CurrLangID, PKCTRL_UWORD|PKCTRL_PACKUNPACK), + PACK_ENTRY(DA_Dummy, DA_IDString, PsdDevice, pd_IDString, PKCTRL_ULONG|PKCTRL_UNPACKONLY), + PACK_ENTRY(DA_Dummy, DA_CloneCount, PsdDevice, pd_CloneCount, PKCTRL_ULONG|PKCTRL_UNPACKONLY), + PACK_ENTRY(DA_Dummy, DA_AtHubPortNumber, PsdDevice, pd_HubPort, PKCTRL_UWORD|PKCTRL_PACKUNPACK), + PACK_ENTRY(DA_Dummy, DA_PowerDrained, PsdDevice, pd_PowerDrain, PKCTRL_UWORD|PKCTRL_UNPACKONLY), + PACK_ENTRY(DA_Dummy, DA_PowerSupply, PsdDevice, pd_PowerSupply, PKCTRL_UWORD|PKCTRL_UNPACKONLY), + PACK_ENTRY(DA_Dummy, DA_IsNewToMe, PsdDevice, pd_IsNewToMe, PKCTRL_UWORD|PKCTRL_UNPACKONLY), + PACK_ENTRY(DA_Dummy, DA_InhibitPopup, PsdDevice, pd_PoPoCfg.poc_InhibitPopup, PKCTRL_UWORD|PKCTRL_PACKUNPACK), + PACK_ENTRY(DA_Dummy, DA_InhibitClassBind, PsdDevice, pd_PoPoCfg.poc_NoClassBind, PKCTRL_UWORD|PKCTRL_PACKUNPACK), + PACK_ENTRY(DA_Dummy, DA_OverridePowerInfo, PsdDevice, pd_PoPoCfg.poc_OverridePowerInfo, PKCTRL_UWORD|PKCTRL_PACKUNPACK), + PACK_ENTRY(DA_Dummy, DA_HubThinkTime, PsdDevice, pd_HubThinkTime, PKCTRL_UWORD|PKCTRL_PACKUNPACK), + PACK_WORDBIT(DA_Dummy, DA_IsLowspeed, PsdDevice, pd_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PDFF_LOWSPEED), + PACK_WORDBIT(DA_Dummy, DA_IsHighspeed, PsdDevice, pd_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PDFF_HIGHSPEED), + PACK_WORDBIT(DA_Dummy, DA_IsConnected, PsdDevice, pd_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PDFF_CONNECTED), + PACK_WORDBIT(DA_Dummy, DA_HasAddress, PsdDevice, pd_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PDFF_HASDEVADDR), + PACK_WORDBIT(DA_Dummy, DA_HasDevDesc, PsdDevice, pd_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PDFF_HASDEVDESC), + PACK_WORDBIT(DA_Dummy, DA_IsConfigured, PsdDevice, pd_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PDFF_CONFIGURED), + PACK_WORDBIT(DA_Dummy, DA_IsDead, PsdDevice, pd_Flags, PKCTRL_BIT|PKCTRL_UNPACKONLY, PDFF_DEAD), + PACK_WORDBIT(DA_Dummy, DA_IsSuspended, PsdDevice, pd_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PDFF_SUSPENDED), + PACK_WORDBIT(DA_Dummy, DA_HasAppBinding, PsdDevice, pd_Flags, PKCTRL_BIT|PKCTRL_UNPACKONLY, PDFF_APPBINDING), + PACK_WORDBIT(DA_Dummy, DA_NeedsSplitTrans, PsdDevice, pd_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PDFF_NEEDSSPLIT), + PACK_WORDBIT(DA_Dummy, DA_LowPower, PsdDevice, pd_Flags, PKCTRL_BIT|PKCTRL_UNPACKONLY, PDFF_LOWPOWER), + PACK_ENDTABLE +}; + +/* Pack table for PsdConfig */ +static const ULONG PsdConfigPT[] = +{ + PACK_STARTTABLE(CA_Dummy), + PACK_ENTRY(CA_Dummy, CA_ConfigNum, PsdConfig, pc_CfgNum, PKCTRL_UWORD|PKCTRL_UNPACKONLY), + PACK_ENTRY(CA_Dummy, CA_MaxPower, PsdConfig, pc_MaxPower, PKCTRL_UWORD|PKCTRL_UNPACKONLY), + PACK_ENTRY(CA_Dummy, CA_ConfigName, PsdConfig, pc_CfgStr, PKCTRL_ULONG|PKCTRL_UNPACKONLY), + PACK_ENTRY(CA_Dummy, CA_NumInterfaces, PsdConfig, pc_NumIfs, PKCTRL_UWORD|PKCTRL_UNPACKONLY), + PACK_ENTRY(CA_Dummy, CA_Attrs, PsdConfig, pc_Attr, PKCTRL_UWORD|PKCTRL_UNPACKONLY), + PACK_ENTRY(CA_Dummy, CA_Device, PsdConfig, pc_Device, PKCTRL_ULONG|PKCTRL_UNPACKONLY), + PACK_WORDBIT(CA_Dummy, CA_SelfPowered, PsdConfig, pc_Attr, PKCTRL_BIT|PKCTRL_PACKUNPACK, USCAF_SELF_POWERED), + PACK_WORDBIT(CA_Dummy, CA_RemoteWakeup, PsdConfig, pc_Attr, PKCTRL_BIT|PKCTRL_UNPACKONLY, USCAF_REMOTE_WAKEUP), + PACK_ENDTABLE +}; + +/* Pack table for PsdDescriptor */ +static const ULONG PsdDescriptorPT[] = +{ + PACK_STARTTABLE(DDA_Dummy), + PACK_ENTRY(DDA_Dummy, DDA_Device, PsdDescriptor, pdd_Device, PKCTRL_ULONG|PKCTRL_UNPACKONLY), + PACK_ENTRY(DDA_Dummy, DDA_Config, PsdDescriptor, pdd_Config, PKCTRL_ULONG|PKCTRL_UNPACKONLY), + PACK_ENTRY(DDA_Dummy, DDA_Interface, PsdDescriptor, pdd_Interface, PKCTRL_ULONG|PKCTRL_UNPACKONLY), + PACK_ENTRY(DDA_Dummy, DDA_Endpoint, PsdDescriptor, pdd_Endpoint, PKCTRL_ULONG|PKCTRL_UNPACKONLY), + PACK_ENTRY(DDA_Dummy, DDA_Name, PsdDescriptor, pdd_Name, PKCTRL_ULONG|PKCTRL_UNPACKONLY), + PACK_ENTRY(DDA_Dummy, DDA_DescriptorType, PsdDescriptor, pdd_Type, PKCTRL_UWORD|PKCTRL_UNPACKONLY), + PACK_ENTRY(DDA_Dummy, DDA_CS_SubType, PsdDescriptor, pdd_CSSubType, PKCTRL_UWORD|PKCTRL_UNPACKONLY), + PACK_ENTRY(DDA_Dummy, DDA_DescriptorData, PsdDescriptor, pdd_Data, PKCTRL_ULONG|PKCTRL_UNPACKONLY), + PACK_ENTRY(DDA_Dummy, DDA_DescriptorLength, PsdDescriptor, pdd_Length, PKCTRL_UWORD|PKCTRL_UNPACKONLY), + PACK_ENDTABLE +}; + +/* Pack table for PsdInterface */ +static const ULONG PsdInterfacePT[] = +{ + PACK_STARTTABLE(IFA_Dummy), + PACK_ENTRY(IFA_Dummy, IFA_InterfaceNum, PsdInterface, pif_IfNum, PKCTRL_UWORD|PKCTRL_UNPACKONLY), + PACK_ENTRY(IFA_Dummy, IFA_AlternateNum, PsdInterface, pif_Alternate, PKCTRL_UWORD|PKCTRL_UNPACKONLY), + PACK_ENTRY(IFA_Dummy, IFA_NumEndpoints, PsdInterface, pif_NumEPs, PKCTRL_UWORD|PKCTRL_UNPACKONLY), + PACK_ENTRY(IFA_Dummy, IFA_Class, PsdInterface, pif_IfClass, PKCTRL_UWORD|PKCTRL_UNPACKONLY), + PACK_ENTRY(IFA_Dummy, IFA_SubClass, PsdInterface, pif_IfSubClass, PKCTRL_UWORD|PKCTRL_UNPACKONLY), + PACK_ENTRY(IFA_Dummy, IFA_Protocol, PsdInterface, pif_IfProto, PKCTRL_UWORD|PKCTRL_UNPACKONLY), + PACK_ENTRY(IFA_Dummy, IFA_InterfaceName, PsdInterface, pif_IfStr, PKCTRL_ULONG|PKCTRL_UNPACKONLY), + PACK_ENTRY(IFA_Dummy, IFA_Config, PsdInterface, pif_Config, PKCTRL_ULONG|PKCTRL_UNPACKONLY), + PACK_ENTRY(IFA_Dummy, IFA_Binding, PsdInterface, pif_IfBinding, PKCTRL_ULONG|PKCTRL_PACKUNPACK), + PACK_ENTRY(IFA_Dummy, IFA_BindingClass, PsdInterface, pif_ClsBinding, PKCTRL_ULONG|PKCTRL_PACKUNPACK), + PACK_ENTRY(IFA_Dummy, IFA_IDString, PsdInterface, pif_IDString, PKCTRL_ULONG|PKCTRL_UNPACKONLY), + PACK_ENDTABLE +}; + +/* Pack table for PsdEndpoint */ +static const ULONG PsdEndpointPT[] = +{ + PACK_STARTTABLE(EA_Dummy), + PACK_ENTRY(EA_Dummy, EA_EndpointNum, PsdEndpoint, pep_EPNum, PKCTRL_UWORD|PKCTRL_UNPACKONLY), + PACK_ENTRY(EA_Dummy, EA_TransferType, PsdEndpoint, pep_TransType, PKCTRL_UWORD|PKCTRL_UNPACKONLY), + PACK_ENTRY(EA_Dummy, EA_MaxPktSize, PsdEndpoint, pep_MaxPktSize, PKCTRL_UWORD|PKCTRL_UNPACKONLY), + PACK_ENTRY(EA_Dummy, EA_Interval, PsdEndpoint, pep_Interval, PKCTRL_UWORD|PKCTRL_UNPACKONLY), + PACK_ENTRY(EA_Dummy, EA_NumTransMuFrame, PsdEndpoint, pep_NumTransMuFr, PKCTRL_UWORD|PKCTRL_UNPACKONLY), + PACK_ENTRY(EA_Dummy, EA_SyncType, PsdEndpoint, pep_SyncType, PKCTRL_UWORD|PKCTRL_UNPACKONLY), + PACK_ENTRY(EA_Dummy, EA_UsageType, PsdEndpoint, pep_UsageType, PKCTRL_UWORD|PKCTRL_UNPACKONLY), + PACK_ENTRY(EA_Dummy, EA_Interface, PsdEndpoint, pep_Interface, PKCTRL_ULONG|PKCTRL_UNPACKONLY), + PACK_WORDBIT(EA_Dummy, EA_IsIn, PsdEndpoint, pep_Direction, PKCTRL_BIT|PKCTRL_UNPACKONLY, 1), + PACK_ENDTABLE +}; + +/* Pack table for PsdPipe */ +static const ULONG PsdPipePT[] = +{ + PACK_STARTTABLE(PPA_Dummy), + PACK_ENTRY(PPA_Dummy, PPA_Endpoint, PsdPipe, pp_Endpoint, PKCTRL_ULONG|PKCTRL_PACKUNPACK), + PACK_ENTRY(PPA_Dummy, PPA_Error, PsdPipe, pp_IOReq.iouh_Req.io_Error, PKCTRL_BYTE|PKCTRL_UNPACKONLY), + PACK_ENTRY(PPA_Dummy, PPA_Actual, PsdPipe, pp_IOReq.iouh_Actual, PKCTRL_ULONG|PKCTRL_UNPACKONLY), + PACK_ENTRY(PPA_Dummy, PPA_EndpointNum, PsdPipe, pp_IOReq.iouh_Endpoint, PKCTRL_UWORD|PKCTRL_UNPACKONLY), + PACK_ENTRY(PPA_Dummy, PPA_DeviceAddress, PsdPipe, pp_IOReq.iouh_DevAddr, PKCTRL_UWORD|PKCTRL_UNPACKONLY), + PACK_ENTRY(PPA_Dummy, PPA_MaxPktSize, PsdPipe, pp_IOReq.iouh_MaxPktSize, PKCTRL_ULONG|PKCTRL_UNPACKONLY), + PACK_ENTRY(PPA_Dummy, PPA_NakTimeoutTime, PsdPipe, pp_IOReq.iouh_NakTimeout, PKCTRL_ULONG|PKCTRL_PACKUNPACK), + PACK_ENTRY(PPA_Dummy, PPA_Interval, PsdPipe, pp_IOReq.iouh_Interval, PKCTRL_UWORD|PKCTRL_PACKUNPACK), + PACK_WORDBIT(PPA_Dummy, PPA_NoShortPackets, PsdPipe, pp_IOReq.iouh_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, UHFF_NOSHORTPKT), + PACK_WORDBIT(PPA_Dummy, PPA_NakTimeout, PsdPipe, pp_IOReq.iouh_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, UHFF_NAKTIMEOUT), + PACK_WORDBIT(PPA_Dummy, PPA_AllowRuntPackets, PsdPipe, pp_IOReq.iouh_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, UHFF_ALLOWRUNTPKTS), + PACK_ENDTABLE +}; + +/* Pack table for PsdAppBinding */ +static const ULONG PsdAppBindingPT[] = +{ + PACK_STARTTABLE(ABA_Dummy), + PACK_ENTRY(ABA_Dummy, ABA_ReleaseHook, PsdAppBinding, pab_ReleaseHook, PKCTRL_ULONG|PKCTRL_PACKUNPACK), + PACK_ENTRY(ABA_Dummy, ABA_Device, PsdAppBinding, pab_Device, PKCTRL_ULONG|PKCTRL_PACKUNPACK), + PACK_ENTRY(ABA_Dummy, ABA_UserData, PsdAppBinding, pab_UserData, PKCTRL_ULONG|PKCTRL_PACKUNPACK), + PACK_ENTRY(ABA_Dummy, ABA_Task, PsdAppBinding, pab_Task, PKCTRL_ULONG|PKCTRL_PACKUNPACK), + PACK_ENTRY(ABA_Dummy, ABA_ForceRelease, PsdAppBinding, pab_ForceRelease, PKCTRL_UWORD|PKCTRL_PACKUNPACK), + PACK_ENDTABLE +}; + +/* Pack table for PsdAppBinding */ +static const ULONG PsdEventNotePT[] = +{ + PACK_STARTTABLE(ENA_Dummy), + PACK_ENTRY(ENA_Dummy, ENA_EventID, PsdEventNote, pen_Event, PKCTRL_UWORD|PKCTRL_UNPACKONLY), + PACK_ENTRY(ENA_Dummy, ENA_Param1, PsdEventNote, pen_Param1, PKCTRL_ULONG|PKCTRL_UNPACKONLY), + PACK_ENTRY(ENA_Dummy, ENA_Param2, PsdEventNote, pen_Param2, PKCTRL_ULONG|PKCTRL_UNPACKONLY), + PACK_ENDTABLE +}; + +/* Pack table for PsdGlobalCfg */ +static const ULONG PsdGlobalCfgPT[] = +{ + PACK_STARTTABLE(GCA_Dummy), + PACK_ENTRY(GCA_Dummy, GCA_LogInfo, PsdGlobalCfg, pgc_LogInfo, PKCTRL_UWORD|PKCTRL_PACKUNPACK), + PACK_ENTRY(GCA_Dummy, GCA_LogWarning, PsdGlobalCfg, pgc_LogWarning, PKCTRL_UWORD|PKCTRL_PACKUNPACK), + PACK_ENTRY(GCA_Dummy, GCA_LogError, PsdGlobalCfg, pgc_LogError, PKCTRL_UWORD|PKCTRL_PACKUNPACK), + PACK_ENTRY(GCA_Dummy, GCA_LogFailure, PsdGlobalCfg, pgc_LogFailure, PKCTRL_UWORD|PKCTRL_PACKUNPACK), + PACK_ENTRY(GCA_Dummy, GCA_BootDelay, PsdGlobalCfg, pgc_BootDelay, PKCTRL_ULONG|PKCTRL_PACKUNPACK), + PACK_ENTRY(GCA_Dummy, GCA_SubTaskPri, PsdGlobalCfg, pgc_SubTaskPri, PKCTRL_WORD|PKCTRL_PACKUNPACK), + PACK_ENTRY(GCA_Dummy, GCA_PopupDeviceNew, PsdGlobalCfg, pgc_PopupDeviceNew, PKCTRL_UWORD|PKCTRL_PACKUNPACK), + PACK_ENTRY(GCA_Dummy, GCA_PopupDeviceGone, PsdGlobalCfg, pgc_PopupDeviceGone, PKCTRL_UWORD|PKCTRL_PACKUNPACK), + PACK_ENTRY(GCA_Dummy, GCA_PopupDeviceDeath, PsdGlobalCfg, pgc_PopupDeviceDeath, PKCTRL_UWORD|PKCTRL_PACKUNPACK), + PACK_ENTRY(GCA_Dummy, GCA_PopupCloseDelay, PsdGlobalCfg, pgc_PopupCloseDelay, PKCTRL_ULONG|PKCTRL_PACKUNPACK), + PACK_ENTRY(GCA_Dummy, GCA_PopupActivateWin, PsdGlobalCfg, pgc_PopupActivateWin, PKCTRL_UWORD|PKCTRL_PACKUNPACK), + PACK_ENTRY(GCA_Dummy, GCA_PopupWinToFront, PsdGlobalCfg, pgc_PopupWinToFront, PKCTRL_UWORD|PKCTRL_PACKUNPACK), + PACK_ENTRY(GCA_Dummy, GCA_AutoDisableLP, PsdGlobalCfg, pgc_AutoDisableLP, PKCTRL_UWORD|PKCTRL_PACKUNPACK), + PACK_ENTRY(GCA_Dummy, GCA_AutoDisableDead, PsdGlobalCfg, pgc_AutoDisableDead, PKCTRL_UWORD|PKCTRL_PACKUNPACK), + PACK_ENTRY(GCA_Dummy, GCA_AutoRestartDead, PsdGlobalCfg, pgc_AutoRestartDead, PKCTRL_UWORD|PKCTRL_PACKUNPACK), + PACK_ENTRY(GCA_Dummy, GCA_PowerSaving, PsdGlobalCfg, pgc_PowerSaving, PKCTRL_UWORD|PKCTRL_PACKUNPACK), + PACK_ENTRY(GCA_Dummy, GCA_ForceSuspend, PsdGlobalCfg, pgc_ForceSuspend, PKCTRL_UWORD|PKCTRL_PACKUNPACK), + PACK_ENTRY(GCA_Dummy, GCA_SuspendTimeout, PsdGlobalCfg, pgc_SuspendTimeout, PKCTRL_ULONG|PKCTRL_PACKUNPACK), + PACK_ENTRY(GCA_Dummy, GCA_PrefsVersion, PsdGlobalCfg, pgc_PrefsVersion, PKCTRL_ULONG|PKCTRL_PACKUNPACK), + PACK_ENDTABLE +}; + +/* Pack table for PsdPipeStream */ +static const ULONG PsdPipeStreamPT[] = +{ + PACK_STARTTABLE(PSA_Dummy), + PACK_ENTRY(PSA_Dummy, PSA_MessagePort, PsdPipeStream, pps_MsgPort, PKCTRL_ULONG|PKCTRL_PACKUNPACK), + PACK_ENTRY(PSA_Dummy, PSA_NumPipes, PsdPipeStream, pps_NumPipes, PKCTRL_ULONG|PKCTRL_PACKUNPACK), + PACK_ENTRY(PSA_Dummy, PSA_BufferSize, PsdPipeStream, pps_BufferSize, PKCTRL_ULONG|PKCTRL_PACKUNPACK), + PACK_ENTRY(PSA_Dummy, PSA_NakTimeoutTime, PsdPipeStream, pps_NakTimeoutTime, PKCTRL_ULONG|PKCTRL_PACKUNPACK), + PACK_ENTRY(PSA_Dummy, PSA_BytesPending, PsdPipeStream, pps_BytesPending, PKCTRL_ULONG|PKCTRL_UNPACKONLY), + PACK_ENTRY(PSA_Dummy, PSA_Error, PsdPipeStream, pps_Error, PKCTRL_LONG|PKCTRL_PACKUNPACK), + PACK_ENTRY(PSA_Dummy, PSA_TermArray, PsdPipeStream, pps_TermArray, PKCTRL_ULONG|PKCTRL_PACKUNPACK), + PACK_ENTRY(PSA_Dummy, PSA_AbortSigMask, PsdPipeStream, pps_AbortSigMask, PKCTRL_ULONG|PKCTRL_PACKUNPACK), + PACK_ENTRY(PSA_Dummy, PSA_ActivePipe, PsdPipeStream, pps_ActivePipe, PKCTRL_ULONG|PKCTRL_UNPACKONLY), + PACK_WORDBIT(PSA_Dummy, PSA_AsyncIO, PsdPipeStream, pps_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PSFF_ASYNCIO), + PACK_WORDBIT(PSA_Dummy, PSA_ShortPktTerm, PsdPipeStream, pps_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PSFF_SHORTTERM), + PACK_WORDBIT(PSA_Dummy, PSA_ReadAhead, PsdPipeStream, pps_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PSFF_READAHEAD), + PACK_WORDBIT(PSA_Dummy, PSA_BufferedRead, PsdPipeStream, pps_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PSFF_BUFFERREAD), + PACK_WORDBIT(PSA_Dummy, PSA_BufferedWrite, PsdPipeStream, pps_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PSFF_BUFFERWRITE), + PACK_WORDBIT(PSA_Dummy, PSA_NoZeroPktTerm, PsdPipeStream, pps_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PSFF_NOSHORTPKT), + PACK_WORDBIT(PSA_Dummy, PSA_NakTimeout, PsdPipeStream, pps_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PSFF_NAKTIMEOUT), + PACK_WORDBIT(PSA_Dummy, PSA_AllowRuntPackets, PsdPipeStream, pps_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PSFF_ALLOWRUNT), + PACK_WORDBIT(PSA_Dummy, PSA_DoNotWait, PsdPipeStream, pps_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PSFF_DONOTWAIT), + PACK_ENDTABLE +}; + +/* Pack table for PsdRTIsoHandler */ +static const ULONG PsdRTIsoHandlerPT[] = +{ + PACK_STARTTABLE(RTA_Dummy), + PACK_ENTRY(RTA_Dummy, RTA_InRequestHook, PsdRTIsoHandler, prt_RTIso.urti_InReqHook, PKCTRL_ULONG|PKCTRL_PACKUNPACK), + PACK_ENTRY(RTA_Dummy, RTA_OutRequestHook, PsdRTIsoHandler, prt_RTIso.urti_OutReqHook, PKCTRL_ULONG|PKCTRL_PACKUNPACK), + PACK_ENTRY(RTA_Dummy, RTA_InDoneHook, PsdRTIsoHandler, prt_RTIso.urti_InDoneHook, PKCTRL_ULONG|PKCTRL_PACKUNPACK), + PACK_ENTRY(RTA_Dummy, RTA_OutDoneHook, PsdRTIsoHandler, prt_RTIso.urti_OutDoneHook, PKCTRL_ULONG|PKCTRL_PACKUNPACK), + PACK_ENTRY(RTA_Dummy, RTA_ReleaseHook, PsdRTIsoHandler, prt_ReleaseHook, PKCTRL_ULONG|PKCTRL_PACKUNPACK), + PACK_ENTRY(RTA_Dummy, RTA_OutPrefetchSize, PsdRTIsoHandler, prt_RTIso.urti_OutPrefetch, PKCTRL_ULONG|PKCTRL_PACKUNPACK), + PACK_ENDTABLE +}; + +/* PGA assignment table */ +static const ULONG *PsdPTArray[] = +{ + NULL, + PsdBasePT, + PsdUsbClassPT, + PsdHardwarePT, + PsdDevicePT, + PsdConfigPT, + PsdInterfacePT, + PsdEndpointPT, + PsdErrorMsgPT, + PsdPipePT, + PsdAppBindingPT, + PsdEventNotePT, + PsdGlobalCfgPT, + PsdPipeStreamPT, + PsdDescriptorPT, + PsdRTIsoHandlerPT +}; +/* \\\ */ + diff --git a/rom/usb/poseidon/poseidon.library.h b/rom/usb/poseidon/poseidon.library.h new file mode 100644 index 000000000..b1bd7e2e9 --- /dev/null +++ b/rom/usb/poseidon/poseidon.library.h @@ -0,0 +1,141 @@ +#ifndef POSEIDON_LIBRARY_H +#define POSEIDON_LIBRARY_H + +/* + *---------------------------------------------------------------------------- + * Includes for poseidon.library + *---------------------------------------------------------------------------- + * By Chris Hodges + */ + +#define RELEASEVERSION 0x20090611 + +#include LC_LIBDEFS_FILE + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "poseidon_intern.h" + +#include +#include +#include +#include +#include +#include +#include + +struct PsdRawDoFmt +{ + ULONG rdf_Len; + STRPTR rdf_Buf; +}; + +/* Protos */ + +void pFreeEndpoint(struct PsdEndpoint *pep); +struct PsdEndpoint * pAllocEndpoint(struct PsdInterface *pif); + +void pFreeInterface(struct PsdInterface *pif); +struct PsdInterface * pAllocInterface(struct PsdConfig *pc); + +void pFreeConfig(struct PsdConfig *pc); +struct PsdConfig * pAllocConfig(struct PsdDevice *pd); + +void pCheckForDeadlock(struct PsdBase *ps, struct PsdLockSem *pls, BOOL excl); +void pInitSem(struct PsdBase *ps, struct PsdLockSem *pls, STRPTR name); +void pDeleteSem(struct PsdBase *ps, struct PsdLockSem *pls); +void pLockSemExcl(struct PsdBase *ps, struct PsdLockSem *pls); +void pLockSemShared(struct PsdBase *ps, struct PsdLockSem *pls); +void pUnlockSem(struct PsdBase *ps, struct PsdLockSem *pls); + +BOOL pOpenDOS(struct PsdBase *ps); + +UWORD pAllocDevAddr(struct PsdDevice *pd); + +BOOL pFixBrokenConfig(struct PsdPipe *pp); +BOOL pGetDevConfig(struct PsdPipe *pp); + +ULONG pGetFormLength(struct PsdIFFContext *pic); + +struct PsdIFFContext * pAllocForm(struct PsdBase *ps, struct PsdIFFContext *parent, ULONG formid); +void pFreeForm(struct PsdBase *ps, struct PsdIFFContext *pic); +ULONG * pInternalWriteForm(struct PsdIFFContext *pic, ULONG *buf); +struct PsdIFFContext * pAddCfgChunk(struct PsdBase *ps, struct PsdIFFContext *pic, APTR chunk); +STRPTR pGetStringChunk(struct PsdBase *ps, struct PsdIFFContext *pic, ULONG chunkid); +BOOL pMatchStringChunk(struct PsdBase *ps, struct PsdIFFContext *pic, ULONG chunkid, STRPTR str); + +BOOL pRemCfgChunk(struct PsdBase *ps, struct PsdIFFContext *pic, ULONG chnkid); +BOOL pAddStringChunk(struct PsdBase *ps, struct PsdIFFContext *pic, ULONG chunkid, STRPTR str); +void pUpdateGlobalCfg(struct PsdBase *ps, struct PsdIFFContext *pic); +APTR pFindCfgChunk(struct PsdBase *ps, struct PsdIFFContext *pic, ULONG chnkid); + +BOOL pGetDevConfig(struct PsdPipe *pp); + +void pClassScan(struct PsdBase *ps); +void pReleaseBinding(struct PsdBase *ps, struct PsdDevice *pd, struct PsdInterface *pif); +void pReleaseDevBinding(struct PsdBase *ps, struct PsdDevice *pd); +void pReleaseIfBinding(struct PsdBase *ps, struct PsdInterface *pif); + +void pGarbageCollectEvents(struct PsdBase *ps); +BOOL pStartEventHandler(struct PsdBase *ps); + +BOOL pCheckCfgChanged(struct PsdBase *ps); + +ULONG pPowerRecurseDrain(struct PsdBase *ps, struct PsdDevice *pd); +void pPowerRecurseSupply(struct PsdBase *ps, struct PsdDevice *pd); + +void pStripString(struct PsdBase *ps, STRPTR str); +struct Node * pFindName(struct PsdBase *ps, struct List *list, STRPTR name); + +#define psdAddErrorMsg0(level, origin, fmtstr) psdAddErrorMsgA(level, origin, fmtstr, NULL) + +AROS_UFP0(void, pDeviceTask); +AROS_UFP0(void, pPoPoGUITask); +AROS_UFP0(void, pEventHandlerTask); + +AROS_UFP2(void, pPutChar, + AROS_UFPA(char, ch, D0), + AROS_UFPA(struct PsdRawDoFmt *, rdf, A3)); + +AROS_UFP2(void, pRawFmtLength, + AROS_UFPA(char, ch, D0), + AROS_UFPA(ULONG *, len, A3)); + +AROS_UFP1(void, pQuickForwardRequest, + AROS_UFPA(struct MsgPort *, msgport, A1)); + +AROS_UFP1(void, pQuickReplyRequest, + AROS_UFPA(struct MsgPort *, msgport, A1)); + +#endif /* POSEIDON_LIBRARY_H */ diff --git a/rom/usb/poseidon/poseidon_intern.h b/rom/usb/poseidon/poseidon_intern.h new file mode 100644 index 000000000..5ab508e9b --- /dev/null +++ b/rom/usb/poseidon/poseidon_intern.h @@ -0,0 +1,911 @@ +/**************************************************************************** + + __ __ V/\V. /\ + |" | |" | mMMnw, || [] + | | | | (o o)W () || || + |__|_|_"| | / |Mw || ||// + (" " \| \ -'_/mw \\||/ + \______) ~%%/WM" \|| + _____ ___ ______ _____ __ _____ ___ __ __/~~__ ~~\ _|| +|"(" \()/\" \ ()/"_ )|"(___) ) )|"(" \ ()/\" \(__)/" ) /" ) " \ /_)O +| ) )/" \ \ (_/"\__/ | )_ ( ( | )_ ) /" \ \ / /|/ / ·\ \/ ,|O +| (___/( (_\__) _\ \_ | (__) ) )| (__) |( (_\__)/ /"/ / |\ '_|O +| | _ \ / / /" \_/ ) | ")__ ( ( | )" ) \ / // /|/ / . .|/\__/ || +|__| (_) \/__/ (______/ |_(___) )_)|_(___/ . \/__/(__/ (__/ .:.:| || + _____ + |" __ \ Poseidon -- The divine USB stack for Amiga computers + | (__) ) Version: 4.3 (30.05.09) + | __ ( Designed and written by + |"(__) ) Chris Hodges + |_____/ Copyright ©2002-2009 Chris Hodges. All rights reserved. + + ****************************************************************************/ + +/* + *---------------------------------------------------------------------------- + * Includes for poseidon.library + *---------------------------------------------------------------------------- + * By Chris Hodges + * + */ + +#ifndef LIBRARIES_POSEIDON_H +#define LIBRARIES_POSEIDON_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Types for psdGetAttrs() and psdSetAttrs() */ +#define PGA_STACK 0x01 +#define PGA_USBCLASS 0x02 +#define PGA_HARDWARE 0x03 +#define PGA_DEVICE 0x04 +#define PGA_CONFIG 0x05 +#define PGA_INTERFACE 0x06 +#define PGA_ENDPOINT 0x07 +#define PGA_ERRORMSG 0x08 +#define PGA_PIPE 0x09 +#define PGA_APPBINDING 0x0a +#define PGA_EVENTNOTE 0x0b +#define PGA_STACKCFG 0x0c +#define PGA_PIPESTREAM 0x0d +#define PGA_DESCRIPTOR 0x0e +#define PGA_RTISO 0x0f +#define PGA_LAST 0x0f + +/* Tags for psdGetAttrs(PGA_STACK,...) */ +#define PA_Dummy (TAG_USER + 2612) +#define PA_ConfigRead (PA_Dummy + 0x01) +#define PA_HardwareList (PA_Dummy + 0x20) +#define PA_ClassList (PA_Dummy + 0x21) +#define PA_ErrorMsgList (PA_Dummy + 0x22) +#define PA_GlobalConfig (PA_Dummy + 0x44) +#define PA_CurrConfigHash (PA_Dummy + 0x45) +#define PA_SavedConfigHash (PA_Dummy + 0x46) +#define PA_MemPoolUsage (PA_Dummy + 0x50) +#define PA_ReleaseVersion (PA_Dummy + 0x60) +#define PA_OSVersion (PA_Dummy + 0x61) + +/* Tags for psdGetAttrs(PGA_ERRORMSG,...) */ +#define EMA_Dummy (TAG_USER + 103) +#define EMA_Level (EMA_Dummy + 0x10) +#define EMA_Origin (EMA_Dummy + 0x11) +#define EMA_Msg (EMA_Dummy + 0x12) +#define EMA_DateStamp (EMA_Dummy + 0x13) + +/* Tags for psdGetAttrs(PGA_USBCLASS,...) */ + +#define UCA_Dummy (TAG_USER + 4489) +#define UCA_ClassBase (UCA_Dummy + 0x10) +#define UCA_ClassName (UCA_Dummy + 0x11) +#define UCA_UseCount (UCA_Dummy + 0x12) +#define UCA_FullPath (UCA_Dummy + 0x13) + +/* Tags for psdGetAttrs(PGA_HARDWARE,...) */ +#define HA_Dummy (TAG_USER + 0x2612) +#define HA_DeviceName (HA_Dummy + 0x10) +#define HA_DeviceUnit (HA_Dummy + 0x11) +#define HA_ProductName (HA_Dummy + 0x12) +#define HA_Manufacturer (HA_Dummy + 0x13) +#define HA_Version (HA_Dummy + 0x14) +#define HA_Revision (HA_Dummy + 0x15) +#define HA_Description (HA_Dummy + 0x16) +#define HA_Copyright (HA_Dummy + 0x17) +#define HA_DriverVersion (HA_Dummy + 0x18) +#define HA_DeviceList (HA_Dummy + 0x20) + +/* Tags for psdGetAttrs(PGA_DEVICE,...) */ +#define DA_Dummy (TAG_USER + 42) +#define DA_IsLowspeed (DA_Dummy + 0x01) +#define DA_IsConnected (DA_Dummy + 0x02) +#define DA_HasAddress (DA_Dummy + 0x03) +#define DA_HasDevDesc (DA_Dummy + 0x04) +#define DA_IsConfigured (DA_Dummy + 0x05) +#define DA_HasAppBinding (DA_Dummy + 0x06) +#define DA_IsHighspeed (DA_Dummy + 0x07) +#define DA_IsDead (DA_Dummy + 0x08) +#define DA_Config (DA_Dummy + 0x09) +#define DA_IsSuspended (DA_Dummy + 0x0a) +#define DA_Address (DA_Dummy + 0x10) +#define DA_NumConfigs (DA_Dummy + 0x11) +#define DA_CurrConfig (DA_Dummy + 0x12) +#define DA_HubDevice (DA_Dummy + 0x13) +#define DA_UsbVersion (DA_Dummy + 0x14) +#define DA_Class (DA_Dummy + 0x15) +#define DA_SubClass (DA_Dummy + 0x16) +#define DA_Protocol (DA_Dummy + 0x17) +#define DA_Version (DA_Dummy + 0x18) +#define DA_VendorID (DA_Dummy + 0x19) +#define DA_ProductID (DA_Dummy + 0x1a) +#define DA_Manufacturer (DA_Dummy + 0x1b) +#define DA_ProductName (DA_Dummy + 0x1c) +#define DA_SerialNumber (DA_Dummy + 0x1d) +#define DA_Hardware (DA_Dummy + 0x1e) +#define DA_Binding (DA_Dummy + 0x1f) +#define DA_ConfigList (DA_Dummy + 0x20) +#define DA_LangIDArray (DA_Dummy + 0x21) +#define DA_CurrLangID (DA_Dummy + 0x22) +#define DA_BindingClass (DA_Dummy + 0x23) +#define DA_IDString (DA_Dummy + 0x24) +#define DA_CloneCount (DA_Dummy + 0x25) +#define DA_AtHubPortNumber (DA_Dummy + 0x26) +#define DA_NeedsSplitTrans (DA_Dummy + 0x27) +#define DA_OrigProductName (DA_Dummy + 0x28) +#define DA_DescriptorList (DA_Dummy + 0x29) +#define DA_MaxPktSize0 (DA_Dummy + 0x2a) +#define DA_HubThinkTime (DA_Dummy + 0x2b) +#define DA_PowerSupply (DA_Dummy + 0x30) +#define DA_PowerDrained (DA_Dummy + 0x31) +#define DA_LowPower (DA_Dummy + 0x32) +#define DA_InhibitPopup (DA_Dummy + 0x40) +#define DA_IsNewToMe (DA_Dummy + 0x41) +#define DA_InhibitClassBind (DA_Dummy + 0x42) +#define DA_OverridePowerInfo (DA_Dummy + 0x43) + +/* Tags for psdGetAttrs(PGA_CONFIG,...) */ +#define CA_Dummy (TAG_USER + 23) +#define CA_Attrs (CA_Dummy + 0x01) +#define CA_SelfPowered (CA_Dummy + 0x02) +#define CA_RemoteWakeup (CA_Dummy + 0x03) +#define CA_ConfigNum (CA_Dummy + 0x10) +#define CA_MaxPower (CA_Dummy + 0x11) +#define CA_ConfigName (CA_Dummy + 0x12) +#define CA_NumInterfaces (CA_Dummy + 0x13) +#define CA_Device (CA_Dummy + 0x14) +#define CA_InterfaceList (CA_Dummy + 0x20) + +/* Tags for psdGetAttrs(PGA_DESCRIPTOR,...) */ +#define DDA_Dummy (TAG_USER + 888) +#define DDA_Device (DDA_Dummy + 0x01) +#define DDA_Config (DDA_Dummy + 0x02) +#define DDA_Interface (DDA_Dummy + 0x03) +#define DDA_Endpoint (DDA_Dummy + 0x04) +#define DDA_Name (DDA_Dummy + 0x08) +#define DDA_DescriptorType (DDA_Dummy + 0x10) +#define DDA_DescriptorData (DDA_Dummy + 0x11) +#define DDA_DescriptorLength (DDA_Dummy + 0x12) +#define DDA_CS_SubType (DDA_Dummy + 0x20) + +/* Tags for psdGetAttrs(PGA_INTERFACE,...) */ +#define IFA_Dummy (TAG_USER + 4711) +#define IFA_InterfaceNum (IFA_Dummy + 0x10) +#define IFA_AlternateNum (IFA_Dummy + 0x11) +#define IFA_Class (IFA_Dummy + 0x12) +#define IFA_SubClass (IFA_Dummy + 0x13) +#define IFA_Protocol (IFA_Dummy + 0x14) +#define IFA_InterfaceName (IFA_Dummy + 0x15) +#define IFA_Config (IFA_Dummy + 0x16) +#define IFA_Binding (IFA_Dummy + 0x17) +#define IFA_NumEndpoints (IFA_Dummy + 0x18) +#define IFA_BindingClass (IFA_Dummy + 0x19) +#define IFA_IDString (IFA_Dummy + 0x1a) +#define IFA_EndpointList (IFA_Dummy + 0x20) +#define IFA_AlternateIfList (IFA_Dummy + 0x21) + +/* Tags for psdGetAttrs(PGA_ENDPOINT,...) */ +#define EA_Dummy (TAG_USER + 1138) +#define EA_IsIn (EA_Dummy + 0x01) +#define EA_EndpointNum (EA_Dummy + 0x10) +#define EA_TransferType (EA_Dummy + 0x11) +#define EA_MaxPktSize (EA_Dummy + 0x12) +#define EA_Interval (EA_Dummy + 0x13) +#define EA_Interface (EA_Dummy + 0x14) +#define EA_NumTransMuFrame (EA_Dummy + 0x15) +#define EA_SyncType (EA_Dummy + 0x16) +#define EA_UsageType (EA_Dummy + 0x17) + +/* Tags for psdGetAttrs(PGA_PIPE,...) */ +#define PPA_Dummy (TAG_USER + 1234) +#define PPA_Endpoint (PPA_Dummy + 0x01) +#define PPA_Error (PPA_Dummy + 0x02) +#define PPA_Actual (PPA_Dummy + 0x03) +#define PPA_EndpointNum (PPA_Dummy + 0x04) +#define PPA_DeviceAddress (PPA_Dummy + 0x05) +#define PPA_IORequest (PPA_Dummy + 0x06) +#define PPA_NoZeroPktTerm (PPA_Dummy + 0x07) +#define PPA_NoShortPackets PPA_NoZeroPktTerm /* obsolete, bad naming */ +#define PPA_NakTimeout (PPA_Dummy + 0x08) +#define PPA_NakTimeoutTime (PPA_Dummy + 0x09) +#define PPA_AllowRuntPackets (PPA_Dummy + 0x0a) +#define PPA_MaxPktSize (PPA_Dummy + 0x0b) +#define PPA_Interval (PPA_Dummy + 0x0c) + +/* Tags for application binding and psdGetAttrs(PGA_APPBINDING,...)*/ +#define ABA_Dummy (TAG_USER + 666) +#define ABA_ReleaseHook (ABA_Dummy + 0x01) +#define ABA_Device (ABA_Dummy + 0x02) +#define ABA_UserData (ABA_Dummy + 0x03) +#define ABA_Task (ABA_Dummy + 0x04) +#define ABA_ForceRelease (ABA_Dummy + 0x10) + +/* Tags for psdGetAttrs(PGA_EVENTNOTE,...)*/ +#define ENA_Dummy (TAG_USER + 777) +#define ENA_EventID (ENA_Dummy + 0x01) +#define ENA_Param1 (ENA_Dummy + 0x02) +#define ENA_Param2 (ENA_Dummy + 0x03) + +/* Tags for psdGetAttrs(PGA_GLOBALCFG,...) */ +#define GCA_Dummy (TAG_USER + 0x1138) +#define GCA_LogInfo (GCA_Dummy + 0x01) +#define GCA_LogWarning (GCA_Dummy + 0x02) +#define GCA_LogError (GCA_Dummy + 0x03) +#define GCA_LogFailure (GCA_Dummy + 0x04) +#define GCA_SubTaskPri (GCA_Dummy + 0x10) +#define GCA_BootDelay (GCA_Dummy + 0x11) +#define GCA_PopupDeviceNew (GCA_Dummy + 0x20) +#define GCA_PopupDeviceGone (GCA_Dummy + 0x21) +#define GCA_PopupDeviceDeath (GCA_Dummy + 0x22) +#define GCA_PopupCloseDelay (GCA_Dummy + 0x23) +#define GCA_PopupActivateWin (GCA_Dummy + 0x30) +#define GCA_PopupWinToFront (GCA_Dummy + 0x31) +#define GCA_InsertionSound (GCA_Dummy + 0x40) +#define GCA_RemovalSound (GCA_Dummy + 0x41) +#define GCA_AutoDisableLP (GCA_Dummy + 0x60) +#define GCA_AutoDisableDead (GCA_Dummy + 0x61) +#define GCA_AutoRestartDead (GCA_Dummy + 0x63) +#define GCA_PowerSaving (GCA_Dummy + 0x64) +#define GCA_ForceSuspend (GCA_Dummy + 0x65) +#define GCA_SuspendTimeout (GCA_Dummy + 0x66) +#define GCA_PrefsVersion (GCA_Dummy + 0x70) + +/* Tags for psdGetAttrs(PGA_PIPESTREAM,...) */ +#define PSA_Dummy (TAG_USER + 0x0409) +#define PSA_MessagePort (PSA_Dummy + 0x01) +#define PSA_AsyncIO (PSA_Dummy + 0x02) +#define PSA_NumPipes (PSA_Dummy + 0x03) +#define PSA_BufferSize (PSA_Dummy + 0x04) +#define PSA_ShortPktTerm (PSA_Dummy + 0x05) +#define PSA_ReadAhead (PSA_Dummy + 0x06) +#define PSA_BufferedRead (PSA_Dummy + 0x07) +#define PSA_BufferedWrite (PSA_Dummy + 0x08) +#define PSA_NoZeroPktTerm (PSA_Dummy + 0x09) +#define PSA_NakTimeout (PSA_Dummy + 0x0a) +#define PSA_NakTimeoutTime (PSA_Dummy + 0x0b) +#define PSA_AllowRuntPackets (PSA_Dummy + 0x0c) +#define PSA_TermArray (PSA_Dummy + 0x0d) +#define PSA_DoNotWait (PSA_Dummy + 0x0e) +#define PSA_AbortSigMask (PSA_Dummy + 0x0f) +#define PSA_BytesPending (PSA_Dummy + 0x10) +#define PSA_Error (PSA_Dummy + 0x11) +#define PSA_ActivePipe (PSA_Dummy + 0x12) + +/* Tags for psdGetAttrs(PGA_RTISO,...) */ +#define RTA_Dummy (TAG_USER + 999) +#define RTA_InRequestHook (RTA_Dummy + 0x01) +#define RTA_OutRequestHook (RTA_Dummy + 0x02) +#define RTA_InDoneHook (RTA_Dummy + 0x03) +#define RTA_OutDoneHook (RTA_Dummy + 0x04) +#define RTA_ReleaseHook (RTA_Dummy + 0x05) +#define RTA_OutPrefetchSize (RTA_Dummy + 0x10) + +/* NumToStr types */ +#define NTS_IOERR 1 +#define NTS_LANGID 2 +#define NTS_TRANSTYPE 3 +#define NTS_VENDORID 4 +#define NTS_CLASSCODE 5 +#define NTS_DESCRIPTOR 6 +#define NTS_SYNCTYPE 7 +#define NTS_USAGETYPE 8 +#define NTS_COMBOCLASS 9 + +/* NTS_COMBOCLASS flags */ +#define NTSCCS_CLASS 0 /* Class field is bits 0-7 */ +#define NTSCCS_SUBCLASS 8 /* Subclass field is bits 8-15 */ +#define NTSCCS_PROTO 16 /* Protocol field is bits 16-24 */ +#define NTSCCF_CLASS (1<<24) /* Class field is valid */ +#define NTSCCF_SUBCLASS (1<<25) /* Subclass field is valid */ +#define NTSCCF_PROTO (1<<26) /* Protocol field is valid */ + +/* Event Handler stuff */ +#define EHMB_ADDHARDWARE 0x01 /* Param1 = phw */ +#define EHMB_REMHARDWARE 0x02 /* Param1 = phw */ +#define EHMB_ADDDEVICE 0x03 /* Param1 = pd */ +#define EHMB_REMDEVICE 0x04 /* Param1 = pd */ +#define EHMB_ADDCLASS 0x05 /* Param1 = puc */ +#define EHMB_REMCLASS 0x06 /* Param1 = puc */ +#define EHMB_ADDBINDING 0x07 /* Param1 = pd */ +#define EHMB_REMBINDING 0x08 /* Param1 = pd */ +#define EHMB_ADDERRORMSG 0x09 /* Param1 = pem */ +#define EHMB_REMERRORMSG 0x0a /* Param1 = pem */ +#define EHMB_CONFIGCHG 0x0b /* Param1 = void */ +#define EHMB_DEVICEDEAD 0x0c /* Param1 = pd */ +#define EHMB_DEVICELOWPW 0x0d /* Param1 = pd */ +#define EHMB_DEVSUSPENDED 0x0e /* Param1 = pd */ +#define EHMB_DEVRESUMED 0x0f /* Param1 = pd */ + +#define EHMF_ADDHARDWARE (1L< (forced binding) + CHNK NAME [varlen] Custom name +[n*] FORM DCFG (Device configuration data) + CHNK OWNR [varlen] name of class for binding (AppName?) + FORM DCPD (device config private data) <- that's the form the class can modify + [...] +[n*] FORM ICFG (Interface configuration data) + CHNK OWNR [varlen] name of class for binding + CHNK IFID [varlen] InterfaceID-String + CHNK FBND [varlen] (forced binding) + FORM ICPD (interface config private data) <- that's the form the class can modify + + psdReadCfg(pic, formdata): + pic == NULL; replace (!) root form with given formdata + pic != NULL; replace given pic with new form data. + psdWriteCfg(pic) + pic == NULL; generate the whole configuration buffer to save + pic != NULL; generate the form buffer of the pic and its subform. + psdFindCfgForm(pic, formid) + pic == NULL -> pic = root form; + find and return pic with given form ID or NULL if no such form exists. + psdNextCfgForm(pic) + get next form pic with same ID or return NULL if this was the only form with this ID. + + psdRemCfgForm(pic) + pic == NULL -> pic = root form; + delete form pic (effectly calls pFreeForm()). + + psdAddCfgChunk(pic, formdata) + pic == NULL -> pic = root form; + add the form OR CHUNK to the pic context form. Do not replace existing forms. + Replaces existing chunks. + + psdRemCfgChunk(pic, chnkid) + pic == NULL -> pic = root form; + delete the chunk from the pic context form. + +*/ + +#if AROS_BIG_ENDIAN +/* While Poseidon writes a correct big endian IFF structure on both big and little endian + * the contents are *not* endian agnostic. Therefore we will avoid loading prefs of + * different endianess by defining the outmost FORM ID endian specific. Also notice that + * compatibility of the config files with 68k and MorphOS versions is not given. */ +#define IFFFORM_PSDCFG MAKE_ID('P','S','B','C') +#else +#define IFFFORM_PSDCFG MAKE_ID('P','S','L','C') +#endif +#define IFFFORM_STACKCFG MAKE_ID('S','T','K','C') +#define IFFFORM_DEVICECFG MAKE_ID('D','E','V','C') +#define IFFFORM_CLASSCFG MAKE_ID('C','L','S','C') +#define IFFFORM_UHWDEVICE MAKE_ID('U','H','W','D') +#define IFFFORM_USBCLASS MAKE_ID('U','C','L','S') +#define IFFFORM_CLASSDATA MAKE_ID('G','C','P','D') +#define IFFFORM_DEVCFGDATA MAKE_ID('D','C','F','G') +#define IFFFORM_DEVCLSDATA MAKE_ID('D','C','P','D') +#define IFFFORM_IFCFGDATA MAKE_ID('I','C','F','G') +#define IFFFORM_IFCLSDATA MAKE_ID('I','C','P','D') + +#define IFFCHNK_OWNER MAKE_ID('O','W','N','R') +#define IFFCHNK_NAME MAKE_ID('N','A','M','E') +#define IFFCHNK_UNIT MAKE_ID('U','N','I','T') +#define IFFCHNK_OFFLINE MAKE_ID('O','F','F','L') +#define IFFCHNK_GLOBALCFG MAKE_ID('G','C','F','G') +#define IFFCHNK_DEVID MAKE_ID('D','V','I','D') +#define IFFCHNK_IFID MAKE_ID('I','F','I','D') +#define IFFCHNK_FORCEDBIND MAKE_ID('F','B','N','D') +#define IFFCHNK_POPUP MAKE_ID('P','O','P','O') +#define IFFCHNK_INSERTSND MAKE_ID('I','N','S','F') +#define IFFCHNK_REMOVESND MAKE_ID('R','M','S','F') + +/* Private stuff starts here */ + +#if defined(__GNUC__) +# pragma pack(2) +#endif + +/* GCA_PopupDeviceNew definitions */ + +#define PGCP_NEVER 0 /* never open a pop-up window */ +#define PGCP_ERROR 1 /* popup, on error condition (e.g. low power) */ +#define PGCP_ISNEW 2 /* popup, if this is the first time the device is connected */ +#define PGCP_NOBINDING 3 /* popup, if there is no binding */ +#define PGCP_ASKCONFIG 4 /* popup and ask to configure, if not existent */ +#define PGCP_CANCONFIG 5 /* popup and ask to configure, if possible */ +#define PGCP_HASBINDING 6 /* popup, if there is a binding to a class */ +#define PGCP_ALWAYS 7 /* popup always */ + +struct PsdGlobalCfg +{ + ULONG pgc_ChunkID; /* ChunkID=IFFCHNK_GLOBALCFG */ + ULONG pgc_Length; /* sizeof(struct PsdGlobalCfg)-8 */ + BOOL pgc_LogInfo; /* Log normal messages */ + BOOL pgc_LogWarning; /* Log warnings */ + BOOL pgc_LogError; /* Log errors */ + BOOL pgc_LogFailure; /* Log failures */ + ULONG pgc_BootDelay; /* boot delay */ + WORD pgc_SubTaskPri; /* Subtask priority */ + UWORD pgc_PopupDeviceNew; /* New device popup */ + BOOL pgc_PopupDeviceGone; /* Device removed popup */ + BOOL pgc_PopupDeviceDeath; /* Device dead popup */ + ULONG pgc_PopupCloseDelay; /* Delay in seconds before closing */ + BOOL pgc_PopupActivateWin; /* Activate window on opening */ + BOOL pgc_PopupWinToFront; /* Pop window to front on content change */ + BOOL pgc_AutoDisableLP; /* Automatically disable on LowPower */ + BOOL pgc_AutoDisableDead; /* Automatically disable on Dead */ + BOOL pgc_AutoRestartDead; /* Automatically restart on Dead */ + ULONG pgc_PrefsVersion; /* Reference version of prefs saved */ + BOOL pgc_PowerSaving; /* Enable power saving features */ + BOOL pgc_ForceSuspend; /* Force Suspend on classes not supporting it, but with remote wakeup */ + ULONG pgc_SuspendTimeout; /* Timeout when to suspend a device after inactivity */ +}; + +/* DA_OverridePowerInfo definitions */ +#define POCP_TRUST_DEVICE 0 +#define POCP_BUS_POWERED 1 +#define POCP_SELF_POWERED 2 + +struct PsdPoPoCfg +{ + ULONG poc_ChunkID; /* ChunkID=IFFCHNK_POPO */ + ULONG poc_Length; /* sizeof(struct PsdPopoCfg)-8 */ + BOOL poc_InhibitPopup; /* Inhibit opening of popup window */ + BOOL poc_NoClassBind; /* Inhibit class scan */ + UWORD poc_OverridePowerInfo; /* 0=keep, 1=buspowered, 2=selfpowered */ +}; + +#if defined(__GNUC__) +# pragma pack() +#endif + +struct PsdLockSem +{ + struct Node pls_Node; /* Linkage */ + BOOL pls_Dead; /* Has Semaphore been deactivated? */ + struct List pls_WaitQueue; /* List of waiting tasks (ReadLock structs) */ + struct List pls_ReadLocks; /* List of obtained shared locks */ + struct Task *pls_Owner; /* Current owner of exclusive lock */ + UWORD pls_ExclLockCount; /* Exclusive lock count */ + UWORD pls_SharedLockCount; /* Count of *different* shared lock owners */ +}; + +struct PsdReadLock +{ + struct Node prl_Node; /* Linkage */ + BOOL prl_IsExcl; /* Is this lock exclusive? */ + struct Task *prl_Task; /* Task waiting for or obtaining this lock */ + UWORD prl_Count; /* Shared lock count */ +}; + +struct PsdSemaInfo +{ + struct Node psi_Node; /* Linkage */ + struct PsdLockSem *psi_LockSem; /* Pointer to semaphore */ +}; + +struct PsdBorrowLock +{ + struct Node pbl_Node; /* Linkage */ + UWORD pbl_ExclLockCount; /* Was exclusive before */ + UWORD pbl_Count; /* Shared lock count */ + struct PsdLockSem *pbl_LockSem; /* Pointer to semaphore */ + struct PsdReadLock *pbl_ReadLock; /* Readlock that was changed */ +}; + +struct PsdPoPo +{ + struct Task *po_Task; /* PoPo Task */ + struct MsgPort *po_MsgPort; /* Port for EventNote messages */ + LONG po_ReadySignal; /* Signal to respond to task changes */ + struct Task *po_ReadySigTask; /* task to signal */ + struct Library *po_IntBase; /* Intuition base for PoPo Task */ + struct Library *po_MUIBase; /* MUI base for PoPo Task */ + struct Library *po_DTBase; /* DataTypes base for PoPo Task */ + struct MsgPort *po_TimerMsgPort; /* Standard timer MsgPort */ + struct timerequest *po_TimerIOReq; /* Standard timer request */ + struct MUI_CustomClass *po_PoPoClass; /* PoPo Action Class */ + ULONG *po_PoPoObj; /* PoPo Action Object */ + ULONG *po_AppObj; /* App Object */ + ULONG *po_WindowObj; /* Window Object */ + ULONG *po_GroupObj; /* Group Object */ + ULONG *po_SaveObj; /* Save Button Object */ + ULONG *po_CloseObj; /* Close Button Object */ + ULONG *po_StickyObj; /* Sticky Object */ + ULONG *po_AboutMI; /* About MenuItem */ + ULONG *po_CloseMI; /* Close MenuItem */ + ULONG *po_TridentMI; /* Trident MenuItem */ + ULONG *po_MUIPrefsMI; /* MUI Prefs MenuItem */ + struct PsdEventHook *po_EventHandler; /* Event handler */ + struct List po_GadgetList; /* List of gadgets for a device */ + BOOL po_OpenRequest; /* open window requested */ + BOOL po_Sticky; /* sticky entries */ + STRPTR po_InsertSndFile; /* Path to insertion sound file */ + STRPTR po_RemoveSndFile; /* Path to removal sound file */ + struct List po_Sounds; /* List of loaded soundfiles */ +}; + +struct PsdHandlerTask +{ + struct Task *ph_Task; /* Event Handler Task */ + struct MsgPort *ph_MsgPort; /* Port for EventNote messages */ + LONG ph_ReadySignal; /* Signal to respond to task changes */ + struct Task *ph_ReadySigTask; /* task to signal */ + struct PsdEventHook *ph_EventHandler; /* Event handler */ + struct MsgPort *ph_TimerMsgPort; /* Port for timer requests */ + struct timerequest *ph_TimerIOReq; /* Standard timer request */ +}; + +struct PsdWStringMap +{ + WORD psm_ID; + STRPTR psm_String; +}; + +struct PsdUWStringMap +{ + UWORD psm_ID; + STRPTR psm_String; +}; + +struct PsdULStringMap +{ + ULONG psm_ID; + STRPTR psm_String; +}; + +/* The library node - private +*/ +struct PsdBase +{ + struct Library ps_Library; /* standard */ + UWORD ps_Flags; /* various flags */ + struct UtilityBase *ps_UtilityBase; /* for tags etc */ + struct Library *ps_DosBase; /* for dos stuff */ + BOOL ps_StackInit; /* Did we initialize the stack yet? */ + APTR ps_MemPool; /* Public Memory Pool */ + APTR ps_SemaMemPool; /* Memory Pool exclusively for Semaphore ReadLocks */ + struct List ps_DeadlockDebug; /* linked list of semaphore allocations */ + struct PsdLockSem ps_Lock; /* PBase lock */ + struct PsdLockSem ps_ConfigLock; /* Config semaphore */ + struct timerequest ps_TimerIOReq; /* Standard timer request */ + struct List ps_Hardware; /* List of Hardware Interfaces in use */ + struct List ps_Classes; /* List of Classes loaded */ + struct List ps_ErrorMsgs; /* List of Error Msgs */ + struct List ps_EventHooks; /* List of EventHandlers */ + struct MsgPort ps_EventReplyPort; /* Replyport for Events */ + struct List ps_ConfigRoot; /* Configuration FORMs */ + struct List ps_AlienConfigs; /* Configuration FORM from outer space */ + BOOL ps_CfgChangeMute; /* Don't generate config changed events */ + struct SignalSemaphore ps_ReentrantLock; /* Lock for non-reentrant stuff */ + struct SignalSemaphore ps_PoPoLock; /* Lock for non-reentrant stuff */ + ULONG ps_MemAllocated; /* Bytes of memory allocated by stack */ + UWORD ps_FunnyCount; /* Funny Message Counter */ + BOOL ps_ConfigRead; /* Has a config been loaded? */ + BOOL ps_CheckConfigReq; /* Set to true, to check if config changed */ + ULONG ps_ConfigHash; /* Last config hash value */ + ULONG ps_SavedConfigHash; /* Hash sum of last saved config */ + struct PsdGlobalCfg *ps_GlobalCfg; /* Global Config structure */ + struct PsdPoPo ps_PoPo; + ULONG ps_ReleaseVersion; /* Release Version for update info */ + ULONG ps_OSVersion; /* Internal OS Version descriptor */ + BOOL ps_StartedAsTask; /* Did we start in Task Mode before DOS was available? */ + struct PsdHandlerTask ps_EventHandler; /* Event handler */ +}; + +struct PsdEventHook +{ + struct Node peh_Node; /* Node linkage */ + struct MsgPort *peh_MsgPort; /* Target message port */ + ULONG peh_MsgMask; /* Mask of messages to send */ +}; + +struct PsdEventNote +{ + struct Message pen_Msg; /* Intertask communication message */ + UWORD pen_Event; /* Event number as specified above */ + APTR pen_Param1; /* Parameter 1 for event */ + APTR pen_Param2; /* Parameter 2 */ +}; + +struct PsdEventNoteInternal +{ + struct Node peni_Node; /* Node linkage */ + struct PsdEventNote peni_EventNote; /* Encapsulated PsdEventNote */ +}; + +struct PsdErrorMsg +{ + struct Node pem_Node; /* Node linkage */ + struct PsdBase *pem_Base; /* Uplinking */ + UWORD pem_Level; /* RC: 0=Note, 5=Warn, 10=Error, 20=Fail */ + STRPTR pem_Origin; /* From whom? */ + STRPTR pem_Msg; /* Actual error message */ + struct DateStamp pem_DateStamp; /* Date Stamp (if DOS available) */ +}; + +struct PsdIFFContext +{ + struct Node pic_Node; /* Node linkage */ + //struct PsdIFFContext *pic_Parent; /* Uplinking */ + struct List pic_SubForms; /* All sub forms */ + ULONG pic_FormID; /* 4 bytes FORM ID */ + ULONG pic_FormLength; /* Length of form */ + ULONG *pic_Chunks; /* Chunks (no forms) */ + ULONG pic_ChunksLen; /* Total length of chunks */ + ULONG pic_BufferLen; /* size of buffer allocated */ +}; + +struct PsdUsbClass +{ + struct Node puc_Node; /* Node linkage */ + struct PsdBase *puc_Base; /* Uplinking */ + struct Library *puc_ClassBase; /* Library pointer */ + STRPTR puc_ClassName; /* Name of class */ + STRPTR puc_FullPath; /* Full path and class name */ + UWORD puc_UseCnt; /* Number of bindings in use */ + BOOL puc_RemoveMe; /* Class scheduled for removal */ +}; + +struct PsdAppBinding +{ + struct Node pab_Node; /* Node linkage */ + struct PsdDevice *pab_Device; /* Uplinking */ + struct Hook *pab_ReleaseHook; /* CallBackHook for releasing binding */ + ULONG pab_UserData; /* User Data */ + struct Task *pab_Task; /* Task bound to */ + BOOL pab_ForceRelease; /* Force release of other app or class bindings */ +}; + +struct PsdHardware +{ + struct Node phw_Node; /* Node linkage */ + struct PsdBase *phw_Base; /* Uplinking */ + struct Task *phw_ReadySigTask; /* Task to send ready signal to */ + LONG phw_ReadySignal; /* Signal to send when ready */ + struct Task *phw_Task; /* Device task */ + STRPTR phw_DevName; /* Device name */ + ULONG phw_Unit; /* Unit number */ + + STRPTR phw_ProductName; /* Product name */ + STRPTR phw_Manufacturer; /* Manufacturer name */ + STRPTR phw_Description; /* Description string */ + STRPTR phw_Copyright; /* Copyright string */ + UWORD phw_Version; /* Version of device */ + UWORD phw_Revision; /* Device revision */ + UWORD phw_DriverVers; /* Driver version */ + ULONG phw_Capabilities; /* Driver/HW capabilities */ + + struct IOUsbHWReq *phw_RootIOReq; /* First IO Request */ + + struct PsdDevice *phw_RootDevice; /* Link to root hub of this hardware */ + struct PsdDevice *phw_DevArray[128]; /* DevAddress->Device mapping */ + struct List phw_Devices; /* List of devices */ + struct List phw_DeadDevices; /* List of disconnected devices */ + BOOL phw_RemoveMe; /* Hardware scheduled for removal */ + struct MsgPort phw_DevMsgPort; /* Quick device message port */ + struct MsgPort phw_TaskMsgPort; /* Quick task message port */ + volatile ULONG phw_MsgCount; /* Number of Messages pending */ +}; + +/* Flags for pd_Flags */ + +#define PDFF_LOWSPEED 0x0001 +#define PDFF_CONNECTED 0x0002 +#define PDFF_HASDEVADDR 0x0004 +#define PDFF_HASDEVDESC 0x0008 +#define PDFF_CONFIGURED 0x0010 +#define PDFF_HIGHSPEED 0x0020 +#define PDFF_NEEDSSPLIT 0x0040 +#define PDFF_LOWPOWER 0x0080 +#define PDFF_DEAD 0x0100 +#define PDFF_SUSPENDED 0x0200 +#define PDFF_APPBINDING 0x4000 +#define PDFF_DELEXPUNGE 0x8000 + +struct PsdDevice +{ + struct Node pd_Node; /* Node linkage */ + struct PsdHardware *pd_Hardware; /* Interfacing hardware */ + struct PsdLockSem pd_Lock; /* Access locking */ + struct PsdDevice *pd_Hub; /* Hub for device */ + APTR pd_DevBinding; /* Device binding */ + struct PsdUsbClass *pd_ClsBinding; /* Which class has the bond? */ + struct PsdConfig *pd_CurrentConfig; /* Direct pointer to currently set config */ + UWORD pd_UseCnt; /* Usage counter */ + UWORD pd_DevAddr; /* Device address */ + UWORD pd_CurrCfg; /* Current Configuration Number */ + UWORD pd_NumCfgs; /* Number of configurations available */ + UWORD pd_PowerDrain; /* Current power usage */ + UWORD pd_PowerSupply; /* Power provided from parent */ + UWORD pd_CurrLangID; /* Current Language ID */ + UWORD *pd_LangIDArray; /* Array of supported languages */ + UWORD pd_Flags; /* Lowspeed? */ + UWORD pd_HubPort; /* Port number at parent hub */ + UWORD pd_HubThinkTime; /* Think time for TT inter-transaction gap */ + UWORD pd_USBVers; /* USB Version */ + UWORD pd_DevClass; /* Class code */ + UWORD pd_DevSubClass; /* Subclass code */ + UWORD pd_DevProto; /* Device protocol code */ + UWORD pd_MaxPktSize0; /* Packet size for EP0 */ + UWORD pd_VendorID; /* Vendor ID */ + UWORD pd_ProductID; /* Product ID */ + UWORD pd_DevVers; /* Device release version */ + UWORD pd_CloneCount; /* Running Number to distinguish same devices */ + UWORD pd_DeadCount; /* Number of timeouts on the device */ + UWORD pd_IOBusyCount; /* Number of busy IOs (not including interrupt transfers) */ + struct timeval pd_LastActivity; /* Timestamp of last IO access (start or end) */ + STRPTR pd_MnfctrStr; /* Manufacturer string */ + STRPTR pd_ProductStr; /* Product string (custom?) */ + STRPTR pd_OldProductStr; /* Original product string */ + STRPTR pd_SerNumStr; /* Serial number string */ + STRPTR pd_IDString; /* Whole Device ID string */ + struct List pd_Configs; /* List of configurations */ + BOOL pd_IsNewToMe; /* Whether the device is connected the first time */ + struct PsdPoPoCfg pd_PoPoCfg; /* Inhibit PopUp and Class scan Config */ + struct List pd_Descriptors; /* Descriptors collected */ + struct List pd_RTIsoHandlers; /* List of RTIsoHandlers */ +}; + +struct PsdDescriptor +{ + struct Node pdd_Node; /* Node linkage */ + struct PsdDevice *pdd_Device; /* Up linkage */ + struct PsdConfig *pdd_Config; /* Up linkage (optional, depending on type of desc) */ + struct PsdInterface *pdd_Interface; /* Up linkage (optional, depending on type of desc) */ + struct PsdEndpoint *pdd_Endpoint; /* Up linkage (optional, depending on type of desc) */ + STRPTR pdd_Name; /* Supposed Descriptor Type Name */ + UWORD pdd_Type; /* Descriptor Type */ + UWORD pdd_Length; /* Number of bytes in descriptor */ + UWORD pdd_CSSubType; /* Subtype of ClassSpecific Descriptor */ + UBYTE *pdd_Data; /* Pointer to data */ +}; + +struct PsdConfig +{ + struct Node pc_Node; /* Node linkage */ + struct PsdDevice *pc_Device; /* Up linkage */ + UWORD pc_CfgNum; /* Config number */ + UWORD pc_Attr; /* Attributes */ + UWORD pc_MaxPower; /* MaxPower (in mA) */ + UWORD pc_NumIfs; /* Number of interfaces */ + STRPTR pc_CfgStr; /* Name of config */ + struct List pc_Interfaces; /* List of interfaces */ +}; + +struct PsdInterface +{ + struct Node pif_Node; /* Node linkage */ + struct PsdConfig *pif_Config; /* Up linkage */ + APTR pif_IfBinding; /* Interface Binding */ + struct PsdUsbClass *pif_ClsBinding; /* Which class has the bond? */ + UWORD pif_IfNum; /* Interface number */ + UWORD pif_Alternate; /* Alternate setting */ + UWORD pif_NumEPs; /* Number of Endpoints */ + UWORD pif_IfClass; /* Interface Class */ + UWORD pif_IfSubClass; /* Interface Subclass */ + UWORD pif_IfProto; /* Interface Protocol */ + STRPTR pif_IfStr; /* Interface String */ + STRPTR pif_IDString; /* Interface ID String */ + struct PsdInterface *pif_ParentIf; /* If interface is an alternate, uplink */ + struct List pif_AlterIfs; /* List of alternate interface not in use */ + struct List pif_EPs; /* List of endpoints */ +}; + +struct PsdEndpoint +{ + struct Node pep_Node; /* Node linkage */ + struct PsdInterface *pep_Interface; /* Up linkage */ + UWORD pep_EPNum; /* Endpoint address */ + UWORD pep_Direction; /* Direction (0=OUT, 1=IN) */ + UWORD pep_TransType; /* TransferType, see USEA-Flags */ + UWORD pep_MaxPktSize; /* Maximum packet size for EP */ + UWORD pep_NumTransMuFr; /* Number of transactions per µFrame */ + UWORD pep_Interval; /* Interval for polling in ms */ + UWORD pep_SyncType; /* Iso Synchronization Type */ + UWORD pep_UsageType; /* Iso Usage Type */ +}; + +/* Flags for pp_Flags */ +#define PFF_INPLACE 0x0001 /* streams: buffer is in place, needs no copying */ + +struct PsdPipe +{ + struct Message pp_Msg; /* Intertask communication message */ + struct PsdDevice *pp_Device; /* Up linkage */ + struct PsdEndpoint *pp_Endpoint; /* Endpoint linkage or NULL for default pipe */ + struct MsgPort *pp_MsgPort; /* Msg Port of task allocated pipe */ + struct PsdPipe *pp_AbortPipe; /* Pipe to abort */ + ULONG pp_Num; /* internal pipe number (used for streams) */ + UWORD pp_Flags; /* internal flags (used for streams) */ + struct IOUsbHWReq pp_IOReq; /* IO Request allocated for this pipe */ +}; + +/* Flags for pps_Flags */ +#define PSFF_ASYNCIO 0x0001 /* async task (r/w) */ +#define PSFF_SHORTTERM 0x0002 /* terminate read on short packet (r) */ +#define PSFF_READAHEAD 0x0004 /* read from usb device until buffer full (r) */ +#define PSFF_BUFFERREAD 0x0008 /* reads smaller than maxpktsize are buffered (r) */ +#define PSFF_BUFFERWRITE 0x0010 /* writes smaller than maxpktsize are buffered -- flush required (w) */ +#define PSFF_NOSHORTPKT 0x0020 /* don't terminate writes with a short packet (w) */ +#define PSFF_NAKTIMEOUT 0x0040 /* enable nak timeout (r/w) */ +#define PSFF_ALLOWRUNT 0x0080 /* allow reading of runt packets (r) */ +#define PSFF_DONOTWAIT 0x0100 /* non blocking IO (r) */ +#define PSFF_OWNMSGPORT 0x8000 /* internal flag */ + +struct PsdPipeStream +{ + struct Node pps_Node; /* Node linkage */ + struct PsdDevice *pps_Device; /* Up linkage */ + struct PsdEndpoint *pps_Endpoint; /* Endpoint linkage */ + struct MsgPort *pps_MsgPort; /* Msg Port of task allocated pipe */ + struct PsdPipe **pps_Pipes; /* Array of pipes */ + struct List pps_FreePipes; /* Inactive pipes */ + struct List pps_ReadyPipes; /* Ready pipes */ + struct Task *pps_AsyncTask; /* Task used for asynchroneous transfers */ + struct SignalSemaphore pps_AccessLock; /* Semaphore for reading & writing */ + struct PsdPipe *pps_ActivePipe; /* Pipe currently active (w) */ + ULONG pps_NumPipes; /* Number of pipes */ + ULONG pps_NakTimeoutTime; /* Nak Timeout time for pipe */ + ULONG pps_AbortSigMask; /* Signal mask for waking up read or write */ + UWORD pps_Flags; /* transfer flags */ + + UBYTE *pps_Buffer; /* globally allocated buffer for all pipes */ + ULONG pps_BufferSize; /* Size of each pipe buffer */ + ULONG pps_Offset; /* read or write offset into the first returned buffer */ + ULONG pps_BytesPending; /* bytes in read or write buffer */ + ULONG pps_ReqBytes; /* number of bytes currently requested */ + LONG pps_Error; /* last error occurred */ + UBYTE *pps_TermArray; /* termination char array */ +}; + +struct PsdRTIsoHandler +{ + struct Node prt_Node; /* Node linkage */ + struct PsdDevice *prt_Device; /* Up linkage */ + struct PsdEndpoint *prt_Endpoint; /* Endpoint linkage */ + struct PsdPipe *prt_Pipe; /* Pipe */ + struct Hook *prt_ReleaseHook; /* Hook to be called when device gets removed */ + struct IOUsbHWRTIso prt_RTIso; /* RT Iso structure */ +}; + +#endif /* LIBRARIES_POSEIDON_H */ diff --git a/rom/usb/poseidon/usbhardware.doc b/rom/usb/poseidon/usbhardware.doc new file mode 100644 index 000000000..fff6a2de3 --- /dev/null +++ b/rom/usb/poseidon/usbhardware.doc @@ -0,0 +1,674 @@ +TABLE OF CONTENTS + +usbhardware.device/--background-- +usbhardware.device/CMD_FLUSH +usbhardware.device/CMD_RESET +usbhardware.device/UHCMD_BULKXFER +usbhardware.device/UHCMD_CONTROLXFER +usbhardware.device/UHCMD_INTXFER +usbhardware.device/UHCMD_ISOXFER +usbhardware.device/UHCMD_QUERYDEVICE +usbhardware.device/UHCMD_USBOPER +usbhardware.device/UHCMD_USBRESET +usbhardware.device/UHCMD_USBRESUME +usbhardware.device/UHCMD_USBSUSPEND + + + usbhardware.device/--background-- usbhardware.device/--background-- + + PURPOSE + A usbhardware.device provides an API to various hardware + implementations of USB host controllers. According to the USB specs, + it may be referenced best as the host controller driver (HDC). + + This hardware API is used by the Poseidon USB protocol stack to + 'talk' to the USB hardware. + + This document is dated to 14-Feb-07 09:26:22. + + OVERVIEW + The abstraction level is that of the transaction layer: the device + must be able to send a series of packets to the USB and receive + and reassemble multiple packets from the USB. + + USB protocol error recovery is done inside the device (NAK handling, + retrial on error) without explicit interaction from the caller. + + The device must support the four transfer types interrupt, control, + bulk and isochroneous, it must be able to handle lowspeed devices + aswell as fullspeed devices. + + Also, USB constraints on the bus bandwidth allocation should be + be followed. + + ROOT HUB + The root hub must appear after a bus reset as default device on the + bus with address 0. It should have the ability to be configured like + any external hub. If your hardware does not provide a standard USB + hub device, you will have to emulate the root hub functionality. See + the USB specifications (chapter 11) for details. + + You must at least support the following standard descriptors: + Device Descriptor, Configuration Descriptor, Interface Descriptor, + Endpoint Descriptor, and Hub Descriptor. Other supported standard + requests and hub class requests must include ClearHubFeature, + ClearPortFeature, GetHubDescriptor, GetHubStatus, GetPortStatus, + SetHubFeature, and SetPortFeature. + + The hub requires to have an interrupt endpoint that returns the + status on a change of the port features. If the hardware allows more + efficient status check, interrupt requests to this endpoint can also + be queued and emulated of course. + + For USB 2.0, the root hub might not get the UHFF_HIGHSPEED bit set + for the first transactions. Normally, this should not be a problem, + but cater for this (see below). + + DATA SEQUENCE TOGGLES + Your driver has to check for correct DATA0/1 PID schemes as + specified in the USB specs. You have to keep track of the outgoing + toggle bits. Toggles are reset for an endpoint if a + ClearFeature(Endpoint_Halt) is successfully sent. + If SetAddress is sent, you must clear all toggle bits for all 16 + possible endpoints of the target device. + + Please be sure to get this right and TEST it. This must be working + for both BULK and INTERRUPT transfers. Control transfers keep track + of their toggle bits within the transfer. + + QUEUEING + Multiple requests to the very same endpoint of a device must be + queued in order (instead of being executed in parallel). This means + you have to keep track of the currently scheduled IORequests for + each endpoint. + + NAK TIMEOUT + It is essential to implement the NAK TIMEOUT feature for BULK, + INTERRUPT and even for CONTROL transfers. Without this, several + higher level class drivers will appear to hang until the device is + removed in certain error cases. On successfully received packets, + the NAK TIMEOUT timer needs to be reset. + + USB 2.0 + With the emerge of USB 2.0, Poseidon has added support for this by + extending the IORequest structure slightly with V3.x. New flags + include UHFF_HIGHSPEED (which has been there since the beginning) + and UHFF_SPLITTRANS. Poseidon V3.6 also adds UHFF_MULTI_1, + UHFF_MULTI_2 and UHFF_MULTI_3 and fixes some bugs. + + The new fields iouh_SplitHubAddr and iouh_SplitHubPort are filled + for USB 2.0 lowspeed and fullspeed split transactions. Note that + these fields are wrong for versions before V3.6 in the case you + have USB devices after a USB 1.1 hub after an USB 2.0 hub. + + If your root hub is USB 2.0, Poseidon will not know this until it + reads a USB 2.0 version number from the device descriptor. Hence, + it will not use UHFF_HIGHSPEED during enumeration of the root hub. + However, this is not a problem because the root hub can assume + highspeed transactions unless the UHFF_SPLITTRANS bit is set for + downstream low- and fullspeed USB 1.1 devices. + + The iouh_Interval field will use units of ms for USB 1.1 or units + of µFrames for highspeed transfers. It will not store x for 2^x, + but the real value 2^x. + + NOTES + The device should support multiple units whenever more than one + host controller of the supported type may be mounted. It is + recommended that units are opened on an exclusive basis. + + All fields except the iouh_Actual, io_Error, iouh_State and + iouh_ExtError fields shall not be modified by the device driver. + + With the V2 driver structures available in Poseidon V3.x and higher, + iouh_DriverPrivate1 and iouh_DriverPrivate2 are for your drivers + private use and can store anything you like. + + Data should be transferred via DMA on hardware implementations where + this is possible. Please take care of alignments and data field + lengths. While it normally should be the case that iouh_Data is + aligned on an even address, for bulk transfers maybe even on + a longword address, this is not guaranteed. Also, the length may + be of any odd value. Do not trash data behind the buffer. + + Be sure that the driver is able to send 0-bytes packets and + transfers accordingly. For OUT transfers, respect the + UHFF_NOSHORTPKT flag whenever the size of the transfer is a multiple + of iouh_MaxPktSize. + + Also notice, that iouh_MaxPktSize does not have to be a power of + two for interrupt or iso endpoints for your arithmetics. + + + usbhardware.device/CMD_FLUSH usbhardware.device/CMD_FLUSH + + NAME + CMD_FLUSH -- cancel all pending transfer requests + + FUNCTION + CMD_FLUSH aborts all UHCMD_CONTROLXFER, UHCMD_ISOXFER, UHCMD_INTXFER + and UHCMD_BULKXFER requests in progress or queued. + + INPUTS + mn_ReplyPort - pointer to message port that receives I/O request + if the quick flag (IOF_QUICK) is clear + io_Device - pointer to device node, must be set by (or copied from + I/O block set by) OpenDevice function + io_Unit - pointer to unit node to flush, set by OpenDevice + io_Command - command number for CMD_FLUSH + io_Flags - flags, must be cleared if not use: + IOF_QUICK - (CLEAR) reply I/O request + + OUTPUTS + none + + + usbhardware.device/CMD_RESET usbhardware.device/CMD_RESET + + NAME + CMD_RESET -- reset the hardware to a predefined state + + FUNCTION + CMD_RESET performs a hardware reset cycle. The hardware then is in a + predefined state. This will also cause a reset on the USB and the + bus going into operational state after about 50ms. + + INPUTS + mn_ReplyPort - pointer to message port that receives I/O request + if the quick flag (IOF_QUICK) is clear + io_Device - pointer to device node, must be set by (or copied from + I/O block set by) OpenDevice() function + io_Unit - pointer to unit node to reset, set by OpenDevice() + io_Command - command number for CMD_RESET + io_Flags - flags, must be cleared if not use: + IOF_QUICK - (CLEAR) reply I/O request + + OUTPUTS + io_Error - either 0, if everything went okay or + UHIOERR_HOSTERROR, if bus was not in operational state + after the bus reset. + SEE ALSO + UHCMD_USBRESET + + + usbhardware.device/UHCMD_BULKXFER usbhardware.device/UHCMD_BULKXFER + + NAME + UHCMD_BULKXFER -- start a bulk transfer to or from the bus + + FUNCTION + Starts a bulk transfer with the amount of data specified. The + direction of the transfer (host to device or device to host) is + determined by the setting in the iouh_Dir field. + + The data itself is split into packets of iouh_MaxPktSize length. + For IN-transactions, iouh_Data holds a pointer to the buffer to be + filled, for OUT-transactions, iouh_Data is a pointer to the data + to send to the device. + + In case of an error, the transfer will be retried up to three times. + + INPUTS + mn_ReplyPort - pointer to message port that receives I/O request + if the quick flag (IOF_QUICK) is clear + io_Device - pointer to device node, must be set by (or copied from + I/O block set by) OpenDevice() function + io_Unit - pointer to unit node to use, set by OpenDevice() + io_Command - command number for UHCMD_CONTROLXFER + io_Flags - flags, must be cleared if not use: + IOF_QUICK - (CLEAR) reply I/O request + + iouh_Flags - UHFF_LOWSPEED for low speed devices. + UHFF_HIGHSPEED for high speed USB2.0 devices. + full speed devices will be assumed otherwise. + UHFF_SPLITTRANS for low or fullspeed devices + behind a USB 2.0 hub. iouh_SplitHubAddr and + iouh_SplitHubPort are set accordingly. + UHFF_MULTI_1, UHFF_MULTI_2, UHFF_MULTI_3 + indicating the number of transactions per µFrame + for highspeed transfers. + UHFF_NOSHORTPKT will not send terminating short + packets (if the transfer length is a multiple + of iouh_MaxPktSize). This allows you to create + a continous bulk stream with multiple requests. + UHFF_NAKTIMEOUT will enable the NAK timeout + feature (see below). + If UHFF_ALLOWRUNTPKTS is set, the request will + not return UHIOERR_RUNTPACKET in any case. You + should check iouh_Actual for the amount of data + transferred. + iouh_Dir - either UHDIR_IN for device to host transfers + or UHDIR_OUT for host to device transfers. + iouh_DevAddr - device address from 0 to 127. + iouh_Endpoint - endpoint number from 0 to 15. + iouh_MaxPktSize - maximum size of a packet for this endpoint. + iouh_Data - pointer to a buffer to transport the data. + iouh_Length - number of bytes to transfer. + iouh_SplitHubAddr - for split transactions only: the hub device + address from 0 to 127. + iouh_SplitHubPort - for split transactions only: the hub port number + the USB 1.1 device is connected to from 0 to 255. + iouh_NakTimeout - if UHFF_NAKTIMEOUT is enabled, this specifies + the time in milliseconds until the request will + be retired with UHIOERR_NAKTIMEOUT due to the + endpoint constantly denying the request with + NAKs. This can be used to avoid hangs on broken + USB unit 1000 (1 second) is a reasonable value. + + + OUTPUTS + iouh_Actual - actual bytes transferred. + io_Error - if something went wrong, you will find a non-null + value here, indicating the error. + + SEE ALSO + UHCMD_CONTROLXFER, UHCMD_INTXFER, UHCMD_ISOXFER + + + usbhardware.device/UHCMD_CONTROLXFER usbhardware.device/UHCMD_CONTROLXFER + + NAME + UHCMD_CONTROLXFER -- start a control transfer to or from the bus + + FUNCTION + Starts a control transfer, containing a Setup phase, optional + Data phases (in or out) and the final Status phase. + + The setup stage contains of a 8 byte packet, with the USB standard + fields bmRequestType, bRequest, wIndex, wValue and wLength. + + If iouh_Length is greater than zero, a data phase is initiated and + the data is split into packets smaller or equal of iouh_MaxPktSize. + + The direction of the transfer (buffer to device or device to buffer) + is determined by the most significant bit of the bmRequestType field + in the setup packet. + + Finally, in the status stage the host controller will send a zero + bytes data packet to terminate the control transfer. + + In case of an error, the transfer will be retried up to three times. + + INPUTS + mn_ReplyPort - pointer to message port that receives I/O request + if the quick flag (IOF_QUICK) is clear + io_Device - pointer to device node, must be set by (or copied from + I/O block set by) OpenDevice() function + io_Unit - pointer to unit node to use, set by OpenDevice() + io_Command - command number for UHCMD_CONTROLXFER + io_Flags - flags, must be cleared if not use: + IOF_QUICK - (CLEAR) reply I/O request + + iouh_Flags - UHFF_LOWSPEED for low speed devices. + UHFF_HIGHSPEED for high speed USB2.0 devices. + full speed devices will be assumed otherwise. + UHFF_SPLITTRANS for low or fullspeed devices + behind a USB 2.0 hub. iouh_SplitHubAddr and + iouh_SplitHubPort are set accordingly. + UHFF_MULTI_1, UHFF_MULTI_2, UHFF_MULTI_3 + indicating the number of transactions per µFrame + for highspeed transfers. + UHFF_NAKTIMEOUT will enable the NAK timeout + feature (see below). + If UHFF_ALLOWRUNTPKTS is set, the request will + not return UHIOERR_RUNTPACKET in any case. You + should check iouh_Actual for the amount of data + transferred. + iouh_DevAddr - device address from 0 to 127. + iouh_Endpoint - endpoint number from 0 to 15. + iouh_MaxPktSize - maximum size of a packet for this endpoint. + iouh_Data - pointer to a buffer to transport the data. + iouh_Length - number of bytes to transfer. + iouh_SetupData - contents of the eight bytes setup packet. + The first bit in the bmRequestType field will + determine the direction (1=in, 0=out). + iouh_SplitHubAddr - for split transactions only: the hub device + address from 0 to 127. + iouh_SplitHubPort - for split transactions only: the hub port number + the USB 1.1 device is connected to from 0 to 255. + iouh_NakTimeout - if UHFF_NAKTIMEOUT is enabled, this specifies + the time in milliseconds until the request will + be retired with UHIOERR_NAKTIMEOUT due to the + endpoint constantly denying the request with + NAKs. This can be used to avoid hangs on broken + USB unit 1000 (1 second) is a reasonable value. + + OUTPUTS + iouh_Actual - actual bytes transferred during the data phase + (excluding the 8 bytes from the setup phase). + io_Error - if something went wrong, you will find a non-null + value here, indicating the error. + + SEE ALSO + UHCMD_BULKXFER, UHCMD_INTXFER, UHCMD_ISOXFER + + + usbhardware.device/UHCMD_INTXFER usbhardware.device/UHCMD_BULKXFER + + NAME + UHCMD_INTXFER -- installs an interrupt transfer to or from the bus + + FUNCTION + Installs an interrupt transfer. If no data is to be sent or the + target endpoint does not accept the packet, it will retry to + send the packets with the given time interval in iouh_Interval + until it succeeds. + + The direction of the transfer (host to device or device to host) is + determined by the setting in the iouh_Dir field. + + The data itself is split into packets of iouh_MaxPktSize length, + although in normal cases you will not request packets larger than + iouh_MaxPktSize. + + For IN-transactions, iouh_Data holds a pointer to the buffer to be + filled, for OUT-transactions, iouh_Data is a pointer to the data + to send to the device. + + In case of an error, the transfer will be retried up to three times. + This does not include the reception of NAK pakets, which does not + decrement the retry count. + + NOTE + An Interrupt transfer request will only return if the device actually + sends the data or if an error occurs. If you do DoIO(), you might get + blocked out, so better do asynchroneous calls like SendIO(). + + INPUTS + mn_ReplyPort - pointer to message port that receives I/O request + if the quick flag (IOF_QUICK) is clear + io_Device - pointer to device node, must be set by (or copied from + I/O block set by) OpenDevice() function + io_Unit - pointer to unit node to use, set by OpenDevice() + io_Command - command number for UHCMD_CONTROLXFER + io_Flags - flags, must be cleared if not use: + IOF_QUICK - (CLEAR) reply I/O request + + iouh_Flags - UHFF_LOWSPEED for low speed devices. + UHFF_HIGHSPEED for high speed USB2.0 devices. + full speed devices will be assumed otherwise. + UHFF_SPLITTRANS for low or fullspeed devices + behind a USB 2.0 hub. iouh_SplitHubAddr and + iouh_SplitHubPort are set accordingly. + UHFF_MULTI_1, UHFF_MULTI_2, UHFF_MULTI_3 + indicating the number of transactions per µFrame + for highspeed transfers. + UHFF_NOSHORTPKT will not send terminating short + packets (if the transfer length is a multiple + of iouh_MaxPktSize). Might not be sensible on + interrupt transfers. + UHFF_NAKTIMEOUT will enable the NAK timeout + feature (see below). + If UHFF_ALLOWRUNTPKTS is set, the request will + not return UHIOERR_RUNTPACKET in any case. You + should check iouh_Actual for the amount of data + transferred. + iouh_Dir - either UHDIR_IN for device to host transfers + or UHDIR_OUT for host to device transfers. + iouh_DevAddr - device address from 0 to 127. + iouh_Endpoint - endpoint number from 0 to 15. + iouh_MaxPktSize - maximum size of a packet for this endpoint. + iouh_Data - pointer to a buffer to transport the data. + iouh_Length - number of bytes to transfer. + iouh_Interval - interval in milliseconds for the request to be + retried in case of a NAK. For highspeed, this + value is in number of µFrames (units of + 125µsecs). + iouh_SplitHubAddr - for split transactions only: the hub device + address from 0 to 127. + iouh_SplitHubPort - for split transactions only: the hub port number + the USB 1.1 device is connected to from 0 to 255. + iouh_NakTimeout - if UHFF_NAKTIMEOUT is enabled, this specifies + the time in milliseconds until the request will + be retired with UHIOERR_NAKTIMEOUT due to the + endpoint constantly denying the request with + NAKs. This can be used to avoid hangs on broken + USB unit 1000 (1 second) is a reasonable value. + + OUTPUTS + iouh_Actual - actual bytes transferred. + io_Error - if something went wrong, you will find a non-null + value here, indicating the error. + + SEE ALSO + UHCMD_CONTROLXFER, UHCMD_BULKXFER, UHCMD_ISOXFER + + + usbhardware.device/UHCMD_ISOXFER usbhardware.device/UHCMD_ISOXFER + + NAME + UHCMD_ISOXFER -- start an isochronous transfer to or from the bus + + FUNCTION + Starts an isochronous transfer with the amount of data specified. + The direction of the transfer (host to device or device to host) is + determined by the setting in the iouh_Dir field. + + The data itself is split into packets of iouh_MaxPktSize length. + For IN-transactions, iouh_Data holds a pointer to the buffer to be + filled, for OUT-transactions, iouh_Data is a pointer to the data + to send to the device. + + Isochronous transfer are normally used for large, time-critical + data which does not need to be transferred reliably. + + In case of an error, the transfer will NOT be retried at all and + io_Error will contain the error number. + + INPUTS + mn_ReplyPort - pointer to message port that receives I/O request + if the quick flag (IOF_QUICK) is clear + io_Device - pointer to device node, must be set by (or copied from + I/O block set by) OpenDevice() function + io_Unit - pointer to unit node to use, set by OpenDevice() + io_Command - command number for UHCMD_CONTROLXFER + io_Flags - flags, must be cleared if not use: + IOF_QUICK - (CLEAR) reply I/O request + + iouh_Flags - UHFF_LOWSPEED for low speed devices. + UHFF_HIGHSPEED for high speed USB2.0 devices. + full speed devices will be assumed otherwise. + UHFF_SPLITTRANS for low or fullspeed devices + behind a USB 2.0 hub. iouh_SplitHubAddr and + iouh_SplitHubPort are set accordingly. + UHFF_MULTI_1, UHFF_MULTI_2, UHFF_MULTI_3 + indicating the number of transactions per µFrame + for highspeed transfers. + UHFF_NOSHORTPKT will not send terminating short + packets (if the transfer length is a multiple + of iouh_MaxPktSize). This allows you to create + a continous bulk stream with multiple requests. + If UHFF_ALLOWRUNTPKTS is set, the request will + not return UHIOERR_RUNTPACKET in any case. You + should check iouh_Actual for the amount of data + transferred. + iouh_Dir - either UHDIR_IN for device to host transfers + or UHDIR_OUT for host to device transfers. + iouh_DevAddr - device address from 0 to 127. + iouh_Endpoint - endpoint number from 0 to 15. + iouh_MaxPktSize - maximum size of a packet for this endpoint. + iouh_Data - pointer to a buffer to transport the data. + iouh_Length - number of bytes to transfer. + iouh_SplitHubAddr - for split transactions only: the hub device + address from 0 to 127. + iouh_SplitHubPort - for split transactions only: the hub port number + the USB 1.1 device is connected to from 0 to 255. + iouh_NakTimeout - if UHFF_NAKTIMEOUT is enabled, this specifies + the time in milliseconds until the request will + be retired with UHIOERR_NAKTIMEOUT due to the + endpoint constantly denying the request with + NAKs. This can be used to avoid hangs on broken + USB unit 1000 (1 second) is a reasonable value. + + OUTPUTS + iouh_Actual - actual bytes transferred. + io_Error - if something went wrong, you will find a non-null + value here, indicating the error. + + SEE ALSO + UHCMD_CONTROLXFER, UHCMD_BULKXFER, UHCMD_INTXFER + + + usbhardware.device/UHCMD_QUERYDEVICE usbhardware.device/UHCMD_QUERYDEVICE + + NAME + UHCMD_QUERYDEVICE -- get hardware information + + FUNCTION + Can be used to acquire information about the hardware and its + driver. The command uses a TagList as parameter in iouh_Data. + + Each taglist entry holds a pointer to a longword (ULONG *), as + usually, and the corresponding data is also written as an ULONG. + + TAGS + Currently defined tags include: + + UHA_State (UWORD) - Returns a bitmap of the current USB state. + See UHS flags in devices/usbhardware.h. + UHA_Manufacturer (STRPTR) - Manufactuerer string. + UHA_ProductName (STRPTR) - Product string. + UHA_Version (UWORD) - Version number. + UHA_Revision (UWORD) - Revision of device. + UHA_Description (STRPTR) - String describing features of device. + UHA_Copyright (STRPTR) - Copyright message. + UHA_DriverVersion (UWORD) - BCD encoded version number of the + IORequest structure. Currently, only + 0x100 and 0x200 are valid. + + INPUTS + mn_ReplyPort - pointer to message port that receives I/O request + if the quick flag (IOF_QUICK) is clear + io_Device - pointer to device node, must be set by (or copied from + I/O block set by) OpenDevice() function + io_Unit - pointer to unit node to use, set by OpenDevice() + io_Command - command number for UHCMD_QUERYDEVICE + io_Flags - flags, must be cleared if not use: + IOF_QUICK - (CLEAR) reply I/O request + iouh_Data - pointer to a TagList to fill + + OUTPUTS + iouh_Actual - number of tags filled. + iouh_State - current status, if UHA_State was included. Will + not be changed otherwise. + + SEE ALSO + devices/usbhardware.h + + + usbhardware.device/UHCMD_USBOPER usbhardware.device/UHCMD_USBOPER + + NAME + UHCMD_USBOPER -- ask USB into operational mode + + FUNCTION + This command try to get the USB operational, whatever mode it + previously might have been. + + INPUTS + mn_ReplyPort - pointer to message port that receives I/O request + if the quick flag (IOF_QUICK) is clear + io_Device - pointer to device node, must be set by (or copied from + I/O block set by) OpenDevice() function + io_Unit - pointer to unit node to use, set by OpenDevice() + io_Command - command number for UHCMD_USBOPER + io_Flags - flags, must be cleared if not use: + IOF_QUICK - (CLEAR) reply I/O request + + OUTPUTS + iouh_State - current status of bus. + io_Error - either 0, if everything went okay or + UHIOERR_HOSTERROR, if bus was not in operational state + after this command. + + SEE ALSO + UHCMD_USBSUSPEND, UHCMD_USBRESUME, UHCMD_USBRESET + + + usbhardware.device/UHCMD_USBRESET usbhardware.device/UHCMD_USBRESET + + NAME + UHCMD_USBRESET -- reset USB + + FUNCTION + This command will reset the USB. After about 50ms the USB will + automatically go into operational mode. + + INPUTS + mn_ReplyPort - pointer to message port that receives I/O request + if the quick flag (IOF_QUICK) is clear + io_Device - pointer to device node, must be set by (or copied from + I/O block set by) OpenDevice() function + io_Unit - pointer to unit node to use, set by OpenDevice() + io_Command - command number for UHCMD_USBRESET + io_Flags - flags, must be cleared if not use: + IOF_QUICK - (CLEAR) reply I/O request + + OUTPUTS + iouh_State - current status of bus. + io_Error - either 0, if everything went okay or + UHIOERR_HOSTERROR, if bus was not in operational state + after the bus reset. + + SEE ALSO + CMD_RESET, UHCMD_USBRESUME, UHCMD_USBSUSPEND, UHCMD_USBOPER + + + usbhardware.device/UHCMD_USBRESUME usbhardware.device/UHCMD_USBRESUME + + NAME + UHCMD_USBRESUME -- go from suspend into operational mode + + FUNCTION + This command will wake the bus from suspend mode. The SOF + generation will restart right after, enabling the bus again. + + INPUTS + mn_ReplyPort - pointer to message port that receives I/O request + if the quick flag (IOF_QUICK) is clear + io_Device - pointer to device node, must be set by (or copied from + I/O block set by) OpenDevice() function + io_Unit - pointer to unit node to use, set by OpenDevice() + io_Command - command number for UHCMD_USBRESUME + io_Flags - flags, must be cleared if not use: + IOF_QUICK - (CLEAR) reply I/O request + + OUTPUTS + iouh_State - current status of bus. + io_Error - either 0, if everything went okay or + UHIOERR_HOSTERROR, if bus was not in operational state + after the resume command. + + SEE ALSO + UHCMD_USBSUSPEND, UHCMD_USBOPER, UHCMD_USBRESET + + + usbhardware.device/UHCMD_USBSUSPEND usbhardware.device/UHCMD_USBSUSPEND + + NAME + UHCMD_USBSUSPEND -- change bus into suspend mode + + FUNCTION + UHCMD_USBSUSPEND will ask the USB to go into suspend mode. SOF + generation will be stopped. + + INPUTS + mn_ReplyPort - pointer to message port that receives I/O request + if the quick flag (IOF_QUICK) is clear + io_Device - pointer to device node, must be set by (or copied from + I/O block set by) OpenDevice() function + io_Unit - pointer to unit node to use, set by OpenDevice() + io_Command - command number for UHCMD_USBSUSPEND + io_Flags - flags, must be cleared if not use: + IOF_QUICK - (CLEAR) reply I/O request + + OUTPUTS + iouh_State - current status of bus. + io_Error - either 0, if everything went okay or + UHIOERR_HOSTERROR, if bus could not be suspended. + + SEE ALSO + UHCMD_USBRESUME, UHCMD_USBRESET, UHCMD_USBOPER + + + diff --git a/rom/usb/trident/ActionClass.c b/rom/usb/trident/ActionClass.c new file mode 100644 index 000000000..23c93ea0e --- /dev/null +++ b/rom/usb/trident/ActionClass.c @@ -0,0 +1,5460 @@ +/***************************************************************************** +** This is the Action custom class, a sub class of Area.mui. +******************************************************************************/ + +#include "debug.h" + +#define USE_INLINE_STDARG +#define __NOLIBBASE__ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Trident.h" +#include "ActionClass.h" +#include "IconListClass.h" +#include "DevWinClass.h" +#include "CfgListClass.h" + +extern struct ExecBase *SysBase; +extern struct Library *ps; +extern struct IntuitionBase *IntuitionBase; +extern struct DosLibrary *DOSBase; + +#define NewList(list) NEWLIST(list) + +#define USE_NEPTUNE8_BODY +//#define USE_NEPTUNE8_HEADER +#define USE_NEPTUNE8_COLORS +#include "neptune8logo.c" + +#define CLASSPATH "SYS:Classes/USB" +#define STACKLOADER "Sys/poseidon.prefs" + +/* /// "Some strings" */ +static STRPTR mainpanels[] = +{ + "General", + "Controllers", + "Devices", + "Classes", + "Options", + "Popups", + "Config", + NULL +}; + +static STRPTR errlvlstrings[] = +{ + "All messages", + "Warnings and worse", + "Errors and failures", + "Failures only", + NULL +}; + +static STRPTR popupnewdevicestrings[] = +{ + "Never open a popup window! Bah!", + "Only popup on an error condition", + "Popup on new, unknown devices", + "Popup, if there is no binding", + "Popup, if there is no config yet", + "Popup on configurable class", + "Popup, regardless of binding", + "Always immediately annoy me", + NULL +}; +/* \\\ */ + +/* /// "Some lyrics" */ +#ifndef __MPREFS__ +static char *aimeelyrics[] = +{ + // 0 + "\33l\33iIn our endeavor we are never seeing eye to eye\n" + "No guts to sever so forever may we wave goodbye\n" + "And you're always telling me that it's my turn to move\n" + "When I wonder what could make the needle jump the groove\n" + "I won't fall for the oldest trick in the book\n" + "So don't sit there and think you're off of the hook\n" + "By saying there is no use changing 'cause\n\n" + "That's just what you are\n" + "That's just what you are\n" + "\33r(Aimee Mann) ", + + // 1 + "\33l\33iI can't do it\n" + "I can't conceive\n" + "You're everything you're\n" + "Trying to make me believe\n" + "'Cause this show is\n" + "Too well designed\n" + "Too well to be held\n" + "With only me in mind\n\n" + "And how am I different?\n" + "How am I different?\n" + "How am I different?\n" + "\33r(Aimee Mann) ", + + // 2 + "\33l\33i'Cause I'll never prove that my\n" + "Motives were pure\n" + "So let's remove any question of cure\n" + "'Cause even though you've made it\n" + "Pretty obscure\n" + "Baby, it's clear, from here -\n" + "You're losing your atmosphere\n" + "From here, you're losing it\n" + "\33r(Aimee Mann) ", + + // 3 + "\33l\33iOh, for the sake of momentum\n" + "Even thought I agree with that stuff\n" + "About seizing the day\n" + "But I hate to think of effort expended\n" + "All those minutes and days and hours\n" + "I've have frittered away\n\n" + "And I know life is getting shorter\n" + "I can't bring myself to set the scene\n" + "Even when it's approaching torture\n" + "I've got my routine\n" + "\33r(Aimee Mann) ", + + // 4 + "\33l\33i'Cause nothing is good enough\n" + "For people like you\n" + "Who have to have someone\n" + "Take the fall\n" + "And something to sabotage -\n" + "Determined to lose it all\n\n" + "Ladies and gentlemen -\n" + "Here's exhibit A\n" + "Didn't I try again?\n" + "And did the effort pay?\n" + "Wouldn't a smarter man\n" + "Simply walk away?\n" + "\33r(Aimee Mann) ", + + // 5 + "\33l\33iIt's not\n" + "What you thought\n" + "When you first\n" + "Began it\n" + "You got\n" + "What you want\n" + "Now you can hardly\n" + "Stand it, though\n" + "But now you know\n" + "It's not going to stop\n" + "It's not going to stop\n" + "It's not going to stop\n" + "'Til you wise up\n" + "\33r(Aimee Mann) ", + + // 6 + "\33l\33iI don't know you from Adam, it could make my day\n" + "If you leave me a message I'll give it away\n" + "'Cause the most perfect strangers that you can talk to\n" + "Are the ones who pretend that you're not really you\n\n" + "And with any attempts here to play Frankenstein\n" + "Come with plenty of chances for changing your mind\n" + "When you're building your own creation\n" + "Nothing's better than real\n" + "Than a real imitation\n" + "\33r(Aimee Mann) ", + + // 7 + "\33l\33iOh, experience is cheap\n" + "If that's the company you keep\n" + "And before you know that it's free\n" + "You've had it\n\n" + "Like most amazing things\n" + "It's easy to miss and easy to mistake\n" + "For when things are really great\n" + "It just means everything's in its place\n" + "\33r(Aimee Mann) ", + + // 8 + "\33l\33iSo here I'm sitting in my car at the same old stoplight\n" + "I keep waiting for a change but I don't know what\n" + "So red turns into green turning into yellow\n" + "But I'm just frozen here on the same old spot\n" + "And all I have to do is just press the pedal\n" + "But I'm not\n" + "No, I'm not\n" + "\33r(Aimee Mann) ", + + // 9 + "\33l\33iSay you were split, you were split in fragments\n" + "And none of the pieces would talk to you\n" + "Wouldn't you want to be who you had been?\n" + "Well, baby I want that, too\n\n" + "So better take the keys and drive forever\n" + "Staying won't put these futures back together\n" + "All the perfect drugs and superheroes\n" + "wouldn't be enough to bring me up to zero\n" + "\33r(Aimee Mann) ", + + // 10 + "\33l\33iBut nobody wants to hear this tale\n" + "The plot is clichéd, the jokes are stale\n" + "And baby we've all heard it all before\n" + "Oh, I could get specific but\n" + "Nobody needs a catalog\n" + "With details of a love I can't sell anyone\n\n" + "And aside from that\n" + "This chain of reaction, baby, is losing a link\n" + "Thought I'd hope you'd know what\n" + "I tried to tell you and if you don't\n" + "I could draw you a picture in invisible ink\n" + "\33r(Aimee Mann) ", + + // 11 + "\33l\33iWell, she's the face\n" + "And I'm the double\n" + "Who keeps the pace\n" + "And clears the rubble\n" + "And, Lost In Space,\n" + "Fills up the bubble with air\n\n" + "By just pretending to care\n" + "Like I'm not even there\n" + "Gone, but I don't know where\n" + "\33r(Aimee Mann) ", + + // 12 + "\33l\33iOh Mario -- why if this is nothing\n" + "I'm finding it so hard to dismiss\n" + "If you're what I need,\n" + "Then only you can save me\n" + "So come on baby -- give me the fix\n" + "And let's just talk about it\n" + "I've got to talk about it\n\n" + "Because nobody knows\n" + "That's how I nearly fell\n" + "Trading clothes\n" + "And ringing Pavlov's bell\n" + "History shows --\n" + "Like it was show and tell\n" + "\33r(Aimee Mann) ", + + // 13 + "\33l\33iWe have crossed the rubicon\n" + "Our ship awash, our rudder gone\n" + "The rats have fled but I'm hanging on\n" + "Let me try, baby, try\n\n" + + "Baby, please -- let me begin\n" + "Let me be your heroin\n" + "Hate the sinner but love the sin\n" + "Let me be your heroin\n" + "\33r(Aimee Mann) ", + + // 14 + "\33l\33iI was undecided like you\n" + "At first\n" + "But I could not stem the tide of overwhelm\n" + "And thirst\n" + "You try to keep it going, but a lot of avenues\n" + "Just aren't open to you\n" + "when you're real bad news\n\n" + "I've got love and anger\n" + "They come as a pair\n" + "You can take your chances\n" + "But buyer beware\n" + "And I won't\n" + "Make you feel bad\n" + "When I show you\n" + "This big ball of sad isn't\n" + "Worth even filling with air\n" + "\33r(Aimee Mann) ", + + // 15 + "\33l\33iThe moth don't care if the flame is real\n" + "'Cause moth and flame got a sweetheart deal\n" + "And nothing fuels a good flirtation\n" + "Like need and anger and desperation\n" + "No, the moth don't care if the flame is real\n" + "No, the moth don't care if the flame is real\n\n" + "So come on, let's go -- ready or not\n" + "'Cause there's a flame I know, hotter than hot\n" + "And with a fuse that's so thoroughly shot away\n" + "\33r(Aimee Mann) ", + + // 16 + "\33l\33iYou've gotta hope\n" + "That there's someone for you\n" + "As strange as you are\n" + "Who can cope\n" + "With the things that you do\n" + "Without trying too hard\n\n" + + "'Cause you can bend the truth\n" + "'Till it's suiting you\n" + "These things that you're wrapping all around you\n" + "Never know what they will amount to\n" + "If you're life is just going on without you\n" + "It's the end of the things you know\n" + "Here we go\n" + "\33r(Jon Brion) ", + + // 17 + "\33l\33iNothing in this world is gonna hold me\n" + "No thugs in this road are gonna roll me\n" + "No fast talking girl is gonna slow me\n" + "Nothing's gonna stop me at all\n" + "I'm walking through walls\n\n" + + "Some people complain\n" + "Yeah they caterwaul\n" + "I could do the same\n" + "But I'm walking through walls\n" + "\33r(Jon Brion) ", + + // 18 + "\33l\33iIt should be boredom by now\n" + "I know the tricks of the trade\n" + "But it goes on anyhow\n" + "Sometimes the answers are ready made\n\n" + + "And I go for it every time\n" + "Just like a heavy drinker\n" + "I go for it every time\n" + "Hook, line and sinker\n" + "\33r(Jon Brion) ", + + // 19 + "\33l\33iIn my dream I'm often running\n" + "To a place that's out of view\n" + "Of every kind of memory\n" + "With strings that tie to you\n\n" + + "And though a change has taken place\n" + "And I no longer do adore her\n" + "Still every God forsaken place\n" + "Is always right around the corner\n" + "\33r(Jon Brion) ", + + // 20 + "\33l\33iThings begin, things decay\n" + "And you've gotta find a way\n" + "To be ok\n" + "But it you want to spend the day\n" + "Wond'ring what it's all about\n" + "Go and knock yourself out\n" + "\33r(Jon Brion) ", + + // 21 + "\33l\33iThink your troubles are so serious\n" + "Well one day you'll be so long gone\n" + "Cause nothing ever lasts\n" + "It all gets torn to shreds\n" + "If something's ever lasting\n" + "It's over our heads\n" + "It's over our heads\n" + "\33r(Jon Brion) ", + + // 22 + "\33l\33iAnd why should I begin?\n" + "Cause there's a whirl pool\n" + "Of people who will stop\n" + "And they will tell you\n" + "The things that you will not\n" + "They roll their eyes and they call you crazy\n\n" + "But you get the feeling\n" + "That you get what it's about\n" + "It's just a feeling\n" + "You can't really spell it out\n" + "You get the feeling\n" + "That you get what it's about\n" + "\33r(Jon Brion) ", + + // 23 + "\33l\33iI don't wait by the phone like I used to\n" + "I don't hope for kind words you might say\n" + "You don't prey on my mind like you used to\n" + "But you can still ruin my day\n" + "You can still ruin my day\n" + "\33r(Jon Brion) ", + + // 24 + "\33l\33iI had to break the window\n" + "It just had to be it was in my way\n" + "Better that I break the window\n" + "Then forget what I had to say\n\n" + + "So again I've done the right thing\n" + "I was never worried about that\n" + "The answer's always been in clear view\n" + "But even when the window's clean\n" + "I still can't see for the fact\n" + "That when it's clean it's so clear\n" + "I can't tell what I'm looking through\n" + "\33r(Fiona Apple) ", + + // 25 + "\33l\33iI seem to you to seek a new disaster every day\n" + "You deem me due to clean my view and be at peace and lay\n" + "I mean to prove, I mean to move in my own way\n" + "And say I've been getting along for long before you came into the play\n\n" + + "If there was a better way to go then it would find me\n" + "I can't help it the road just rolls out behind me\n" + "Be kind to me, or treat me mean\n" + "I'll make the most of it, I'm an extraordinary machine\n" + "\33r(Fiona Apple) ", + + // 26 + "\33l\33iEverything good I deem too good to be true\n" + "Everything else is just a bore\n" + "Everything I have to look forward to\n" + "Has a pretty painful and very imposing before\n\n" + + "Oh sailor why'd you do it\n" + "What'd you do that for\n" + "Saying there's nothing to it\n" + "And then letting it go by the boards\n" + "\33r(Fiona Apple) ", + + // 27 + "\33l\33iIf you don't have a date\n" + "Celebrate\n" + "Go out and sit on the lawn\n" + "And do nothing\n" + "'Cause it's just what you must do\n" + "And nobody does it anymore\n\n" + "No, I don't believe in the wasting of time,\n" + "But I don't believe that I'm wasting mine\n" + "\33r(Fiona Apple) ", + + // 28 + "\33l\33i'Cause I do know what's good for me\n" + "And I've done what I could for you\n" + "But you're not benefiting, and yet I'm sitting\n" + "Singing again, sing, sing again\n\n" + "How can I deal with this, if he won't get with this\n" + "Am I gonna heal from this, he won't admit to it\n" + "Nothing to figure out, I got to get him out\n" + "It's time the truth was out that he don't give a shit about me\n" + "\33r(Fiona Apple) ", + + // 29 + "\33l\33iSo my darling, give me your absence tonight\n" + "Take all of your sympathy and leave it outside\n" + "'Cause there's no kind of loving that can make this alright\n" + "I'm trying to find a place I belong\n\n" + "And I suddenly feel like a different person\n" + "From the roots of my soul come a gentle coercion\n" + "And I ran my hand over a strange inversion\n" + "As the darkness turns into the dawn\n" + "The child is gone\n" + "\33r(Fiona Apple) ", + + // 30 + "\33l\33iBut then the dove of hope began its downward slope\n" + "And I believed for a moment that my chances were\n" + "Approaching to be grabbed\n" + "But as it came down near, so did a weary tear\n" + "I thought it was a bird, but it was just a paper bag\n" + "\33r(Fiona Apple) ", + + // 31 + "\33l\33iWait 'til I get him back\n" + "He won't have a back to scratch\n" + "Yeah, keep turning that chin\n" + "And you will see my face\n" + "As I figure how to kill what I cannot catch\n" + "\33r(Fiona Apple) " + +}; +#endif + +char poseidonshorthelp[] = +{ + "Poseidon (his latin name Neptune) the god of the sea\n" + "and its inhabitants, and one of the Olympians, the son\n" + "of Cronus and Rhea, brother of Zeus, Hades, Demeter,\n" + "Hera, Hestia. He was married to Amphitrite, a Nereid,\n" + "and had by her the son Triton, a merman. Like other\n" + "Olympians, had many love affairs (e.g. with Medusa)\n" + "and numerous children (e.g. Pegasos)." +}; +/* \\\ */ + +/* /// "HardwareListDisplayHook()" */ +AROS_UFH3(LONG, HardwareListDisplayHook, + AROS_UFHA(struct Hook *, hook, A0), + AROS_UFHA(char **, strarr, A2), + AROS_UFHA(struct HWListEntry *, hlnode, A1)) +{ + AROS_USERFUNC_INIT + + static char buf[16]; + static char buf2[32]; + char *cmpstr; + char *strptr; + struct IconListData *data = (struct IconListData *) INST_DATA(IconListClass->mcc_Class, ((struct ActionData *) hook->h_Data)->hwlistobj); + + if(hlnode) + { + psdSafeRawDoFmt(buf, 16, "%ld", hlnode->unit); + psdSafeRawDoFmt(buf2, 32, "\33O[%08lx] %s", hlnode->phw ? data->mimainlist[18] : data->mimainlist[5], hlnode->phw ? "Yes" : "No"); + strptr = hlnode->devname; + cmpstr = strptr; + while(*cmpstr) + { + switch(*cmpstr++) + { + case ':': + case '/': + strptr = cmpstr; + break; + } + } + *strarr++ = strptr; + *strarr++ = buf; + *strarr++ = buf2; + *strarr = hlnode->prodname ? hlnode->prodname : (STRPTR) "\33iunknown until online"; + } else { + *strarr++ = "\33l\33uName"; + *strarr++ = "\33l\33uUnit"; + *strarr++ = "\33l\33uOnline"; + *strarr = "\33l\33uProduct"; + } + return(0); + AROS_USERFUNC_EXIT +} +/* \\\ */ + +/* /// "PrefsListDisplayHook()" */ +AROS_UFH3(LONG, PrefsListDisplayHook, + AROS_UFHA(struct Hook *, hook, A0), + AROS_UFHA(char **, strarr, A2), + AROS_UFHA(struct PrefsListEntry *, plnode, A1)) +{ + AROS_USERFUNC_INIT + + static char buf[16]; + + if(plnode) + { + psdSafeRawDoFmt(buf, 16, "%ld", plnode->size); + *strarr++ = plnode->type; + *strarr++ = plnode->id; + *strarr++ = plnode->owner; + *strarr = buf; + } else { + *strarr++ = "\33l\33uType"; + *strarr++ = "\33l\33uDescription"; + *strarr++ = "\33l\33uOwner"; + *strarr = "\33l\33uSize"; + } + return(0); + AROS_USERFUNC_EXIT +} +/* \\\ */ + +/* /// "CheckDeviceValid()" */ +BOOL CheckDeviceValid(struct DevListEntry *dlnode) +{ + struct Node *pd = NULL; + if(dlnode) + { + if(dlnode->pd) + { + while((pd = psdGetNextDevice(pd))) + { + if(pd == dlnode->pd) + { + return(TRUE); + } + } + } + dlnode->pd = NULL; + } + return(FALSE); +} +/* \\\ */ + +/* /// "DeviceListDisplayHook()" */ +AROS_UFH3(LONG, DeviceListDisplayHook, + AROS_UFHA(struct Hook *, hook, A0), + AROS_UFHA(char **, strarr, A2), + AROS_UFHA(struct DevListEntry *, dlnode, A1)) +{ + AROS_USERFUNC_INIT + + ULONG clsimg; + ULONG stateimg; + IPTR devclass; + IPTR devsubclass; + IPTR devproto; + IPTR devislowspeed; + IPTR devishighspeed; + IPTR devisconnected; + IPTR devhasaddress; + IPTR devhasdevdesc; + IPTR devhasappbinding; + IPTR devisconfigured; + IPTR devlowpower = 0; + IPTR devisdead = 0; + IPTR devissuspended = 0; + APTR devbinding; + BOOL goodbinding = FALSE; + BOOL hasmultiple = FALSE; + IPTR ifclass; + IPTR ifsubclass; + IPTR ifproto; + struct List *pclist; + struct List *piflist; + struct Node *pc; + struct Node *pif; + APTR ifbinding; + struct Library *bindingcls; + struct Task *bindingtask; + STRPTR statestr; + STRPTR tmpcptr; + static char buf[100]; + static char buf2[32]; + static char buf3[32]; + STRPTR bufptr; + ULONG buflen = 99; + struct IconListData *data = (struct IconListData *) INST_DATA(IconListClass->mcc_Class, ((struct ActionData *) hook->h_Data)->devlistobj); + + if(dlnode) + { + if(!CheckDeviceValid(dlnode)) + { + psdSafeRawDoFmt(buf2, 32, "\33O[%08lx] %s", + data->mimainlist[0], + "Spiritual"); + psdSafeRawDoFmt(buf3, 32, "\33O[%08lx] %s", + data->mimainlist[5], "Ghost"); + *strarr++ = ""; + *strarr++ = "Zero"; + *strarr++ = buf3; + *strarr++ = buf2; + *strarr = "None"; + return(0); + } + + psdGetAttrs(PGA_DEVICE, dlnode->pd, + DA_Binding, &devbinding, + DA_BindingClass, &bindingcls, + DA_ProductName, strarr++, + DA_IsLowspeed, &devislowspeed, + DA_IsHighspeed, &devishighspeed, + DA_IsConnected, &devisconnected, + DA_HasAddress, &devhasaddress, + DA_HasDevDesc, &devhasdevdesc, + DA_IsConfigured, &devisconfigured, + DA_IsDead, &devisdead, + DA_IsSuspended, &devissuspended, + DA_LowPower, &devlowpower, + DA_HasAppBinding, &devhasappbinding, + DA_Class, &devclass, + DA_SubClass, &devsubclass, + DA_Protocol, &devproto, + DA_ConfigList, &pclist, + TAG_END); + *strarr++ = (devislowspeed ? "Low" : (devishighspeed ? "High" : "Full")); + if(devissuspended) + { + statestr = "Suspended"; + stateimg = 19; + } + else if(devisdead) + { + statestr = devlowpower ? "Dead / LP" : "Dead"; + stateimg = 5; + } + else if(devlowpower) + { + statestr = "Low Power"; + stateimg = 19; + } + else if(devisconfigured) + { + statestr = "Running"; + stateimg = 18; + } + else if(devhasdevdesc) + { + statestr = "DevDesc"; + stateimg = 5; + } + else if(devhasaddress) + { + statestr = "ValidAddr"; + stateimg = 5; + } + else if(devisconnected) + { + statestr = "Connected"; + stateimg = 5; + } else { + statestr = "Dead"; + stateimg = 5; + } + *strarr++ = buf3; + if(!devclass) + { + ifclass = 0; + pc = pclist->lh_Head; + while(pc->ln_Succ) + { + psdGetAttrs(PGA_CONFIG, pc, + CA_InterfaceList, &piflist, + TAG_END); + pif = piflist->lh_Head; + while(pif->ln_Succ) + { + psdGetAttrs(PGA_INTERFACE, pif, + IFA_Class, &ifclass, + IFA_SubClass, &ifsubclass, + IFA_Protocol, &ifproto, + TAG_END); + if(ifclass) + { + if(!devclass) + { + devclass = ifclass; + devsubclass = ifsubclass; + devproto = ifproto; + } else { + if(devclass != ifclass) + { + devclass = 0; + hasmultiple = TRUE; + break; + } else { + if(devsubclass != ifsubclass) + { + devsubclass = 0; + devproto = 0; + } else { + if(devproto != ifproto) + { + devproto = 0; + } + } + } + } + } + pif = pif->ln_Succ; + } + pc = pc->ln_Succ; + } + } + clsimg = 5; + switch(devclass) + { + case STILLIMG_CLASSCODE: + clsimg = 22; + break; + case BLUETOOTH_CLASSCODE: + clsimg = 21; + break; + case FWUPGRADE_CLASSCODE: + clsimg = 1; + break; + case VENDOR_CLASSCODE: + clsimg++; + case SECURITY_CLASSCODE: + clsimg++; + case SMARTCARD_CLASSCODE: + clsimg++; + case CDCDATA_CLASSCODE: + clsimg++; + case HUB_CLASSCODE: + clsimg++; + case MASSSTORE_CLASSCODE: + clsimg++; + case PRINTER_CLASSCODE: + clsimg++; + case PHYSICAL_CLASSCODE: + clsimg++; + case HID_CLASSCODE: + clsimg += 2; + case CDCCTRL_CLASSCODE: + clsimg++; + case AUDIO_CLASSCODE: + clsimg++; + break; + + default: + clsimg = 0; + } + if(!hasmultiple) + { + psdSafeRawDoFmt(buf2, 32, "\33O[%08lx] %s", + data->mimainlist[clsimg], + psdNumToStr(NTS_COMBOCLASS, + (devclass<mimainlist[0], "Multiple"); + } + *strarr++ = buf2; + if(devbinding) + { + if(devhasappbinding) + { + psdGetAttrs(PGA_APPBINDING, devbinding, + ABA_Task, &bindingtask, + TAG_END); + *strarr = bindingtask->tc_Node.ln_Name; + } else { + *strarr = bindingcls->lib_Node.ln_Name; + } + goodbinding = TRUE; + } else { + *strarr = bufptr = buf; + strcpy(buf, "None"); + pc = pclist->lh_Head; + while(pc->ln_Succ) + { + psdGetAttrs(PGA_CONFIG, pc, + CA_InterfaceList, &piflist, + TAG_END); + pif = piflist->lh_Head; + while(pif->ln_Succ) + { + psdGetAttrs(PGA_INTERFACE, pif, + IFA_Binding, &ifbinding, + IFA_BindingClass, &bindingcls, + TAG_END); + if(ifbinding) + { + goodbinding = TRUE; + if((buflen < 99) && ( buflen > 3)) + { + *bufptr++ = ','; + *bufptr++ = ' '; + buflen -= 2; + } + tmpcptr = bindingcls->lib_Node.ln_Name; + while((*bufptr++ = *tmpcptr++)) + { + if(!(--buflen)) + { + *bufptr = 0; + break; + } + } + bufptr--; + } + pif = pif->ln_Succ; + if(!buflen) + { + break; + } + } + pc = pc->ln_Succ; + if(!buflen) + { + break; + } + } + } + if(!goodbinding && (stateimg == 18)) + { + stateimg = 20; + } + psdSafeRawDoFmt(buf3, 32, "\33O[%08lx] %s", + data->mimainlist[stateimg], statestr); + } else { + *strarr++ = "\33l\33uName"; + *strarr++ = "\33l\33uSpeed"; + *strarr++ = "\33l\33uState"; + *strarr++ = "\33l\33uClass"; + *strarr = "\33l\33uBindings"; + } + return(0); + AROS_USERFUNC_EXIT +} +/* \\\ */ + +/* /// "ClassListDisplayHook()" */ +AROS_UFH3(LONG, ClassListDisplayHook, + AROS_UFHA(struct Hook *, hook, A0), + AROS_UFHA(char **, strarr, A2), + AROS_UFHA(struct ClsListEntry *, clnode, A1)) +{ + AROS_USERFUNC_INIT + + static char buf[16]; + IPTR usecnt; + struct Library *UsbClsBase; + struct List *lst; + struct Node *puc; + + if(clnode) + { + psdGetAttrs(PGA_STACK, NULL, PA_ClassList, &lst, TAG_END); + puc = lst->lh_Head; + while(puc->ln_Succ) + { + if(clnode->puc == puc) + { + break; + } + puc = puc->ln_Succ; + } + if(!puc->ln_Succ) + { + clnode->puc = NULL; + *strarr++ = ""; + *strarr++ = ""; + *strarr = ""; + return(0); + } + psdGetAttrs(PGA_USBCLASS, clnode->puc, + UCA_ClassBase, &UsbClsBase, + UCA_ClassName, strarr++, + UCA_UseCount, &usecnt, + TAG_END); + psdSafeRawDoFmt(buf, 16, "%ld", usecnt); + *strarr++ = buf; + usbGetAttrs(UGA_CLASS, NULL, + UCCA_Description, strarr, + TAG_END); + + } else { + *strarr++ = "\33l\33uName"; + *strarr++ = "\33l\33uUse#"; + *strarr = "\33l\33uDescription"; + } + return(0); + AROS_USERFUNC_EXIT +} +/* \\\ */ + +/* /// "ErrorListDisplayHook()" */ +AROS_UFH3(LONG, ErrorListDisplayHook, + AROS_UFHA(struct Hook *, hook, A0), + AROS_UFHA(char **, strarr, A2), + AROS_UFHA(struct ErrListEntry *, elnode, A1)) +{ + AROS_USERFUNC_INIT + + IPTR level; + struct DateStamp *ds; + struct DateTime dt; + static char strtime[LEN_DATSTRING]; + + if(elnode) + { + ds = NULL; + psdGetAttrs(PGA_ERRORMSG, elnode->pem, + EMA_Level, &level, + EMA_Origin, &strarr[2], + EMA_Msg, &strarr[3], + EMA_DateStamp, &ds, + TAG_END); + + if(ds) + { + dt.dat_Stamp.ds_Days = ds->ds_Days; + dt.dat_Stamp.ds_Minute = ds->ds_Minute; + dt.dat_Stamp.ds_Tick = ds->ds_Tick; + dt.dat_Format = FORMAT_DEF; + dt.dat_Flags = 0; + dt.dat_StrDay = NULL; + dt.dat_StrDate = NULL; + dt.dat_StrTime = strtime; + DateToStr(&dt); + strarr[0] = strtime; + } else { + strarr[0] = ""; + } + strarr[1] = ((level == RETURN_OK) ? "" : + ((level == RETURN_WARN) ? "Warning" : + ((level == RETURN_ERROR) ? "Error" : + ((level == RETURN_FAIL) ? "Failure" : "???")))); + } + return(0); + AROS_USERFUNC_EXIT +} +/* \\\ */ + +/* /// "IconListDisplayHook()" */ +AROS_UFH3(LONG, IconListDisplayHook, + AROS_UFHA(struct Hook *, hook, A0), + AROS_UFHA(char **, strarr, A2), + AROS_UFHA(STRPTR, str, A1)) +{ + AROS_USERFUNC_INIT + + static char buf[32]; + struct IconListData *data = (struct IconListData *) INST_DATA(IconListClass->mcc_Class, ((struct ActionData *) hook->h_Data)->cfgpagelv); + + if(str) + { + LONG pos = ((IPTR *) strarr)[-1]; + + if(pos == 5) + { + pos = 24; // fix for PoPo + } + else if(pos == 6) + { + pos = 16; // fix for Configure Management menu + } + else if(pos == 7) + { + pos = 23; // fix for Online menu + } + + psdSafeRawDoFmt(buf, 32, "\33O[%08lx] %s", + data->mimainlist[pos], + str); + *strarr = buf; + } + return(0); + AROS_USERFUNC_EXIT +} +/* \\\ */ + +/* /// "AllocHWEntry()" */ +struct HWListEntry * AllocHWEntry(struct ActionData *data, struct Node *phw) +{ + struct HWListEntry *hlnode; + STRPTR str; + hlnode = psdAllocVec(sizeof(struct HWListEntry)); + if(hlnode) + { + if(phw) + { + psdGetAttrs(PGA_HARDWARE, phw, + HA_DeviceName, &str, + HA_DeviceUnit, &hlnode->unit, + HA_ProductName, &hlnode->prodname, + TAG_END); + hlnode->devname = psdCopyStr(str); + hlnode->phw = phw; + } + AddTail(&data->hwlist, &hlnode->node); + } + return(hlnode); +} +/* \\\ */ + +/* /// "FreeHWEntry()" */ +void FreeHWEntry(struct ActionData *data, struct HWListEntry *hlnode) +{ + struct Node *phw; + struct List *lst; + + Remove(&hlnode->node); + if(hlnode->phw) + { + psdLockWritePBase(); + psdGetAttrs(PGA_STACK, NULL, PA_HardwareList, &lst, TAG_END); + phw = lst->lh_Head; + while(phw->ln_Succ) + { + if(phw == hlnode->phw) + { + psdUnlockPBase(); + psdRemHardware(phw); + hlnode->phw = NULL; + phw = NULL; + break; + } + phw = phw->ln_Succ; + } + if(phw) + { + psdUnlockPBase(); + } + } + if(hlnode->infowindow) + { + set(hlnode->infowindow, MUIA_Window_Open, FALSE); + if(data->appobj) + { + DoMethod(data->appobj, OM_REMMEMBER, hlnode->infowindow); + DoMethod(hlnode->infowindow, OM_DISPOSE); + } + hlnode->infowindow = NULL; + } + psdFreeVec(hlnode->devname); + psdFreeVec(hlnode); +} +/* \\\ */ + +/* /// "AllocDevEntry()" */ +struct DevListEntry * AllocDevEntry(struct ActionData *data, struct Node *pd) +{ + struct DevListEntry *dlnode; + + dlnode = psdAllocVec(sizeof(struct DevListEntry)); + if(dlnode) + { + dlnode->pd = pd; + dlnode->adata = data; + AddTail(&data->devlist, &dlnode->node); + } + return(dlnode); +} +/* \\\ */ + +/* /// "FreeDevEntry()" */ +void FreeDevEntry(struct ActionData *data, struct DevListEntry *dlnode) +{ + if(dlnode->infowindow) + { + set(dlnode->infowindow, MUIA_Window_Open, FALSE); + if(data->appobj) + { + DoMethod(data->appobj, OM_REMMEMBER, dlnode->infowindow); + DoMethod(dlnode->infowindow, OM_DISPOSE); + } + dlnode->infowindow = NULL; + if(dlnode->devdata) + { + dlnode->devdata->dlnode = NULL; + } + } + Remove(&dlnode->node); + psdFreeVec(dlnode); +} +/* \\\ */ + +/* /// "AllocClsEntry()" */ +struct ClsListEntry * AllocClsEntry(struct ActionData *data, struct Node *puc) +{ + struct ClsListEntry *clnode; + clnode = psdAllocVec(sizeof(struct ClsListEntry)); + if(clnode) + { + clnode->puc = puc; + + AddTail(&data->clslist, &clnode->node); + } + return(clnode); +} +/* \\\ */ + +/* /// "FreeClsEntry()" */ +void FreeClsEntry(struct ActionData *data, struct ClsListEntry *clnode) +{ + Remove(&clnode->node); + psdFreeVec(clnode); +} +/* \\\ */ + +/* /// "FreeErrorList()" */ +void FreeErrorList(struct ActionData *data) +{ + struct Node *node; + node = data->errlist.lh_Head; + while(node->ln_Succ) + { + Remove(node); + psdFreeVec(node); + node = data->errlist.lh_Head; + } +} +/* \\\ */ + +/* /// "CreateErrorList()" */ +void CreateErrorList(struct ActionData *data) +{ + struct Node *pem; + struct List *lst; + struct ErrListEntry *elnode; + IPTR level; + + set(data->errlistobj, MUIA_List_Quiet, TRUE); + DoMethod(data->errlistobj, MUIM_List_Clear); + FreeErrorList(data); + psdGetAttrs(PGA_STACK, NULL, PA_ErrorMsgList, &lst, TAG_END); + Forbid(); + pem = lst->lh_Head; + while(pem->ln_Succ) + { + psdGetAttrs(PGA_ERRORMSG, pem, + EMA_Level, &level, + TAG_END); + if(level >= data->errorlevel) + { + if((elnode = psdAllocVec(sizeof(struct ErrListEntry)))) + { + elnode->pem = pem; + AddTail(&data->errlist, &elnode->node); + DoMethod(data->errlistobj, MUIM_List_InsertSingle, elnode, MUIV_List_Insert_Bottom); + } + } + pem = pem->ln_Succ; + } + Permit(); + set(data->errlistobj, MUIA_List_Quiet, FALSE); + set(data->errlistobj, MUIA_List_Active, MUIV_List_Active_Bottom); +} +/* \\\ */ + +/* /// "FreePrefsList()" */ +void FreePrefsList(struct ActionData *data) +{ + struct PrefsListEntry *plnode; + plnode = (struct PrefsListEntry *) data->prefslist.lh_Head; + while(plnode->node.ln_Succ) + { + Remove(&plnode->node); + psdFreeVec(plnode->id); + psdFreeVec(plnode->owner); + psdFreeVec(plnode->devid); + psdFreeVec(plnode->ifid); + psdFreeVec(plnode); + plnode = (struct PrefsListEntry *) data->prefslist.lh_Head; + } +} +/* \\\ */ + +/* /// "AllocPrefsEntry()" */ +struct PrefsListEntry * AllocPrefsEntry(struct ActionData *data, ULONG formid, ULONG size, STRPTR id, STRPTR owner) +{ + struct PrefsListEntry *plnode = NULL; + + if((plnode = psdAllocVec(sizeof(struct PrefsListEntry)))) + { + plnode->id = id; + if(strlen(id) > 39) + { + id[37] = '.'; + id[38] = '.'; + id[39] = '.'; + id[40] = 0; + } + plnode->chunkid = formid; + plnode->size = size; + switch(formid) + { + case IFFFORM_STACKCFG: + plnode->type = "Core Cfg"; + plnode->node.ln_Pri = 100; + break; + + case IFFFORM_DEVICECFG: + plnode->type = "USB Device"; + break; + + case IFFFORM_CLASSCFG: + plnode->type = "Class Cfg"; + plnode->node.ln_Pri = 20; + break; + + case IFFFORM_DEVCFGDATA: + plnode->type = " Device Cfg"; + break; + + case IFFFORM_IFCFGDATA: + plnode->type = " Interface Cfg"; + break; + + case MAKE_ID('P','S','D','L'): + plnode->type = "Licence"; + plnode->node.ln_Pri = 50; + break; + + case 0: + break; + + default: + plnode->type = "Unknown"; + plnode->node.ln_Pri = -100; + break; + } + if(data->devidstr) + { + plnode->devid = psdCopyStr(data->devidstr); + if(data->ifidstr) + { + plnode->ifid = psdCopyStr(data->ifidstr); + } + } + plnode->owner = owner; + Enqueue(&data->prefslist, &plnode->node); + } + return(plnode); +} +/* \\\ */ + +/* /// "FindCfgChunk()" */ +ULONG * FindCfgChunk(ULONG *form, ULONG chnkid) +{ + ULONG *buf = form + 3; + ULONG len = (AROS_LONG2BE(form[1]) - 3) & ~1UL; + ULONG chlen; + + while(len) + { + if(AROS_LONG2BE(*buf) == chnkid) + { + return(buf); + } + chlen = (AROS_LONG2BE(buf[1]) + 9) & ~1UL; + len -= chlen; + buf = (ULONG *) (((UBYTE *) buf) + chlen); + } + return(NULL); +} +/* \\\ */ + +/* /// "GetStringChunk()" */ +STRPTR GetStringChunk(ULONG *form, ULONG chnkid, STRPTR defstr) +{ + ULONG *chunkptr; + STRPTR str = NULL; + if((chunkptr = FindCfgChunk(form, chnkid))) + { + if((str = (STRPTR) psdAllocVec(chunkptr[1] + 1))) + { + memcpy(str, &chunkptr[2], (size_t) AROS_LONG2BE(chunkptr[1])); + return(str); + } + } + if(defstr) + { + str = psdCopyStr(defstr); + } + return(str); +} +/* \\\ */ + +/* /// "RecursePrefsForm()" */ +void RecursePrefsForm(struct ActionData *data, ULONG *form, ULONG depth, STRPTR stack) +{ + struct PrefsListEntry *plnode; + ULONG *endptr; + ULONG *currptr; + ULONG chunklen; + ULONG chunkid; + ULONG formid = AROS_LONG2BE(form[2]); + STRPTR newstack; + ULONG *chunkptr; + STRPTR owner; + STRPTR id; + ULONG formsize = AROS_LONG2BE(form[1]) + 8; + BOOL allocdevid = FALSE; + BOOL allocifid = FALSE; + + newstack = (STRPTR) psdAllocVec((ULONG) strlen(stack) + 5); + if(!newstack) + { + return; + } + strcpy(newstack, stack); + *((ULONG *) &newstack[strlen(stack)]) = AROS_LONG2BE(formid); + + if(AROS_LONG2BE(*((ULONG *) newstack)) != IFFFORM_PSDCFG) + { + owner = GetStringChunk(form, IFFCHNK_OWNER, "Unknown"); + id = psdCopyStr("This is not a poseidon config!"); + plnode = AllocPrefsEntry(data, formid, formsize, id, owner); + } + else if(!strcmp(newstack + 4, "STKC")) + { + plnode = AllocPrefsEntry(data, formid, formsize, psdCopyStr("Global Stack Configuration"), psdCopyStr("Trident")); + } + else if(!strcmp(newstack + 4, "DEVC")) + { + id = GetStringChunk(form, IFFCHNK_DEVID, "Unknown"); + data->devidstr = psdCopyStr(id); + allocdevid = TRUE; + plnode = AllocPrefsEntry(data, formid, formsize, id, psdCopyStr("Trident")); + } + else if(!strcmp(newstack + 4, "DEVCDCFG")) + { + owner = GetStringChunk(form, IFFCHNK_OWNER, "Unknown"); + if(!strcmp(owner, "Trident")) + { + id = psdCopyStr("Generic Prefs"); + } else { + id = psdCopyStrFmt("%s Prefs", owner); + } + plnode = AllocPrefsEntry(data, formid, formsize, id, owner); + } + else if(!strcmp(newstack + 4, "DEVCICFG")) + { + if(formsize > 4) + { + data->ifidstr = GetStringChunk(form, IFFCHNK_IFID, "Unknown"); + allocifid = TRUE; + owner = GetStringChunk(form, IFFCHNK_OWNER, "Unknown"); + plnode = AllocPrefsEntry(data, formid, formsize, psdCopyStrFmt("%s Prefs for %s", owner, data->ifidstr), owner); + } + } + else if(!strcmp(newstack + 4, "CLSC")) + { + if(formsize > 4) + { + owner = GetStringChunk(form, IFFCHNK_OWNER, "Unknown"); + id = psdCopyStrFmt("(Default) Prefs for %s", owner); + plnode = AllocPrefsEntry(data, formid, formsize, id, owner); + } + } + else if(!strcmp(newstack + 4, "PSDL")) + { + owner = GetStringChunk(form, IFFCHNK_OWNER, "Unknown"); + chunkptr = FindCfgChunk(form, MAKE_ID('S','K','E','Y')); + if(chunkptr) + { + id = psdCopyStrFmt("Keyfile Serial #%04ld", chunkptr[3] & 0xffff); + } else { + id = psdCopyStr("Corrupted Keyfile?"); + } + plnode = AllocPrefsEntry(data, formid, formsize, id, psdCopyStr("Secret")); + } else { + if(depth == 1) + { + owner = GetStringChunk(form, IFFCHNK_OWNER, "Unknown"); + id = psdCopyStr("Unknown prefs data (XXXX)"); + if(id) + { + *((ULONG *) &id[20]) = AROS_LONG2BE(formid); + } + plnode = AllocPrefsEntry(data, formid, formsize, id, owner); + } + } + depth++; + currptr = &form[3]; + endptr = (ULONG *) (((UBYTE *) form) + ((AROS_LONG2BE(form[1]) + 9) & ~1UL)); + while(currptr < endptr) + { + chunkid = AROS_LONG2BE(currptr[0]); + chunklen = (AROS_LONG2BE(currptr[1]) + 9) & ~1UL; + if((chunkid == ID_FORM) && (depth < 3)) + { + RecursePrefsForm(data, currptr, depth, newstack); + } else { + switch(chunkid) + { + case IFFCHNK_FORCEDBIND: + if(!strcmp(newstack + 4, "DEVC")) + { + owner = GetStringChunk(form, chunkid, "Unknown"); + plnode = AllocPrefsEntry(data, chunkid, chunklen, psdCopyStrFmt("Forced Device Binding to %s", owner), owner); + if(plnode) + { + plnode->type = " Binding"; + } + } + else if(!strcmp(newstack + 4, "DEVCICFG")) + { + owner = GetStringChunk(form, IFFCHNK_OWNER, "Unknown"); + plnode = AllocPrefsEntry(data, chunkid, chunklen, psdCopyStrFmt("Forced IFace Binding to %s", owner), owner); + if(plnode) + { + plnode->type = " Binding"; + } + } + break; + } + } + currptr = (ULONG *) (((UBYTE *) currptr) + chunklen); + } + if(allocdevid) + { + psdFreeVec(data->devidstr); + data->devidstr = NULL; + } + if(allocifid) + { + psdFreeVec(data->ifidstr); + data->ifidstr = NULL; + } + psdFreeVec(newstack); +} +/* \\\ */ + +/* /// "CreatePrefsList()" */ +void CreatePrefsList(struct ActionData *data) +{ + struct PrefsListEntry *plnode; + IPTR oldpos; + IPTR oldhash = 0; + IPTR currhash = 0; + + set(data->prefslistobj, MUIA_List_Quiet, TRUE); + get(data->prefslistobj, MUIA_List_Active, &oldpos); + DoMethod(data->prefslistobj, MUIM_List_Clear); + FreePrefsList(data); + data->configroot = psdWriteCfg(NULL); + if(data->configroot) + { + RecursePrefsForm(data, data->configroot, 0, ""); + psdFreeVec(data->configroot); + data->configroot = NULL; + } + plnode = (struct PrefsListEntry *) data->prefslist.lh_Head; + while(plnode->node.ln_Succ) + { + DoMethod(data->prefslistobj, MUIM_List_InsertSingle, plnode, MUIV_List_Insert_Bottom); + plnode = (struct PrefsListEntry *) plnode->node.ln_Succ; + } + set(data->prefslistobj, MUIA_List_Active, oldpos); + set(data->prefslistobj, MUIA_List_Quiet, FALSE); + psdGetAttrs(PGA_STACK, NULL, + PA_CurrConfigHash, &currhash, + PA_SavedConfigHash, &oldhash, + TAG_END); + set(data->saveobj, MUIA_Disabled, (oldhash == currhash)); +} +/* \\\ */ + +/* /// "FreeGUILists()" */ +void FreeGUILists(struct ActionData *data) +{ + struct HWListEntry *hlnode; + struct DevListEntry *dlnode; + struct ClsListEntry *clnode; + + hlnode = (struct HWListEntry *) data->hwlist.lh_Head; + while(hlnode->node.ln_Succ) + { + //hlnode->infowindow = NULL; + hlnode->phw = NULL; + FreeHWEntry(data, hlnode); + hlnode = (struct HWListEntry *) data->hwlist.lh_Head; + } + dlnode = (struct DevListEntry *) data->devlist.lh_Head; + while(dlnode->node.ln_Succ) + { + //dlnode->infowindow = NULL; + FreeDevEntry(data, dlnode); + dlnode = (struct DevListEntry *) data->devlist.lh_Head; + } + clnode = (struct ClsListEntry *) data->clslist.lh_Head; + while(clnode->node.ln_Succ) + { + FreeClsEntry(data, clnode); + clnode = (struct ClsListEntry *) data->clslist.lh_Head; + } +} +/* \\\ */ + +/* /// "CreateClassPopup()" */ +Object * CreateClassPopup(void) +{ + Object *mi_root; + Object *mi_top; + Object *mi_sub; + struct List *lst; + struct Node *puc; + STRPTR clname; + + mi_root = MenustripObject, + Child, mi_top = MenuObjectT("Forced binding"), + Child, MenuitemObject, + MUIA_Menuitem_Title, "None", + End, + End, + End; + + if(mi_root) + { + psdLockReadPBase(); + psdGetAttrs(PGA_STACK, NULL, PA_ClassList, &lst, TAG_END); + puc = lst->lh_Head; + while(puc->ln_Succ) + { + psdGetAttrs(PGA_USBCLASS, puc, + UCA_ClassName, &clname, + TAG_END); + + mi_sub = MenuitemObject, + MUIA_Menuitem_Title, clname, + End; + if(mi_sub) + { + DoMethod(mi_top, OM_ADDMEMBER, mi_sub); + } + puc = puc->ln_Succ; + } + psdUnlockPBase(); + } + return(mi_root); +} +/* \\\ */ + +/* /// "InternalCreateConfig()" */ +BOOL InternalCreateConfig(void) +{ + ULONG tmpform[3]; + APTR pic; + APTR subpic; + STRPTR name; + IPTR unit; + struct Node *phw; + struct Node *puc; + struct List *lst; + + pic = psdFindCfgForm(NULL, IFFFORM_STACKCFG); + if(!pic) + { + tmpform[0] = AROS_LONG2BE(ID_FORM); + tmpform[1] = AROS_LONG2BE(4); + tmpform[2] = AROS_LONG2BE(IFFFORM_STACKCFG); + psdAddCfgEntry(NULL, tmpform); + pic = psdFindCfgForm(NULL, IFFFORM_STACKCFG); + } + if(!pic) + { + return(FALSE); + } + + /* First mark all old hardware entries as offline */ + subpic = psdFindCfgForm(pic, IFFFORM_UHWDEVICE); + while(subpic) + { + tmpform[0] = AROS_LONG2BE(IFFCHNK_OFFLINE); + tmpform[1] = AROS_LONG2BE(4); + tmpform[2] = TRUE; + psdAddCfgEntry(subpic, tmpform); + subpic = psdNextCfgForm(subpic); + } + + /* Add existing hardware entries */ + psdLockReadPBase(); + psdGetAttrs(PGA_STACK, NULL, PA_HardwareList, &lst, TAG_END); + phw = lst->lh_Head; + while(phw->ln_Succ) + { + psdGetAttrs(PGA_HARDWARE, phw, + HA_DeviceName, &name, + HA_DeviceUnit, &unit, + TAG_END); + + // find corresponding form in config + subpic = psdFindCfgForm(pic, IFFFORM_UHWDEVICE); + while(subpic) + { + if(psdMatchStringChunk(subpic, IFFCHNK_NAME, name)) + { + ULONG *unitchk = psdGetCfgChunk(subpic, IFFCHNK_UNIT); + if(unitchk && unitchk[2] == unit) + { + psdFreeVec(unitchk); + break; + } + psdFreeVec(unitchk); + } + subpic = psdNextCfgForm(subpic); + } + + if(!subpic) + { + // not found, add it + tmpform[0] = AROS_LONG2BE(ID_FORM); + tmpform[1] = AROS_LONG2BE(4); + tmpform[2] = AROS_LONG2BE(IFFFORM_UHWDEVICE); + subpic = psdAddCfgEntry(pic, tmpform); + } + + if(subpic) + { + psdAddStringChunk(subpic, IFFCHNK_NAME, name); + tmpform[0] = AROS_LONG2BE(IFFCHNK_UNIT); + tmpform[1] = AROS_LONG2BE(4); + tmpform[2] = unit; + psdAddCfgEntry(subpic, tmpform); + // remove offline chunk to make sure the thing is going online next time + psdRemCfgChunk(subpic, IFFCHNK_OFFLINE); + } + phw = phw->ln_Succ; + } + psdUnlockPBase(); + + /* Add existing class entries */ + psdLockReadPBase(); + psdGetAttrs(PGA_STACK, NULL, PA_ClassList, &lst, TAG_END); + puc = lst->lh_Head; + while(puc->ln_Succ) + { + tmpform[0] = AROS_LONG2BE(ID_FORM); + tmpform[1] = AROS_LONG2BE(4); + tmpform[2] = AROS_LONG2BE(IFFFORM_USBCLASS); + subpic = psdAddCfgEntry(pic, tmpform); + if(subpic) + { + name = NULL; + psdGetAttrs(PGA_USBCLASS, puc, + UCA_FullPath, &name, + TAG_END); + if(!name) + { + psdGetAttrs(PGA_USBCLASS, puc, + UCA_ClassName, &name, + TAG_END); + name = psdCopyStrFmt("USB/%s", name); + if(name) + { + psdAddStringChunk(subpic, IFFCHNK_NAME, name); + psdFreeVec(name); + } + } else { + psdAddStringChunk(subpic, IFFCHNK_NAME, name); + } + } + puc = puc->ln_Succ; + } + psdUnlockPBase(); + return(TRUE); +} +/* \\\ */ + +/* /// "InternalCreateConfigGUI()" */ +BOOL InternalCreateConfigGUI(struct ActionData *data) +{ + ULONG tmpform[3]; + APTR pic; + APTR subpic; + STRPTR name; + IPTR unit; + struct Node *phw; + struct HWListEntry *hlnode; + struct ClsListEntry *clnode; + struct List *lst; + + pic = psdFindCfgForm(NULL, IFFFORM_STACKCFG); + if(!pic) + { + tmpform[0] = AROS_LONG2BE(ID_FORM); + tmpform[1] = AROS_LONG2BE(4); + tmpform[2] = AROS_LONG2BE(IFFFORM_STACKCFG); + psdAddCfgEntry(NULL, tmpform); + pic = psdFindCfgForm(NULL, IFFFORM_STACKCFG); + } + if(!pic) + { + return(FALSE); + } + + psdLockReadPBase(); + + + /* First remove all old hardware entries */ + while((subpic = psdFindCfgForm(pic, IFFFORM_UHWDEVICE))) + { + psdRemCfgForm(subpic); + } + + /* Add hardware entries from GUI, but mark them as offline */ + hlnode = (struct HWListEntry *) data->hwlist.lh_Head; + while(hlnode->node.ln_Succ) + { + tmpform[0] = AROS_LONG2BE(ID_FORM); + tmpform[1] = AROS_LONG2BE(4); + tmpform[2] = AROS_LONG2BE(IFFFORM_UHWDEVICE); + subpic = psdAddCfgEntry(pic, tmpform); + if(subpic) + { + psdAddStringChunk(subpic, IFFCHNK_NAME, hlnode->devname); + tmpform[0] = AROS_LONG2BE(IFFCHNK_UNIT); + tmpform[1] = AROS_LONG2BE(4); + tmpform[2] = hlnode->unit; + psdAddCfgEntry(subpic, tmpform); + tmpform[0] = AROS_LONG2BE(IFFCHNK_OFFLINE); + tmpform[1] = AROS_LONG2BE(4); + tmpform[2] = TRUE; + psdAddCfgEntry(subpic, tmpform); + } + hlnode = (struct HWListEntry *) hlnode->node.ln_Succ; + } + + /* Now find all hardware entries that are online and mark them as such */ + psdGetAttrs(PGA_STACK, NULL, PA_HardwareList, &lst, TAG_END); + phw = lst->lh_Head; + while(phw->ln_Succ) + { + psdGetAttrs(PGA_HARDWARE, phw, + HA_DeviceName, &name, + HA_DeviceUnit, &unit, + TAG_END); + + // find corresponding form in config + subpic = psdFindCfgForm(pic, IFFFORM_UHWDEVICE); + while(subpic) + { + if(psdMatchStringChunk(subpic, IFFCHNK_NAME, name)) + { + ULONG *unitchk = psdGetCfgChunk(subpic, IFFCHNK_UNIT); + if(unitchk && unitchk[2] == unit) + { + psdFreeVec(unitchk); + psdRemCfgChunk(subpic, IFFCHNK_OFFLINE); + break; + } + psdFreeVec(unitchk); + } + subpic = psdNextCfgForm(subpic); + } + phw = phw->ln_Succ; + } + + /* Delete all old class entries */ + while((subpic = psdFindCfgForm(pic, IFFFORM_USBCLASS))) + { + psdRemCfgForm(subpic); + } + /* Add existing class entries */ + clnode = (struct ClsListEntry *) data->clslist.lh_Head; + while(clnode->node.ln_Succ) + { + tmpform[0] = AROS_LONG2BE(ID_FORM); + tmpform[1] = AROS_LONG2BE(4); + tmpform[2] = AROS_LONG2BE(IFFFORM_USBCLASS); + subpic = psdAddCfgEntry(pic, tmpform); + if(subpic) + { + name = NULL; + psdGetAttrs(PGA_USBCLASS, clnode->puc, + UCA_FullPath, &name, + TAG_END); + if(!name) + { + psdGetAttrs(PGA_USBCLASS, clnode->puc, + UCA_ClassName, &name, + TAG_END); + name = psdCopyStrFmt("USB/%s", name); + if(name) + { + psdAddStringChunk(subpic, IFFCHNK_NAME, name); + psdFreeVec(name); + } + } else { + psdAddStringChunk(subpic, IFFCHNK_NAME, name); + } + } + clnode = (struct ClsListEntry *) clnode->node.ln_Succ; + } + psdUnlockPBase(); + data->swallowconfigevent = TRUE; + return(TRUE); +} +/* \\\ */ + +/* /// "CleanupEventHandler()" */ +void CleanupEventHandler(struct ActionData *data) +{ + if(data->eventhandler) + { + psdRemEventHandler(data->eventhandler); + data->eventhandler = NULL; + } + if(data->eventmsgport) + { + DeleteMsgPort(data->eventmsgport); + data->eventmsgport = NULL; + } +} +/* \\\ */ + +/* /// "SetupEventHandler()" */ +BOOL SetupEventHandler(struct ActionData *data) +{ + if((data->eventmsgport = CreateMsgPort())) + { + data->eventhandler = psdAddEventHandler(data->eventmsgport, ~0); + if(data->eventhandler) + { + return(TRUE); + } + } else { + data->eventhandler = NULL; + } + return(FALSE); +} +/* \\\ */ + +/* /// "EventHandler()" */ +void EventHandler(struct ActionData *data) +{ + APTR pen; + ULONG eventmask; + IPTR penid; + IPTR penparam1; + IPTR penparam2; + BOOL cfgchanged = FALSE; + + eventmask = 0; + while((pen = GetMsg(data->eventmsgport))) + { + psdGetAttrs(PGA_EVENTNOTE, pen, + ENA_EventID, &penid, + ENA_Param1, &penparam1, + ENA_Param2, &penparam2, + TAG_END); + eventmask |= (1L<pen_Event, pen->pen_Param1);*/ + switch(penid) + { + case EHMB_ADDHARDWARE: + { + struct Node *phw; + struct List *lst; + struct HWListEntry *hlnode; + STRPTR devname; + IPTR unit; + STRPTR prodname; + + psdLockReadPBase(); + psdGetAttrs(PGA_STACK, NULL, PA_HardwareList, &lst, TAG_END); + phw = lst->lh_Head; + while(phw->ln_Succ) + { + if(phw == (struct Node *) penparam1) + { + break; + } + phw = phw->ln_Succ; + } + if(phw->ln_Succ) + { + psdGetAttrs(PGA_HARDWARE, phw, + HA_DeviceName, &devname, + HA_DeviceUnit, &unit, + HA_ProductName, &prodname, + TAG_END); + + hlnode = (struct HWListEntry *) data->hwlist.lh_Head; + while(hlnode->node.ln_Succ) + { + if((!strcmp(devname, hlnode->devname)) && + (unit == hlnode->unit)) + { + if(!hlnode->phw) + { + hlnode->phw = phw; + hlnode->prodname = prodname; + } + break; + } + hlnode = (struct HWListEntry *) hlnode->node.ln_Succ; + } + if(!hlnode->node.ln_Succ) + { + if((hlnode = AllocHWEntry(data, phw))) + { + DoMethod(data->hwlistobj, MUIM_List_InsertSingle, hlnode, MUIV_List_Insert_Bottom); + } + } else { + DoMethod(data->hwlistobj, MUIM_List_Redraw, MUIV_List_Redraw_All); + } + } + psdUnlockPBase(); + break; + } + + case EHMB_REMHARDWARE: + { + struct HWListEntry *hlnode; + psdLockReadPBase(); + hlnode = (struct HWListEntry *) data->hwlist.lh_Head; + while(hlnode->node.ln_Succ) + { + if(hlnode->phw == (struct Node *) penparam1) + { + hlnode->phw = NULL; + hlnode->prodname = NULL; + break; + } + hlnode = (struct HWListEntry *) hlnode->node.ln_Succ; + } + if(hlnode->node.ln_Succ) + { + DoMethod(data->hwlistobj, MUIM_List_Redraw, MUIV_List_Redraw_All); + } + psdUnlockPBase(); + break; + } + + case EHMB_ADDDEVICE: + { + struct Node *pd = NULL; + struct DevListEntry *dlnode; + psdLockReadPBase(); + while((pd = psdGetNextDevice(pd))) + { + if(pd == (struct Node *) penparam1) + { + dlnode = (struct DevListEntry *) data->devlist.lh_Head; + while(dlnode->node.ln_Succ) + { + if(dlnode->pd == pd) + { + // ignore existing entry! + break; + } + dlnode = (struct DevListEntry *) dlnode->node.ln_Succ; + } + if(!dlnode->node.ln_Succ) + { + dlnode = AllocDevEntry(data, pd); + if(dlnode) + { + DoMethod(data->devlistobj, MUIM_List_InsertSingle, dlnode, MUIV_List_Insert_Bottom); + } + } + break; + } + } + psdUnlockPBase(); + break; + } + + case EHMB_REMDEVICE: + { + struct DevListEntry *dlnode; + struct DevListEntry *tmpnode; + ULONG pos = 0; + set(data->devlistobj, MUIA_List_Quiet, TRUE); + dlnode = (struct DevListEntry *) data->devlist.lh_Head; + while(dlnode->node.ln_Succ) + { + if((dlnode->pd == (struct Node *) penparam1) || (!dlnode->pd)) + { + dlnode->pd = NULL; + do + { + DoMethod(data->devlistobj, MUIM_List_GetEntry, pos, &tmpnode); + if(!tmpnode) + break; + if(tmpnode == dlnode) + { + DoMethod(data->devlistobj, MUIM_List_Remove, pos); + break; + } + pos++; + } while(TRUE); + FreeDevEntry(data, dlnode); + break; + } + dlnode = (struct DevListEntry *) dlnode->node.ln_Succ; + } + break; + } + + case EHMB_ADDCLASS: + { + struct ClsListEntry *clnode; + clnode = (struct ClsListEntry *) data->clslist.lh_Head; + while(clnode->node.ln_Succ) + { + if(clnode->puc == (struct Node *) penparam1) + { + break; + } + clnode = (struct ClsListEntry *) clnode->node.ln_Succ; + } + if(!clnode->node.ln_Succ) + { + if((clnode = AllocClsEntry(data, (struct Node *) penparam1))) + { + DoMethod(data->clslistobj, MUIM_List_InsertSingle, clnode, MUIV_List_Insert_Bottom); + } + } + break; + } + + case EHMB_REMCLASS: + { + struct ClsListEntry *clnode; + struct ClsListEntry *tmpnode; + ULONG pos = 0; + set(data->clslistobj, MUIA_List_Quiet, TRUE); + clnode = (struct ClsListEntry *) data->clslist.lh_Head; + while(clnode->node.ln_Succ) + { + if((clnode->puc == (struct Node *) penparam1) || (!clnode->puc)) + { + clnode->puc = NULL; + do + { + DoMethod(data->clslistobj, MUIM_List_GetEntry, pos, &tmpnode); + if(!tmpnode) + break; + if(tmpnode == clnode) + { + DoMethod(data->clslistobj, MUIM_List_Remove, pos); + break; + } + pos++; + } while(TRUE); + tmpnode = (struct ClsListEntry *) clnode->node.ln_Succ; + FreeClsEntry(data, clnode); + clnode = tmpnode; + } else { + clnode = (struct ClsListEntry *) clnode->node.ln_Succ; + } + } + break; + } + + case EHMB_ADDERRORMSG: + { + struct ErrListEntry *elnode; + IPTR level; + + psdGetAttrs(PGA_ERRORMSG, (APTR) penparam1, + EMA_Level, &level, + TAG_END); + if(level >= data->errorlevel) + { + if((elnode = psdAllocVec(sizeof(struct ErrListEntry)))) + { + elnode->pem = (struct Node *) penparam1; + AddTail(&data->errlist, &elnode->node); + DoMethod(data->errlistobj, MUIM_List_InsertSingle, elnode, MUIV_List_Insert_Bottom); + } + } + break; + } + + case EHMB_CONFIGCHG: + if(!cfgchanged) + { + psdDelayMS(100); + cfgchanged = TRUE; + } + break; + + } + ReplyMsg(pen); + } + if(eventmask & EHMF_REMERRORMSG) + { + CreateErrorList(data); + } + if(eventmask & EHMF_ADDERRORMSG) + { + set(data->errlistobj, MUIA_List_Active, MUIV_List_Active_Bottom); + } + if(eventmask & (EHMF_ADDBINDING|EHMF_REMBINDING|EHMF_DEVICEDEAD|EHMF_DEVICELOWPW|EHMF_DEVSUSPENDED|EHMF_DEVRESUMED)) + { + DoMethod(data->devlistobj, MUIM_List_Redraw, MUIV_List_Redraw_All); + DoMethod(data->clslistobj, MUIM_List_Redraw, MUIV_List_Redraw_All); + DoMethod(data->selfobj, MUIM_Action_Dev_Activate); + } + if(eventmask & EHMF_REMDEVICE) + { + set(data->devlistobj, MUIA_List_Quiet, FALSE); + } + if(eventmask & EHMF_REMCLASS) + { + set(data->clslistobj, MUIA_List_Quiet, FALSE); + } + if(eventmask & (EHMF_ADDCLASS|EHMF_REMCLASS)) + { + set(data->devlistobj, MUIA_ContextMenu, NULL); + MUI_DisposeObject(data->mi_classpopup); + data->mi_classpopup = CreateClassPopup(); + set(data->devlistobj, MUIA_ContextMenu, data->mi_classpopup); + } + if(cfgchanged) + { + if(!data->swallowconfigevent) + { + UpdateConfigToGUI(data); + } else { + IPTR oldhash = 0; + IPTR currhash = 0; + psdGetAttrs(PGA_STACK, NULL, + PA_CurrConfigHash, &currhash, + PA_SavedConfigHash, &oldhash, + TAG_END); + set(data->saveobj, MUIA_Disabled, (oldhash == currhash)); + } + data->swallowconfigevent = FALSE; + } +} +/* \\\ */ + +/* /// "UpdateConfigToGUI()" */ +void UpdateConfigToGUI(struct ActionData *data) +{ + struct Node *phw; + struct List *lst; + struct HWListEntry *hlnode; + struct Node *puc; + struct ClsListEntry *clnode; + APTR stackcfg; + IPTR bootdelay; + IPTR subtaskpri; + IPTR loginfo; + IPTR logwarn; + IPTR logerr; + IPTR logfail; + IPTR popupnew = 0; + IPTR popupgone = FALSE; + IPTR popupdeath = FALSE; + IPTR popupdelay = 0; + IPTR popupactivate = FALSE; + IPTR popuptofront = TRUE; + IPTR autodisablelp = FALSE; + IPTR autodisabledead = TRUE; + IPTR powersaving = FALSE; + IPTR forcesuspend = FALSE; + IPTR suspendtimeout = 30; + STRPTR devdtxsoundfile = ""; + STRPTR devremsoundfile = ""; + IPTR prefsversion = 0; + IPTR relversion = 0; + + ULONG numclasses = 0; + APTR pic; + APTR subpic; + APTR oldphw; + ULONG curpos = 0; + IPTR selpos = MUIV_List_Active_Off; + IPTR clsselpos = MUIV_List_Active_Off; + + get(data->hwlistobj, MUIA_List_Active, &selpos); + get(data->clslistobj, MUIA_List_Active, &clsselpos); + + set(data->hwlistobj, MUIA_List_Quiet, TRUE); + DoMethod(data->hwlistobj, MUIM_List_Clear); + set(data->clslistobj, MUIA_List_Quiet, TRUE); + DoMethod(data->clslistobj, MUIM_List_Clear); + + oldphw = data->acthlnode ? data->acthlnode->phw : NULL; + + // remove all GUI entries first + hlnode = (struct HWListEntry *) data->hwlist.lh_Head; + while(hlnode->node.ln_Succ) + { + hlnode->phw = NULL; + FreeHWEntry(data, hlnode); + hlnode = (struct HWListEntry *) data->hwlist.lh_Head; + } + + clnode = (struct ClsListEntry *) data->clslist.lh_Head; + while(clnode->node.ln_Succ) + { + FreeClsEntry(data, clnode); + clnode = (struct ClsListEntry *) data->clslist.lh_Head; + } + + /* get stuff that's online first */ + psdGetAttrs(PGA_STACK, NULL, + PA_HardwareList, &lst, + PA_ReleaseVersion, &relversion, + PA_GlobalConfig, &stackcfg, + TAG_END); + phw = lst->lh_Head; + while(phw->ln_Succ) + { + if((hlnode = AllocHWEntry(data, phw))) + { + if(phw == oldphw) + { + selpos = curpos; + } + DoMethod(data->hwlistobj, MUIM_List_InsertSingle, hlnode, MUIV_List_Insert_Bottom); + curpos++; + } + phw = phw->ln_Succ; + } + + psdLockReadPBase(); + pic = psdFindCfgForm(NULL, IFFFORM_STACKCFG); + /* now check for additional entries that are offline */ + subpic = pic ? psdFindCfgForm(pic, IFFFORM_UHWDEVICE) : NULL; + while(subpic) + { + hlnode = (struct HWListEntry *) data->hwlist.lh_Head; + while(hlnode->node.ln_Succ) + { + if(psdMatchStringChunk(subpic, IFFCHNK_NAME, hlnode->devname)) + { + ULONG *unitchk = psdGetCfgChunk(subpic, IFFCHNK_UNIT); + if(unitchk && unitchk[2] == hlnode->unit) + { + psdFreeVec(unitchk); + break; + } + psdFreeVec(unitchk); + } + + hlnode = (struct HWListEntry *) hlnode->node.ln_Succ; + } + if(!hlnode->node.ln_Succ) + { + if((hlnode = AllocHWEntry(data, NULL))) + { + ULONG *unitchk = psdGetCfgChunk(subpic, IFFCHNK_UNIT); + if(unitchk) + { + hlnode->unit = unitchk[2]; + psdFreeVec(unitchk); + } + hlnode->devname = psdGetStringChunk(subpic, IFFCHNK_NAME); + DoMethod(data->hwlistobj, MUIM_List_InsertSingle, hlnode, MUIV_List_Insert_Bottom); + curpos++; + } + } + subpic = psdNextCfgForm(subpic); + } + + psdGetAttrs(PGA_STACK, NULL, PA_ClassList, &lst, TAG_END); + puc = lst->lh_Head; + while(puc->ln_Succ) + { + if((clnode = AllocClsEntry(data, puc))) + { + numclasses++; + DoMethod(data->clslistobj, MUIM_List_InsertSingle, clnode, MUIV_List_Insert_Bottom); + } + puc = puc->ln_Succ; + } + + if(stackcfg) + { + psdGetAttrs(PGA_STACKCFG, stackcfg, GCA_PrefsVersion, &prefsversion, TAG_END); + } + psdUnlockPBase(); + + if(relversion > prefsversion) + { + psdAddErrorMsg(RETURN_WARN, "Trident", "Forcing a DirScan for (new) classes, as you probably updated to a newer version."); + psdSetAttrs(PGA_STACKCFG, stackcfg, GCA_PrefsVersion, relversion, TAG_END); + DoMethod(data->selfobj, MUIM_Action_Cls_Scan); + } + else if(!(numclasses || data->autoclassesadded)) + { + psdAddErrorMsg(RETURN_WARN, "Trident", "Doing a DirScan for classes, because none were in config."); + DoMethod(data->selfobj, MUIM_Action_Cls_Scan); + } + data->autoclassesadded = TRUE; + + set(data->hwlistobj, MUIA_List_Active, selpos); + set(data->clslistobj, MUIA_List_Active, clsselpos); + set(data->hwlistobj, MUIA_List_Quiet, FALSE); + set(data->devlistobj, MUIA_List_Quiet, FALSE); + set(data->clslistobj, MUIA_List_Quiet, FALSE); + CreatePrefsList(data); + + if(stackcfg) + { + psdGetAttrs(PGA_STACKCFG, stackcfg, + GCA_SubTaskPri, &subtaskpri, + GCA_BootDelay, &bootdelay, + GCA_LogInfo, &loginfo, + GCA_LogWarning, &logwarn, + GCA_LogError, &logerr, + GCA_LogFailure, &logfail, + GCA_PopupDeviceNew, &popupnew, + GCA_PopupDeviceGone, &popupgone, + GCA_PopupDeviceDeath, &popupdeath, + GCA_PopupCloseDelay, &popupdelay, + GCA_PopupActivateWin, &popupactivate, + GCA_PopupWinToFront, &popuptofront, + GCA_InsertionSound, &devdtxsoundfile, + GCA_RemovalSound, &devremsoundfile, + GCA_AutoDisableLP, &autodisablelp, + GCA_AutoDisableDead, &autodisabledead, + GCA_PowerSaving, &powersaving, + GCA_ForceSuspend, &forcesuspend, + GCA_SuspendTimeout, &suspendtimeout, + TAG_END); + nnset(data->cfgtaskpriobj, MUIA_Numeric_Value, subtaskpri); + nnset(data->cfgbootdelayobj, MUIA_Numeric_Value, bootdelay); + nnset(data->cfgloginfoobj, MUIA_Selected, loginfo); + nnset(data->cfglogwarnobj, MUIA_Selected, logwarn); + nnset(data->cfglogerrobj, MUIA_Selected, logerr); + nnset(data->cfglogfailobj, MUIA_Selected, logfail); + nnset(data->cfgpopupnewobj, MUIA_Cycle_Active, popupnew); + nnset(data->cfgpopupgoneobj, MUIA_Selected, popupgone); + nnset(data->cfgpopupdeathobj, MUIA_Selected, popupdeath); + nnset(data->cfgpopupdelayobj, MUIA_Numeric_Value, popupdelay); + nnset(data->cfgpopupactivateobj, MUIA_Selected, popupactivate); + nnset(data->cfgpopuptofrontobj, MUIA_Selected, popuptofront); + nnset(data->cfgdevdtxsoundobj, MUIA_String_Contents, devdtxsoundfile); + nnset(data->cfgdevremsoundobj, MUIA_String_Contents, devremsoundfile); + nnset(data->cfgautolpobj, MUIA_Selected, autodisablelp); + nnset(data->cfgautodeadobj, MUIA_Selected, autodisabledead); + nnset(data->cfgpowersavingobj, MUIA_Selected, powersaving); + nnset(data->cfgforcesuspendobj, MUIA_Selected, forcesuspend); + nnset(data->cfgsuspendtimeoutobj, MUIA_Numeric_Value, suspendtimeout); + } +} +/* \\\ */ + +Object *MyTextObject(char *Text,char *Help) +{ + Object *obj; + obj = TextObject, + MUIA_ShortHelp, Help, + ButtonFrame, + MUIA_Background, MUII_ButtonBack, + MUIA_CycleChain, 1, + MUIA_InputMode, MUIV_InputMode_RelVerify, + MUIA_Text_Contents, Text, + End; + + return(obj); +} + +Object *MyTextObjectDisabled(char *Text,char *Help) +{ + Object *obj; + obj = TextObject, + MUIA_ShortHelp, Help, + ButtonFrame, + MUIA_Background, MUII_ButtonBack, + MUIA_CycleChain, 1, + MUIA_InputMode, MUIV_InputMode_RelVerify, + MUIA_Text_Contents, Text, + MUIA_Disabled, TRUE, + End; + + return(obj); +} + +/* /// "Action_OM_NEW()" */ +Object * Action_OM_NEW(struct IClass *cl, Object *obj, Msg msg) +{ + struct ActionData *data; + + IPTR bootdelay = 0; + IPTR subtaskpri = 5; + IPTR loginfo = TRUE; + IPTR logwarn = TRUE; + IPTR logerr = TRUE; + IPTR logfail = TRUE; + IPTR popupnew = 0; + IPTR popupgone = FALSE; + IPTR popupdeath = FALSE; + IPTR popupdelay = 0; + IPTR popupactivate = FALSE; + IPTR popuptofront = TRUE; + IPTR autodisablelp = FALSE; + IPTR autodisabledead = FALSE; + IPTR autorestartdead = TRUE; + IPTR powersaving = FALSE; + IPTR forcesuspend = FALSE; + IPTR suspendtimeout = 30; + STRPTR devdtxsoundfile = ""; + STRPTR devremsoundfile = ""; + APTR stackcfg = NULL; + STRPTR aimeemsg; + APTR pd = NULL; + struct DevListEntry *dlnode; + + if(!(obj = (Object *) DoSuperMethodA(cl, obj, msg))) + return(0); + + data = INST_DATA(cl, obj); + data->selfobj = obj; + NewList(&data->hwlist); + NewList(&data->devlist); + NewList(&data->clslist); + NewList(&data->errlist); + NewList(&data->prefslist); + + data->acthlnode = NULL; + data->errorlevel = 0; + data->HardwareDisplayHook.h_Data = data; + data->DeviceDisplayHook.h_Data = data; + data->ClassDisplayHook.h_Data = data; + data->ErrorDisplayHook.h_Data = data; + data->IconDisplayHook.h_Data = data; + data->PrefsDisplayHook.h_Data = data; + + data->HardwareDisplayHook.h_Entry = (APTR) HardwareListDisplayHook; + data->DeviceDisplayHook.h_Entry = (APTR) DeviceListDisplayHook; + data->ClassDisplayHook.h_Entry = (APTR) ClassListDisplayHook; + data->ErrorDisplayHook.h_Entry = (APTR) ErrorListDisplayHook; + data->IconDisplayHook.h_Entry = (APTR) IconListDisplayHook; + data->PrefsDisplayHook.h_Entry = (APTR) PrefsListDisplayHook; + + aimeemsg = aimeelyrics[(((ULONG) aimeelyrics) / 333) & 31]; + + /* get current global config */ + psdGetAttrs(PGA_STACK, NULL, PA_GlobalConfig, &stackcfg, TAG_END); + if(stackcfg) + { + psdGetAttrs(PGA_STACKCFG, stackcfg, + GCA_SubTaskPri, &subtaskpri, + GCA_BootDelay, &bootdelay, + GCA_LogInfo, &loginfo, + GCA_LogWarning, &logwarn, + GCA_LogError, &logerr, + GCA_LogFailure, &logfail, + GCA_PopupDeviceNew, &popupnew, + GCA_PopupDeviceGone, &popupgone, + GCA_PopupDeviceDeath, &popupdeath, + GCA_PopupCloseDelay, &popupdelay, + GCA_PopupActivateWin, &popupactivate, + GCA_PopupWinToFront, &popuptofront, + GCA_InsertionSound, &devdtxsoundfile, + GCA_RemovalSound, &devremsoundfile, + GCA_AutoDisableLP, &autodisablelp, + GCA_AutoDisableDead, &autodisabledead, + GCA_AutoRestartDead, &autorestartdead, + GCA_PowerSaving, &powersaving, + GCA_ForceSuspend, &forcesuspend, + GCA_SuspendTimeout, &suspendtimeout, + TAG_END); + } + + /* General panel */ + data->cfgcntobj[0] = ScrollgroupObject, + MUIA_HelpNode, "tridentgeneral", + MUIA_Scrollgroup_Contents, VirtgroupObject, + Child, VGroup, + Child, VSpace(0), + Child, HGroup, + Child, HSpace(0), + Child, HGroup, + Child, VGroup, + Child, BodychunkObject, + MUIA_ShortHelp, poseidonshorthelp, + MUIA_Bitmap_SourceColors, neptune8_colors, + MUIA_FixWidth, NEPTUNE8_WIDTH, + MUIA_FixHeight, NEPTUNE8_HEIGHT, + MUIA_Bitmap_Width, NEPTUNE8_WIDTH, + MUIA_Bitmap_Height, NEPTUNE8_HEIGHT, + MUIA_Bodychunk_Depth, NEPTUNE8_DEPTH, + MUIA_Bodychunk_Body, neptune8_body, + MUIA_Bodychunk_Compression, NEPTUNE8_COMPRESSION, + MUIA_Bodychunk_Masking, NEPTUNE8_MASKING, + MUIA_Bitmap_Transparent, 0, + MUIA_Bitmap_UseFriend, TRUE, + MUIA_Bitmap_Precision, PRECISION_ICON, + End, + Child, VSpace(0), + End, + Child, VGroup, + Child, VSpace(0), + Child, Label("\33cTrident V4.3 Graphical User Interface"), + Child, Label("\33cfor the Poseidon USB Stack"), + Child, VSpace(20), + Child, Label("\33cCopyright ©2002-2009 Chris Hodges"), + Child, Label("\33cAll rights reserved."), + Child, VSpace(20), + Child, Label("\33cMason Icons are\ncourtesy of Martin Merz."), + Child, VSpace(0), + End, + End, + Child, HSpace(0), + End, + Child, VSpace(20), + Child, HGroup, + Child, HSpace(0), + Child, Label(aimeemsg), + Child, HSpace(0), + End, + Child, VSpace(0), + End, + End, + End; + + /* Hardware panel */ + data->cfgcntobj[1] = VGroup, + MUIA_HelpNode, "tridenthardware", + Child, Label("\33c\33bUSB Hardware Controllers available"), + Child, ListviewObject, + MUIA_CycleChain, 1, + MUIA_ShortHelp, "This is the list of available hardware controllers.\n" + "Several different controllers can be in the system at\n" + "the same time.\n" + "To add an entry, use the 'New' gadget at the bottom.\n" + "You need to manually set an hardware controller online\n" + "the first time you add the device.", + MUIA_Listview_List, data->hwlistobj = + NewObject(IconListClass->mcc_Class, 0, InputListFrame, MUIA_List_MinLineHeight, 16, MUIA_List_Format, "BAR,BAR,BAR,", MUIA_List_Title, TRUE, MUIA_List_DisplayHook, &data->HardwareDisplayHook, TAG_END), + End, + Child, data->hwdevgrpobj = HGroup, + MUIA_Disabled, TRUE, + Child, Label("Device:"), + Child, data->hwdevaslobj = PopaslObject, + MUIA_CycleChain, 1, + MUIA_ShortHelp, "Give the name of the controller device\n" + "driver in this field. These devices are\n" + "normally stored in DEVS:USBHardware.", + MUIA_Popstring_String, data->hwdevobj = StringObject, + StringFrame, + MUIA_CycleChain, 1, + MUIA_String_AdvanceOnCR, TRUE, + End, + MUIA_Popstring_Button, PopButton(MUII_PopFile), + ASLFR_TitleText, "Select USBHardware device...", + End, + Child, Label("Unit:"), + Child, data->hwunitobj = StringObject, + MUIA_ShortHelp, "If there are multiple cards of the\n" + "same kind in your machine, enter\n" + "the unit number of the board here.", + StringFrame, + MUIA_HorizWeight, 10, + MUIA_CycleChain, 1, + MUIA_String_AdvanceOnCR, TRUE, + MUIA_String_Integer, 0, + MUIA_String_Accept, "0123456789", + End, + End, + Child, ColGroup(3), + MUIA_Group_SameWidth, TRUE, + Child, data->hwnewobj = MyTextObject("\33c New ", + "Click here to create a\n" + "new hardware driver entry."), + Child, data->hwcopyobj = MyTextObject("\33c Copy ", + "Click here to copy the selected\n" + "hardware driver entry."), + Child, data->hwdelobj = MyTextObject("\33c Delete ", + "Click here to remove the selected entry.\n" + "The hardware will automatically go offline,\n" + "taking all its connected devices down."), + Child, data->hwonlineobj = MyTextObject("\33c Online ", + "Click here to activate an\n" + "individual hardware driver."), + Child, data->hwofflineobj = MyTextObject("\33c Offline ", + "Click here to deactivate an\n" + "individual hardware driver."), + Child, data->hwinfoobj = MyTextObject("\33c Info ", + "To get information on the device driver,\n" + "click here. The device needs to be online\n" + "for the information to be available."), + End, + End; + + /* Devices panel */ + data->cfgcntobj[2] = VGroup, + MUIA_HelpNode, "tridentdevices", + Child, Label("\33c\33bUSB Devices in the system"), + Child, ListviewObject, + MUIA_CycleChain, 1, + MUIA_Listview_List, data->devlistobj = + NewObject(IconListClass->mcc_Class, 0, MUIA_ShortHelp, "This is the list of USB devices (functions)\ncurrently in the system. It also shows the\ncurrently existing device or interface bindings.", InputListFrame, MUIA_List_MinLineHeight, 16, MUIA_List_Format, "BAR,BAR,BAR,BAR,", MUIA_List_Title, TRUE, MUIA_List_DisplayHook, &data->DeviceDisplayHook, TAG_END), + End, + Child, ColGroup(4), + MUIA_Group_SameWidth, TRUE, + Child, data->devbindobj = MyTextObject("\33c Class Scan ", + "Clicking on this button will start a class scan. This means that\n" + "each device will be examined if it matches some of the standard\n" + "classes in the system. In this case, a binding will be established\n" + "and the functionality will be added to the system automatically.\n"), + Child, data->devunbindobj = MyTextObjectDisabled("\33c Unbind ", + "Manually removes a binding. This can be\n" + "useful to temporarily deactivate a device.\n" + "Use 'Class Scan' to reactivate the binding."), + Child, data->devinfoobj = MyTextObject("\33c Information ", + "Opens a detailed information window.\n" + "Just try it, nothing can go wrong."), + Child, data->devcfgobj = MyTextObjectDisabled("\33c Settings ", + "If there is a device binding and the class\n" + "supports a configuration GUI. Clicking on this\n" + "button will open the preferences window.\n\n" + "Note well, that the corrsponding button for the\n" + "interface binding settings can be found inside\n" + "the information window."), + Child, data->devsuspendobj = MyTextObjectDisabled("\33c Suspend ", + "Sends device into power saving suspend mode.\n" + "If a class binding does not support suspend,\n" + "this button will do nothing."), + Child, data->devresumeobj = MyTextObjectDisabled("\33c Resume ", + "Resumes the device to full operation after\n" + "it was placed into suspend mode.\n"), + Child, data->devpowercycleobj = MyTextObjectDisabled("\33c Powercycle ", + "Power cycles the hub port and re-enumerates\n" + "device. Comes handy to reactivate dead devices.\n"), + Child, data->devdisableobj = MyTextObjectDisabled("\33c Disable ", + "Permanently powers off the port. It cannot be\n" + "reactivated by unplugging/replugging the device.\n"), + End, + End; + + /* Classes panel */ + data->cfgcntobj[3] = VGroup, + MUIA_HelpNode, "tridentclasses", + Child, Label("\33c\33bUSB Classes available"), + Child, data->clslistobj = ListviewObject, + MUIA_CycleChain, 1, + MUIA_Listview_List, ListObject, + MUIA_ShortHelp, "This is the list of USB classes available.\n" + "Each class is a software driver for a group of\n" + "USB devices. Classes can be manually added using\n" + "the 'Add' button or automatically with 'Dir Scan'.", + InputListFrame, + MUIA_List_Format, "BAR,BAR,", + MUIA_List_Title, TRUE, + MUIA_List_DisplayHook, &data->ClassDisplayHook, + End, + End, + Child, HGroup, + Child, Label("Class library:"), + Child, PopaslObject, + MUIA_CycleChain, 1, + MUIA_ShortHelp, "To manually add an usb class driver,\n" + "enter its name here and click on 'Add'.", + MUIA_Popstring_String, data->clsnameobj = StringObject, + StringFrame, + MUIA_CycleChain, 1, + MUIA_String_AdvanceOnCR, TRUE, + MUIA_String_Contents, CLASSPATH "/", + End, + MUIA_Popstring_Button, PopButton(MUII_PopFile), + ASLFR_TitleText, "Select USB class library...", + End, + End, + Child, HGroup, + MUIA_Group_SameWidth, TRUE, + Child, data->clsaddobj = MyTextObject("\33c Add ", + "To manually add an usb class\n" + "driver, enter its name above\n" + "and click on this button."), + Child, data->clsremobj = MyTextObjectDisabled("\33c Remove ", + "Click here to remove a class driver\n" + "and all its current bindings."), + Child, data->clscfgobj = MyTextObjectDisabled("\33c Configure ", + "If a class driver supports some kind of\n" + "configuration, click here and it will\n" + "open a configuration window of the class."), + Child, data->clsscanobj = MyTextObject("\33c Dir Scan ", + "Automatically scans for class\n" + "drivers in " CLASSPATH " and\n" + "adds all drivers found to the system."), + End, + End; + + /* Options panel */ + data->cfgcntobj[4] = VGroup, + MUIA_HelpNode, "tridentoptions", + Child, Label("\33c\33bVarious Settings"), + Child, VSpace(0), + Child, VGroup, GroupFrameT("Stack Settings"), + Child, VSpace(0), + Child, HGroup, + Child, Label("SubTask priority:"), + Child, data->cfgtaskpriobj = SliderObject, SliderFrame, + MUIA_ShortHelp, "Defines the task priority of all\n" + "subtasks started by Poseidon.", + MUIA_CycleChain, 1, + MUIA_Numeric_Min, 0, + MUIA_Numeric_Max, 127, + MUIA_Numeric_Value, subtaskpri, + End, + Child, Label("Boot delay:"), + Child, data->cfgbootdelayobj = SliderObject, SliderFrame, + MUIA_ShortHelp, "If reset resident, this value defines,\n" + "how long Poseidon should wait for USB\n" + "devices to settle, allowing to boot from\n" + "slow devices such as an USB CD drive.\n", + MUIA_CycleChain, 1, + MUIA_Numeric_Min, 0, + MUIA_Numeric_Max, 15, + MUIA_Numeric_Value, bootdelay, + MUIA_Numeric_Format, "%ld sec.", + End, + End, + Child, ColGroup(2), + Child, HGroup, + Child, HSpace(0), + Child, Label("Automatically disable hub port on low power conditions:"), + End, + Child, data->cfgautolpobj = ImageObject, ImageButtonFrame, + MUIA_ShortHelp, "If a low power condition is detected at a port,\n" + "selecting this switch will automatically turn off\n" + "the device causing the low power condition.", + MUIA_Background, MUII_ButtonBack, + MUIA_CycleChain, 1, + MUIA_InputMode, MUIV_InputMode_Toggle, + MUIA_Image_Spec, MUII_CheckMark, + MUIA_Image_FreeVert, TRUE, + MUIA_Selected, autodisablelp, + MUIA_ShowSelState, FALSE, + End, + Child, HGroup, + Child, HSpace(0), + Child, Label("Automatically disable hub port, if device drops dead:"), + End, + Child, data->cfgautodeadobj = ImageObject, ImageButtonFrame, + MUIA_ShortHelp, "If a device drops dead (transfer timeouts),\n" + "and this switch is selected, then the hub port\n" + "will be disabled automatically to avoid unnecessary\n" + "performance penalties.", + MUIA_Background, MUII_ButtonBack, + MUIA_CycleChain, 1, + MUIA_InputMode, MUIV_InputMode_Toggle, + MUIA_Image_Spec, MUII_CheckMark, + MUIA_Image_FreeVert, TRUE, + MUIA_Selected, autodisabledead, + MUIA_Disabled, autorestartdead, + MUIA_ShowSelState, FALSE, + End, + Child, HGroup, + Child, HSpace(0), + Child, Label("Automatically power cycle hub port, if device drops dead:"), + End, + Child, data->cfgautopcobj = ImageObject, ImageButtonFrame, + MUIA_ShortHelp, "If a device drops dead (transfer timeouts),\n" + "and this switch is selected, then the hub port\n" + "will be reset automatically to try to revive the\n" + "device. However, this can lead to nasty infinity loops.", + MUIA_Background, MUII_ButtonBack, + MUIA_CycleChain, 1, + MUIA_InputMode, MUIV_InputMode_Toggle, + MUIA_Image_Spec, MUII_CheckMark, + MUIA_Image_FreeVert, TRUE, + MUIA_Selected, autorestartdead, + MUIA_ShowSelState, FALSE, + End, + Child, HGroup, + Child, HSpace(0), + Child, Label("Enable power-saving suspend mode:"), + End, + Child, data->cfgpowersavingobj = ImageObject, ImageButtonFrame, + MUIA_ShortHelp, "Devices will be placed into suspend mode after\n" + "a specified interval of inactivity.\n" + "Power consumption goes down to less than 1mA.\n" + "Resuming of operation usually takes place within 25ms.", + MUIA_Background, MUII_ButtonBack, + MUIA_CycleChain, 1, + MUIA_InputMode, MUIV_InputMode_Toggle, + MUIA_Image_Spec, MUII_CheckMark, + MUIA_Image_FreeVert, TRUE, + MUIA_Selected, powersaving, + MUIA_ShowSelState, FALSE, + End, + Child, HGroup, + Child, HSpace(0), + Child, Label("Force suspend mode, even if not supported by class:"), + End, + Child, data->cfgforcesuspendobj = ImageObject, ImageButtonFrame, + MUIA_ShortHelp, "Class drivers should support going into suspend\n" + "mode. If they don't, enabling this switch will\n" + "simply release the binding prior to suspending.\n" + "This is only performed on remote wakeup devices,\n" + "otherwise the class wouldn't rebind automatically.", + MUIA_Background, MUII_ButtonBack, + MUIA_CycleChain, 1, + MUIA_InputMode, MUIV_InputMode_Toggle, + MUIA_Image_Spec, MUII_CheckMark, + MUIA_Image_FreeVert, TRUE, + MUIA_Selected, forcesuspend, + MUIA_ShowSelState, FALSE, + End, + End, + Child, HGroup, + Child, Label("Inactivity timeout for suspend:"), + Child, data->cfgsuspendtimeoutobj = SliderObject, SliderFrame, + MUIA_ShortHelp, "Timeout before trying to place a device into\n" + "power saving suspend mode.", + MUIA_CycleChain, 1, + MUIA_Numeric_Min, 5, + MUIA_Numeric_Max, 600, + MUIA_Numeric_Value, suspendtimeout, + MUIA_Numeric_Format, "%ld sec.", + End, + End, + Child, VSpace(0), + End, + Child, VSpace(0), + Child, VGroup, GroupFrameT("Logging Options"), + Child, VSpace(0), + Child, HGroup, + Child, HSpace(0), + Child, ColGroup(4), + Child, HGroup, + Child, HSpace(0), + Child, Label("Log info messages:"), + End, + Child, data->cfgloginfoobj = ImageObject, ImageButtonFrame, + MUIA_ShortHelp, "Toggles logging of normal\n" + "information messages.", + MUIA_Background, MUII_ButtonBack, + MUIA_CycleChain, 1, + MUIA_InputMode, MUIV_InputMode_Toggle, + MUIA_Image_Spec, MUII_CheckMark, + MUIA_Image_FreeVert, TRUE, + MUIA_Selected, loginfo, + MUIA_ShowSelState, FALSE, + End, + Child, HGroup, + Child, HSpace(0), + Child, Label("Log warnings:"), + End, + Child, data->cfglogwarnobj = ImageObject, ImageButtonFrame, + MUIA_ShortHelp, "Toggles logging of warnings.", + MUIA_Background, MUII_ButtonBack, + MUIA_CycleChain, 1, + MUIA_InputMode, MUIV_InputMode_Toggle, + MUIA_Image_Spec, MUII_CheckMark, + MUIA_Image_FreeVert, TRUE, + MUIA_Selected, logwarn, + MUIA_ShowSelState, FALSE, + End, + Child, HGroup, + Child, HSpace(0), + Child, Label("Log errors:"), + End, + Child, data->cfglogerrobj = ImageObject, ImageButtonFrame, + MUIA_ShortHelp, "Toggles logging of errors.", + MUIA_Background, MUII_ButtonBack, + MUIA_CycleChain, 1, + MUIA_InputMode, MUIV_InputMode_Toggle, + MUIA_Image_Spec, MUII_CheckMark, + MUIA_Image_FreeVert, TRUE, + MUIA_Selected, logerr, + MUIA_ShowSelState, FALSE, + End, + Child, HGroup, + Child, HSpace(0), + Child, Label("Log failures:"), + End, + Child, data->cfglogfailobj = ImageObject, ImageButtonFrame, + MUIA_ShortHelp, "Toggles logging of failures.", + MUIA_Background, MUII_ButtonBack, + MUIA_CycleChain, 1, + MUIA_InputMode, MUIV_InputMode_Toggle, + MUIA_Image_Spec, MUII_CheckMark, + MUIA_Image_FreeVert, TRUE, + MUIA_Selected, logfail, + MUIA_ShowSelState, FALSE, + End, + End, + Child, HSpace(0), + End, + Child, VSpace(0), + End, + Child, VSpace(0), + Child, HGroup, + Child, HSpace(0), + Child, Label("Memory allocated in Poseidon Pool:"), + Child, data->mempoolobj = TextObject, + MUIA_Text_Contents, "?", + End, + Child, HSpace(0), + End, + End; + + /* PoPo panel */ + data->cfgcntobj[5] = VGroup, + MUIA_HelpNode, "tridentpopups", + Child, Label("\33c\33bPopup Settings"), + Child, VSpace(0), + Child, VGroup, GroupFrameT("Popup Window Options"), + Child, VSpace(0), + Child, ColGroup(2), + Child, Label("On connecting:"), + Child, HGroup, + Child, data->cfgpopupnewobj = CycleObject, + MUIA_ShortHelp, "Popup display behaviour on\n" + "connecting new USB devices", + MUIA_CycleChain, 1, + MUIA_Cycle_Entries, popupnewdevicestrings, + MUIA_Cycle_Active, popupnew, + End, + End, + Child, Label("On disconnect:"), + Child, HGroup, + Child, data->cfgpopupgoneobj = ImageObject, ImageButtonFrame, + MUIA_ShortHelp, "Whether to popup a window\n" + "if the device is removed.", + MUIA_Background, MUII_ButtonBack, + MUIA_CycleChain, 1, + MUIA_InputMode, MUIV_InputMode_Toggle, + MUIA_Image_Spec, MUII_CheckMark, + MUIA_Image_FreeVert, TRUE, + MUIA_Selected, popupgone, + MUIA_ShowSelState, FALSE, + End, + Child, HSpace(0), + Child, Label("On device death:"), + Child, data->cfgpopupdeathobj = ImageObject, ImageButtonFrame, + MUIA_ShortHelp, "Open a requester, if device seems to be dead.", + MUIA_Background, MUII_ButtonBack, + MUIA_CycleChain, 1, + MUIA_InputMode, MUIV_InputMode_Toggle, + MUIA_Image_Spec, MUII_CheckMark, + MUIA_Image_FreeVert, TRUE, + MUIA_Selected, popupdeath, + MUIA_ShowSelState, FALSE, + End, + End, + Child, Label("Popup delay:"), + Child, data->cfgpopupdelayobj = SliderObject, SliderFrame, + MUIA_ShortHelp, "How long should the requester be displayed\n" + "before disappearing automatically.", + MUIA_CycleChain, 1, + MUIA_Numeric_Min, 0, + MUIA_Numeric_Max, 25, + MUIA_Numeric_Value, popupdelay, + MUIA_Numeric_Format, "%ld sec.", + End, + Child, Label("Activate window:"), + Child, HGroup, + Child, data->cfgpopupactivateobj = ImageObject, ImageButtonFrame, + MUIA_ShortHelp, "Make the window active when opening.", + MUIA_Background, MUII_ButtonBack, + MUIA_CycleChain, 1, + MUIA_InputMode, MUIV_InputMode_Toggle, + MUIA_Image_Spec, MUII_CheckMark, + MUIA_Image_FreeVert, TRUE, + MUIA_Selected, popupactivate, + MUIA_ShowSelState, FALSE, + End, + Child, HSpace(0), + Child, Label("Pop to front:"), + Child, data->cfgpopuptofrontobj = ImageObject, ImageButtonFrame, + MUIA_ShortHelp, "Pop window to front, if content changes.", + MUIA_Background, MUII_ButtonBack, + MUIA_CycleChain, 1, + MUIA_InputMode, MUIV_InputMode_Toggle, + MUIA_Image_Spec, MUII_CheckMark, + MUIA_Image_FreeVert, TRUE, + MUIA_Selected, popuptofront, + MUIA_ShowSelState, FALSE, + End, + End, + Child, Label("Connection sound:"), + Child, PopaslObject, + MUIA_CycleChain, 1, + MUIA_ShortHelp, "This sound will be replayed everytime\n" + "a device is connected to the bus.", + MUIA_Popstring_String, data->cfgdevdtxsoundobj = StringObject, + StringFrame, + MUIA_CycleChain, 1, + MUIA_String_AdvanceOnCR, TRUE, + MUIA_String_Contents, devdtxsoundfile, + End, + MUIA_Popstring_Button, PopButton(MUII_PopFile), + ASLFR_TitleText, "Select a sound file to be replayed...", + End, + Child, Label("Disconnect sound:"), + Child, PopaslObject, + MUIA_CycleChain, 1, + MUIA_ShortHelp, "This sound will be replayed everytime\n" + "a device is removed from the bus.", + MUIA_Popstring_String, data->cfgdevremsoundobj = StringObject, + StringFrame, + MUIA_CycleChain, 1, + MUIA_String_AdvanceOnCR, TRUE, + MUIA_String_Contents, devremsoundfile, + End, + MUIA_Popstring_Button, PopButton(MUII_PopFile), + ASLFR_TitleText, "Select a sound file to be replayed...", + End, + End, + Child, VSpace(0), + End, + Child, VSpace(0), + End; + + /* Configuration panel */ + data->cfgcntobj[6] = VGroup, + MUIA_HelpNode, "tridentconfig", + Child, Label("\33c\33bConfiguration management (Use drag & drop)"), + Child, data->prefslistobj = ListviewObject, + MUIA_CycleChain, 1, + MUIA_ShortHelp, "In this box you can see all the preferences that are\n" + "saved along the prefs file (ENVARC:" STACKLOADER ").\n" + "You can use this panel to delete or export prefs.\n\n" + "Use drag & drop to copy or replace preferences.\n", + MUIA_Listview_DragType, MUIV_Listview_DragType_Immediate, + MUIA_Listview_List, + NewObject(CfgListClass->mcc_Class, 0, InputListFrame, MUIA_List_Format, "BAR,BAR,BAR,", MUIA_List_Title, TRUE, MUIA_List_DisplayHook, &data->PrefsDisplayHook, MUIA_List_ShowDropMarks, TRUE, MUIA_List_AutoVisible, TRUE, TAG_END), + End, + Child, HGroup, + MUIA_Group_SameWidth, TRUE, + Child, data->prefssaveasobj = MyTextObject("\33c Save as ", + "Save all the prefs under given name\n" + "for reloading it later."), + Child, data->prefsexportobj = MyTextObjectDisabled("\33c Export ", + "Allows you to save a selected entry\n" + "to reload it later."), + Child, data->prefsimportobj = MyTextObject("\33c Import ", + "Imports a previously saved piece of prefs."), + Child, data->prefsremoveobj = MyTextObjectDisabled("\33c Remove ", + "Deletes the selected prefs entry."), + End, + End; + + data->mainobj = VGroup, + Child, HGroup, + Child, ListviewObject, + MUIA_CycleChain, 1, + MUIA_ShowMe, !registermode, + MUIA_Listview_MultiSelect, MUIV_Listview_MultiSelect_None, + MUIA_Listview_List, data->cfgpagelv = + NewObject(IconListClass->mcc_Class, 0, InputListFrame, MUIA_List_MinLineHeight, 16, MUIA_List_SourceArray, mainpanels, MUIA_List_AdjustWidth, TRUE, MUIA_List_Active, 0, MUIA_List_DisplayHook, &data->IconDisplayHook, TAG_END), + End, + Child, VGroup, + /*ReadListFrame,*/ + /*MUIA_Background, MUII_GroupBack,*/ + Child, data->cfgpagegrp = (registermode ? + (RegisterGroup(mainpanels), + MUIA_CycleChain, 1, + MUIA_Register_Frame, TRUE, + Child, data->cfgcntobj[0], + Child, data->cfgcntobj[1], + Child, data->cfgcntobj[2], + Child, data->cfgcntobj[3], + Child, data->cfgcntobj[4], + Child, data->cfgcntobj[5], + Child, data->cfgcntobj[6], + End) : + (VGroup, + MUIA_Group_PageMode, TRUE, + MUIA_Group_ActivePage, MUIV_Group_ActivePage_First, + Child, data->cfgcntobj[0], + Child, data->cfgcntobj[1], + Child, data->cfgcntobj[2], + Child, data->cfgcntobj[3], + Child, data->cfgcntobj[4], + Child, data->cfgcntobj[5], + Child, data->cfgcntobj[6], + End)), + End, + End, + Child, BalanceObject, + MUIA_ObjectID, MAKE_ID('I','L','B','P'), + End, + Child, VGroup, GroupFrameT("Message Log"), + MUIA_VertWeight, 20, + Child, HGroup, + Child, Label("Information level:"), + Child, data->errlvlobj = CycleObject, + MUIA_CycleChain, 1, + MUIA_ShortHelp, "This gadget determines the amount and\n" + "type of messages shown below.", + MUIA_Cycle_Entries, errlvlstrings, + End, + Child, HSpace(0), + Child, HGroup, + MUIA_Group_SameWidth, TRUE, + Child, data->errsaveobj = MyTextObject("\33c Save to disk ", + "To generate a logfile of the errors,\n" + "e.g. to send the information to me\n" + "for bug reporting or help."), + Child, data->errflushobj = MyTextObject("\33c Flush all ", + "Clicking on this button will remove all\n" + "the messages in the stack. There's no way\n" + "to get them back."), + End, + End, + Child, data->errlistobj = ListviewObject, + MUIA_CycleChain, 1, + MUIA_Listview_Input, FALSE, + MUIA_Listview_List, ListObject, + MUIA_ShortHelp, "These are the messages of the Poseidon stack\n" + "generated so far. If you want to clear this list\n" + "just click on the 'Flush all messages' button.", + ReadListFrame, + MUIA_List_Format, "BAR,BAR,BAR,", + MUIA_List_DisplayHook, &data->ErrorDisplayHook, + End, + End, + End, + Child, HGroup, + MUIA_Group_SameWidth, TRUE, + Child, data->onlineobj = MyTextObject( "\33c All Online ", + "Start all USB hardware device drivers that\n" + "have been entered in the 'Hardware' panel.\n" + "Moreover, the found devices will be checked\n" + "for possible bindings."), + Child, data->offlineobj = MyTextObject("\33c All Offline ", + "Using 'Offline' you can take down all the USB\n" + "hardware device drivers.\n" + "This totally halts the stack."), + Child, data->restartobj = MyTextObject("\33c Restart ", + "Clicking on 'Restart' will stop and restart\n" + "all hardware device drivers.\n"), + Child, HSpace(0), + Child, data->saveobj = MyTextObject("\33c Save ", + "To save your current prefs to disk, click\n" + "on this buttion. The configuration will be\n" + "stored in both ENVARC:" STACKLOADER " and\n" + "ENV:" STACKLOADER "."), + Child, data->useobj = MyTextObject("\33c Use ", \ + "To use, but not permanently save your prefs\n" + "click this button. The configuration will be\n" + "stored in ENV:" STACKLOADER "."), + End, + End; + + DoMethod(obj, OM_ADDMEMBER, data->mainobj); + + DoMethod(data->cfgpagelv, MUIM_Notify, MUIA_List_Active, MUIV_EveryTime, + data->cfgpagegrp, 3, MUIM_Set, MUIA_Group_ActivePage, MUIV_TriggerValue); + DoMethod(data->cfgpagelv, MUIM_Notify, MUIA_List_Active, MUIV_EveryTime, + obj, 1, MUIM_Action_Info_MemPool); + + DoMethod(data->hwnewobj, MUIM_Notify, MUIA_Pressed, FALSE, + obj, 1, MUIM_Action_HW_New); + DoMethod(data->hwcopyobj, MUIM_Notify, MUIA_Pressed, FALSE, + obj, 1, MUIM_Action_HW_Copy); + DoMethod(data->hwdelobj, MUIM_Notify, MUIA_Pressed, FALSE, + obj, 1, MUIM_Action_HW_Del); + DoMethod(data->hwinfoobj, MUIM_Notify, MUIA_Pressed, FALSE, + obj, 1, MUIM_Action_HW_Info); + DoMethod(data->hwonlineobj, MUIM_Notify, MUIA_Pressed, FALSE, + obj, 1, MUIM_Action_HW_Online); + DoMethod(data->hwofflineobj, MUIM_Notify, MUIA_Pressed, FALSE, + obj, 1, MUIM_Action_HW_Offline); + + DoMethod(data->hwlistobj, MUIM_Notify, MUIA_Listview_DoubleClick, TRUE, + obj, 1, MUIM_Action_HW_Info); + DoMethod(data->hwlistobj, MUIM_Notify, MUIA_List_Active, MUIV_EveryTime, + obj, 1, MUIM_Action_HW_Activate); + DoMethod(data->hwdevobj, MUIM_Notify, MUIA_String_Acknowledge, MUIV_EveryTime, + obj, 2, MUIM_Action_HW_Update, NULL); + DoMethod(data->hwunitobj, MUIM_Notify, MUIA_String_Acknowledge, MUIV_EveryTime, + obj, 2, MUIM_Action_HW_Update, NULL); + + DoMethod(data->errsaveobj, MUIM_Notify, MUIA_Pressed, FALSE, + obj, 1, MUIM_Action_SaveErrors); + DoMethod(data->errflushobj, MUIM_Notify, MUIA_Pressed, FALSE, + obj, 1, MUIM_Action_FlushErrors); + DoMethod(data->errlvlobj, MUIM_Notify, MUIA_Cycle_Active, MUIV_EveryTime, + obj, 1, MUIM_Action_ChgErrLevel); + + DoMethod(data->onlineobj, MUIM_Notify, MUIA_Pressed, FALSE, + obj, 1, MUIM_Action_Online); + DoMethod(data->offlineobj, MUIM_Notify, MUIA_Pressed, FALSE, + obj, 1, MUIM_Action_Offline); + DoMethod(data->restartobj, MUIM_Notify, MUIA_Pressed, FALSE, + obj, 1, MUIM_Action_Restart); + + DoMethod(data->saveobj, MUIM_Notify, MUIA_Pressed, FALSE, + obj, 1, MUIM_Action_SaveQuit); + DoMethod(data->useobj, MUIM_Notify, MUIA_Pressed, FALSE, + obj, 1, MUIM_Action_UseQuit); + + DoMethod(data->devlistobj, MUIM_Notify, MUIA_List_Active, MUIV_EveryTime, + obj, 1, MUIM_Action_Dev_Activate); + DoMethod(data->devbindobj, MUIM_Notify, MUIA_Pressed, FALSE, + obj, 1, MUIM_Action_Dev_Bind); + DoMethod(data->devinfoobj, MUIM_Notify, MUIA_Pressed, FALSE, + obj, 1, MUIM_Action_Dev_Info); + DoMethod(data->devunbindobj, MUIM_Notify, MUIA_Pressed, FALSE, + obj, 1, MUIM_Action_Dev_Unbind); + DoMethod(data->devsuspendobj, MUIM_Notify, MUIA_Pressed, FALSE, + obj, 1, MUIM_Action_Dev_Suspend); + DoMethod(data->devresumeobj, MUIM_Notify, MUIA_Pressed, FALSE, + obj, 1, MUIM_Action_Dev_Resume); + DoMethod(data->devpowercycleobj, MUIM_Notify, MUIA_Pressed, FALSE, + obj, 1, MUIM_Action_Dev_PowerCycle); + DoMethod(data->devdisableobj, MUIM_Notify, MUIA_Pressed, FALSE, + obj, 1, MUIM_Action_Dev_Disable); + DoMethod(data->devlistobj, MUIM_Notify, MUIA_Listview_DoubleClick, TRUE, + obj, 1, MUIM_Action_Dev_Info); + DoMethod(data->devlistobj, MUIM_Notify, MUIA_ContextMenuTrigger, MUIV_EveryTime, + obj, 2, MUIM_Action_Dev_ForceBind, MUIV_TriggerValue); + + DoMethod(data->devcfgobj, MUIM_Notify, MUIA_Pressed, FALSE, + obj, 1, MUIM_Action_Dev_Configure); + + DoMethod(data->clslistobj, MUIM_Notify, MUIA_List_Active, MUIV_EveryTime, + obj, 1, MUIM_Action_Cls_Activate); + DoMethod(data->clsaddobj, MUIM_Notify, MUIA_Pressed, FALSE, + obj, 1, MUIM_Action_Cls_Add); + DoMethod(data->clsnameobj, MUIM_Notify, MUIA_String_Acknowledge, MUIV_EveryTime, + obj, 1, MUIM_Action_Cls_Add); + DoMethod(data->clsremobj, MUIM_Notify, MUIA_Pressed, FALSE, + obj, 1, MUIM_Action_Cls_Remove); + DoMethod(data->clscfgobj, MUIM_Notify, MUIA_Pressed, FALSE, + obj, 1, MUIM_Action_Cls_Configure); + DoMethod(data->clsscanobj, MUIM_Notify, MUIA_Pressed, FALSE, + obj, 1, MUIM_Action_Cls_Scan); + DoMethod(data->clslistobj, MUIM_Notify, MUIA_Listview_DoubleClick, TRUE, + obj, 1, MUIM_Action_Cls_Configure); + + DoMethod(data->cfgtaskpriobj, MUIM_Notify, MUIA_Numeric_Value, MUIV_EveryTime, + obj, 1, MUIM_Action_Cfg_Changed); + DoMethod(data->cfgbootdelayobj, MUIM_Notify, MUIA_Numeric_Value, MUIV_EveryTime, + obj, 1, MUIM_Action_Cfg_Changed); + DoMethod(data->cfgloginfoobj, MUIM_Notify, MUIA_Selected, MUIV_EveryTime, + obj, 1, MUIM_Action_Cfg_Changed); + DoMethod(data->cfglogwarnobj, MUIM_Notify, MUIA_Selected, MUIV_EveryTime, + obj, 1, MUIM_Action_Cfg_Changed); + DoMethod(data->cfglogerrobj, MUIM_Notify, MUIA_Selected, MUIV_EveryTime, + obj, 1, MUIM_Action_Cfg_Changed); + DoMethod(data->cfglogfailobj, MUIM_Notify, MUIA_Selected, MUIV_EveryTime, + obj, 1, MUIM_Action_Cfg_Changed); + + DoMethod(data->cfgpopupnewobj, MUIM_Notify, MUIA_Cycle_Active, MUIV_EveryTime, + obj, 1, MUIM_Action_Cfg_Changed); + DoMethod(data->cfgpopupgoneobj, MUIM_Notify, MUIA_Selected, MUIV_EveryTime, + obj, 1, MUIM_Action_Cfg_Changed); + DoMethod(data->cfgpopupdeathobj, MUIM_Notify, MUIA_Selected, MUIV_EveryTime, + obj, 1, MUIM_Action_Cfg_Changed); + DoMethod(data->cfgpopupdelayobj, MUIM_Notify, MUIA_Numeric_Value, MUIV_EveryTime, + obj, 1, MUIM_Action_Cfg_Changed); + DoMethod(data->cfgpopupactivateobj, MUIM_Notify, MUIA_Selected, MUIV_EveryTime, + obj, 1, MUIM_Action_Cfg_Changed); + DoMethod(data->cfgpopuptofrontobj, MUIM_Notify, MUIA_Selected, MUIV_EveryTime, + obj, 1, MUIM_Action_Cfg_Changed); + DoMethod(data->cfgdevdtxsoundobj, MUIM_Notify, MUIA_String_Acknowledge, MUIV_EveryTime, + obj, 1, MUIM_Action_Cfg_Snd_Changed); + DoMethod(data->cfgdevremsoundobj, MUIM_Notify, MUIA_String_Acknowledge, MUIV_EveryTime, + obj, 1, MUIM_Action_Cfg_Snd_Changed); + + DoMethod(data->cfgautolpobj, MUIM_Notify, MUIA_Selected, MUIV_EveryTime, + obj, 1, MUIM_Action_Cfg_Changed); + DoMethod(data->cfgautodeadobj, MUIM_Notify, MUIA_Selected, MUIV_EveryTime, + obj, 1, MUIM_Action_Cfg_Changed); + DoMethod(data->cfgautopcobj, MUIM_Notify, MUIA_Selected, MUIV_EveryTime, + obj, 1, MUIM_Action_Cfg_Changed); + + DoMethod(data->cfgpowersavingobj, MUIM_Notify, MUIA_Selected, MUIV_EveryTime, + obj, 1, MUIM_Action_Cfg_Changed); + DoMethod(data->cfgforcesuspendobj, MUIM_Notify, MUIA_Selected, MUIV_EveryTime, + obj, 1, MUIM_Action_Cfg_Changed); + DoMethod(data->cfgsuspendtimeoutobj, MUIM_Notify, MUIA_Numeric_Value, MUIV_EveryTime, + obj, 1, MUIM_Action_Cfg_Changed); + + DoMethod(data->prefslistobj, MUIM_Notify, MUIA_List_Active, MUIV_EveryTime, + obj, 1, MUIM_Action_Cfg_Activate); + DoMethod(data->prefssaveasobj, MUIM_Notify, MUIA_Pressed, FALSE, + obj, 1, MUIM_Action_SavePrefsAs); + DoMethod(data->prefsexportobj, MUIM_Notify, MUIA_Pressed, FALSE, + obj, 1, MUIM_Action_Cfg_Export); + DoMethod(data->prefsimportobj, MUIM_Notify, MUIA_Pressed, FALSE, + obj, 1, MUIM_Action_Cfg_Import); + DoMethod(data->prefsremoveobj, MUIM_Notify, MUIA_Pressed, FALSE, + obj, 1, MUIM_Action_Cfg_Remove); + + data->mi_classpopup = CreateClassPopup(); + set(data->devlistobj, MUIA_ContextMenu, data->mi_classpopup); + + Action_HW_Activate(cl, obj, msg); + + CreateErrorList(data); + SetupEventHandler(data); + while((pd = psdGetNextDevice(pd))) + { + dlnode = AllocDevEntry(data, pd); + if(dlnode) + { + DoMethod(data->devlistobj, MUIM_List_InsertSingle, dlnode, MUIV_List_Insert_Bottom); + } + } + UpdateConfigToGUI(data); + return(obj); +} +/* \\\ */ + +/* /// "Action_OM_DISPOSE()" */ +IPTR Action_OM_DISPOSE(struct IClass *cl, Object *obj, Msg msg) +{ + struct ActionData *data = INST_DATA(cl, obj); + FreeErrorList(data); + FreePrefsList(data); + FreeGUILists(data); + if(data->mi_classpopup) + { + MUI_DisposeObject(data->mi_classpopup); + data->mi_classpopup = NULL; + } + CleanupEventHandler(data); + return(FALSE); +} +/* \\\ */ + +/* /// "Action_Setup()" */ +IPTR Action_Setup(struct IClass *cl, Object *obj, Msg msg) +{ + struct ActionData *data = INST_DATA(cl, obj); + + data->appobj = _app(obj); + data->winobj = _win(obj); + if(!DoSuperMethodA(cl,obj,msg)) return(FALSE); + + data->eventihn.ihn_Object = obj; + data->eventihn.ihn_Signals = 1UL<eventmsgport->mp_SigBit; + data->eventihn.ihn_Flags = 0; + data->eventihn.ihn_Method = MUIM_Action_HandlePsdEvents; + DoMethod(data->appobj, MUIM_Application_AddInputHandler, &data->eventihn); + //MUI_RequestIDCMP(obj, IDCMP_INTUITICKS); + return(TRUE); +} +/* \\\ */ + +/* /// "Action_HW_New()" */ +IPTR Action_HW_New(struct IClass *cl, Object *obj, Msg msg) +{ + struct ActionData *data = INST_DATA(cl, obj); + struct HWListEntry *hlnode; + hlnode = AllocHWEntry(data, NULL); + if(hlnode) + { + hlnode->devname = psdCopyStr("DEVS:USBHardware/"); + DoMethod(data->hwlistobj, MUIM_List_InsertSingle, hlnode, MUIV_List_Insert_Bottom); + set(data->hwlistobj, MUIA_List_Active, MUIV_List_Active_Bottom); + DoMethod(data->hwdevaslobj, MUIM_Popstring_Open); + InternalCreateConfigGUI(data); + } + return(TRUE); +} +/* \\\ */ + +/* /// "Action_HW_Copy()" */ +IPTR Action_HW_Copy(struct IClass *cl, Object *obj, Msg msg) +{ + struct ActionData *data = INST_DATA(cl, obj); + struct HWListEntry *hlnode; + if(data->acthlnode) + { + hlnode = AllocHWEntry(data, NULL); + if(hlnode) + { + hlnode->devname = psdCopyStr(data->acthlnode->devname); + hlnode->unit = data->acthlnode->unit + 1; + DoMethod(data->hwlistobj, MUIM_List_InsertSingle, hlnode, MUIV_List_Insert_Bottom); + set(data->hwlistobj, MUIA_List_Active, MUIV_List_Active_Bottom); + InternalCreateConfigGUI(data); + } + } + return(TRUE); +} +/* \\\ */ + +/* /// "Action_HW_Del()" */ +IPTR Action_HW_Del(struct IClass *cl, Object *obj, Msg msg) +{ + struct ActionData *data = INST_DATA(cl, obj); + struct HWListEntry *hlnode; + if(data->acthlnode) + { + hlnode = data->acthlnode; + DoMethod(data->hwlistobj, MUIM_List_Remove, MUIV_List_Remove_Active); + FreeHWEntry(data, hlnode); + InternalCreateConfigGUI(data); + } + return(TRUE); +} +/* \\\ */ + +/* /// "Action_HW_Update()" */ +IPTR Action_HW_Update(struct IClass *cl, Object *obj, Msg msg) +{ + struct ActionData *data = INST_DATA(cl, obj); + struct HWListEntry *hlnode; + hlnode = (struct HWListEntry *) ((struct opSet *) msg)->ops_AttrList; + if(!hlnode) + { + hlnode = data->acthlnode; + } + if(hlnode) + { + STRPTR str; + psdFreeVec(hlnode->devname); + get(data->hwdevobj, MUIA_String_Contents, &str); + hlnode->devname = psdCopyStr(str); + get(data->hwunitobj, MUIA_String_Integer, &hlnode->unit); + DoMethod(data->hwlistobj, MUIM_List_Redraw, MUIV_List_Redraw_All); + InternalCreateConfigGUI(data); + } + return(TRUE); +} +/* \\\ */ + +/* /// "Action_HW_Activate()" */ +IPTR Action_HW_Activate(struct IClass *cl, Object *obj, Msg msg) +{ + struct ActionData *data = INST_DATA(cl, obj); + struct HWListEntry *hlnode; + if(data->acthlnode) + { + DoMethod(obj, MUIM_Action_HW_Update, data->acthlnode); + } + DoMethod(data->hwlistobj, MUIM_List_GetEntry, MUIV_List_GetEntry_Active, &hlnode); + if((data->acthlnode = hlnode)) + { + set(data->hwdevgrpobj, MUIA_Disabled, FALSE); + set(data->hwcopyobj, MUIA_Disabled, FALSE); + set(data->hwdelobj, MUIA_Disabled, FALSE); + set(data->hwinfoobj, MUIA_Disabled, !hlnode->phw); + set(data->hwofflineobj, MUIA_Disabled, !hlnode->phw); + set(data->hwonlineobj, MUIA_Disabled, hlnode->phw); + set(data->hwdevobj, MUIA_String_Contents, hlnode->devname); + set(data->hwunitobj, MUIA_String_Integer, hlnode->unit); + } else { + set(data->hwdevgrpobj, MUIA_Disabled, TRUE); + set(data->hwcopyobj, MUIA_Disabled, TRUE); + set(data->hwdelobj, MUIA_Disabled, TRUE); + set(data->hwinfoobj, MUIA_Disabled, TRUE); + set(data->hwofflineobj, MUIA_Disabled, TRUE); + set(data->hwonlineobj, MUIA_Disabled, TRUE); + } + return(TRUE); +} +/* \\\ */ + +/* /// "Action_HW_Info()" */ +IPTR Action_HW_Info(struct IClass *cl, Object *obj, Msg msg) +{ + struct ActionData *data = INST_DATA(cl, obj); + struct HWListEntry *hlnode; + IPTR revision = 0; + IPTR version = 0; + IPTR unitnr = -1; + STRPTR devname = "unknown"; + STRPTR manufacturer = "unknown"; + STRPTR prodname = "unknown"; + STRPTR description = "unknown"; + STRPTR copyright = "unknown"; + STRPTR textbuf1; + + DoMethod(data->hwlistobj, MUIM_List_GetEntry, MUIV_List_GetEntry_Active, &hlnode); + if(hlnode) + { + if(hlnode->infowindow || (!hlnode->phw)) + { + return(TRUE); + } + psdGetAttrs(PGA_HARDWARE, hlnode->phw, + HA_DeviceName, &devname, + HA_DeviceUnit, &unitnr, + HA_Version, &version, + HA_Revision, &revision, + HA_ProductName, &prodname, + HA_Manufacturer, &manufacturer, + HA_Description, &description, + HA_Copyright, ©right, + TAG_END); + + textbuf1 = psdCopyStrFmt("%s\n%ld\n%V%ld.%ld\n%s\n%s\n%s\n%s", + devname, unitnr, version, revision, prodname, + manufacturer, description, copyright); + hlnode->infowindow = WindowObject, + MUIA_Window_ID , MAKE_ID('H','I','N','F'), + MUIA_Window_Title, "Hardware driver information window", + MUIA_Window_IsSubWindow, FALSE, + WindowContents, HGroup, + MUIA_ShortHelp, "These fields show some general information\n" + "on the USB hardware driver.", + MUIA_FrameTitle, "General USB hardware driver information", + Child, LabelB("Device:\nUnit:\nVersion:\nProduct:\nManufacturer:\nDescription:\nCopyright:"), + Child, TextObject, + TextFrame, + MUIA_Background, MUII_TextBack, + MUIA_Text_Contents, textbuf1, + End, + End, + End; + if(hlnode->infowindow) + { + DoMethod(data->appobj, OM_ADDMEMBER, hlnode->infowindow); + DoMethod(hlnode->infowindow, MUIM_Notify, MUIA_Window_CloseRequest, TRUE, + data->appobj, 5, MUIM_Application_PushMethod, obj, 2, MUIM_Action_CloseSubWinReq, hlnode); + + set(hlnode->infowindow, MUIA_Window_Open, TRUE); + } + psdFreeVec(textbuf1); + } + return(TRUE); +} +/* \\\ */ + +/* /// "Action_HW_Online()" */ +IPTR Action_HW_Online(struct IClass *cl, Object *obj, Msg msg) +{ + struct ActionData *data = INST_DATA(cl, obj); + struct HWListEntry *hlnode = data->acthlnode; + if((!hlnode) || hlnode->phw) + { + return(FALSE); + } + + set(data->appobj, MUIA_Application_Sleep, TRUE); + if((hlnode->phw = psdAddHardware(hlnode->devname, hlnode->unit))) + { + psdGetAttrs(PGA_HARDWARE, hlnode->phw, + HA_ProductName, &hlnode->prodname, + TAG_END); + psdEnumerateHardware(hlnode->phw); + } + + DoMethod(obj, MUIM_Action_HW_Activate); + DoMethod(data->hwlistobj, MUIM_List_Redraw, MUIV_List_Redraw_All); + psdClassScan(); + set(data->appobj, MUIA_Application_Sleep, FALSE); + // update the online status to the config + InternalCreateConfigGUI(data); + return(TRUE); +} +/* \\\ */ + +/* /// "Action_HW_Offline()" */ +IPTR Action_HW_Offline(struct IClass *cl, Object *obj, Msg msg) +{ + struct ActionData *data = INST_DATA(cl, obj); + struct HWListEntry *hlnode = data->acthlnode; + struct Node *phw; + struct List *lst; + + if((!hlnode) || (!hlnode->phw)) + { + return(FALSE); + } + + set(data->appobj, MUIA_Application_Sleep, TRUE); + + psdLockWritePBase(); + psdGetAttrs(PGA_STACK, NULL, PA_HardwareList, &lst, TAG_END); + phw = lst->lh_Head; + while(phw->ln_Succ) + { + if(phw == hlnode->phw) + { + psdUnlockPBase(); + psdRemHardware(phw); + phw = NULL; + break; + } + phw = phw->ln_Succ; + } + if(phw) + { + psdUnlockPBase(); + } + hlnode->phw = NULL; + hlnode->prodname = NULL; + + DoMethod(obj, MUIM_Action_HW_Activate); + DoMethod(data->hwlistobj, MUIM_List_Redraw, MUIV_List_Redraw_All); + set(data->appobj, MUIA_Application_Sleep, FALSE); + // update the online status to the config + // NOTE! This means that the hardware will not come online on next loading. + InternalCreateConfigGUI(data); + return(TRUE); +} +/* \\\ */ + +/* /// "Action_Online()" */ +IPTR Action_Online(struct IClass *cl, Object *obj, Msg msg) +{ + struct ActionData *data = INST_DATA(cl, obj); + struct HWListEntry *hlnode; + set(data->appobj, MUIA_Application_Sleep, TRUE); + hlnode = (struct HWListEntry *) data->hwlist.lh_Head; + while(hlnode->node.ln_Succ) + { + if(!hlnode->phw) + { + if((hlnode->phw = psdAddHardware(hlnode->devname, hlnode->unit))) + { + psdGetAttrs(PGA_HARDWARE, hlnode->phw, + HA_ProductName, &hlnode->prodname, + TAG_END); + psdEnumerateHardware(hlnode->phw); + } + } + hlnode = (struct HWListEntry *) hlnode->node.ln_Succ; + } + DoMethod(obj, MUIM_Action_HW_Activate); + DoMethod(data->hwlistobj, MUIM_List_Redraw, MUIV_List_Redraw_All); + psdClassScan(); + set(data->appobj, MUIA_Application_Sleep, FALSE); + // update the online status to the config + InternalCreateConfigGUI(data); + return(TRUE); +} +/* \\\ */ + +/* /// "Action_Offline()" */ +IPTR Action_Offline(struct IClass *cl, Object *obj, Msg msg) +{ + struct ActionData *data = INST_DATA(cl, obj); + struct HWListEntry *hlnode; + set(data->appobj, MUIA_Application_Sleep, TRUE); + hlnode = (struct HWListEntry *) data->hwlist.lh_Head; + while(hlnode->node.ln_Succ) + { + if(hlnode->phw) + { + struct Node *phw; + struct List *lst; + psdLockWritePBase(); + psdGetAttrs(PGA_STACK, NULL, PA_HardwareList, &lst, TAG_END); + phw = lst->lh_Head; + while(phw->ln_Succ) + { + if(phw == hlnode->phw) + { + psdUnlockPBase(); + psdRemHardware(phw); + phw = NULL; + break; + } + phw = phw->ln_Succ; + } + if(phw) + { + psdUnlockPBase(); + } + hlnode->phw = NULL; + hlnode->prodname = NULL; + } + hlnode = (struct HWListEntry *) hlnode->node.ln_Succ; + } + DoMethod(obj, MUIM_Action_HW_Activate); + DoMethod(data->hwlistobj, MUIM_List_Redraw, MUIV_List_Redraw_All); + set(data->appobj, MUIA_Application_Sleep, FALSE); + // update the online status to the config + // NOTE! This means that the hardware will not come online on next loading. + InternalCreateConfigGUI(data); + return(TRUE); +} +/* \\\ */ + +/* /// "Action_Restart()" */ +IPTR Action_Restart(struct IClass *cl, Object *obj, Msg msg) +{ + struct ActionData *data = INST_DATA(cl, obj); + struct HWListEntry *hlnode; + set(data->appobj, MUIA_Application_Sleep, TRUE); + hlnode = (struct HWListEntry *) data->hwlist.lh_Head; + while(hlnode->node.ln_Succ) + { + if(hlnode->phw) + { + struct Node *phw; + struct List *lst; + psdLockWritePBase(); + psdGetAttrs(PGA_STACK, NULL, PA_HardwareList, &lst, TAG_END); + phw = lst->lh_Head; + while(phw->ln_Succ) + { + if(phw == hlnode->phw) + { + psdUnlockPBase(); + psdRemHardware(phw); + phw = NULL; + break; + } + phw = phw->ln_Succ; + } + if(phw) + { + psdUnlockPBase(); + } + hlnode->phw = NULL; + hlnode->prodname = NULL; + } + hlnode = (struct HWListEntry *) hlnode->node.ln_Succ; + } + hlnode = (struct HWListEntry *) data->hwlist.lh_Head; + while(hlnode->node.ln_Succ) + { + if(!hlnode->phw) + { + if((hlnode->phw = psdAddHardware(hlnode->devname, hlnode->unit))) + { + psdGetAttrs(PGA_HARDWARE, hlnode->phw, + HA_ProductName, &hlnode->prodname, + TAG_END); + psdEnumerateHardware(hlnode->phw); + } + } + hlnode = (struct HWListEntry *) hlnode->node.ln_Succ; + } + DoMethod(obj, MUIM_Action_HW_Activate); + DoMethod(data->hwlistobj, MUIM_List_Redraw, MUIV_List_Redraw_All); + psdClassScan(); + set(data->appobj, MUIA_Application_Sleep, FALSE); + return(TRUE); +} +/* \\\ */ + +/* /// "Action_ChgErrLevel()" */ +IPTR Action_ChgErrLevel(struct IClass *cl, Object *obj, Msg msg) +{ + struct ActionData *data = INST_DATA(cl, obj); + IPTR lev; + get(data->errlvlobj, MUIA_Cycle_Active, &lev); + switch(lev) + { + case 0: + data->errorlevel = RETURN_OK; + break; + case 1: + data->errorlevel = RETURN_WARN; + break; + case 2: + data->errorlevel = RETURN_ERROR; + break; + case 3: + data->errorlevel = RETURN_FAIL; + break; + } + CreateErrorList(data); + return(TRUE); +} +/* \\\ */ + +/* /// "WriteErrorLogFile()" */ +void WriteErrorLogFile(BPTR fh) +{ + struct List *lst; + struct Node *pem; + IPTR level; + STRPTR origin; + STRPTR errstr; + struct DateStamp *ds; + struct DateTime dt; + struct DateStamp currdate; + UBYTE strdate[LEN_DATSTRING]; + UBYTE strtime[LEN_DATSTRING]; + + DateStamp(&currdate); + psdLockReadPBase(); + psdGetAttrs(PGA_STACK, NULL, PA_ErrorMsgList, &lst, TAG_END); + pem = lst->lh_Head; + while(pem->ln_Succ) + { + ds = NULL; + psdGetAttrs(PGA_ERRORMSG, pem, + EMA_Level, &level, + EMA_Origin, &origin, + EMA_Msg, &errstr, + EMA_DateStamp, &ds, + TAG_END); + if(ds) + { + dt.dat_Stamp.ds_Days = ds->ds_Days; + dt.dat_Stamp.ds_Minute = ds->ds_Minute; + dt.dat_Stamp.ds_Tick = ds->ds_Tick; + dt.dat_Format = FORMAT_DEF; + dt.dat_Flags = 0; + dt.dat_StrDay = NULL; + dt.dat_StrDate = strdate; + dt.dat_StrTime = strtime; + DateToStr(&dt); + if(currdate.ds_Days == ds->ds_Days) + { + FPrintf(fh, "%s| %2ld-%s: %s\n", strtime, level, origin, errstr); + } else { + FPrintf(fh, "%s %s| %2ld-%s: %s\n", strdate, strtime, level, origin, errstr); + } + } else { + FPrintf(fh, "%2ld-%s: %s\n", level, origin, errstr); + } + pem = pem->ln_Succ; + } + psdUnlockPBase(); +} +/* \\\ */ + +/* /// "Action_SaveErrors()" */ +IPTR Action_SaveErrors(struct IClass *cl, Object *obj, Msg msg) +{ + struct FileRequester *aslreq; + char path[256]; + struct TagItem asltags[] = { { ASLFR_InitialDrawer, (IPTR) "RAM:" }, + { ASLFR_InitialFile, (IPTR) "Errors.log" }, + { ASLFR_DoSaveMode, (IPTR) TRUE }, + { ASLFR_TitleText, (IPTR) "Select file to save errors to..." }, + { TAG_END, (IPTR) NULL } }; + BPTR fh; + + if((aslreq = MUI_AllocAslRequest(ASL_FileRequest, asltags))) + { + if(MUI_AslRequest(aslreq, TAG_END)) + { + strcpy(path, aslreq->fr_Drawer); + AddPart(path, aslreq->fr_File, 256); + if((fh = Open(path, MODE_NEWFILE))) + { + WriteErrorLogFile(fh); + Close(fh); + psdAddErrorMsg(RETURN_OK, "Trident", "Error log saved to file %s.", path); + } else { + psdAddErrorMsg(RETURN_ERROR, "Trident", "Error opening file %s for writing.", path); + } + MUI_FreeAslRequest(aslreq); + } + } + return(TRUE); +} +/* \\\ */ + +/* /// "Action_FlushErrors()" */ +IPTR Action_FlushErrors(struct IClass *cl, Object *obj, Msg msg) +{ + struct ActionData *data = INST_DATA(cl, obj); + struct List *lst; + psdGetAttrs(PGA_STACK, NULL, PA_ErrorMsgList, &lst, TAG_END); + Forbid(); + while(lst->lh_Head->ln_Succ) + { + psdRemErrorMsg(lst->lh_Head); + } + Permit(); + CreateErrorList(data); + return(TRUE); +} +/* \\\ */ + +/* /// "Action_SaveDeviceList()" */ +IPTR Action_SaveDeviceList(struct IClass *cl, Object *obj, Msg msg) +{ + struct FileRequester *aslreq; + char path[256]; + struct TagItem asltags[] = { { ASLFR_InitialDrawer, (IPTR) "RAM:" }, + { ASLFR_InitialFile, (IPTR) "DevList.log" }, + { ASLFR_DoSaveMode, (IPTR) TRUE }, + { ASLFR_TitleText, (IPTR) "Select file to save device list to..." }, + { TAG_END, (IPTR) NULL } }; + BPTR fh; + + if((aslreq = MUI_AllocAslRequest(ASL_FileRequest, asltags))) + { + if(MUI_AslRequest(aslreq, TAG_END)) + { + strcpy(path, aslreq->fr_Drawer); + AddPart(path, aslreq->fr_File, 256); + if((fh = Open(path, MODE_NEWFILE))) + { + + if(SystemTags("UsbDevLister", SYS_Output, fh, TAG_END)) + { + psdAddErrorMsg(RETURN_ERROR, "Trident", "Error executing UsbDevLister"); + } else { + psdAddErrorMsg(RETURN_OK, "Trident", "DevLister saved to %s.", path); + } + Close(fh); + } else { + psdAddErrorMsg(RETURN_ERROR, "Trident", "Error opening file %s for writing.", path); + } + MUI_FreeAslRequest(aslreq); + } + } + return(TRUE); +} +/* \\\ */ + +/* /// "Action_LoadPrefs()" */ +IPTR Action_LoadPrefs(struct IClass *cl, Object *obj, Msg msg) +{ + //struct ActionData *data = INST_DATA(cl, obj); + struct FileRequester *aslreq; + char path[256]; + struct TagItem asltags[] = { { ASLFR_InitialDrawer, (IPTR) "ENVARC:Sys" }, + { ASLFR_InitialFile, (IPTR) "Poseidon.prefs" }, + { ASLFR_TitleText, (IPTR) "Select a Poseidon Prefs file..." }, + { TAG_END, (IPTR) NULL } }; + + if((aslreq = MUI_AllocAslRequest(ASL_FileRequest, asltags))) + { + if(MUI_AslRequest(aslreq, TAG_END)) + { + strcpy(path, aslreq->fr_Drawer); + AddPart(path, aslreq->fr_File, 256); + if(psdLoadCfgFromDisk(path)) + { + psdAddErrorMsg(RETURN_OK, "Trident", "Config loaded from %s.", path); + //UpdateConfigToGUI(data); + } + } + MUI_FreeAslRequest(aslreq); + } + return(TRUE); +} +/* \\\ */ + +/* /// "Action_SavePrefsAs()" */ +IPTR Action_SavePrefsAs(struct IClass *cl, Object *obj, Msg msg) +{ + struct ActionData *data = INST_DATA(cl, obj); + struct FileRequester *aslreq; + char path[256]; + struct TagItem asltags[] = { { ASLFR_InitialDrawer, (IPTR) "ENVARC:Sys" }, + { ASLFR_InitialFile, (IPTR) "Poseidon.prefs" }, + { ASLFR_TitleText, (IPTR) "Select file to save prefs to..." }, + { ASLFR_DoSaveMode, (IPTR) TRUE }, + { TAG_END, (IPTR) NULL } }; + + if((aslreq = MUI_AllocAslRequest(ASL_FileRequest, asltags))) + { + if(MUI_AslRequest(aslreq, TAG_END)) + { + strcpy(path, aslreq->fr_Drawer); + AddPart(path, aslreq->fr_File, 256); + InternalCreateConfigGUI(data); + if(psdSaveCfgToDisk(path, FALSE)) + { + psdAddErrorMsg(RETURN_OK, "Trident", "Configuration successfully saved to %s.", path); + { + IPTR hash = 0; + psdGetAttrs(PGA_STACK, NULL, PA_CurrConfigHash, &hash, TAG_END); + psdSetAttrs(PGA_STACK, NULL, PA_SavedConfigHash, hash, TAG_END); + } + } else { + psdAddErrorMsg(RETURN_ERROR, "Trident", "Couldn't save config to %s.", path); + } + MUI_FreeAslRequest(aslreq); + } + } + return(TRUE); +} +/* \\\ */ + +/* /// "Action_SavePrefs()" */ +IPTR Action_SavePrefs(struct IClass *cl, Object *obj, Msg msg) +{ + struct ActionData *data = INST_DATA(cl, obj); + + DoMethod(obj, MUIM_Action_Cfg_Snd_Changed); + InternalCreateConfigGUI(data); + + if(!psdSaveCfgToDisk(NULL, FALSE)) + { + psdAddErrorMsg(RETURN_ERROR, "Trident", "Config not saved!"); + } else { + psdAddErrorMsg(RETURN_OK, "Trident", "Configuration successfully saved."); + } + + return(TRUE); +} +/* \\\ */ + +/* /// "Action_Prefs_Changed()" */ +IPTR Action_Prefs_Changed(struct IClass *cl, Object *obj, Msg msg) +{ + IPTR oldhash = 0; + IPTR currhash = 0; + DoMethod(obj, MUIM_Action_Cfg_Snd_Changed); + psdGetAttrs(PGA_STACK, NULL, + PA_CurrConfigHash, &currhash, + PA_SavedConfigHash, &oldhash, + TAG_END); + return((IPTR) (currhash != oldhash)); +} +/* \\\ */ + +/* /// "Action_UseQuit()" */ +IPTR Action_UseQuit(struct IClass *cl, Object *obj, Msg msg) +{ + struct ActionData *data = INST_DATA(cl, obj); + LONG res; + //DoMethod(obj, MUIM_Action_Cfg_Snd_Changed); + DoMethod(obj, MUIM_Action_Use); + if(DoMethod(obj, MUIM_Action_Prefs_Changed)) + { + res = MUI_RequestA(data->appobj, data->winobj, 0, NULL, "Use|Save|Cancel", + "The current configuration has been changed\n" + "and not been saved yet.", NULL); + if(res == 0) + { + return(FALSE); + } + if(res == 2) + { + DoMethod(obj, MUIM_Action_SavePrefs); + } + } + DoMethod(data->appobj, MUIM_Application_ReturnID, MUIV_Application_ReturnID_Quit); + return(TRUE); +} +/* \\\ */ + +/* /// "Action_SaveQuit()" */ +IPTR Action_SaveQuit(struct IClass *cl, Object *obj, Msg msg) +{ + struct ActionData *data = INST_DATA(cl, obj); + DoMethod(obj, MUIM_Action_Cfg_Snd_Changed); + DoMethod(obj, MUIM_Action_Use); + if(!(psdSaveCfgToDisk(NULL, FALSE))) + { + psdAddErrorMsg(RETURN_ERROR, "Trident", "Couldn't save config."); + } else { + DoMethod(data->appobj, MUIM_Application_ReturnID, MUIV_Application_ReturnID_Quit); + } + return(TRUE); +} +/* \\\ */ + +/* /// "Action_LoadPrefsFrom()" */ +IPTR Action_LoadPrefsFrom(struct IClass *cl, Object *obj, Msg msg) +{ + //struct ActionData *data = INST_DATA(cl, obj); + STRPTR path = (STRPTR) ((struct opSet *) msg)->ops_AttrList; + if(psdLoadCfgFromDisk(path)) + { + psdAddErrorMsg(RETURN_OK, "Trident", "Config loaded from %s.", path); + return(TRUE); + } + return(FALSE); +} +/* \\\ */ + +/* /// "Action_SavePrefsTo()" */ +IPTR Action_SavePrefsTo(struct IClass *cl, Object *obj, Msg msg) +{ + struct ActionData *data = INST_DATA(cl, obj); + STRPTR path = (STRPTR) ((struct opSet *) msg)->ops_AttrList; + InternalCreateConfigGUI(data); + if(psdSaveCfgToDisk(path, FALSE)) + { + psdAddErrorMsg(RETURN_OK, "Trident", "Configuration successfully saved to %s.", path); + return(TRUE); + } + return(FALSE); +} +/* \\\ */ + +/* /// "Action_Dev_Activate()" */ +IPTR Action_Dev_Activate(struct IClass *cl, Object *obj, Msg msg) +{ + struct ActionData *data = INST_DATA(cl, obj); + struct DevListEntry *dlnode; + APTR binding; + APTR cbind; + struct List *pclist; + struct List *piflist; + struct Node *pc; + struct Node *pif; + struct Node *puc; + IPTR hascfggui = FALSE; + IPTR issuspended = FALSE; + struct Library *UsbClsBase; + + DoMethod(data->devlistobj, MUIM_List_GetEntry, MUIV_List_GetEntry_Active, &dlnode); + if(CheckDeviceValid(dlnode)) + { + psdLockReadDevice(dlnode->pd); + set(data->devinfoobj, MUIA_Disabled, FALSE); + psdGetAttrs(PGA_DEVICE, dlnode->pd, + DA_Binding, &binding, + DA_BindingClass, &puc, + DA_ConfigList, &pclist, + DA_IsSuspended, &issuspended, + TAG_END); + if(binding && puc) + { + psdGetAttrs(PGA_USBCLASS, puc, + UCA_ClassBase, &UsbClsBase, + TAG_END); + usbGetAttrs(UGA_CLASS, NULL, + UCCA_HasBindingCfgGUI, &hascfggui, + TAG_END); + } + pc = pclist->lh_Head; + while((!binding) && pc->ln_Succ) + { + psdGetAttrs(PGA_CONFIG, pc, + CA_InterfaceList, &piflist, + TAG_END); + pif = piflist->lh_Head; + while(pif->ln_Succ) + { + psdGetAttrs(PGA_INTERFACE, pif, + IFA_Binding, &cbind, + IFA_BindingClass, &puc, + TAG_END); + if(cbind) + { + binding = cbind; + } + if(cbind && puc && !hascfggui) + { + psdGetAttrs(PGA_USBCLASS, puc, + UCA_ClassBase, &UsbClsBase, + TAG_END); + usbGetAttrs(UGA_CLASS, NULL, + UCCA_HasBindingCfgGUI, &hascfggui, + TAG_END); + } + pif = pif->ln_Succ; + } + pc = pc->ln_Succ; + } + psdUnlockDevice(dlnode->pd); + set(data->devunbindobj, MUIA_Disabled, !binding); + set(data->devcfgobj, MUIA_Disabled, !hascfggui); + /*if(dlnode->infowindow) FIXME + { + DoMethod(obj, MUIM_Action_Dev_If_Activate, dlnode); + }*/ + set(data->devsuspendobj, MUIA_Disabled, issuspended); + set(data->devresumeobj, MUIA_Disabled, !issuspended); + set(data->devpowercycleobj, MUIA_Disabled, FALSE); + set(data->devdisableobj, MUIA_Disabled, FALSE); + set(data->devlistobj, MUIA_ContextMenu, data->mi_classpopup); + } else { + set(data->devunbindobj, MUIA_Disabled, TRUE); + set(data->devinfoobj, MUIA_Disabled, TRUE); + set(data->devcfgobj, MUIA_Disabled, TRUE); + set(data->devsuspendobj, MUIA_Disabled, TRUE); + set(data->devresumeobj, MUIA_Disabled, TRUE); + set(data->devpowercycleobj, MUIA_Disabled, TRUE); + set(data->devdisableobj, MUIA_Disabled, TRUE); + set(data->devlistobj, MUIA_ContextMenu, NULL); + } + return(TRUE); +} +/* \\\ */ + +/* /// "Action_Dev_Info()" */ +IPTR Action_Dev_Info(struct IClass *cl, Object *obj, Msg msg) +{ + struct ActionData *data = INST_DATA(cl, obj); + struct DevListEntry *dlnode; + + DoMethod(data->devlistobj, MUIM_List_GetEntry, MUIV_List_GetEntry_Active, &dlnode); + if(dlnode) + { + if(dlnode->infowindow) + { + return(TRUE); + } + dlnode->infowindow = NewObject(DevWinClass->mcc_Class, 0, MUIA_DevWin_DevEntry, dlnode, WindowContents, VGroup, End, TAG_END); + if(dlnode->infowindow) + { + DoMethod(data->appobj, OM_ADDMEMBER, dlnode->infowindow); + DoMethod(dlnode->infowindow, MUIM_Notify, MUIA_Window_CloseRequest, TRUE, + data->appobj, 5, MUIM_Application_PushMethod, obj, 2, MUIM_Action_CloseSubWinReq, dlnode); + set(dlnode->infowindow, MUIA_Window_Open, TRUE); + } + } + return(TRUE); +} +/* \\\ */ + +/* /// "Action_Dev_Bind()" */ +IPTR Action_Dev_Bind(struct IClass *cl, Object *obj, Msg msg) +{ + struct ActionData *data = INST_DATA(cl, obj); + psdClassScan(); + DoMethod(obj, MUIM_Action_Dev_Activate); + DoMethod(data->devlistobj, MUIM_List_Redraw, MUIV_List_Redraw_All); + return(TRUE); +} +/* \\\ */ + +/* /// "Action_Dev_Unbind()" */ +IPTR Action_Dev_Unbind(struct IClass *cl, Object *obj, Msg msg) +{ + struct ActionData *data = INST_DATA(cl, obj); + struct DevListEntry *dlnode; + APTR binding; + struct List *pclist; + struct List *piflist; + struct Node *pc; + struct Node *pif; + + DoMethod(data->devlistobj, MUIM_List_GetEntry, MUIV_List_GetEntry_Active, &dlnode); + if(CheckDeviceValid(dlnode)) + { + psdGetAttrs(PGA_DEVICE, dlnode->pd, + DA_Binding, &binding, + DA_ConfigList, &pclist, + TAG_END); + if(binding) + { + psdReleaseDevBinding(dlnode->pd); + } else { + pc = pclist->lh_Head; + while(pc->ln_Succ) + { + psdGetAttrs(PGA_CONFIG, pc, + CA_InterfaceList, &piflist, + TAG_END); + pif = piflist->lh_Head; + while(pif->ln_Succ) + { + psdGetAttrs(PGA_INTERFACE, pif, + IFA_Binding, &binding, + TAG_END); + if(binding) + { + psdReleaseIfBinding(pif); + } + pif = pif->ln_Succ; + } + pc = pc->ln_Succ; + } + } + set(data->devunbindobj, MUIA_Disabled, TRUE); + set(data->devcfgobj, MUIA_Disabled, TRUE); + /*if(dlnode->infowindow) FIXME + { + DoMethod(obj, MUIM_Action_Dev_If_Activate, dlnode); + DoMethod(dlnode->iflvobj, MUIM_List_Redraw, MUIV_List_Redraw_All); + }*/ + } + DoMethod(data->devlistobj, MUIM_List_Redraw, MUIV_List_Redraw_All); + return(TRUE); +} +/* \\\ */ + +/* /// "Action_Dev_Suspend()" */ +IPTR Action_Dev_Suspend(struct IClass *cl, Object *obj, Msg msg) +{ + struct ActionData *data = INST_DATA(cl, obj); + struct DevListEntry *dlnode; + + DoMethod(data->devlistobj, MUIM_List_GetEntry, MUIV_List_GetEntry_Active, &dlnode); + if(CheckDeviceValid(dlnode)) + { + psdSuspendDevice(dlnode->pd); + } + DoMethod(data->devlistobj, MUIM_List_Redraw, MUIV_List_Redraw_All); + return(TRUE); +} +/* \\\ */ + +/* /// "Action_Dev_Resume()" */ +IPTR Action_Dev_Resume(struct IClass *cl, Object *obj, Msg msg) +{ + struct ActionData *data = INST_DATA(cl, obj); + struct DevListEntry *dlnode; + + DoMethod(data->devlistobj, MUIM_List_GetEntry, MUIV_List_GetEntry_Active, &dlnode); + if(CheckDeviceValid(dlnode)) + { + psdResumeDevice(dlnode->pd); + } + DoMethod(data->devlistobj, MUIM_List_Redraw, MUIV_List_Redraw_All); + return(TRUE); +} +/* \\\ */ + +/* /// "Action_Dev_PowerCycle()" */ +IPTR Action_Dev_PowerCycle(struct IClass *cl, Object *obj, Msg msg) +{ + struct ActionData *data = INST_DATA(cl, obj); + struct DevListEntry *dlnode; + IPTR hubport = 0; + struct Node *hubpd = NULL; + struct Node *puc = NULL; + struct Library *UsbClsBase; + + DoMethod(data->devlistobj, MUIM_List_GetEntry, MUIV_List_GetEntry_Active, &dlnode); + if(CheckDeviceValid(dlnode)) + { + psdGetAttrs(PGA_DEVICE, dlnode->pd, + DA_HubDevice, &hubpd, + DA_AtHubPortNumber, &hubport, + TAG_END); + if(hubpd) + { + psdGetAttrs(PGA_DEVICE, hubpd, + DA_BindingClass, &puc, + TAG_END); + } + if(puc) + { + psdGetAttrs(PGA_USBCLASS, puc, + UCA_ClassBase, &UsbClsBase, + TAG_END); + usbDoMethod(UCM_HubPowerCyclePort, hubpd, hubport); + } + } + DoMethod(data->devlistobj, MUIM_List_Redraw, MUIV_List_Redraw_All); + return(TRUE); +} +/* \\\ */ + +/* /// "Action_Dev_Disable()" */ +IPTR Action_Dev_Disable(struct IClass *cl, Object *obj, Msg msg) +{ + struct ActionData *data = INST_DATA(cl, obj); + struct DevListEntry *dlnode; + IPTR hubport = 0; + struct Node *hubpd = NULL; + struct Node *puc = NULL; + struct Library *UsbClsBase; + + DoMethod(data->devlistobj, MUIM_List_GetEntry, MUIV_List_GetEntry_Active, &dlnode); + if(CheckDeviceValid(dlnode)) + { + psdGetAttrs(PGA_DEVICE, dlnode->pd, + DA_HubDevice, &hubpd, + DA_AtHubPortNumber, &hubport, + TAG_END); + if(hubpd) + { + psdGetAttrs(PGA_DEVICE, hubpd, + DA_BindingClass, &puc, + TAG_END); + } + if(puc) + { + psdGetAttrs(PGA_USBCLASS, puc, + UCA_ClassBase, &UsbClsBase, + TAG_END); + usbDoMethod(UCM_HubDisablePort, hubpd, hubport); + } + + } + DoMethod(data->devlistobj, MUIM_List_Redraw, MUIV_List_Redraw_All); + return(TRUE); +} +/* \\\ */ + +/* /// "Action_Dev_Configure()" */ +IPTR Action_Dev_Configure(struct IClass *cl, Object *obj, Msg msg) +{ + struct ActionData *data = INST_DATA(cl, obj); + struct DevListEntry *dlnode; + APTR binding; + struct List *pclist; + struct List *piflist; + struct Node *pc; + struct Node *pif; + struct Node *puc; + struct Library *UsbClsBase; + + DoMethod(data->devlistobj, MUIM_List_GetEntry, MUIV_List_GetEntry_Active, &dlnode); + if(CheckDeviceValid(dlnode)) + { + psdLockReadDevice(dlnode->pd); + psdGetAttrs(PGA_DEVICE, dlnode->pd, + DA_Binding, &binding, + DA_BindingClass, &puc, + DA_ConfigList, &pclist, + TAG_END); + UsbClsBase = NULL; + if(puc) + { + psdGetAttrs(PGA_USBCLASS, puc, + UCA_ClassBase, &UsbClsBase, + TAG_END); + } + if(binding && UsbClsBase) + { + usbDoMethod(UCM_OpenBindingCfgWindow, binding); + } else { + pc = pclist->lh_Head; + while(pc->ln_Succ) + { + psdGetAttrs(PGA_CONFIG, pc, + CA_InterfaceList, &piflist, + TAG_END); + pif = piflist->lh_Head; + while(pif->ln_Succ) + { + psdGetAttrs(PGA_INTERFACE, pif, + IFA_Binding, &binding, + IFA_BindingClass, &puc, + TAG_END); + UsbClsBase = NULL; + if(puc) + { + psdGetAttrs(PGA_USBCLASS, puc, + UCA_ClassBase, &UsbClsBase, + TAG_END); + } + if(binding && UsbClsBase) + { + usbDoMethod(UCM_OpenBindingCfgWindow, binding); + } + pif = pif->ln_Succ; + } + pc = pc->ln_Succ; + } + } + psdUnlockDevice(dlnode->pd); + return(TRUE); + } + return(FALSE); +} +/* \\\ */ + +/* /// "Action_Dev_ForceBind()" */ +IPTR Action_Dev_ForceBind(struct IClass *cl, Object *obj, Msg msg) +{ + struct ActionData *data = INST_DATA(cl, obj); + struct DevListEntry *dlnode; + Object *mi = (Object *) ((IPTR *) msg)[1]; + STRPTR name = NULL; + STRPTR devid = NULL; + STRPTR devname = NULL; + LONG clever; + + DoMethod(data->devlistobj, MUIM_List_GetEntry, MUIV_List_GetEntry_Active, &dlnode); + if(CheckDeviceValid(dlnode)) + { + get(mi, MUIA_Menuitem_Title, &name); + if(!strcmp(name, "None")) + { + name = NULL; + } + psdGetAttrs(PGA_DEVICE, dlnode->pd, + DA_ProductName, &devname, + DA_IDString, &devid, + TAG_END); + if(name) + { + clever = MUI_RequestA(data->appobj, data->winobj, 0, NULL, "I'm not dumb!|I'll reconsider", + "You are about to establish a forced \33bdevice\33n\n" + "binding. This is not an interface binding. As\n" + "most people are not capable of reading the\n" + "manual and they cause more harm than good.\n" + "Please make sure you know, what you're doing\n" + "and not breaking things (and then bugger me with\n" + "silly emails).", NULL); + if(!clever) + { + return(FALSE); + } + } + if(psdSetForcedBinding(name, devid, NULL)) + { + if(name) + { + psdAddErrorMsg(RETURN_OK, "Trident", "Forcing device binding of %s to %s.", devname, name); + } else { + psdAddErrorMsg(RETURN_OK, "Trident", "Removed forced device binding of %s.", devname); + } + } + } + return(TRUE); +} +/* \\\ */ + +/* /// "Action_Cfg_Changed()" */ +IPTR Action_Cfg_Changed(struct IClass *cl, Object *obj, Msg msg) +{ + struct ActionData *data = INST_DATA(cl, obj); + IPTR bootdelay; + IPTR subtaskpri; + IPTR loginfo; + IPTR logwarn; + IPTR logerr; + IPTR logfail; + IPTR popupnew; + IPTR popupgone; + IPTR popupdeath; + IPTR popupdelay; + IPTR popupactivate; + IPTR popuptofront; + IPTR autodisablelp; + IPTR autodisabledead; + IPTR autorestartdead; + IPTR powersaving; + IPTR forcesuspend; + IPTR suspendtimeout; + APTR stackcfg = NULL; + + psdGetAttrs(PGA_STACK, NULL, PA_GlobalConfig, &stackcfg, TAG_END); + get(data->cfgtaskpriobj, MUIA_Numeric_Value, &subtaskpri); + get(data->cfgbootdelayobj, MUIA_Numeric_Value, &bootdelay); + get(data->cfgloginfoobj, MUIA_Selected, &loginfo); + get(data->cfglogwarnobj, MUIA_Selected, &logwarn); + get(data->cfglogerrobj, MUIA_Selected, &logerr); + get(data->cfglogfailobj, MUIA_Selected, &logfail); + get(data->cfgpopupnewobj, MUIA_Cycle_Active, &popupnew); + get(data->cfgpopupgoneobj, MUIA_Selected, &popupgone); + get(data->cfgpopupdeathobj, MUIA_Selected, &popupdeath); + get(data->cfgpopupdelayobj, MUIA_Numeric_Value, &popupdelay); + get(data->cfgpopupactivateobj, MUIA_Selected, &popupactivate); + get(data->cfgpopuptofrontobj, MUIA_Selected, &popuptofront); + get(data->cfgautolpobj, MUIA_Selected, &autodisablelp); + get(data->cfgautodeadobj, MUIA_Selected, &autodisabledead); + get(data->cfgautopcobj, MUIA_Selected, &autorestartdead); + get(data->cfgpowersavingobj, MUIA_Selected, &powersaving); + get(data->cfgforcesuspendobj, MUIA_Selected, &forcesuspend); + get(data->cfgsuspendtimeoutobj, MUIA_Numeric_Value, &suspendtimeout); + + if(autorestartdead && autodisabledead) + { + autodisabledead = FALSE; + nnset(data->cfgautodeadobj, MUIA_Selected, FALSE); + } + if(autorestartdead) + { + nnset(data->cfgautodeadobj, MUIA_Disabled, TRUE); + } else { + nnset(data->cfgautodeadobj, MUIA_Disabled, FALSE); + } + if(stackcfg) + { + psdSetAttrs(PGA_STACKCFG, stackcfg, + GCA_SubTaskPri, subtaskpri, + GCA_BootDelay, bootdelay, + GCA_LogInfo, loginfo, + GCA_LogWarning, logwarn, + GCA_LogError, logerr, + GCA_LogFailure, logfail, + GCA_PopupDeviceNew, popupnew, + GCA_PopupDeviceGone, popupgone, + GCA_PopupDeviceDeath, popupdeath, + GCA_PopupCloseDelay, popupdelay, + GCA_PopupActivateWin, popupactivate, + GCA_PopupWinToFront, popuptofront, + GCA_AutoDisableLP, autodisablelp, + GCA_AutoDisableDead, autodisabledead, + GCA_AutoRestartDead, autorestartdead, + GCA_PowerSaving, powersaving, + GCA_ForceSuspend, forcesuspend, + GCA_SuspendTimeout, suspendtimeout, + TAG_END); + } + return(TRUE); +} +/* \\\ */ + +/* /// "Action_Cfg_Snd_Changed()" */ +IPTR Action_Cfg_Snd_Changed(struct IClass *cl, Object *obj, Msg msg) +{ + struct ActionData *data = INST_DATA(cl, obj); + STRPTR dtxsndfile = ""; + STRPTR remsndfile = ""; + APTR stackcfg = NULL; + + psdGetAttrs(PGA_STACK, NULL, PA_GlobalConfig, &stackcfg, TAG_END); + get(data->cfgdevdtxsoundobj, MUIA_String_Contents, &dtxsndfile); + get(data->cfgdevremsoundobj, MUIA_String_Contents, &remsndfile); + if(stackcfg) + { + psdSetAttrs(PGA_STACKCFG, stackcfg, + GCA_InsertionSound, dtxsndfile, + GCA_RemovalSound, remsndfile, + TAG_END); + } + return(TRUE); +} +/* \\\ */ + +/* /// "Action_Cls_Activate()" */ +IPTR Action_Cls_Activate(struct IClass *cl, Object *obj, Msg msg) +{ + struct ActionData *data = INST_DATA(cl, obj); + struct ClsListEntry *clnode; + DoMethod(data->clslistobj, MUIM_List_GetEntry, MUIV_List_GetEntry_Active, &clnode); + if(clnode) + { + struct Node *puc; + struct List *lst; + IPTR hascfggui = FALSE; + struct Library *UsbClsBase; + + set(data->clsremobj, MUIA_Disabled, FALSE); + + psdLockReadPBase(); + psdGetAttrs(PGA_STACK, NULL, PA_ClassList, &lst, TAG_END); + puc = lst->lh_Head; + while(puc->ln_Succ) + { + if(puc == clnode->puc) + { + psdGetAttrs(PGA_USBCLASS, clnode->puc, + UCA_ClassBase, &UsbClsBase, + TAG_END); + usbGetAttrs(UGA_CLASS, NULL, + UCCA_HasClassCfgGUI, &hascfggui, + TAG_END); + set(data->clscfgobj, MUIA_Disabled, !hascfggui); + break; + } + puc = puc->ln_Succ; + } + psdUnlockPBase(); + } else { + set(data->clsremobj, MUIA_Disabled, TRUE); + set(data->clscfgobj, MUIA_Disabled, TRUE); + } + return(TRUE); +} +/* \\\ */ + +/* /// "Action_Cls_Add()" */ +IPTR Action_Cls_Add(struct IClass *cl, Object *obj, Msg msg) +{ + struct ActionData *data = INST_DATA(cl, obj); + STRPTR clsname; + get(data->clsnameobj, MUIA_String_Contents, &clsname); + psdAddClass(clsname, 0); + InternalCreateConfigGUI(data); + return(TRUE); +} +/* \\\ */ + +/* /// "Action_Cls_Remove()" */ +IPTR Action_Cls_Remove(struct IClass *cl, Object *obj, Msg msg) +{ + struct ActionData *data = INST_DATA(cl, obj); + struct ClsListEntry *clnode; + DoMethod(data->clslistobj, MUIM_List_GetEntry, MUIV_List_GetEntry_Active, &clnode); + if(clnode) + { + struct Node *puc; + struct List *lst; + psdLockReadPBase(); + psdGetAttrs(PGA_STACK, NULL, PA_ClassList, &lst, TAG_END); + puc = lst->lh_Head; + while(puc->ln_Succ) + { + if(puc == clnode->puc) + { + clnode->puc = NULL; + DoMethod(data->clslistobj, MUIM_List_Remove, MUIV_List_Remove_Active); + FreeClsEntry(data, clnode); + psdUnlockPBase(); + psdRemClass(puc); + puc = NULL; + break; + } + puc = puc->ln_Succ; + } + if(puc) + { + psdUnlockPBase(); + } + } + InternalCreateConfigGUI(data); + return(TRUE); +} +/* \\\ */ + +/* /// "Action_Cls_Scan()" */ +IPTR Action_Cls_Scan(struct IClass *cl, Object *obj, Msg msg) +{ + struct ActionData *data = INST_DATA(cl, obj); + struct ExAllControl *exall; + BPTR lock; + struct ExAllData *exdata; + ULONG ents; + struct List *puclist; + UBYTE buf[1024]; + UBYTE sbuf[128]; + BOOL exready; + + psdGetAttrs(PGA_STACK, NULL, PA_ClassList, &puclist, TAG_END); + if((exall = AllocDosObject(DOS_EXALLCONTROL, NULL))) + { + if((lock = Lock(CLASSPATH, ACCESS_READ))) + { + exall->eac_LastKey = 0; + exall->eac_MatchString = NULL; + exall->eac_MatchFunc = NULL; + do + { + exready = ExAll(lock, (struct ExAllData *) buf, 1024, ED_NAME, exall); + exdata = (struct ExAllData *) buf; + ents = exall->eac_Entries; + while(ents--) + { + psdSafeRawDoFmt(sbuf, 128, CLASSPATH "/%s", exdata->ed_Name); + + if(!FindName(puclist, exdata->ed_Name)) + { + psdAddClass(sbuf, 0); + } + exdata = exdata->ed_Next; + } + } while(exready); + UnLock(lock); + InternalCreateConfigGUI(data); + psdClassScan(); + } else { + /*errmsg = "Could not lock on SYS:Classes/USB.\n";*/ + } + FreeDosObject(DOS_EXALLCONTROL, exall); + } + return(TRUE); +} +/* \\\ */ + +/* /// "Action_Cls_Configure()" */ +IPTR Action_Cls_Configure(struct IClass *cl, Object *obj, Msg msg) +{ + struct ActionData *data = INST_DATA(cl, obj); + struct ClsListEntry *clnode; + DoMethod(data->clslistobj, MUIM_List_GetEntry, MUIV_List_GetEntry_Active, &clnode); + if(clnode) + { + struct Node *puc; + struct List *lst; + struct Library *UsbClsBase; + + psdLockReadPBase(); + psdGetAttrs(PGA_STACK, NULL, PA_ClassList, &lst, TAG_END); + puc = lst->lh_Head; + while(puc->ln_Succ) + { + if(puc == clnode->puc) + { + psdGetAttrs(PGA_USBCLASS, clnode->puc, + UCA_ClassBase, &UsbClsBase, + TAG_END); + usbDoMethod(UCM_OpenCfgWindow); + break; + } + puc = puc->ln_Succ; + } + psdUnlockPBase(); + + return(TRUE); + } + return(FALSE); +} +/* \\\ */ + +/* /// "Action_Info_MemPool()" */ +IPTR Action_Info_MemPool(struct IClass *cl, Object *obj, Msg msg) +{ + struct ActionData *data = INST_DATA(cl, obj); + char buf[32]; + IPTR mem; + psdGetAttrs(PGA_STACK, NULL, PA_MemPoolUsage, &mem, TAG_END); + psdSafeRawDoFmt(buf, 32, "%ld KB", (mem+512)>>10); + set(data->mempoolobj, MUIA_Text_Contents, buf); + return(TRUE); +} +/* \\\ */ + +/* /// "Action_Cfg_Activate()" */ +IPTR Action_Cfg_Activate(struct IClass *cl, Object *obj, Msg msg) +{ + struct ActionData *data = INST_DATA(cl, obj); + struct PrefsListEntry *plnode; + DoMethod(data->prefslistobj, MUIM_List_GetEntry, MUIV_List_GetEntry_Active, &plnode); + if(plnode) + { + BOOL noexport = FALSE; + switch(plnode->chunkid) + { + case IFFCHNK_FORCEDBIND: + case MAKE_ID('P','S','D','L'): + noexport = TRUE; + } + + set(data->prefsremoveobj, MUIA_Disabled, plnode->chunkid == IFFFORM_STACKCFG); + set(data->prefsexportobj, MUIA_Disabled, noexport); + } else { + set(data->prefsremoveobj, MUIA_Disabled, TRUE); + set(data->prefsexportobj, MUIA_Disabled, TRUE); + } + return(TRUE); +} +/* \\\ */ + +/* /// "Action_Cfg_Remove()" */ +IPTR Action_Cfg_Remove(struct IClass *cl, Object *obj, Msg msg) +{ + struct ActionData *data = INST_DATA(cl, obj); + struct PrefsListEntry *plnode; + DoMethod(data->prefslistobj, MUIM_List_GetEntry, MUIV_List_GetEntry_Active, &plnode); + if(plnode) + { + LONG result; + APTR pic; + switch(plnode->chunkid) + { + case IFFFORM_STACKCFG: + break; + + case IFFFORM_DEVICECFG: + result = MUI_RequestA(data->appobj, data->winobj, 0, NULL, "Remove|Cancel", + "You are about to \33bremove\33n the configuration\n" + "data related to the device with the ID\n" + "\33b%s\33n.\n" + "This includes all individually saved class\n" + "setting for the device or interfaces, as well\n" + "as the stuff Trident saves (such as custom name or\n" + "popup inhibit).\n\n" + "Are you sure you want to remove these prefs?", &plnode->devid); + if(result) + { + pic = psdFindCfgForm(NULL, plnode->chunkid); + while(pic) + { + if(psdMatchStringChunk(pic, IFFCHNK_DEVID, plnode->devid)) + { + psdRemCfgForm(pic); + break; + } + pic = psdNextCfgForm(pic); + } + } + break; + + case IFFFORM_CLASSCFG: + result = MUI_RequestA(data->appobj, data->winobj, 0, NULL, "Remove|Cancel", + "You are about to \33bremove\33n the (default)\n" + "configuration of the class \33b%s\33n.\n" + "This will set the classes initial prefs to the\n" + "internal defaults \33bon next boot\33n!\n" + "It does normally not affect the device or interface\n" + "individually saved settings.\n\n" + "Are you sure you want to remove these prefs?", &plnode->owner); + if(result) + { + pic = psdFindCfgForm(NULL, IFFFORM_CLASSCFG); + while(pic) + { + if(psdMatchStringChunk(pic, IFFCHNK_OWNER, plnode->owner)) + { + psdRemCfgForm(pic); + break; + } + pic = psdNextCfgForm(pic); + } + } + break; + + case IFFFORM_DEVCFGDATA: + result = MUI_Request(data->appobj, data->winobj, 0, NULL, "Remove|Cancel", + "You are about to \33bremove\33n the class\n" + "configuration of the class \33b%s\33n,\n" + "specifically saved for device with ID\n" + "\33b%s\33n.\n\n" + "Are you sure you want to remove these prefs?", plnode->owner, plnode->devid); + if(result) + { + pic = psdFindCfgForm(NULL, IFFFORM_DEVICECFG); + while(pic) + { + if(psdMatchStringChunk(pic, IFFCHNK_DEVID, plnode->devid)) + { + pic = psdFindCfgForm(pic, plnode->chunkid); + while(pic) + { + if(psdMatchStringChunk(pic, IFFCHNK_OWNER, plnode->owner)) + { + psdRemCfgForm(pic); + break; + } + pic = psdNextCfgForm(pic); + } + break; + } + pic = psdNextCfgForm(pic); + } + } + break; + + case IFFFORM_IFCFGDATA: + result = MUI_Request(data->appobj, data->winobj, 0, NULL, "Remove|Cancel", + "You are about to \33bremove\33n the class\n" + "configuration of the class \33b%s\33n\n" + "saved for the particular interface\n" + "\33b%s\33n of the device with ID\n" + "\33b%s\33n.\n\n" + "Are you sure you want to remove these prefs?", + plnode->owner, plnode->ifid, plnode->devid); + if(result) + { + pic = psdFindCfgForm(NULL, IFFFORM_DEVICECFG); + while(pic) + { + if(psdMatchStringChunk(pic, IFFCHNK_DEVID, plnode->devid)) + { + pic = psdFindCfgForm(pic, plnode->chunkid); + while(pic) + { + if(psdMatchStringChunk(pic, IFFCHNK_IFID, plnode->ifid)) + { + if(psdMatchStringChunk(pic, IFFCHNK_OWNER, plnode->owner)) + { + psdRemCfgForm(pic); + break; + } + } + pic = psdNextCfgForm(pic); + } + break; + } + pic = psdNextCfgForm(pic); + } + } + break; + + case IFFCHNK_FORCEDBIND: + psdSetForcedBinding(NULL, plnode->devid, plnode->ifid); + break; + + default: + if(plnode->chunkid) + { + result = MUI_RequestA(data->appobj, data->winobj, 0, NULL, "Remove|Cancel", + "Do you really want to remove this\n" + "\33bunknown prefs data\33n from the preferences?", NULL); + if(result) + { + pic = psdFindCfgForm(NULL, plnode->chunkid); + if(pic) + { + psdRemCfgForm(pic); + } + } + } + break; + } + } + return(TRUE); +} +/* \\\ */ + +/* /// "Action_Cfg_Export()" */ +IPTR Action_Cfg_Export(struct IClass *cl, Object *obj, Msg msg) +{ + struct ActionData *data = INST_DATA(cl, obj); + struct PrefsListEntry *plnode; + struct FileRequester *aslreq; + char path[256]; + struct TagItem asltags[] = { { ASLFR_InitialFile, (IPTR) "unknown.prefs" }, + { ASLFR_InitialDrawer, (IPTR) "SYS:Prefs/Presets/Poseidon" }, + { ASLFR_TitleText, (IPTR) "Select file to export prefs to..." }, + { ASLFR_DoSaveMode, (IPTR) TRUE }, + { TAG_END, (IPTR) NULL } }; + BPTR fh; + ULONG *form; + + DoMethod(data->prefslistobj, MUIM_List_GetEntry, MUIV_List_GetEntry_Active, &plnode); + if(plnode) + { + APTR pic = NULL; + switch(plnode->chunkid) + { + case IFFFORM_STACKCFG: + asltags[0].ti_Data = (IPTR) "stackcfg.prefs"; + pic = psdFindCfgForm(NULL, plnode->chunkid); + break; + + case IFFFORM_DEVICECFG: + asltags[0].ti_Data = (IPTR) "devicecfg.prefs"; + pic = psdFindCfgForm(NULL, plnode->chunkid); + while(pic) + { + if(psdMatchStringChunk(pic, IFFCHNK_DEVID, plnode->devid)) + { + break; + } + pic = psdNextCfgForm(pic); + } + break; + + case IFFFORM_CLASSCFG: + asltags[0].ti_Data = (IPTR) "classcfg.prefs"; + pic = psdFindCfgForm(NULL, plnode->chunkid); + while(pic) + { + if(psdMatchStringChunk(pic, IFFCHNK_OWNER, plnode->owner)) + { + break; + } + pic = psdNextCfgForm(pic); + } + break; + + case IFFFORM_DEVCFGDATA: + asltags[0].ti_Data = (IPTR) "devclscfg.prefs"; + pic = psdFindCfgForm(NULL, IFFFORM_DEVICECFG); + while(pic) + { + if(psdMatchStringChunk(pic, IFFCHNK_DEVID, plnode->devid)) + { + pic = psdFindCfgForm(pic, plnode->chunkid); + while(pic) + { + if(psdMatchStringChunk(pic, IFFCHNK_OWNER, plnode->owner)) + { + break; + } + pic = psdNextCfgForm(pic); + } + break; + } + pic = psdNextCfgForm(pic); + } + break; + + case IFFFORM_IFCFGDATA: + asltags[0].ti_Data = (IPTR) "ifclscfg.prefs"; + pic = psdFindCfgForm(NULL, IFFFORM_DEVICECFG); + while(pic) + { + if(psdMatchStringChunk(pic, IFFCHNK_DEVID, plnode->devid)) + { + pic = psdFindCfgForm(pic, plnode->chunkid); + while(pic) + { + if(psdMatchStringChunk(pic, IFFCHNK_IFID, plnode->ifid)) + { + if(psdMatchStringChunk(pic, IFFCHNK_OWNER, plnode->owner)) + { + break; + } + } + pic = psdNextCfgForm(pic); + } + break; + } + pic = psdNextCfgForm(pic); + } + break; + + case IFFCHNK_FORCEDBIND: + break; + + default: + if(plnode->chunkid) + { + pic = psdFindCfgForm(NULL, plnode->chunkid); + } + break; + } + if(!pic) + { + return(FALSE); + } + if((aslreq = MUI_AllocAslRequest(ASL_FileRequest, asltags))) + { + if(MUI_AslRequest(aslreq, TAG_END)) + { + strcpy(path, aslreq->fr_Drawer); + AddPart(path, aslreq->fr_File, 256); + fh = Open(path, MODE_NEWFILE); + if(fh) + { + form = psdWriteCfg(pic); + if(form) + { + Write(fh, form, form[1]+8); + psdFreeVec(form); + } + Close(fh); + } else { + psdAddErrorMsg(RETURN_FAIL, "Trident", "Failed to open file %s.", path); + } + } + MUI_FreeAslRequest(aslreq); + } + return(TRUE); + } + return(FALSE); +} +/* \\\ */ + +/* /// "Action_Cfg_Import()" */ +IPTR Action_Cfg_Import(struct IClass *cl, Object *obj, Msg msg) +{ + struct ActionData *data = INST_DATA(cl, obj); + struct PrefsListEntry *plnode; + struct FileRequester *aslreq; + char path[256]; + BPTR fh; + ULONG iffhead[3]; + ULONG *buff; + APTR pic; + + struct TagItem asltags[] = { { ASLFR_InitialDrawer, (IPTR) "SYS:Prefs/Presets/Poseidon" }, + { ASLFR_TitleText, (IPTR) "Select file to import prefs from..." }, + { TAG_END, (IPTR) NULL } }; + + DoMethod(data->prefslistobj, MUIM_List_GetEntry, MUIV_List_GetEntry_Active, &plnode); + + if((aslreq = MUI_AllocAslRequest(ASL_FileRequest, asltags))) + { + if(MUI_AslRequest(aslreq, TAG_END)) + { + strcpy(path, aslreq->fr_Drawer); + AddPart(path, aslreq->fr_File, 256); + fh = Open(path, MODE_OLDFILE); + if(fh) + { + Read(fh, iffhead, 12); + if(AROS_LONG2BE(iffhead[0]) == ID_FORM) + { + buff = psdAllocVec(AROS_LONG2BE(iffhead[1])+8); + if(buff) + { + buff[0] = iffhead[0]; + buff[1] = iffhead[1]; + buff[2] = iffhead[2]; + if(Read(fh, &buff[3], AROS_LONG2BE(iffhead[1])-4) == AROS_LONG2BE(iffhead[1])-4) + { + switch(buff[2]) + { + case IFFFORM_STACKCFG: + pic = psdFindCfgForm(NULL, AROS_LONG2BE(buff[2])); + if(pic) + { + psdReadCfg(pic, buff); + } else { + psdAddCfgEntry(NULL, buff); + } + break; + + case IFFFORM_DEVICECFG: + case IFFFORM_CLASSCFG: + psdAddCfgEntry(NULL, buff); + break; + + case IFFFORM_DEVCFGDATA: + case IFFFORM_IFCFGDATA: + if(plnode) + { + if((plnode->chunkid == AROS_LONG2BE(buff[2])) || + (plnode->chunkid == IFFFORM_DEVICECFG) || + (plnode->chunkid == IFFFORM_IFCFGDATA)) + { + pic = psdFindCfgForm(NULL, IFFFORM_DEVICECFG); + while(pic) + { + if(psdMatchStringChunk(pic, IFFCHNK_DEVID, plnode->devid)) + { + psdAddCfgEntry(pic, buff); + break; + } + pic = psdNextCfgForm(pic); + } + break; + } + } + MUI_RequestA(data->appobj, data->winobj, 0, NULL, "Oops!", + "To import device or interface\n" + "prefs data, you need to select\n" + "the device entry where it should" + "be added.", NULL); + break; + + case IFFFORM_PSDCFG: + psdLoadCfgFromDisk(path); + break; + + default: + MUI_RequestA(data->appobj, data->winobj, 0, NULL, "Oops!", + "I don't know that kind of prefs file.", NULL); + break; + } + } else { + psdAddErrorMsg(RETURN_ERROR, "Trident", "Read error on loading prefs file %s.", path); + } + psdFreeVec(buff); + } else { + psdAddErrorMsg(RETURN_ERROR, "Trident", "Failed to allocate buffer for loading %s.", path); + } + } else { + psdAddErrorMsg(RETURN_ERROR, "Trident", "%s does not seem to be an iff file.", path); + } + Close(fh); + } else { + psdAddErrorMsg(RETURN_FAIL, "Trident", "Failed to open file %s.", path); + } + } + MUI_FreeAslRequest(aslreq); + } + return(TRUE); +} +/* \\\ */ + +/* /// "ActionDispatcher()" */ +AROS_UFH3(IPTR, ActionDispatcher, + AROS_UFHA(struct IClass *, cl, A0), + AROS_UFHA(Object *, obj, A2), + AROS_UFHA(Msg, msg, A1)) +{ + AROS_USERFUNC_INIT + // There should never be an uninitialized pointer, but just in case, try to get an mungwall hit if so. + struct ActionData *data = (struct ActionData *) 0xABADCAFE; + + // on OM_NEW the obj pointer will be void, so don't try to get the data base in this case. + if(msg->MethodID != OM_NEW) data = INST_DATA(cl, obj); + + switch(msg->MethodID) + { + case OM_NEW: + return((IPTR) Action_OM_NEW(cl, obj, msg)); + + case MUIM_Setup: + return(Action_Setup(cl, obj, msg)); + + case MUIM_Cleanup: + //MUI_RejectIDCMP(obj, IDCMP_INTUITICKS); + while(data->OnlUpdTask) + { + Delay(50); + } + DoMethod(data->appobj, MUIM_Application_RemInputHandler, &data->eventihn); + data->appobj = NULL; + data->winobj = NULL; + return(DoSuperMethodA(cl,obj,msg)); + + case OM_DISPOSE: + Action_OM_DISPOSE(cl, obj, msg); + break; + + case MUIM_Action_HandlePsdEvents: + EventHandler(data); + return(TRUE); + + case MUIM_Action_CloseSubWinReq: + { + struct DefListEntry *winnode; + winnode = (struct DefListEntry *) ((struct opSet *) msg)->ops_AttrList; + if(winnode->infowindow) + { + set(winnode->infowindow, MUIA_Window_Open, FALSE); + DoMethod(data->appobj, OM_REMMEMBER, winnode->infowindow); + DoMethod(winnode->infowindow, OM_DISPOSE); + winnode->infowindow = NULL; + } + return(TRUE); + } + + case MUIM_Action_Cfg_Changed: + return(Action_Cfg_Changed(cl, obj, msg)); + + case MUIM_Action_Cfg_Snd_Changed: + return(Action_Cfg_Snd_Changed(cl, obj, msg)); + + case MUIM_Action_HW_New: + return(Action_HW_New(cl, obj, msg)); + + case MUIM_Action_HW_Copy: + return(Action_HW_Copy(cl, obj, msg)); + + case MUIM_Action_HW_Del: + return(Action_HW_Del(cl, obj, msg)); + + case MUIM_Action_HW_Update: + return(Action_HW_Update(cl, obj, msg)); + + case MUIM_Action_HW_Activate: + return(Action_HW_Activate(cl, obj, msg)); + + case MUIM_Action_HW_Info: + return(Action_HW_Info(cl, obj, msg)); + + case MUIM_Action_HW_Online: + return(Action_HW_Online(cl, obj, msg)); + + case MUIM_Action_HW_Offline: + return(Action_HW_Offline(cl, obj, msg)); + + case MUIM_Action_Online: + return(Action_Online(cl, obj, msg)); + + case MUIM_Action_Offline: + return(Action_Offline(cl, obj, msg)); + + case MUIM_Action_Restart: + return(Action_Restart(cl, obj, msg)); + + case MUIM_Action_ChgErrLevel: + return(Action_ChgErrLevel(cl, obj, msg)); + + case MUIM_Action_SaveErrors: + return(Action_SaveErrors(cl, obj, msg)); + + case MUIM_Action_FlushErrors: + return(Action_FlushErrors(cl, obj, msg)); + + case MUIM_Action_SaveDeviceList: + return(Action_SaveDeviceList(cl, obj, msg)); + + case MUIM_Action_Use: + InternalCreateConfigGUI(data); + psdSaveCfgToDisk("ENV:PsdStackloader", TRUE); + psdSaveCfgToDisk("ENV:Sys/poseidon.prefs", FALSE); + return(TRUE); + + case MUIM_Action_LoadPrefs: + return(Action_LoadPrefs(cl, obj, msg)); + + case MUIM_Action_SavePrefsAs: + return(Action_SavePrefsAs(cl, obj, msg)); + + case MUIM_Action_SavePrefs: + return(Action_SavePrefs(cl, obj, msg)); + + case MUIM_Action_Prefs_Changed: + return(Action_Prefs_Changed(cl, obj, msg)); + + case MUIM_Action_UseQuit: + return(Action_UseQuit(cl, obj, msg)); + + case MUIM_Action_SaveQuit: + return(Action_SaveQuit(cl, obj, msg)); + + case MUIM_Action_LoadPrefsFrom: + return(Action_LoadPrefsFrom(cl, obj, msg)); + + case MUIM_Action_SavePrefsTo: + return(Action_SavePrefsTo(cl, obj, msg)); + + case MUIM_Action_Dev_Activate: + return(Action_Dev_Activate(cl, obj, msg)); + + case MUIM_Action_Dev_Bind: + return(Action_Dev_Bind(cl, obj, msg)); + + case MUIM_Action_Dev_Unbind: + return(Action_Dev_Unbind(cl, obj, msg)); + + case MUIM_Action_Dev_Suspend: + return(Action_Dev_Suspend(cl, obj, msg)); + + case MUIM_Action_Dev_Resume: + return(Action_Dev_Resume(cl, obj, msg)); + + case MUIM_Action_Dev_PowerCycle: + return(Action_Dev_PowerCycle(cl, obj, msg)); + + case MUIM_Action_Dev_Disable: + return(Action_Dev_Disable(cl, obj, msg)); + + case MUIM_Action_Dev_ForceBind: + return(Action_Dev_ForceBind(cl, obj, msg)); + + case MUIM_Action_Dev_Info: + return(Action_Dev_Info(cl, obj, msg)); + + case MUIM_Action_Dev_Configure: + return(Action_Dev_Configure(cl, obj, msg)); + + case MUIM_Action_Cls_Activate: + return(Action_Cls_Activate(cl, obj, msg)); + + case MUIM_Action_Cls_Add: + return(Action_Cls_Add(cl, obj, msg)); + + case MUIM_Action_Cls_Remove: + return(Action_Cls_Remove(cl, obj, msg)); + + case MUIM_Action_Cls_Scan: + return(Action_Cls_Scan(cl, obj, msg)); + + case MUIM_Action_Cls_Configure: + return(Action_Cls_Configure(cl, obj, msg)); + + case MUIM_Action_Info_MemPool: + return(Action_Info_MemPool(cl, obj, msg)); + + case MUIM_Action_About: + DoMethod(data->cfgpagelv, MUIM_Set, MUIA_List_Active, 0); + return(TRUE); + + case MUIM_Action_WakeUp: + set(data->appobj, MUIA_Application_Iconified, FALSE); + DoMethod(data->winobj, MUIM_Window_ToFront); + set(data->winobj, MUIA_Window_Activate, TRUE); + return(TRUE); + + case MUIM_Action_Cfg_Activate: + return(Action_Cfg_Activate(cl, obj, msg)); + + case MUIM_Action_Cfg_Remove: + return(Action_Cfg_Remove(cl, obj, msg)); + + case MUIM_Action_Cfg_Export: + return(Action_Cfg_Export(cl, obj, msg)); + + case MUIM_Action_Cfg_Import: + return(Action_Cfg_Import(cl, obj, msg)); + + } + return(DoSuperMethodA(cl,obj,msg)); + AROS_USERFUNC_EXIT +} +/* \\\ */ diff --git a/rom/usb/trident/ActionClass.h b/rom/usb/trident/ActionClass.h new file mode 100644 index 000000000..c4c2a1ae2 --- /dev/null +++ b/rom/usb/trident/ActionClass.h @@ -0,0 +1,287 @@ +/***************************************************************************** +** This is the Action custom class, a sub class of Group.mui. +******************************************************************************/ +#ifndef ACTIONCLASS_H +#define ACTIONCLASS_H +/* private structures */ + +struct DefListEntry +{ + struct Node node; + Object *infowindow; +}; + +struct HWListEntry +{ + struct Node node; + Object *infowindow; + Object *classpopup; + struct Node *phw; + STRPTR devname; + IPTR unit; + STRPTR prodname; +}; + +struct PrefsListEntry +{ + struct Node node; + Object *infowindow; + APTR *pic; + STRPTR id; + STRPTR owner; + STRPTR type; + ULONG chunkid; + STRPTR devid; + STRPTR ifid; + ULONG size; +}; + +struct DevListEntry +{ + struct Node node; + Object *infowindow; + struct Node *pd; + struct DevWinData *devdata; + struct ActionData *adata; +}; + +struct ClsListEntry +{ + struct Node node; + Object *infowindow; + struct Node *puc; + STRPTR desc; +}; + +struct ErrListEntry +{ + struct Node node; + struct Node *pem; +}; + + +struct ActionData +{ + struct Hook HardwareDisplayHook; + struct Hook PrefsDisplayHook; + struct Hook DeviceDisplayHook; + struct Hook ClassDisplayHook; + struct Hook ErrorDisplayHook; + struct Hook IconDisplayHook; + + struct List hwlist; + struct List prefslist; + struct HWListEntry *acthlnode; + struct List devlist; + struct List clslist; + struct List errlist; + ULONG errorlevel; + struct MsgPort *eventmsgport; + APTR eventhandler; + + ULONG *configroot; + STRPTR devidstr; + STRPTR ifidstr; + + BOOL autoclassesadded; + BOOL swallowconfigevent; + + struct Task *OnlUpdTask; + + struct MUI_InputHandlerNode eventihn; + + Object *selfobj; + Object *appobj; + Object *winobj; + Object *mainobj; + Object *cfgpagelv; + Object *cfgpagegrp; + Object *cfgcntobj[7]; + + Object *hwlistobj; + Object *hwdevgrpobj; + Object *hwdevaslobj; + Object *hwdevobj; + Object *hwunitobj; + Object *hwnewobj; + Object *hwcopyobj; + Object *hwdelobj; + Object *hwinfoobj; + Object *hwonlineobj; + Object *hwofflineobj; + + Object *onlineobj; + Object *offlineobj; + Object *restartobj; + Object *saveobj; + Object *useobj; + + Object *devlistobj; + Object *devbindobj; + Object *devunbindobj; + Object *devpowercycleobj; + Object *devdisableobj; + Object *devsuspendobj; + Object *devresumeobj; + Object *devinfoobj; + Object *devcfgobj; + + Object *clslistobj; + Object *clsnameobj; + Object *clsaddobj; + Object *clsremobj; + Object *clscfgobj; + Object *clsscanobj; + Object *errlvlobj; + Object *errsaveobj; + Object *errflushobj; + Object *errlistobj; + + Object *cfgtaskpriobj; + Object *cfgbootdelayobj; + Object *cfgloginfoobj; + Object *cfglogwarnobj; + Object *cfglogerrobj; + Object *cfglogfailobj; + Object *cfgpopupnewobj; + Object *cfgpopupgoneobj; + Object *cfgpopupdeathobj; + Object *cfgpopupdelayobj; + Object *cfgpopupactivateobj; + Object *cfgpopuptofrontobj; + Object *cfgdevdtxsoundobj; + Object *cfgdevremsoundobj; + + Object *cfgautolpobj; + Object *cfgautodeadobj; + Object *cfgautopcobj; + + Object *cfgpowersavingobj; + Object *cfgforcesuspendobj; + Object *cfgsuspendtimeoutobj; + + Object *mempoolobj; + + Object *prefslistobj; + Object *prefsexportobj; + Object *prefsimportobj; + Object *prefsremoveobj; + Object *prefssaveasobj; + + Object *mi_classpopup; +}; + +#define TAGBASE_Action (TAG_USER | 23<<16) +#define MUIM_Action_HW_New (TAGBASE_Action | 0x0001) +#define MUIM_Action_HW_Copy (TAGBASE_Action | 0x0002) +#define MUIM_Action_HW_Del (TAGBASE_Action | 0x0003) +#define MUIM_Action_HW_Info (TAGBASE_Action | 0x0004) +#define MUIM_Action_HW_InfoClose (TAGBASE_Action | 0x0005) +#define MUIM_Action_HW_Activate (TAGBASE_Action | 0x0006) +#define MUIM_Action_HW_Update (TAGBASE_Action | 0x0007) +#define MUIM_Action_HW_Online (TAGBASE_Action | 0x0008) +#define MUIM_Action_HW_Offline (TAGBASE_Action | 0x0009) +#define MUIM_Action_Online (TAGBASE_Action | 0x0010) +#define MUIM_Action_Offline (TAGBASE_Action | 0x0011) +#define MUIM_Action_ChgErrLevel (TAGBASE_Action | 0x0012) +#define MUIM_Action_FlushErrors (TAGBASE_Action | 0x0013) +#define MUIM_Action_Use (TAGBASE_Action | 0x0014) +#define MUIM_Action_LoadPrefs (TAGBASE_Action | 0x0015) +#define MUIM_Action_SavePrefs (TAGBASE_Action | 0x0016) +#define MUIM_Action_SavePrefsAs (TAGBASE_Action | 0x0017) +#define MUIM_Action_SaveQuit (TAGBASE_Action | 0x0018) +#define MUIM_Action_UseQuit (TAGBASE_Action | 0x0019) +#define MUIM_Action_SaveErrors (TAGBASE_Action | 0x001b) +#define MUIM_Action_SaveDeviceList (TAGBASE_Action | 0x001c) +#define MUIM_Action_Restart (TAGBASE_Action | 0x001d) +#define MUIM_Action_Dev_Activate (TAGBASE_Action | 0x0020) +#define MUIM_Action_Dev_Bind (TAGBASE_Action | 0x0021) +#define MUIM_Action_Dev_Unbind (TAGBASE_Action | 0x0022) +#define MUIM_Action_Dev_Info (TAGBASE_Action | 0x0023) +#define MUIM_Action_Dev_Configure (TAGBASE_Action | 0x0025) +#define MUIM_Action_Dev_ForceBind (TAGBASE_Action | 0x0026) +#define MUIM_Action_Dev_Suspend (TAGBASE_Action | 0x0027) +#define MUIM_Action_Dev_Resume (TAGBASE_Action | 0x0028) +#define MUIM_Action_Dev_PowerCycle (TAGBASE_Action | 0x0029) +#define MUIM_Action_Dev_Disable (TAGBASE_Action | 0x002a) +#define MUIM_Action_Cls_Activate (TAGBASE_Action | 0x0030) +#define MUIM_Action_Cls_Add (TAGBASE_Action | 0x0031) +#define MUIM_Action_Cls_Remove (TAGBASE_Action | 0x0032) +#define MUIM_Action_Cls_Configure (TAGBASE_Action | 0x0033) +#define MUIM_Action_Cls_Scan (TAGBASE_Action | 0x0034) +#define MUIM_Action_Cfg_Changed (TAGBASE_Action | 0x0040) +#define MUIM_Action_Cfg_Snd_Changed (TAGBASE_Action | 0x0041) +#define MUIM_Action_Info_MemPool (TAGBASE_Action | 0x0050) +#define MUIM_Action_CloseSubWinReq (TAGBASE_Action | 0x0051) +#define MUIM_Action_About (TAGBASE_Action | 0x0060) +#define MUIM_Action_WakeUp (TAGBASE_Action | 0x0061) +#define MUIM_Action_HandlePsdEvents (TAGBASE_Action | 0x0062) +#define MUIM_Action_Cfg_Activate (TAGBASE_Action | 0x0070) +#define MUIM_Action_Cfg_Export (TAGBASE_Action | 0x0071) +#define MUIM_Action_Cfg_Import (TAGBASE_Action | 0x0072) +#define MUIM_Action_Cfg_Remove (TAGBASE_Action | 0x0073) + +/* MPREFS */ +#define MUIM_Action_LoadPrefsFrom (TAGBASE_Action | 0x0080) +#define MUIM_Action_SavePrefsTo (TAGBASE_Action | 0x0081) +#define MUIM_Action_Prefs_Changed (TAGBASE_Action | 0x0082) + + +/* prototypes */ + +struct HWListEntry * AllocHWEntry(struct ActionData *data, struct Node *phw); +void FreeHWEntry(struct ActionData *data, struct HWListEntry *hlnode); +struct DevListEntry * AllocDevEntry(struct ActionData *data, struct Node *pd); +void FreeDevEntry(struct ActionData *data, struct DevListEntry *dlnode); +struct ClsListEntry * AllocClsEntry(struct ActionData *data, struct Node *puc); +void FreeClsEntry(struct ActionData *data, struct ClsListEntry *clnode); +void FreeErrorList(struct ActionData *data); +void CreateErrorList(struct ActionData *data); +Object * CreateClassPopup(void); +void CleanupEventHandler(struct ActionData *data); +BOOL SetupEventHandler(struct ActionData *data); +void UpdateConfigToGUI(struct ActionData *data); + +BOOL InternalCreateConfig(void); +BOOL InternalCreateConfigGUI(struct ActionData *data); +BOOL WriteSysConfig(STRPTR name); +BOOL LoadConfigFromFile(STRPTR name); + +IPTR Action_HW_Activate(struct IClass *cl, Object *obj, Msg msg); + +AROS_UFP3(LONG, HardwareListDisplayHook, + AROS_UFPA(struct Hook *, hook, A0), + AROS_UFPA(char **, strarr, A2), + AROS_UFPA(struct HWListEntry *, hlnode, A1)); + +AROS_UFP3(LONG, PrefsListDisplayHook, + AROS_UFPA(struct Hook *, hook, A0), + AROS_UFPA(char **, strarr, A2), + AROS_UFPA(struct PrefsListEntry *, plnode, A1)); + +AROS_UFP3(LONG, DeviceListDisplayHook, + AROS_UFPA(struct Hook *, hook, A0), + AROS_UFPA(char **, strarr, A2), + AROS_UFPA(struct DevListEntry *, dlnode, A1)); + +AROS_UFP3(LONG, ClassListDisplayHook, + AROS_UFPA(struct Hook *, hook, A0), + AROS_UFPA(char **, strarr, A2), + AROS_UFPA(struct ClsListEntry *, clnode, A1)); + +AROS_UFP3(LONG, ErrorListDisplayHook, + AROS_UFPA(struct Hook *, hook, A0), + AROS_UFPA(char **, strarr, A2), + AROS_UFPA(struct ErrListEntry *, elnode, A1)); + +AROS_UFP3(LONG, IconListDisplayHook, + AROS_UFPA(struct Hook *, hook, A0), + AROS_UFPA(char **, strarr, A2), + AROS_UFPA(STRPTR, str, A1)); + +AROS_UFP3(IPTR, ActionDispatcher, + AROS_UFPA(struct IClass *, cl, A0), + AROS_UFPA(Object *, obj, A2), + AROS_UFPA(Msg, msg, A1)); + +#endif diff --git a/rom/usb/trident/CfgListClass.c b/rom/usb/trident/CfgListClass.c new file mode 100644 index 000000000..d77b18734 --- /dev/null +++ b/rom/usb/trident/CfgListClass.c @@ -0,0 +1,372 @@ + +/***************************************************************************** +** This is the CfgList custom class, a sub class of List.mui. +******************************************************************************/ + +#include "debug.h" + +#define USE_INLINE_STDARG +#define __NOLIBBASE__ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Trident.h" +#include "ActionClass.h" +#include "IconListClass.h" +#include "DevWinClass.h" +#include "CfgListClass.h" + +extern struct ExecBase *SysBase; +extern struct Library *ps; +extern struct IntuitionBase *IntuitionBase; + +/* /// "CheckDragAccept()" */ +BOOL CheckDragAccept(Object *obj, LONG targetentry) +{ + struct PrefsListEntry *targetplnode = NULL; + struct PrefsListEntry *sourceplnode = NULL; + ULONG sourceid, targetid; + IPTR sourceentry = -1; + + get(obj, MUIA_List_Active, &sourceentry); + if((((LONG) sourceentry) < 0) || (targetentry < 0)) + { + return(FALSE); + } + DoMethod(obj, MUIM_List_GetEntry, sourceentry, &sourceplnode); + DoMethod(obj, MUIM_List_GetEntry, targetentry, &targetplnode); + if((!(sourceplnode && targetplnode)) || (sourceplnode == targetplnode)) + { + return(FALSE); + } + sourceid = sourceplnode->chunkid; + targetid = targetplnode->chunkid; + + switch(sourceid) + { + case IFFFORM_DEVICECFG: + if(targetid == IFFFORM_DEVICECFG) + { + return(TRUE); + } + break; + + case IFFFORM_DEVCFGDATA: + if((targetid == IFFFORM_DEVICECFG) || + (targetid == IFFFORM_DEVCFGDATA)) + { + return(TRUE); + } + break; + + case IFFFORM_IFCFGDATA: + if((targetid == IFFFORM_DEVICECFG) || + (targetid == IFFFORM_IFCFGDATA)) + { + return(TRUE); + } + break; + + case IFFCHNK_FORCEDBIND: + if((targetid == IFFFORM_DEVICECFG) || + (targetid == IFFFORM_DEVCFGDATA) || + (targetid == IFFFORM_IFCFGDATA) || + (targetid == IFFCHNK_FORCEDBIND)) + { + return(TRUE); + } + break; + } + return(FALSE); +} +/* \\\ */ + +/* /// "ApplyDragAction()" */ +BOOL ApplyDragAction(Object *obj, LONG targetentry) +{ + struct PrefsListEntry *targetplnode = NULL; + struct PrefsListEntry *sourceplnode = NULL; + ULONG sourceid, targetid; + IPTR sourceentry = -1; + LONG result; + APTR pic, spic, tpic; + APTR form; + + get(obj, MUIA_List_Active, &sourceentry); + if((((LONG) sourceentry) < 0) || (targetentry < 0)) + { + return(FALSE); + } + DoMethod(obj, MUIM_List_GetEntry, sourceentry, &sourceplnode); + DoMethod(obj, MUIM_List_GetEntry, targetentry, &targetplnode); + if((!(sourceplnode && targetplnode)) || (sourceplnode == targetplnode)) + { + return(FALSE); + } + sourceid = sourceplnode->chunkid; + targetid = targetplnode->chunkid; + + switch(sourceid) + { + case IFFFORM_DEVICECFG: + if(targetid == IFFFORM_DEVICECFG) + { + result = MUI_Request(_app(obj), _win(obj), 0, NULL, "Replace|Merge|Cancel", + "Do you want to \33breplace\33n or \33bmerge\33n the prefs of\n" + "\33b%s\33n\n" + "with the contents from\n" + "\33b%s\33n?", targetplnode->id, sourceplnode->id); + if(result < 1) + { + return(FALSE); + } + tpic = NULL; + spic = NULL; + pic = psdFindCfgForm(NULL, IFFFORM_DEVICECFG); + while(pic) + { + if(psdMatchStringChunk(pic, IFFCHNK_DEVID, targetplnode->devid)) + { + tpic = pic; + } + if(psdMatchStringChunk(pic, IFFCHNK_DEVID, sourceplnode->devid)) + { + spic = pic; + } + pic = psdNextCfgForm(pic); + } + if(!(tpic && spic)) + { + return(FALSE); + } + // delete old contents + if(result == 1) + { + while((pic = psdFindCfgForm(tpic, IFFFORM_DEVCFGDATA))) + { + psdRemCfgForm(pic); + } + while((pic = psdFindCfgForm(tpic, IFFFORM_IFCFGDATA))) + { + psdRemCfgForm(pic); + } + } + + // copy device cfg data + pic = psdFindCfgForm(spic, IFFFORM_DEVCFGDATA); + while(pic) + { + form = psdWriteCfg(pic); + if(form) + { + psdAddCfgEntry(tpic, form); + psdFreeVec(form); + } + pic = psdNextCfgForm(pic); + } + // copy interface cfg data + pic = psdFindCfgForm(spic, IFFFORM_IFCFGDATA); + while(pic) + { + form = psdWriteCfg(pic); + if(form) + { + psdAddCfgEntry(tpic, form); + psdFreeVec(form); + } + pic = psdNextCfgForm(pic); + } + return(TRUE); + } + break; + + case IFFFORM_IFCFGDATA: + case IFFFORM_DEVCFGDATA: + if((targetid == IFFFORM_DEVCFGDATA) || (targetid == IFFFORM_IFCFGDATA)) + { + if(strcmp(sourceplnode->owner, targetplnode->owner)) + { + result = MUI_RequestA(_app(obj), _win(obj), 0, NULL, "Add to device|Cancel", + "Sorry, but only prefs of the same owner can\n" + "be replaced.\n\n" + "Do you wish to add this prefs\n" + "to the device instead?", NULL); + if(result < 1) + { + return(FALSE); + } + targetid = IFFFORM_DEVICECFG; + } else { + result = MUI_Request(_app(obj), _win(obj), 0, NULL, "Replace|Cancel", + "Do you want to \33breplace\33n the prefs of\n" + "\33b%s\33n\n" + "by those of\n" + "\33b%s\33n?", targetplnode->id, sourceplnode->id); + + if(result < 1) + { + return(FALSE); + } + pic = psdGetUsbDevCfg(sourceplnode->owner, sourceplnode->devid, sourceplnode->ifid); + if(pic) + { + form = psdWriteCfg(pic); + if(form) + { + psdSetUsbDevCfg(sourceplnode->owner, targetplnode->devid, targetplnode->ifid, form); + psdFreeVec(form); + } + } + return(TRUE); + } + } + if(targetid == IFFFORM_DEVICECFG) + { + pic = psdGetUsbDevCfg(sourceplnode->owner, targetplnode->devid, sourceplnode->ifid); + if(pic) + { + result = MUI_Request(_app(obj), _win(obj), 0, NULL, "Replace|Cancel", + "Do you want to \33breplace\33n the prefs of\n" + "\33b%s\33n\n" + "by the one in\n" + "\33b%s\33n?", targetplnode->id, sourceplnode->id); + } else { + result = MUI_Request(_app(obj), _win(obj), 0, NULL, "Add|Cancel", + "Do you want to \33badd\33n the prefs of\n" + "\33b%s\33n\n" + "to the device\n" + "\33b%s\33n?", sourceplnode->id, targetplnode->id); + } + if(result < 1) + { + return(FALSE); + } + pic = psdGetUsbDevCfg(sourceplnode->owner, sourceplnode->devid, sourceplnode->ifid); + if(pic) + { + form = psdWriteCfg(pic); + if(form) + { + psdSetUsbDevCfg(sourceplnode->owner, targetplnode->devid, sourceplnode->ifid, form); + psdFreeVec(form); + } + } + return(TRUE); + } + break; + + case IFFCHNK_FORCEDBIND: + if((targetid == IFFFORM_DEVICECFG) || + (targetid == IFFFORM_DEVCFGDATA) || + (targetid == IFFFORM_IFCFGDATA) || + (targetid == IFFCHNK_FORCEDBIND)) + { + psdSetForcedBinding(sourceplnode->owner, targetplnode->devid, targetplnode->ifid); + return(TRUE); + } + break; + } + return(FALSE); +} +/* \\\ */ + +/* /// "CfgListDispatcher()" */ +AROS_UFH3(IPTR, CfgListDispatcher, + AROS_UFHA(struct IClass *, cl, A0), + AROS_UFHA(Object *, obj, A2), + AROS_UFHA(Msg, msg, A1)) +{ + AROS_USERFUNC_INIT + // There should never be an uninitialized pointer, but just in case, try to get an mungwall hit if so. + struct CfgListData *data = (struct CfgListData *) 0xABADCAFE; + + // on OM_NEW the obj pointer will be void, so don't try to get the data base in this case. + if(msg->MethodID != OM_NEW) data = INST_DATA(cl,obj); + + switch(msg->MethodID) + { + case OM_NEW: + if(!(obj = (Object *) DoSuperMethodA(cl,obj,msg))) + return(0); + return((IPTR) obj); + + case MUIM_DragBegin: + data->cl_Dragging = TRUE; + break; + + case MUIM_DragFinish: + data->cl_Dragging = FALSE; + break; + + case MUIM_DragQuery: + { + struct MUI_List_TestPos_Result tpr; + struct Window *win; + + win = _window(obj); + if(!win) + { + return(MUIV_DragQuery_Refuse); + } + DoMethod(obj, MUIM_List_TestPos, win->MouseX, win->MouseY, &tpr); + return((IPTR) (CheckDragAccept(obj, tpr.entry) ? MUIV_DragQuery_Accept : MUIV_DragQuery_Refuse)); + } + +#ifndef MUI_LPR_FULLDROP +#define MUI_LPR_FULLDROP (1<<15) +#endif + case MUIM_List_TestPos: + { + struct MUIP_List_TestPos *tpmsg = (struct MUIP_List_TestPos *) msg; + struct MUI_List_TestPos_Result *res = tpmsg->res; + IPTR rc; + rc = DoSuperMethodA(cl, obj, msg); + if(data->cl_Dragging && (res->entry != -1)) + { + if(!CheckDragAccept(obj, res->entry)) + { + res->entry = -1; // illegal combination + } else { + res->flags |= MUI_LPR_FULLDROP; + } + } + return(rc); + } + + case MUIM_DragDrop: + { + //struct MUIP_DragDrop *ddmsg = (struct MUIP_DragDrop *) msg; + struct MUI_List_TestPos_Result tpr; + struct Window *win; + + win = _window(obj); + if(!win) + { + return(FALSE); + } + DoMethod(obj, MUIM_List_TestPos, win->MouseX, win->MouseY, &tpr); + //DoMethod(obj, MUIM_List_TestPos, ddmsg->x, ddmsg->y, &tpr); + if(CheckDragAccept(obj, tpr.entry)) + { + ApplyDragAction(obj, tpr.entry); + } else { + MUI_RequestA(_app(obj), _win(obj), 0, NULL, "Oops!", + "Sorry, drag'n drop operation to\n" + "that target is not supported.", NULL); + return(FALSE); + } + return(TRUE); + } + + } + return(DoSuperMethodA(cl,obj,msg)); + AROS_USERFUNC_EXIT +} +/* \\\ */ diff --git a/rom/usb/trident/CfgListClass.h b/rom/usb/trident/CfgListClass.h new file mode 100644 index 000000000..364e89c19 --- /dev/null +++ b/rom/usb/trident/CfgListClass.h @@ -0,0 +1,19 @@ +/***************************************************************************** +** This is the CfgList custom class, a sub class of List.mui. +******************************************************************************/ +#ifndef CFGLISTCLASS_H +#define CFGLISTCLASS_H + +struct CfgListData +{ + BOOL cl_Dragging; +}; + +#define TAGBASE_CfgList (TAG_USER | 3242<<16) + +AROS_UFP3(IPTR, CfgListDispatcher, + AROS_UFPA(struct IClass *, cl, A0), + AROS_UFPA(Object *, obj, A2), + AROS_UFPA(Msg, msg, A1)); + +#endif diff --git a/rom/usb/trident/DevWinClass.c b/rom/usb/trident/DevWinClass.c new file mode 100644 index 000000000..8b6c29178 --- /dev/null +++ b/rom/usb/trident/DevWinClass.c @@ -0,0 +1,930 @@ + +/***************************************************************************** +** This is the DevWinList custom class, a sub class of Window.mui. +******************************************************************************/ + +#include "debug.h" + +#define USE_INLINE_STDARG +#define __NOLIBBASE__ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Trident.h" +#include "ActionClass.h" +#include "IconListClass.h" +#include "DevWinClass.h" +#include "CfgListClass.h" + +extern struct ExecBase *SysBase; +extern struct Library *ps; +extern struct IntuitionBase *IntuitionBase; +extern struct Library *UtilityBase; +/*extern struct IntuitionBase *IntuitionBase; +extern struct DosLibrary *DOSBase;*/ + +#define NewList(list) NEWLIST(list) + +static char *overridepowerstrings[] = +{ + "Trust device", + "Override to bus-powered", + "Override to self-powered", + NULL +}; + + +/* /// "AllocIfEntry()" */ +struct IfListEntry * AllocIfEntry(struct DevWinData *data, struct Node *pif, BOOL intend) +{ + struct IfListEntry *iflnode; + iflnode = psdAllocVec(sizeof(struct IfListEntry)); + if(iflnode) + { + iflnode->pif = pif; + AddTail(&data->iflist, &iflnode->node); + } + return(iflnode); +} +/* \\\ */ + +/* /// "FreeIfEntry()" */ +void FreeIfEntry(struct DevWinData *data, struct IfListEntry *iflnode) +{ + Remove(&iflnode->node); + psdFreeVec(iflnode); +} +/* \\\ */ + +/* /// "InterfaceListDisplayHook()" */ +AROS_UFH3(LONG, InterfaceListDisplayHook, + AROS_UFHA(struct Hook *, hook, A0), + AROS_UFHA(char **, strarr, A2), + AROS_UFHA(struct IfListEntry *, iflnode, A1)) +{ + AROS_USERFUNC_INIT + + static char buf1[12]; + static char buf3[48]; + static char buf4[8]; + static char buf5[8]; + static char buf6[8]; + struct IconListData *data; + struct DevWinData *devdata = (struct DevWinData *) hook->h_Data; + + if(iflnode) + { + IPTR clsimg; + IPTR ifnum; + IPTR ifaltnum; + IPTR ifclass; + IPTR ifsubclass; + IPTR ifproto; + STRPTR ifname; + IPTR ifnumeps; + APTR binding; + struct Library *bindingcls; + data = (struct IconListData *) INST_DATA(IconListClass->mcc_Class, devdata->iflvobj); + + psdGetAttrs(PGA_INTERFACE, iflnode->pif, + IFA_InterfaceNum, &ifnum, + IFA_AlternateNum, &ifaltnum, + IFA_Class, &ifclass, + IFA_SubClass, &ifsubclass, + IFA_Protocol, &ifproto, + IFA_InterfaceName, &ifname, + IFA_NumEndpoints, &ifnumeps, + IFA_Binding, &binding, + IFA_BindingClass, &bindingcls, + TAG_END); + psdSafeRawDoFmt(buf1, 12, "%ld/%ld", ifnum, ifaltnum); + clsimg = 5; + switch(ifclass) + { + case STILLIMG_CLASSCODE: + clsimg = 22; + break; + case BLUETOOTH_CLASSCODE: + clsimg = 21; + break; + case FWUPGRADE_CLASSCODE: + clsimg = 1; + break; + case VENDOR_CLASSCODE: + clsimg++; + case SECURITY_CLASSCODE: + clsimg++; + case SMARTCARD_CLASSCODE: + clsimg++; + case CDCDATA_CLASSCODE: + clsimg++; + case HUB_CLASSCODE: + clsimg++; + case MASSSTORE_CLASSCODE: + clsimg++; + case PRINTER_CLASSCODE: + clsimg++; + case PHYSICAL_CLASSCODE: + clsimg++; + case HID_CLASSCODE: + clsimg++; + case CDCCTRL_CLASSCODE: + clsimg += 2; + case AUDIO_CLASSCODE: + clsimg++; + } + + psdSafeRawDoFmt(buf3, 48, "\33O[%08lx] %ld (%s)", + data->mimainlist[clsimg], + ifclass, + psdNumToStr(NTS_COMBOCLASS, (ifclass<lib_Node.ln_Name; + } else { + *strarr = "None"; + } + } else { + *strarr++ = "\33l\33uNum"; + *strarr++ = "\33l\33uName"; + *strarr++ = "\33l\33uClass"; + *strarr++ = "\33l\33uSub"; + *strarr++ = "\33l\33uProto"; + *strarr++ = "\33l\33uEPs"; + *strarr = "\33l\33uBinding"; + } + return(0); + AROS_USERFUNC_EXIT +} +/* \\\ */ + +/* /// "DevWinDispatcher()" */ +AROS_UFH3(IPTR, DevWinDispatcher, + AROS_UFHA(struct IClass *, cl, A0), + AROS_UFHA(Object *, obj, A2), + AROS_UFHA(Msg, msg, A1)) +{ + AROS_USERFUNC_INIT + // There should never be an uninitialized pointer, but just in case, try to get an mungwall hit if so. + struct DevWinData *data = (struct DevWinData *) 0xABADCAFE; + + // on OM_NEW the obj pointer will be void, so don't try to get the data base in this case. + if(msg->MethodID != OM_NEW) data = INST_DATA(cl,obj); + + switch(msg->MethodID) + { + case OM_NEW: + { + struct DevListEntry *dlnode; + struct IfListEntry *iflnode; + IPTR devadr; + IPTR devusbvers; + IPTR devclass; + IPTR devsubclass; + IPTR devproto; + IPTR devvendorid; + IPTR devprodid; + IPTR devversion; + STRPTR devmanufact; + STRPTR devprodname = NULL; + STRPTR devserial; + STRPTR devidstr; + STRPTR customname; + IPTR devcurrlang; + UWORD *devlangarray; + IPTR devislowspeed; + IPTR devishighspeed; + IPTR devisconnected; + IPTR devhasaddress; + IPTR devhasdevdesc; + IPTR devisconfigured; + IPTR devlowpower = 0; + IPTR devnumcfgs; + IPTR devdontpopup = 0; + IPTR noclassbind = 0; + IPTR overridepower = 0; + IPTR devpowerdrain = 0; + IPTR devpowersupply = 0; + IPTR devhubport = 0; + struct Node *devhub = NULL; + STRPTR devhubname = ""; + + struct List *cfgs; + struct Node *pc; + IPTR cfgselfpow; + IPTR cfgremwake; + IPTR cfgnum; + IPTR cfgmaxpower; + STRPTR cfgname; + IPTR cfgnumifs; + + struct List *ifs; + struct Node *pif; + struct Node *altpif; + struct List *altiflist; + + APTR binding; + struct Library *bindingcls; + + STRPTR textbuf1, textbuf2, textbuf3; + STRPTR devstate; + + Object *oldroot = NULL; + + if(!(obj = (Object *) DoSuperMethodA(cl, obj, msg))) + { + return(0); + } + data = INST_DATA(cl, obj); + NewList(&data->iflist); + data->InterfaceDisplayHook.h_Data = data; + data->InterfaceDisplayHook.h_Entry = (APTR) InterfaceListDisplayHook; + + dlnode = (struct DevListEntry *) GetTagData(MUIA_DevWin_DevEntry, (IPTR) NULL, ((struct opSet *) msg)->ops_AttrList); + + if(dlnode) + { + dlnode->devdata = data; + data->dlnode = dlnode; + data->pd = dlnode->pd; + psdGetAttrs(PGA_DEVICE, dlnode->pd, + DA_Address, &devadr, + DA_UsbVersion, &devusbvers, + DA_Class, &devclass, + DA_SubClass, &devsubclass, + DA_Protocol, &devproto, + DA_VendorID, &devvendorid, + DA_ProductID, &devprodid, + DA_Version, &devversion, + DA_Manufacturer, &devmanufact, + DA_OrigProductName, &devprodname, + DA_ProductName, &customname, + DA_SerialNumber, &devserial, + DA_IDString, &devidstr, + DA_CurrLangID, &devcurrlang, + DA_LangIDArray, &devlangarray, + DA_IsLowspeed, &devislowspeed, + DA_IsHighspeed, &devishighspeed, + DA_IsConnected, &devisconnected, + DA_HasAddress, &devhasaddress, + DA_HasDevDesc, &devhasdevdesc, + DA_IsConfigured, &devisconfigured, + DA_LowPower, &devlowpower, + DA_NumConfigs, &devnumcfgs, + DA_ConfigList, &cfgs, + DA_Binding, &binding, + DA_BindingClass, &bindingcls, + DA_InhibitPopup, &devdontpopup, + DA_InhibitClassBind, &noclassbind, + DA_OverridePowerInfo, &overridepower, + DA_PowerSupply, &devpowersupply, + DA_PowerDrained, &devpowerdrain, + DA_AtHubPortNumber, &devhubport, + DA_HubDevice, &devhub, + TAG_END); + if(devhub) + { + psdGetAttrs(PGA_DEVICE, devhub, + DA_ProductName, &devhubname, + TAG_END); + } + + if(!devprodname) /* backward compatibility */ + { + devprodname = customname; + } + textbuf1 = psdAllocVec(3*1024); + textbuf2 = &textbuf1[1*1024]; + textbuf3 = &textbuf1[2*1024]; + if(!textbuf1) + { + return(FALSE); + } + psdSafeRawDoFmt(textbuf1, 1024, "%s\n%ld (=0x%04lx)\n%04lx\n%s\n%ld (=0x%04lx)\n%s\n%s\n%ld mA supply / %ldmA drained", + devprodname, devprodid, devprodid, devversion, devmanufact, devvendorid, devvendorid, + psdNumToStr(NTS_VENDORID, (LONG) devvendorid, "unknown"), + devserial, + devpowersupply, devpowerdrain); + if(devisconfigured) + { + devstate = "Configured"; + } + else if(devhasdevdesc) + { + devstate = "DevDescriptor"; + } + else if(devhasaddress) + { + devstate = "Valid addr"; + } + else if(devisconnected) + { + devstate = "Connected"; + } else { + devstate = "Dead"; + } + + psdSafeRawDoFmt(textbuf2, 1024, "%s%s\n%s\n%ld\nPort %ld at %s\n%ld (%s)\n%ld\n%ld\n%04lx", + devstate, (devlowpower ? " (Lowpower)" : ""), + (devislowspeed ? "Lowspeed" : (devishighspeed ? "Highspeed" : "Fullspeed")), + devadr, + devhubport, devhubname, + devclass, + psdNumToStr(NTS_COMBOCLASS, + (devclass<lh_Head; + textbuf3[0] = 0; + while(pc->ln_Succ) + { + psdGetAttrs(PGA_CONFIG, pc, + CA_SelfPowered, &cfgselfpow, + CA_RemoteWakeup, &cfgremwake, + CA_ConfigNum, &cfgnum, + CA_MaxPower, &cfgmaxpower, + CA_ConfigName, &cfgname, + CA_NumInterfaces, &cfgnumifs, + CA_InterfaceList, &ifs, + TAG_END); + + psdSafeRawDoFmt(&textbuf3[strlen(textbuf3)], (ULONG) 1024-strlen(textbuf3), + "Config %ld (%s)\n Attributes: %s%s\n MaxPower: %ld mA\n %ld interface%s.\n", + cfgnum, cfgname, + cfgselfpow ? "self-powered " : "bus-powered ", + cfgremwake ? "remote-wakeup" : "", + cfgmaxpower, cfgnumifs, + (cfgnumifs != 1) ? "s" : ""); + pc = pc->ln_Succ; + } + + data->classpopup = CreateClassPopup(); + data->contents = VGroup, + Child, HGroup, + MUIA_ShortHelp, "These fields show some general information\n" + "on the USB device. Note that strings are not\n" + "mandatory and might be artificially created\n" + "from the product and vendor IDs.", + MUIA_FrameTitle, "General device information", + Child, LabelB("Product name:\nProduct ID:\nProduct version:\nManufacturer:\nVendor:\n\nSerial #:\nPower State:"), + Child, TextObject, + TextFrame, + MUIA_Background, MUII_TextBack, + MUIA_Text_Contents, textbuf1, + End, + //Child, HSpace(0), + Child, LabelB("State:\nSpeed:\nAddress:\nConnected:\nDevClass:\nSubclass:\nProtocol:\nUSB vers:"), + Child, TextObject, + TextFrame, + MUIA_Background, MUII_TextBack, + MUIA_Text_Contents, textbuf2, + End, + End, + Child, HGroup, + Child, Label("Custom Device Name:"), + Child, data->cwnameobj = StringObject, + MUIA_ShortHelp, "You can enter a more readable name\n" + "here, if the device does not provide\n" + "a sensible name.", + StringFrame, + //MUIA_HorizWeight, 10, + MUIA_CycleChain, 1, + MUIA_String_Contents, customname, + MUIA_String_AdvanceOnCR, TRUE, + End, + Child, HGroup, + MUIA_Group_SameWidth, TRUE, + Child, data->changenameobj = TextObject, + MUIA_ShortHelp, "Click on this button to change the name of the\n" + "name of the device to the new one.", + ButtonFrame, + MUIA_Background, MUII_ButtonBack, + MUIA_CycleChain, 1, + MUIA_InputMode, MUIV_InputMode_RelVerify, + MUIA_Text_Contents, "\33c Change Name ", + End, + Child, data->resetnameobj = TextObject, + MUIA_ShortHelp, "Removes the custom name and restores\n" + "the original one that Poseidon generated.", + ButtonFrame, + MUIA_Background, MUII_ButtonBack, + MUIA_CycleChain, 1, + MUIA_InputMode, MUIV_InputMode_RelVerify, + MUIA_Text_Contents, "\33c Restore Name ", + End, + End, + End, + Child, HGroup, + Child, Label("Disable class bindings:"), + Child, data->noclassbindobj = ImageObject, ImageButtonFrame, + MUIA_ShortHelp, "Skips this device during class scan,\n" + "making it available for application bindings.", + MUIA_Background, MUII_ButtonBack, + MUIA_CycleChain, 1, + MUIA_InputMode, MUIV_InputMode_Toggle, + MUIA_Image_Spec, MUII_CheckMark, + MUIA_Image_FreeVert, TRUE, + MUIA_Selected, noclassbind, + MUIA_ShowSelState, FALSE, + End, + Child, HSpace(0), + Child, Label("Inhibit popup:"), + Child, data->dontpopupobj = ImageObject, ImageButtonFrame, + MUIA_ShortHelp, "Inhibits a popup window appearing\n" + "for this particular device.", + MUIA_Background, MUII_ButtonBack, + MUIA_CycleChain, 1, + MUIA_InputMode, MUIV_InputMode_Toggle, + MUIA_Image_Spec, MUII_CheckMark, + MUIA_Image_FreeVert, TRUE, + MUIA_Selected, devdontpopup, + MUIA_ShowSelState, FALSE, + End, + Child, HSpace(0), + Child, Label("Power info:"), + Child, data->overridepowerobj = CycleObject, + MUIA_CycleChain, 1, + MUIA_ShortHelp, "Some devices and hubs give wrong information\n" + "about being self-powered, when they're actually\n" + "bus-powered, making me lose my hair.\n" + "Hence, you can override the information the\n" + "device gives about itself, allowing the power\n" + "management to work nicely.", + MUIA_Cycle_Entries, overridepowerstrings, + MUIA_Cycle_Active, overridepower, + End, + End, + Child, HGroup, + Child, VGroup, + MUIA_ShortHelp, "This is a list of supported languages\n" + "for the USB device. It's not manadatory\n" + "and in fact cheap devices won't even use\n" + "any string descriptors in their firmware.", + Child, data->langlvobj = ListviewObject, + MUIA_FrameTitle, "Supported languages", + MUIA_Listview_List, ListObject, + ReadListFrame, + End, + End, + Child, HGroup, + Child, LabelB("Current language:"), + Child, TextObject, + TextFrame, + MUIA_Background, MUII_TextBack, + MUIA_Text_Contents, psdNumToStr(NTS_LANGID, devcurrlang, ""), + End, + End, + End, + Child, HGroup, + MUIA_ShortHelp, "USB devices are able to support\n" + "different configurations. However,\n" + "this is really rare.", + MUIA_FrameTitle, "Configurations", + Child, data->cfglvobj = FloattextObject, + ReadListFrame, + MUIA_Floattext_Text, textbuf3, + End, + End, + End, + Child, HGroup, + Child, ListviewObject, + MUIA_ShortHelp, "This is a list of so called interfaces\n" + "the device has. USB devices can be built\n" + "as compound, so that each interface has\n" + "different functions. Each interface can be\n" + "bound to a different class.", + MUIA_FrameTitle, "Interfaces", + MUIA_Listview_List, data->iflvobj = + NewObject(IconListClass->mcc_Class, 0, MUIA_ContextMenu, data->classpopup, InputListFrame, MUIA_List_MinLineHeight, 16, MUIA_List_Format, "BAR,BAR,BAR,BAR,BAR,BAR,", MUIA_List_Title, TRUE,MUIA_List_DisplayHook, &data->InterfaceDisplayHook, TAG_END), + End, + End, + Child, HGroup, + MUIA_Group_SameWidth, TRUE, + Child, data->clsscanobj = TextObject, + MUIA_ShortHelp, "Clicking on this button will start a class scan. This means that\n" + "each device will be examined if it matches some of the standard\n" + "classes in the system. In this case, a binding will be established\n" + "and the functionality will be added to the system automatically.", + ButtonFrame, + MUIA_Background, MUII_ButtonBack, + MUIA_CycleChain, 1, + MUIA_InputMode, MUIV_InputMode_RelVerify, + MUIA_Text_Contents, "\33c Class Scan ", + End, + Child, data->unbindobj = TextObject, + MUIA_ShortHelp, "Manually removes an interface binding. This can be\n" + "useful to temporarily deactivate a device.\n" + "Use 'Class Scan' to reactivate the binding.", + MUIA_Disabled, TRUE, + ButtonFrame, + MUIA_Background, MUII_ButtonBack, + MUIA_CycleChain, 1, + MUIA_InputMode, MUIV_InputMode_RelVerify, + MUIA_Text_Contents, "\33c Release Binding ", + End, + Child, data->cfgobj = TextObject, + MUIA_ShortHelp, "If there is an interface binding and the class\n" + "supports a configuration GUI. Clicking on this\n" + "button will open the interface preferences window.\n\n" + "Note well, that the corrsponding button for the\n" + "device binding settings can be found in the device\n" + "list window.", + MUIA_Disabled, TRUE, + ButtonFrame, + MUIA_Background, MUII_ButtonBack, + MUIA_CycleChain, 1, + MUIA_InputMode, MUIV_InputMode_RelVerify, + MUIA_Text_Contents, "\33c Settings ", + End, + End, + End; + psdFreeVec(textbuf1); + if(data->contents) + { + set(obj, MUIA_Window_IsSubWindow, FALSE); + set(obj, MUIA_Window_Title, devidstr); + get(obj, MUIA_Window_RootObject, &oldroot); + set(obj, MUIA_Window_RootObject, data->contents); + DoMethod(oldroot, OM_DISPOSE); + set(obj, MUIA_Window_ID, MAKE_ID('D','I','N','F')); + if(devlangarray) + { + UWORD *wptr = devlangarray; + while(*wptr) + { + DoMethod(data->langlvobj, MUIM_List_InsertSingle, + psdNumToStr(NTS_LANGID, (ULONG) *wptr++, ""), MUIV_List_Insert_Bottom); + } + } else { + DoMethod(data->langlvobj, MUIM_List_InsertSingle, "", MUIV_List_Insert_Bottom); + } + pc = cfgs->lh_Head; + while(pc->ln_Succ) + { + psdGetAttrs(PGA_CONFIG, pc, + CA_InterfaceList, &ifs, + TAG_END); + + pif = ifs->lh_Head; + while(pif->ln_Succ) + { + iflnode = AllocIfEntry(data, pif, FALSE); + if(iflnode) + { + DoMethod(data->iflvobj, MUIM_List_InsertSingle, iflnode, MUIV_List_Insert_Bottom); + } + psdGetAttrs(PGA_INTERFACE, pif, + IFA_AlternateIfList, &altiflist, + TAG_END); + altpif = altiflist->lh_Head; + while(altpif->ln_Succ) + { + iflnode = AllocIfEntry(data, altpif, TRUE); + if(iflnode) + { + DoMethod(data->iflvobj, MUIM_List_InsertSingle, iflnode, MUIV_List_Insert_Bottom); + } + + altpif = altpif->ln_Succ; + } + pif = pif->ln_Succ; + } + pc = pc->ln_Succ; + } + + DoMethod(data->clsscanobj, MUIM_Notify, MUIA_Pressed, FALSE, + obj, 1, MUIM_DevWin_Dev_Bind); + DoMethod(data->unbindobj, MUIM_Notify, MUIA_Pressed, FALSE, + obj, 1, MUIM_DevWin_If_Unbind); + DoMethod(data->cfgobj, MUIM_Notify, MUIA_Pressed, FALSE, + obj, 2, MUIM_DevWin_If_Config); + DoMethod(data->iflvobj, MUIM_Notify, MUIA_Listview_DoubleClick, TRUE, + obj, 1, MUIM_DevWin_If_Config); + DoMethod(data->iflvobj, MUIM_Notify, MUIA_List_Active, MUIV_EveryTime, + obj, 1, MUIM_DevWin_If_Activate); + DoMethod(data->iflvobj, MUIM_Notify, MUIA_ContextMenuTrigger, MUIV_EveryTime, + obj, 2, MUIM_DevWin_If_FBind, MUIV_TriggerValue); + DoMethod(data->cwnameobj, MUIM_Notify, MUIA_String_Acknowledge, MUIV_EveryTime, + obj, 1, MUIM_DevWin_SetCustomName); + DoMethod(data->changenameobj, MUIM_Notify, MUIA_Pressed, FALSE, + obj, 1, MUIM_DevWin_SetCustomName); + DoMethod(data->resetnameobj, MUIM_Notify, MUIA_Pressed, FALSE, + obj, 1, MUIM_DevWin_ResetCustomName); + DoMethod(data->dontpopupobj, MUIM_Notify, MUIA_Selected, MUIV_EveryTime, + obj, 1, MUIM_DevWin_PopupInhibitChg); + DoMethod(data->noclassbindobj, MUIM_Notify, MUIA_Selected, MUIV_EveryTime, + obj, 1, MUIM_DevWin_NoClassBindChg); + DoMethod(data->overridepowerobj, MUIM_Notify, MUIA_Cycle_Active, MUIV_EveryTime, + obj, 1, MUIM_DevWin_PowerInfoChg); + } else { + CoerceMethod(cl, obj, OM_DISPOSE); + return((IPTR) NULL); + } + } + return((IPTR) obj); + } + + case OM_DISPOSE: + { + struct IfListEntry *iflnode; + if(data->dlnode) + { + if(data->dlnode->infowindow) + { + data->dlnode->infowindow = NULL; + } + data->dlnode->devdata = NULL; + } + if(data->classpopup) + { + DoMethod(data->classpopup, OM_DISPOSE); + data->classpopup = NULL; + } + iflnode = (struct IfListEntry *) data->iflist.lh_Head; + while(iflnode->node.ln_Succ) + { + FreeIfEntry(data, iflnode); + iflnode = (struct IfListEntry *) data->iflist.lh_Head; + } + data->dlnode = NULL; + break; + } + + case MUIM_DevWin_Dev_Bind: + psdClassScan(); + DoMethod(obj, MUIM_DevWin_If_Activate); + DoMethod(data->iflvobj, MUIM_List_Redraw, MUIV_List_Redraw_All); + return(TRUE); + + case MUIM_DevWin_If_Activate: + { + APTR binding; + struct Node *puc; + IPTR hascfggui = FALSE; + struct Library *UsbClsBase; + struct IfListEntry *iflnode; + + DoMethod(data->iflvobj, MUIM_List_GetEntry, MUIV_List_GetEntry_Active, &iflnode); + if(iflnode) + { + psdGetAttrs(PGA_INTERFACE, iflnode->pif, + IFA_Binding, &binding, + IFA_BindingClass, &puc, + TAG_END); + set(data->unbindobj, MUIA_Disabled, !binding); + if(binding && puc) + { + psdGetAttrs(PGA_USBCLASS, puc, + UCA_ClassBase, &UsbClsBase, + TAG_END); + usbGetAttrs(UGA_CLASS, NULL, + UCCA_HasBindingCfgGUI, &hascfggui, + TAG_END); + set(data->cfgobj, MUIA_Disabled, !hascfggui); + } else { + set(data->cfgobj, MUIA_Disabled, TRUE); + } + set(data->iflvobj, MUIA_ContextMenu, data->classpopup); + } else { + set(data->unbindobj, MUIA_Disabled, TRUE); + set(data->cfgobj, MUIA_Disabled, TRUE); + set(data->iflvobj, MUIA_ContextMenu, NULL); + } + return(TRUE); + } + + case MUIM_DevWin_If_Unbind: + { + APTR binding; + struct IfListEntry *iflnode; + + DoMethod(data->iflvobj, MUIM_List_GetEntry, MUIV_List_GetEntry_Active, &iflnode); + if(iflnode) + { + psdGetAttrs(PGA_INTERFACE, iflnode->pif, + IFA_Binding, &binding, + TAG_END); + if(binding) + { + psdReleaseIfBinding(iflnode->pif); + set(data->unbindobj, MUIA_Disabled, TRUE); + set(data->cfgobj, MUIA_Disabled, TRUE); + DoMethod(data->iflvobj, MUIM_List_Redraw, MUIV_List_Redraw_All); + } + } + return(TRUE); + } + + case MUIM_DevWin_If_Config: + { + APTR binding; + struct Node *puc; + struct Library *UsbClsBase; + struct IfListEntry *iflnode; + + DoMethod(data->iflvobj, MUIM_List_GetEntry, MUIV_List_GetEntry_Active, &iflnode); + if(iflnode) + { + psdGetAttrs(PGA_INTERFACE, iflnode->pif, + IFA_Binding, &binding, + IFA_BindingClass, &puc, + TAG_END); + if(binding && puc) + { + psdGetAttrs(PGA_USBCLASS, puc, + UCA_ClassBase, &UsbClsBase, + TAG_END); + usbDoMethod(UCM_OpenBindingCfgWindow, binding); + } + } + return(TRUE); + } + + case MUIM_DevWin_If_FBind: + { + Object *mi = (Object *) (((IPTR *) msg)[1]); + STRPTR name = NULL; + STRPTR devid = NULL; + STRPTR ifid = NULL; + STRPTR devname = NULL; + BOOL clever; + struct IfListEntry *iflnode; + + DoMethod(data->iflvobj, MUIM_List_GetEntry, MUIV_List_GetEntry_Active, &iflnode); + if(iflnode) + { + get(mi, MUIA_Menuitem_Title, &name); + if(!strcmp(name, "None")) + { + name = NULL; + } + psdGetAttrs(PGA_DEVICE, data->pd, + DA_ProductName, &devname, + DA_IDString, &devid, + TAG_END); + psdGetAttrs(PGA_INTERFACE, iflnode->pif, + IFA_IDString, &ifid, + TAG_END); + if(name) + { + clever = MUI_RequestA(_app(obj), obj, 0, NULL, "I'm not dumb!|I'll reconsider", + "You are about to establish a forced \33binterface\33n\n" + "binding. As most people are not capable of reading the\n" + "manual and they cause more harm than good,\n" + "please make sure you know, what you're doing\n" + "and not breaking things (and then bugger me with\n" + "silly emails).", NULL); + if(!clever) + { + return(FALSE); + } + } + if(psdSetForcedBinding(name, devid, ifid)) + { + if(name) + { + psdAddErrorMsg(RETURN_OK, "Trident", "Forcing interface binding of %s to %s.", devname, name); + } else { + psdAddErrorMsg(RETURN_OK, "Trident", "Removed forced interface binding of %s.", devname); + } + } + } + + return(TRUE); + } + + case MUIM_DevWin_SetCustomName: + { + APTR pic; + STRPTR devidstr = NULL; + STRPTR oldname = NULL; + STRPTR newname; + STRPTR newnewname; + psdGetAttrs(PGA_DEVICE, data->pd, + DA_IDString, &devidstr, + DA_ProductName, &oldname, + TAG_END); + if(!devidstr) + { + return(FALSE); + } + get(data->cwnameobj, MUIA_String_Contents, &newname); + if(!(*newname)) + { + newname = "Empty"; + } + if(!strcmp(newname, oldname)) + { + return(FALSE); + } + pic = psdGetUsbDevCfg("Trident", devidstr, NULL); + if(!pic) + { + psdSetUsbDevCfg("Trident", devidstr, NULL, NULL); + pic = psdGetUsbDevCfg("Trident", devidstr, NULL); + } + if(pic) + { + if(psdAddStringChunk(pic, IFFCHNK_NAME, newname)) + { + psdAddErrorMsg(RETURN_OK, "Trident", "Set new custom name '%s'.", newname); + newnewname = psdCopyStr(newname); + if(newnewname) + { + psdSetAttrs(PGA_DEVICE, data->pd, + DA_ProductName, newnewname, + TAG_END); + psdFreeVec(oldname); + } + } + } + set(data->cwnameobj, MUIA_String_Contents, newname); + DoMethod(data->dlnode->adata->devlistobj, MUIM_List_Redraw, MUIV_List_Redraw_All); + return(TRUE); + } + + case MUIM_DevWin_ResetCustomName: + { + APTR pic; + STRPTR devidstr = NULL; + STRPTR oldname = NULL; + STRPTR origname = NULL; + STRPTR newname; + psdGetAttrs(PGA_DEVICE, data->pd, + DA_IDString, &devidstr, + DA_ProductName, &oldname, + DA_OrigProductName, &origname, + TAG_END); + if(!devidstr) + { + return(FALSE); + } + pic = psdGetUsbDevCfg("Trident", devidstr, NULL); + if(pic) + { + if(psdRemCfgChunk(pic, IFFCHNK_NAME)) + { + psdAddErrorMsg(RETURN_OK, "Trident", "Custom name '%s' removed.", oldname); + if(origname) + { + newname = psdCopyStr(origname); + if(newname) + { + psdSetAttrs(PGA_DEVICE, data->pd, + DA_ProductName, newname, + TAG_END); + psdFreeVec(oldname); + } + } + } + } + psdGetAttrs(PGA_DEVICE, data->pd, + DA_ProductName, &oldname, + TAG_END); + set(data->cwnameobj, MUIA_String_Contents, oldname); + DoMethod(data->dlnode->adata->devlistobj, MUIM_List_Redraw, MUIV_List_Redraw_All); + return(TRUE); + } + + case MUIM_DevWin_PopupInhibitChg: + case MUIM_DevWin_NoClassBindChg: + case MUIM_DevWin_PowerInfoChg: + { + IPTR dontpopup; + IPTR noclassbind; + IPTR overridepower; + get(data->dontpopupobj, MUIA_Selected, &dontpopup); + get(data->noclassbindobj, MUIA_Selected, &noclassbind); + get(data->overridepowerobj, MUIA_Cycle_Active, &overridepower); + + psdSetAttrs(PGA_DEVICE, data->pd, + DA_InhibitPopup, dontpopup, + DA_InhibitClassBind, noclassbind, + DA_OverridePowerInfo, overridepower, + TAG_END); + return(TRUE); + } + + } + return(DoSuperMethodA(cl,obj,msg)); + AROS_USERFUNC_EXIT +} +/* \\\ */ diff --git a/rom/usb/trident/DevWinClass.h b/rom/usb/trident/DevWinClass.h new file mode 100644 index 000000000..2b3127c98 --- /dev/null +++ b/rom/usb/trident/DevWinClass.h @@ -0,0 +1,69 @@ +/***************************************************************************** +** This is the DevWin custom class, a sub class of Window.mui. +******************************************************************************/ +#ifndef DEVWINCLASS_H +#define DEVWINCLASS_H + +#include "ActionClass.h" + +struct DevWinData +{ + struct Hook InterfaceDisplayHook; + struct DevListEntry *dlnode; + //struct ActionData *adata; + struct Node *pd; + Object *contents; + //Object *infowindow; + Object *classpopup; + Object *cwnameobj; + Object *changenameobj; + Object *resetnameobj; + Object *langlvobj; + Object *cfglvobj; + Object *iflvobj; + Object *clsscanobj; + Object *unbindobj; + Object *cfgobj; + Object *dontpopupobj; + Object *noclassbindobj; + Object *overridepowerobj; + struct List iflist; +}; + +struct IfListEntry +{ + struct Node node; + Object *infowindow; + Object *classpopup; + struct Node *pif; + char buf[128]; +}; + + +#define TAGBASE_DevWin (TAG_USER | 342<<16) +#define MUIA_DevWin_DevEntry (TAGBASE_DevWin | 0x0001) +#define MUIM_DevWin_Dev_Bind (TAGBASE_DevWin | 0x0021) +#define MUIM_DevWin_If_Activate (TAGBASE_DevWin | 0x0028) +#define MUIM_DevWin_If_Unbind (TAGBASE_DevWin | 0x0029) +#define MUIM_DevWin_If_Config (TAGBASE_DevWin | 0x002a) +#define MUIM_DevWin_If_FBind (TAGBASE_DevWin | 0x002b) +#define MUIM_DevWin_SetCustomName (TAGBASE_DevWin | 0x0030) +#define MUIM_DevWin_ResetCustomName (TAGBASE_DevWin | 0x0031) +#define MUIM_DevWin_PopupInhibitChg (TAGBASE_DevWin | 0x0040) +#define MUIM_DevWin_NoClassBindChg (TAGBASE_DevWin | 0x0041) +#define MUIM_DevWin_PowerInfoChg (TAGBASE_DevWin | 0x0042) + +struct IfListEntry * AllocIfEntry(struct DevWinData *data, struct Node *pif, BOOL intend); +void FreeIfEntry(struct DevWinData *data, struct IfListEntry *iflnode); + +AROS_UFP3(LONG, InterfaceListDisplayHook, + AROS_UFPA(struct Hook *, hook, A0), + AROS_UFPA(char **, strarr, A2), + AROS_UFPA(struct IfListEntry *, iflnode, A1)); + +AROS_UFP3(IPTR, DevWinDispatcher, + AROS_UFPA(struct IClass *, cl, A0), + AROS_UFPA(Object *, obj, A2), + AROS_UFPA(Msg, msg, A1)); + +#endif diff --git a/rom/usb/trident/IconListClass.c b/rom/usb/trident/IconListClass.c new file mode 100644 index 000000000..8325057da --- /dev/null +++ b/rom/usb/trident/IconListClass.c @@ -0,0 +1,212 @@ + +/***************************************************************************** +** This is the IconList custom class, a sub class of List.mui. +******************************************************************************/ + +#include "debug.h" + +#define USE_INLINE_STDARG +#define __NOLIBBASE__ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Trident.h" +#include "ActionClass.h" +#include "IconListClass.h" +#include "DevWinClass.h" +#include "CfgListClass.h" + +extern struct ExecBase *SysBase; +extern struct Library *ps; +/*extern struct Library *UtilityBase; */ + +#define NewList(list) NEWLIST(list) + +/* /// "Icon data stuff" */ +const ULONG Mason_colors[96] = +{ + 0x96969696,0x96969696,0x96969696, + 0x2d2d2d2d,0x28282828,0x9e9e9e9e, + 0x00000000,0x65656565,0x9a9a9a9a, + 0x35353535,0x75757575,0xaaaaaaaa, + 0x65656565,0x8a8a8a8a,0xbabababa, + 0x0c0c0c0c,0x61616161,0xffffffff, + 0x24242424,0x5d5d5d5d,0x24242424, + 0x35353535,0x8a8a8a8a,0x35353535, + 0x86868686,0xb2b2b2b2,0x3d3d3d3d, + 0x0c0c0c0c,0xe3e3e3e3,0x00000000, + 0x4d4d4d4d,0x9e9e9e9e,0x8e8e8e8e, + 0x82828282,0x00000000,0x00000000, + 0xdfdfdfdf,0x35353535,0x35353535, + 0xdbdbdbdb,0x65656565,0x39393939, + 0xdbdbdbdb,0x8e8e8e8e,0x41414141, + 0xdfdfdfdf,0xbabababa,0x45454545, + 0xefefefef,0xe7e7e7e7,0x14141414, + 0x82828282,0x61616161,0x4d4d4d4d, + 0xa6a6a6a6,0x7e7e7e7e,0x61616161, + 0xcacacaca,0x9a9a9a9a,0x75757575, + 0x9a9a9a9a,0x55555555,0xaaaaaaaa, + 0xffffffff,0x00000000,0xffffffff, + 0xffffffff,0xffffffff,0xffffffff, + 0xdfdfdfdf,0xdfdfdfdf,0xdfdfdfdf, + 0xcacacaca,0xcacacaca,0xcacacaca, + 0xbabababa,0xbabababa,0xbabababa, + 0xaaaaaaaa,0xaaaaaaaa,0xaaaaaaaa, + 0x8a8a8a8a,0x8a8a8a8a,0x8a8a8a8a, + 0x65656565,0x65656565,0x65656565, + 0x4d4d4d4d,0x4d4d4d4d,0x4d4d4d4d, + 0x3c3c3c3c,0x3c3c3c3c,0x3b3b3b3b, + 0x00000000,0x00000000,0x00000000, +}; + +#define USE_CLASSES_BODY +#define USE_DEVICES_BODY +#define USE_GENERAL_BODY +#define USE_HARDWARE_BODY +#define USE_SETTINGS_BODY +#define USE_CLASS_NONE_BODY +#define USE_CLASS_AUDIO_BODY +#define USE_CLASS_CDCCONTROL_BODY +#define USE_CLASS_CDCDATA_BODY +#define USE_CLASS_CHIPSMARTCARD_BODY +#define USE_CLASS_COMMDEVICE_BODY +#define USE_CLASS_HID_BODY +#define USE_CLASS_HUB_BODY +#define USE_CLASS_MASSSTORAGE_BODY +#define USE_CLASS_PHYSICAL_BODY +#define USE_CLASS_PRINTER_BODY +#define USE_CLASS_SECURITY_BODY +#define USE_CLASS_VENDOR_BODY +#define USE_GREENLED_BODY +#define USE_ORANGELED_BODY +#define USE_ORANGELEDQ_BODY +#define USE_CLASS_BLUETOOTH_BODY +#define USE_CLASS_STILLIMAGE_BODY +#define USE_ONLINE_BODY +#define USE_POPUP_BODY + +#include "MasonIcons/MI_Classes.c" +#include "MasonIcons/MI_Devices.c" +#include "MasonIcons/MI_General.c" +#include "MasonIcons/MI_Hardware.c" +#include "MasonIcons/MI_Settings.c" +#include "MasonIcons/MI_Class_None.c" +#include "MasonIcons/MI_Class_Audio.c" +#include "MasonIcons/MI_Class_CDCControl.c" +#include "MasonIcons/MI_Class_CDCData.c" +#include "MasonIcons/MI_Class_ChipSmartCard.c" +#include "MasonIcons/MI_Class_CommDevice.c" +#include "MasonIcons/MI_Class_HID.c" +#include "MasonIcons/MI_Class_Hub.c" +#include "MasonIcons/MI_Class_MassStorage.c" +#include "MasonIcons/MI_Class_Physical.c" +#include "MasonIcons/MI_Class_Printer.c" +#include "MasonIcons/MI_Class_Security.c" +#include "MasonIcons/MI_Class_Vendor.c" +#include "MasonIcons/MI_GreenLED.c" +#include "MasonIcons/MI_OrangeLED.c" +#include "MasonIcons/MI_OrangeLEDQ.c" +#include "MasonIcons/MI_Class_Bluetooth.c" +#include "MasonIcons/MI_Class_StillImage.c" +#include "MasonIcons/MI_Online.c" +#include "MasonIcons/MI_Popup.c" + +static const UBYTE *mibodies[MAXMASONICONS] = +{ + General_body, + Hardware_body, + Devices_body, + Classes_body, + Settings_body, + Class_None_body, + Class_Audio_body, + Class_CommDevice_body, + Class_CDCControl_body, + Class_HID_body, + Class_Physical_body, + Class_Printer_body, + Class_MassStorage_body, + Class_Hub_body, + Class_CDCData_body, + Class_ChipSmartCard_body, + Class_Security_body, + Class_Vendor_body, + GreenLED_body, + OrangeLED_body, + OrangeLEDQ_body, + Class_Bluetooth_body, + Class_StillImage_body, + Online_body, + Popup_body +}; +/* \\\ */ + +/* /// "IconListDispatcher()" */ +AROS_UFH3(IPTR, IconListDispatcher, + AROS_UFHA(struct IClass *, cl, A0), + AROS_UFHA(Object *, obj, A2), + AROS_UFHA(Msg, msg, A1)) +{ + AROS_USERFUNC_INIT + // There should never be an uninitialized pointer, but just in case, try to get an mungwall hit if so. + struct IconListData *data = (struct IconListData *) 0xABADCAFE; + + // on OM_NEW the obj pointer will be void, so don't try to get the data base in this case. + if(msg->MethodID != OM_NEW) data = INST_DATA(cl,obj); + + switch(msg->MethodID) + { + case OM_NEW: + if(!(obj = (Object *) DoSuperMethodA(cl,obj,msg))) + return(0); + return((IPTR) obj); + + case MUIM_Setup: + { + ULONG cnt; + for(cnt = 0; cnt < MAXMASONICONS; cnt++) + { + data->mimainbody[cnt] = BodychunkObject, + MUIA_Bitmap_SourceColors, Mason_colors, + MUIA_FixWidth, 16, + MUIA_FixHeight, 16, + MUIA_Bitmap_Width, 16, + MUIA_Bitmap_Height, 16, + MUIA_Bodychunk_Depth, 5, + MUIA_Bodychunk_Body, mibodies[cnt], + MUIA_Bodychunk_Compression, 1, + MUIA_Bodychunk_Masking, 2, + MUIA_Bitmap_Transparent, 0, + MUIA_Bitmap_UseFriend, TRUE, + MUIA_Bitmap_Precision, PRECISION_ICON, + End; + data->mimainlist[cnt] = (Object *) DoMethod(obj, MUIM_List_CreateImage, data->mimainbody[cnt], 0); + } + } + break; + + case MUIM_Cleanup: + { + ULONG cnt; + for(cnt = 0; cnt < MAXMASONICONS; cnt++) + { + DoMethod(obj, MUIM_List_DeleteImage, data->mimainlist[cnt]); + DoMethod(data->mimainbody[cnt], OM_DISPOSE); + data->mimainlist[cnt] = NULL; + data->mimainbody[cnt] = NULL; + } + } + break; + + } + return(DoSuperMethodA(cl,obj,msg)); + AROS_USERFUNC_EXIT +} +/* \\\ */ diff --git a/rom/usb/trident/IconListClass.h b/rom/usb/trident/IconListClass.h new file mode 100644 index 000000000..8832e2e24 --- /dev/null +++ b/rom/usb/trident/IconListClass.h @@ -0,0 +1,23 @@ +/***************************************************************************** +** This is the IconList custom class, a sub class of List.mui. +******************************************************************************/ + +#ifndef ICONLISTCLASS_H +#define ICONLISTCLASS_H + +#define MAXMASONICONS 25 + +struct IconListData +{ + Object *mimainlist[MAXMASONICONS]; + Object *mimainbody[MAXMASONICONS]; +}; + +#define TAGBASE_IconList (TAG_USER | 25<<16) + +AROS_UFP3(IPTR, IconListDispatcher, + AROS_UFPA(struct IClass *, cl, A0), + AROS_UFPA(Object *, obj, A2), + AROS_UFPA(Msg, msg, A1)); + +#endif diff --git a/rom/usb/trident/MasonIcons/Class_Audio b/rom/usb/trident/MasonIcons/Class_Audio new file mode 100644 index 0000000000000000000000000000000000000000..9b965b4e86df0534b08b4c90f66d75b51671399f GIT binary patch literal 422 zcwQ~fze_?<6bJD0)%=kOIXH+G7&x><(;Ff!d}=0mQH02bAcqGA4K9zOK*gcq4dUb= zAx#l)il%rpH2Wv$@PwitQw|MpkZ1Rb_k6hLa1Y#b??Iu&h|tgFWhS%3G!X?Uz@toI zmjg}SgEQ(Vr&zMcduQElcWbjxN>5UCMKk=BS?n|>Y0~X;!v9XJ-)<3^k~C6wM(w0& zWPZPbtqOanR|Y+`ccjl~#+PZDgTcTs3|-eXO;Z$wF&2;S@&VaWQs!xiyyQ(KSyt3V zSAf#RTy%a8f?PL}RAJmS2D;2Mr?;qnu?4L94mSmHy6F^$k}0E*;Q}q_(9%C4e(!xBKJWYR4$r%`xurz#);G$ktg0&_ zk`qg}t|>wDVJ7jFl6s|$DQQb8s`Og#yPZyF?nzf%-`NjbFU-~^v+rje&-r@3l>IHL zd)5|-9cSde7@d{kaP|Lfu3b|`pe^!Ghl8`Qs%KBs6< z{m!EuK8!JwquFC=nM#BaX=g+J z6CTtl>QJ9*hN{oYZDfpGAi0Dy1>_q04*MzgUs{J0PkA<^@s`F7dqZ|Drh7E|T5=D% C!fsyx literal 0 HcwPel00001 diff --git a/rom/usb/trident/MasonIcons/Class_CDCControl b/rom/usb/trident/MasonIcons/Class_CDCControl new file mode 100644 index 0000000000000000000000000000000000000000..1b86b0d42de869729ca4eeac587d2163a840b2bb GIT binary patch literal 404 zcwS|WF-yZx6ov0enkGmH9XdFObm-vXm_e*V(rB&tXo%QWtzd`zgo2Yu2ZtaXJ9H>r z6pUKINrJy1zd-1a!NE;C2)f1hf?MDD;2z$&ocDGb9wWkaecxs_+jWSjNCmDo9Vikm zc?P*8wX4i>d3H7&4%gSln<3XP&G0mC3F&kJ(wEgu_ z?04DiMK>PxMu%ZaDL+Y)#Bm%&Q5c3n5cs~&7^_q^`2#i2viZo7Mq1TkHQ`;QK#p54 zW%nT14d;maH(s_NkOpX=Irt)nJV?L7NO?~Bh#MKJE?!kZOF`=%x{Hn~z#ZftQK4ou zAx}k}WC-XR3U49gbiv6n_VTDqaBc{uOL%Hxd4d;1AbU_hMU#>70J#GyfK~+Hf1C60 He=h0|%b#t_ literal 0 HcwPel00001 diff --git a/rom/usb/trident/MasonIcons/Class_CDCData b/rom/usb/trident/MasonIcons/Class_CDCData new file mode 100644 index 0000000000000000000000000000000000000000..b5e97402e2a5df71aee4028f169b4270d9baff35 GIT binary patch literal 406 zcwS|Wze@sP7{{NlB}fQ5=o(izgb=kHlquYuni;)#NP-Q;Ib4I&4Y@SLi$lW=ZaFwu zQ^QRWwA}R0H#g;QLPKMJ!u7t==JWl)^W}MXew=o?j0ltVg~cp()*zw+<)!*`n@)kt z9yYX8zs^is_MGW-y1zFkccza5*AKIUq;y@jeoVGU7Onq9_c*AP9WlcU_k;R;`}M1Ff!U$+Srs%G6EPQr=GIsbROZ zRUHJY)3}oUODMmxls$-hh4G2vCCU!Oo#M&C%~B1C zrNZFwIC2DgMbkh>D5DV^Liq#aqId+SrqG7i3Q#*2z{z#zgP0E7_?x~xo$4L~_YW(B4QXJ5wvpj^VVY14Ey z<}swsGA&(|+O>-(@xMx}ifNZ=+a_C{#|*yn`kELR?wgw4PPM$<=XigY>-*;-O^LqC z>Jm@QDxDR&>OaGOAh>`3{;5-^cJ11=YSpT)uCCP7R9|0T8yjn&1@1wPPC$x#13E;U~mcWQ~--JGB7&%yF>!nFM)KxzzR7`fJf7;r9-A^!vDF)+;l E0GWGwE&u=k literal 0 HcwPel00001 diff --git a/rom/usb/trident/MasonIcons/Class_CommDevice b/rom/usb/trident/MasonIcons/Class_CommDevice new file mode 100644 index 0000000000000000000000000000000000000000..312d39a81995396cf15efbd0248e87b2ba2460f7 GIT binary patch literal 398 zcwUW-FH8b)6vy8e#W6-8kSq`g7UOL?(c_L&VDmR_Og9YvAzZOKDj)&33p5EAusFj7 z-P|lUH~Te%iEzQ-MzJAt$j`@3y1(yld!P5dZ{N39sR|-=%lo>}Madwd6eU?T%10w; zvxlWjq*f4`$=+GN-(O!FkmV>1*Rs7tU1pE7imh}Xw-fIq2E7hZpeRFYbJ)`YZ};;f z)v1fSX5Duh&Y>$w@(Y5%_kGXvT-UX2+p;VnL@u|*2Z~iq=dw&OiWM|boU<8Cl3|uJ z;T#0LVjMBQa@fBF)R5jlnvj`5ogi&MJ%Cz5{u!+)c3d>?(Y(dw3FHi>hlg*_%AEPX z#c?x5YxdX5Rh*CU67pya_X>2uEG0%?xQ@?Fx!66GP=7*`?e-Je;GD4GI3`-uh3FR- C(VrOr literal 0 HcwPel00001 diff --git a/rom/usb/trident/MasonIcons/Class_HID b/rom/usb/trident/MasonIcons/Class_HID new file mode 100644 index 0000000000000000000000000000000000000000..ed817b7edacdfd3af30982e35157a9bb3d15679b GIT binary patch literal 412 zcwS|WJxD@P6vxlsk2HFqkV8{CIJ87d5Bf07k20Z)B1JX?Iy{^sgj(`rXn2TINEk>h z4R36GLpeJI(PZ!psiw%$z`ETVHFf_#I6v-zbIy7y!-#O2+>Ej)+lUj9kGvvTsyS^a ziyrI&TQI?i{R#pbrbiHm1hR;SZ3P17(8UDq{DV~mAD%VI$y6N!rAAUC;V5tfjic6uqE zP6mGdL5QZ}yTUCo>|bCjV`3F{g3^Yk4gUrF1NeIgco80e5srG2u_=^>$S61%N@@=9 z5r#qVFDYb`^0JS@5QPt%Il(_sxdfh3>Ep(aTaNPw+&v<94?f2^wwl;E#DWVYE?IiQ j{2M&e2y@B!B;0+tM(}WnU6IfL_K`#g4aDic^)K`d<)n>| literal 0 HcwPel00001 diff --git a/rom/usb/trident/MasonIcons/Class_Hub b/rom/usb/trident/MasonIcons/Class_Hub new file mode 100644 index 0000000000000000000000000000000000000000..9208bd2121ffcfb73a3b0c02eaf01b8ad846d341 GIT binary patch literal 400 zcwUW;u}cC`9LIlO%Wx2Mu(3|U!6ljwicG!pN`)SZr0HN}aDReRkl`S4gQLR*wnW1X z4MEGJzu@LJ!5bPHTP4cZyGQN4@8kWxzu)KaeebB&U_`j79-GW$6^n>cl$2`IT{MDg z$*_`+v`fsWOLjh)Ot!OAvR%FJ*$$8QM5de39ewn45Pu^!9S?~DU7y)|v#}BI!;kmW zu*V**dcNCto1P#cR}cig?{m&Q&vP8dwr$2(F1IfqC^rmKmQ{*TtYolq=_!(fRl$LS|%E%b7C zTw&poqoBHGD?Gb%v8C88tg?av1A+Bccxz*h3q^MXv~QK7Xz>|Es2J5sQ&`Hs{nkJI E0Bll?&;S4c literal 0 HcwPel00001 diff --git a/rom/usb/trident/MasonIcons/Class_MassStorage b/rom/usb/trident/MasonIcons/Class_MassStorage new file mode 100644 index 0000000000000000000000000000000000000000..cb2b882540554a76df24edbac72ef7c7b75bef6b GIT binary patch literal 404 zcwS{sze@sf6n~#9!$HD8T6J&;B564&vaUO?ROpK$1v(Tt9P|$ewdmK8SUj4I)PrhuY?_DLdBQ z=P1%Bv%6~9?o>KQrbiwx$8l`iwk*puO~WuWO=FBDlUsa2x*#jO%~OzqDVe2xo)3gc z&1YkiIS5KlEph(N!)5>!5#2zP5F0}pBdS6=gp|SV6KX%$F;Tro^%nILcrMN?+w{unQQ<6 literal 0 HcwPel00001 diff --git a/rom/usb/trident/MasonIcons/Class_None b/rom/usb/trident/MasonIcons/Class_None new file mode 100644 index 0000000000000000000000000000000000000000..30140a701ac14a426317ceff574fce53b31fd32c GIT binary patch literal 422 zcwR+MJxIe~5WUyfTCmkt1Um>8Euw=zOF*%rsnuHWqfro4DA*w&4sI@DV{M^I5GSe9 zp*V;`7D1eXxF`yp#6bjy2nvD-Iyg8;;+HPoJ$Uc#aU5?lHOq)lNlwRDj7`OfsD%Q& z=gD%rkmDYNuxoytNiz4AN~Kb7cZHO)xTY(b;mg>ObVSs|;@ODrg;-@TPh^VXlQQ(Q zCz-~?=UYoY!%oypwY*lI(`~YOnWkB-Rt>|@bzRdmMNt@I(daOLkeHQXoa)F+-f@W~ z94)&86ql3X+8%^hD!#z=J3L3AC7V$H?7%;U0M}n=|3YX0JpnY!Xj{hU4?1@c{D889 zp>wDkNL*vJ140qQ7uZmdxWU~%+z-gU!%|VmL%#*w$gab(?E>UexcZ^q+cvfY93OxV zu(`sgoPe2L;_Gzw{CyZ9Zhwh=K9xx``|n-(Mwg6j_Yb}?!p+=$j!G<_p9i1uHE VqG&jT|Ix|O^y5Hy=HS_C{0AREguws+ literal 0 HcwPel00001 diff --git a/rom/usb/trident/MasonIcons/Class_Physical b/rom/usb/trident/MasonIcons/Class_Physical new file mode 100644 index 0000000000000000000000000000000000000000..9223b785f2e9e930c3c82a7d7a36e59f15ebaa23 GIT binary patch literal 406 zcwS}BKS;ws6bA73^^eU^q(j{#MCc#|#|&bHCT*<+kA`Ax1(kNl(#gRt4iY*zWa!oo z9jc3h5gi2wdpMx zgT*t%l~}vPG=pcI@p!zoIVE$V_8rr9)7>z4np17{`eir$No+bC5Cy6_Gq-0$EpRK} zU)e#I-CuS6Nq^FGLJIi_g24BE*L5Aov2EKlO~zQEu)`myHZ+~L1W6>7G*%U}k<3up zs43As2ztGI%;yijY^lKW4T4NiBDRGa3%7(K!6P(#ARqa2c$Y%)9czckci>$JqYlpI zP%L3F{5W3$b5b;ld}}#UUGbO$n_eT8~H@I7tb3K>U~ghEkCu;29)= NRwD~eg#UfH=nqd)chUd= literal 0 HcwPel00001 diff --git a/rom/usb/trident/MasonIcons/Class_Printer b/rom/usb/trident/MasonIcons/Class_Printer new file mode 100644 index 0000000000000000000000000000000000000000..2251fb8f0814c1f87d719c0c089ba6c5f4f9da4f GIT binary patch literal 422 zcwQZkze`(D6vxl!#%REl1c{J})KH{|pa|s+QcHfAs)1e%Vnv5iGdyhn0N0vY=YBw(Dh^L@5T_P8)IoE-FZX=7=leb1;oLj7xTHmBRbG~KNiUQ| zBqM2CtMWUpsN0NKPOZ-BV%28rjYeZ)tR-&K+4Nm6NY>2g>ruyZKK**0ycFHq*%k>M z=iHq>-zkQ{i$7PH?VA4fzSeGTHedNhj6Go(w%hF>2z=l7JkNDqt@X^zGrM4ZsaUeD zM-q~lE$aD5SL10ZS1Y;h9HF#WUbFfdsUu&z_d0R`Id}_JXW<5wK>4VBq?cHSOfT^j z;>%aCwh|Uaa}ReCX|jdV}jxC|R&9mXA=` zz_kNPE3JfaT*k#7ltZg_ZV=nE=vw7nKN#-HD6Ammwtj=t42t~OPYb3ENVo6@I9u{N LExF$yHn@HPS23L@ literal 0 HcwPel00001 diff --git a/rom/usb/trident/MasonIcons/Class_StillImage b/rom/usb/trident/MasonIcons/Class_StillImage new file mode 100644 index 0000000000000000000000000000000000000000..40d10868a30cf711efe892c279daebf2563900e3 GIT binary patch literal 400 zcwQ}!IY2b%GmFcN2q*IkDpT29iiiT#EnJwF zAfm5B>STh=3gIDiQ<5c?M7?ep#!%#vw33oBHQn;3d3Y_X=t|*s%KuL6@+?Q>D9W2Q z{&tpdtm&_hKrYS7*|c5ClvYemT$tlHwryLMWtyh0>zbx9#$vHau|Qo+t%~%CXarFY zCq!eCT@|S(Oc1g^lEE7UPce3g_%`C7$gg8Qh&u371+U`Vhn5B!K+^?xF|dhZ0kwAU zFG<;po_jP}(R=`Zz-S)14Y=QEioh8b1I!5oSkn#uIJ>y~@ rdsVnxa%JGLh=Uz5M-u8p=pB9ih;vEXFxtA%T7i#CP!Wjd{xban4O^H8 literal 0 HcwPel00001 diff --git a/rom/usb/trident/MasonIcons/Class_Vendor b/rom/usb/trident/MasonIcons/Class_Vendor new file mode 100644 index 0000000000000000000000000000000000000000..721e1f70cfd08b09c31c30b1ec0c409dbf7433a6 GIT binary patch literal 418 zcwRM6IY|HogD4*0kz&C@M2kRBNfrx>MJ!XK zkQ8FESc%nEse?%Rh%1O#SZHY>i9bQ-4a|Ep%o}EQX;}cwMi;^&EaoEsJZO1HDPLorNk@!Tm7n`p5IL=uMk(4XMnA$C2hQP8M3XJ z&v(yRT->DMg=`|bYF1E@VcT}0P_Qh^G)==WG))si`2Caez}#{uEK5CHa7~BAT$RTf zS`djvdux4y;ibri~d%!ku2pj~xU;rEd*TBUZPk~K3_jT?_sq++E z$#X1EH<->d8DwXWeL-&PRe1=W{Yy=8jO**rm4nT-#0m+5|_^PbKpGRelDYD&VSeC4nH1HVB5 BavuNy literal 0 HcwPel00001 diff --git a/rom/usb/trident/MasonIcons/Classes b/rom/usb/trident/MasonIcons/Classes new file mode 100644 index 0000000000000000000000000000000000000000..ff72f2e00f5ea01a934b7e073015974617ef9574 GIT binary patch literal 418 zcwRNmJ4gdT5C-7+&qt0Vg@uJ$ge!8!w>BpRqvrBb!6hN_{Y;8$tSq9HXt1!jB4v;i zDHRR`v68E-gO!bi;DLgcT8M>(=kB39AI$6yv%8sWo)MuwzmQ-FHkTrzPU_&1rb3&9 z3h$vskyevT&+%TdR;vy7HOQ!I`<7wa!IB%^3TvizdOa0x1(G7jXOM5;i@UNbL;ZsKgC2q+34ucdj!>?6bLuD5 zZ>&ooPxJ}VXJr1ju`;Ip&`pqE7~jCm1>(J+h%j}48542;Uw3y9#}A-o(2B5Fz|JL< r5fn#-{sBbp(Y1+*Z6P#-?mM*aA#^DCuFyUP+`{)E@B+8|cV7Ml{>p2m literal 0 HcwPel00001 diff --git a/rom/usb/trident/MasonIcons/Devices b/rom/usb/trident/MasonIcons/Devices new file mode 100644 index 0000000000000000000000000000000000000000..93d498de83ae4d327e1711840048b820713282c8 GIT binary patch literal 424 zcwQZkKS)AR6voeInqpxN5tKy{4h^*wkBVoRe=37+PlBL^{y4nZB_V<|8VVkvn~;Pw zHN2r9qTvP6?9?9dgdl?;w+N~Gy0?2i?)T$-=W@6U+A1T$#nN(|#aSvzMBNk=HBWOM z7Y;>+wjtMgg2mDz+bNgJVYqgqXS*B?khN0^^V=NL;#e&7vSX`K!eB?{S*rMdL zCrHWk($Ie>(U65d48a9lk?(2kH(%{f7Su>bnFnmx_Q!k(!b)`G`gy-f_JBpuy2c zD9xhFk5i5k$F2+6JhDBwYN5%|`9sm?A|ECjVBM*|q-UXO~havTC@x>_KX+QJdzlCvDmT ziX0|Nj-x~zG)G0sVYY~agM*aY_|3lesqgo_cX)kc@fk*hqwz_Z$!si2MD9FNX(|AmSp(6UYN6dkHF2;6|W5iHTQ4u27K4+weD`hdnWEM1^Y!0q4R~6xD?o!f*v{Jr2SGnm!=8A!iZEqILj&6Cod(s~rOG@b)0shhW&D UavxPMP7wc}Ls^l-!v_*Bq4k3bA%-Zn z4rdYo*$nW)X|YFpOrisq4C?X{xHqvP>zB#pc)nDVyG4;{yXn zAX^r}V4EW-7*Sxm!q_f?(-==6kb`p_vu6mqAberF1EGtO0|^J#bOag*++aI{!~ibd zF==w1Y*1`?{z1Nnyoqx=6g#4ih+2r6xbNH64hj|uCXWBo2VDM38z;E!p={!AkTWVF sZlc`fR~TLup>M>y2zxoc2!_89>L3{7xDPS(!had=aO`ac`>#KL0mQC*^#A|> literal 0 HcwPel00001 diff --git a/rom/usb/trident/MasonIcons/Hardware b/rom/usb/trident/MasonIcons/Hardware new file mode 100644 index 0000000000000000000000000000000000000000..724f7e473f46d9888a4d64b183aa06907b446631 GIT binary patch literal 420 zcwR-1F-t;G6oAjs1Oo>Hn{{w#acFo$WW;-FCUjAxhcyH_Jffk|%~B+U-r!K+AmLc_ z+8UDHP&5ej_9ll5H8}bQ>fO$H2;Tc~&-w1ToXgoMR|Npxmi7!`h}}E@Bp^<^0GUV# z+f>7FDs+$&dWCAo{eC~QHUw*+H5|)!V|A52N^7>(ecFosfEe~V08-N?*2bi#OSdqa zCOUO-cTx8Sje+SXP_(3!p69u)>o|^W+m>YsA+p&``k+|V4GK#Tg=kI}Mb0acIOHp( zRB(@gMmc{-`IMT?H@1FJ`9vV2b-X^o8z0Xk^HIR(*+M@}^k@7UB{MOx8|b-YF0b%S zEp)sx*JhX*H}G|Y>YGc=B)%-8nzB+(yq}_f&q{3}iE0%e73+SIwT&w11YyQ`z^@u> W>yIWvvxY6jQ_xA(ZJ(e?f(ZYTQk{kX literal 0 HcwPel00001 diff --git a/rom/usb/trident/MasonIcons/MI_Class_Audio.c b/rom/usb/trident/MasonIcons/MI_Class_Audio.c new file mode 100644 index 000000000..5efbd0f3b --- /dev/null +++ b/rom/usb/trident/MasonIcons/MI_Class_Audio.c @@ -0,0 +1,68 @@ +#ifdef USE_CLASS_AUDIO_COLORS +const ULONG Class_Audio_colors[96] = +{ + 0x96969696,0x96969696,0x96969696, + 0x2d2d2d2d,0x28282828,0x9e9e9e9e, + 0x00000000,0x65656565,0x9a9a9a9a, + 0x35353535,0x75757575,0xaaaaaaaa, + 0x65656565,0x8a8a8a8a,0xbabababa, + 0x0c0c0c0c,0x61616161,0xffffffff, + 0x24242424,0x5d5d5d5d,0x24242424, + 0x35353535,0x8a8a8a8a,0x35353535, + 0x86868686,0xb2b2b2b2,0x3d3d3d3d, + 0x0c0c0c0c,0xe3e3e3e3,0x00000000, + 0x4d4d4d4d,0x9e9e9e9e,0x8e8e8e8e, + 0x82828282,0x00000000,0x00000000, + 0xdfdfdfdf,0x35353535,0x35353535, + 0xdbdbdbdb,0x65656565,0x39393939, + 0xdbdbdbdb,0x8e8e8e8e,0x41414141, + 0xdfdfdfdf,0xbabababa,0x45454545, + 0xefefefef,0xe7e7e7e7,0x14141414, + 0x82828282,0x61616161,0x4d4d4d4d, + 0xa6a6a6a6,0x7e7e7e7e,0x61616161, + 0xcacacaca,0x9a9a9a9a,0x75757575, + 0x9a9a9a9a,0x55555555,0xaaaaaaaa, + 0xffffffff,0x00000000,0xffffffff, + 0xffffffff,0xffffffff,0xffffffff, + 0xdfdfdfdf,0xdfdfdfdf,0xdfdfdfdf, + 0xcacacaca,0xcacacaca,0xcacacaca, + 0xbabababa,0xbabababa,0xbabababa, + 0xaaaaaaaa,0xaaaaaaaa,0xaaaaaaaa, + 0x8a8a8a8a,0x8a8a8a8a,0x8a8a8a8a, + 0x65656565,0x65656565,0x65656565, + 0x4d4d4d4d,0x4d4d4d4d,0x4d4d4d4d, + 0x3c3c3c3c,0x3c3c3c3c,0x3b3b3b3b, + 0x00000000,0x00000000,0x00000000, +}; +#endif + +#define CLASS_AUDIO_WIDTH 16 +#define CLASS_AUDIO_HEIGHT 16 +#define CLASS_AUDIO_DEPTH 5 +#define CLASS_AUDIO_COMPRESSION 1 +#define CLASS_AUDIO_MASKING 2 + +#ifdef USE_CLASS_AUDIO_HEADER +const struct BitMapHeader Class_Audio_header = +{ 16,16,88,26,5,2,1,0,0,1,1,800,600 }; +#endif + +#ifdef USE_CLASS_AUDIO_BODY +const UBYTE Class_Audio_body[233] = { +0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0x01,0x00,0xa0,0x01,0x00, +0x90,0xff,0x00,0x01,0x00,0xf0,0x01,0x00,0xf0,0x01,0x01,0xb0,0x01,0x01,0xe8, +0x01,0x00,0xf0,0x01,0x01,0x78,0x01,0x01,0xf8,0x01,0x03,0xf8,0x01,0x02,0xfc, +0x01,0x00,0x70,0x01,0x03,0xfc,0x01,0x03,0xfc,0x01,0x06,0x68,0x01,0x07,0xfe, +0x01,0x00,0xf8,0x01,0x07,0xfe,0x01,0x07,0xfe,0x01,0x09,0xf4,0x01,0x0a,0xfe, +0x01,0x05,0xf8,0x01,0x0f,0xfe,0x01,0x0f,0xfe,0x01,0x35,0x00,0x01,0x3d,0xda, +0x01,0x01,0x3c,0x01,0x2f,0xfe,0x01,0x2f,0xfe,0x01,0x7a,0xe0,0x01,0x7b,0xb8, +0x01,0x06,0x9c,0x01,0x4d,0x7e,0x01,0x4f,0xfe,0x01,0x45,0xa8,0x01,0x69,0x70, +0x01,0x14,0x1c,0x01,0x57,0xfe,0x01,0x57,0xfe,0x01,0x77,0xe6,0x01,0x49,0xe4, +0x01,0x3d,0x18,0x01,0x7f,0xfe,0x01,0x7f,0xfe,0x01,0x21,0x4c,0x01,0x3e,0x9e, +0x01,0x1d,0xe0,0x01,0x3f,0xfe,0x01,0x3f,0xfe,0x01,0x06,0xbc,0x01,0x07,0xda, +0x01,0x00,0xe0,0x01,0x07,0xfe,0x01,0x07,0xfe,0x01,0x1b,0x18,0x01,0x1a,0x6c, +0x01,0x00,0xf0,0x01,0x1b,0xfc,0x01,0x1b,0xfc,0x01,0x75,0x90,0x01,0x75,0x68, +0x01,0x0a,0x70,0x01,0x7f,0xf8,0x01,0x7f,0xf8,0x01,0x0a,0x80,0x01,0x0a,0xf0, +0x01,0x01,0x00,0x01,0x0b,0xf0,0x01,0x0b,0xf0,0x01,0x01,0xc0,0x01,0x01,0xc0, +0xff,0x00,0x01,0x01,0xc0,0x01,0x01,0xc0, }; +#endif diff --git a/rom/usb/trident/MasonIcons/MI_Class_Bluetooth.c b/rom/usb/trident/MasonIcons/MI_Class_Bluetooth.c new file mode 100644 index 000000000..fa7fadabc --- /dev/null +++ b/rom/usb/trident/MasonIcons/MI_Class_Bluetooth.c @@ -0,0 +1,68 @@ +#ifdef USE_CLASS_BLUETOOTH_COLORS +const ULONG Class_Bluetooth_colors[96] = +{ + 0x96969696,0x96969696,0x96969696, + 0x2d2d2d2d,0x28282828,0x9e9e9e9e, + 0x00000000,0x65656565,0x9a9a9a9a, + 0x35353535,0x75757575,0xaaaaaaaa, + 0x65656565,0x8a8a8a8a,0xbabababa, + 0x0c0c0c0c,0x61616161,0xffffffff, + 0x24242424,0x5d5d5d5d,0x24242424, + 0x35353535,0x8a8a8a8a,0x35353535, + 0x86868686,0xb2b2b2b2,0x3d3d3d3d, + 0x0c0c0c0c,0xe3e3e3e3,0x00000000, + 0x4d4d4d4d,0x9e9e9e9e,0x8e8e8e8e, + 0x82828282,0x00000000,0x00000000, + 0xdfdfdfdf,0x35353535,0x35353535, + 0xdbdbdbdb,0x65656565,0x39393939, + 0xdbdbdbdb,0x8e8e8e8e,0x41414141, + 0xdfdfdfdf,0xbabababa,0x45454545, + 0xefefefef,0xe7e7e7e7,0x14141414, + 0x82828282,0x61616161,0x4d4d4d4d, + 0xa6a6a6a6,0x7e7e7e7e,0x61616161, + 0xcacacaca,0x9a9a9a9a,0x75757575, + 0x9a9a9a9a,0x55555555,0xaaaaaaaa, + 0xffffffff,0x00000000,0xffffffff, + 0xffffffff,0xffffffff,0xffffffff, + 0xdfdfdfdf,0xdfdfdfdf,0xdfdfdfdf, + 0xcacacaca,0xcacacaca,0xcacacaca, + 0xbabababa,0xbabababa,0xbabababa, + 0xaaaaaaaa,0xaaaaaaaa,0xaaaaaaaa, + 0x8a8a8a8a,0x8a8a8a8a,0x8a8a8a8a, + 0x65656565,0x65656565,0x65656565, + 0x4d4d4d4d,0x4d4d4d4d,0x4d4d4d4d, + 0x3c3c3c3c,0x3c3c3c3c,0x3b3b3b3b, + 0x00000000,0x00000000,0x00000000, +}; +#endif + +#define CLASS_BLUETOOTH_WIDTH 16 +#define CLASS_BLUETOOTH_HEIGHT 16 +#define CLASS_BLUETOOTH_DEPTH 5 +#define CLASS_BLUETOOTH_COMPRESSION 1 +#define CLASS_BLUETOOTH_MASKING 0 + +#ifdef USE_CLASS_BLUETOOTH_HEADER +const struct BitMapHeader Class_Bluetooth_header = +{ 16,16,0,0,5,0,1,0,0,11,10,16,16 }; +#endif + +#ifdef USE_CLASS_BLUETOOTH_BODY +const UBYTE Class_Bluetooth_body[237] = { +0x01,0x00,0xd0,0x01,0x03,0x10,0x01,0x04,0x20,0x01,0x04,0x30,0x01,0x04,0x30, +0x01,0x1d,0x78,0x01,0x1e,0xc8,0x01,0x00,0x80,0x01,0x10,0x08,0x01,0x10,0x88, +0x01,0x37,0x3c,0x01,0x38,0xe4,0x01,0x00,0xc0,0x01,0x20,0x04,0x01,0x20,0xc4, +0x01,0x2f,0x5c,0x01,0x30,0xb0,0x01,0x00,0xa0,0xff,0x00,0x01,0x00,0xa0,0x01, +0x7f,0x4c,0x01,0x6c,0x90,0x01,0x08,0xb2,0x01,0x40,0x02,0x01,0x48,0x92,0x01, +0x1b,0x5e,0x01,0x66,0xe0,0x01,0x04,0xa0,0xff,0x00,0x01,0x04,0xa0,0x01,0x3d, +0x3e,0x01,0x43,0xc0,0x01,0x02,0xc0,0xff,0x00,0x01,0x02,0xc0,0x01,0x7e,0x7f, +0x01,0x01,0x81,0x01,0x01,0x82,0x01,0x00,0x03,0x01,0x01,0x83,0x01,0x7e,0x7f, +0x01,0x03,0xc1,0x01,0x01,0x84,0x01,0x00,0x05,0x01,0x01,0x85,0x01,0x7d,0x3e, +0x01,0x06,0xe0,0x01,0x02,0xc2,0x01,0x00,0x02,0x01,0x02,0xc2,0x01,0x7b,0x5e, +0x01,0x0c,0xb0,0x01,0x04,0xa4,0x01,0x00,0x04,0x01,0x04,0xa4,0x01,0x77,0x6c, +0x01,0x40,0xb0,0x01,0x00,0x9a,0x01,0x48,0x0a,0x01,0x48,0x9a,0x01,0x3f,0x5c, +0x01,0x00,0xe0,0x01,0x00,0xb4,0x01,0x00,0x14,0x01,0x00,0xb4,0x01,0x1f,0x3c, +0x01,0x00,0xc4,0x01,0x20,0xe8,0x01,0x20,0x2c,0x01,0x20,0xec,0x01,0x7f,0x78, +0x01,0x40,0x88,0x01,0x31,0xd0,0x01,0x71,0x58,0x01,0x71,0xd8,0x01,0x6b,0xd0, +0x01,0x60,0x10,0x01,0x1e,0xa0,0x01,0x7e,0xb0,0x01,0x7e,0xb0, }; +#endif diff --git a/rom/usb/trident/MasonIcons/MI_Class_CDCControl.c b/rom/usb/trident/MasonIcons/MI_Class_CDCControl.c new file mode 100644 index 000000000..5101c618d --- /dev/null +++ b/rom/usb/trident/MasonIcons/MI_Class_CDCControl.c @@ -0,0 +1,67 @@ +#ifdef USE_CLASS_CDCCONTROL_COLORS +const ULONG Class_CDCControl_colors[96] = +{ + 0x96969696,0x96969696,0x96969696, + 0x2d2d2d2d,0x28282828,0x9e9e9e9e, + 0x00000000,0x65656565,0x9a9a9a9a, + 0x35353535,0x75757575,0xaaaaaaaa, + 0x65656565,0x8a8a8a8a,0xbabababa, + 0x0c0c0c0c,0x61616161,0xffffffff, + 0x24242424,0x5d5d5d5d,0x24242424, + 0x35353535,0x8a8a8a8a,0x35353535, + 0x86868686,0xb2b2b2b2,0x3d3d3d3d, + 0x0c0c0c0c,0xe3e3e3e3,0x00000000, + 0x4d4d4d4d,0x9e9e9e9e,0x8e8e8e8e, + 0x82828282,0x00000000,0x00000000, + 0xdfdfdfdf,0x35353535,0x35353535, + 0xdbdbdbdb,0x65656565,0x39393939, + 0xdbdbdbdb,0x8e8e8e8e,0x41414141, + 0xdfdfdfdf,0xbabababa,0x45454545, + 0xefefefef,0xe7e7e7e7,0x14141414, + 0x82828282,0x61616161,0x4d4d4d4d, + 0xa6a6a6a6,0x7e7e7e7e,0x61616161, + 0xcacacaca,0x9a9a9a9a,0x75757575, + 0x9a9a9a9a,0x55555555,0xaaaaaaaa, + 0xffffffff,0x00000000,0xffffffff, + 0xffffffff,0xffffffff,0xffffffff, + 0xdfdfdfdf,0xdfdfdfdf,0xdfdfdfdf, + 0xcacacaca,0xcacacaca,0xcacacaca, + 0xbabababa,0xbabababa,0xbabababa, + 0xaaaaaaaa,0xaaaaaaaa,0xaaaaaaaa, + 0x8a8a8a8a,0x8a8a8a8a,0x8a8a8a8a, + 0x65656565,0x65656565,0x65656565, + 0x4d4d4d4d,0x4d4d4d4d,0x4d4d4d4d, + 0x3c3c3c3c,0x3c3c3c3c,0x3b3b3b3b, + 0x00000000,0x00000000,0x00000000, +}; +#endif + +#define CLASS_CDCCONTROL_WIDTH 16 +#define CLASS_CDCCONTROL_HEIGHT 16 +#define CLASS_CDCCONTROL_DEPTH 5 +#define CLASS_CDCCONTROL_COMPRESSION 1 +#define CLASS_CDCCONTROL_MASKING 2 + +#ifdef USE_CLASS_CDCCONTROL_HEADER +const struct BitMapHeader Class_CDCControl_header = +{ 16,16,88,83,5,2,1,0,0,1,1,800,600 }; +#endif + +#ifdef USE_CLASS_CDCCONTROL_BODY +const UBYTE Class_CDCControl_body[216] = { +0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff, +0x00,0xff,0x00,0xff,0x00,0x01,0x00,0x08,0x01,0x01,0x08,0x01,0x00,0xf0,0x01, +0x01,0x00,0x01,0x01,0x00,0x01,0x00,0x52,0x01,0x02,0xf8,0x01,0x01,0x00,0x01, +0x02,0x06,0x01,0x02,0x06,0xff,0xad,0x01,0xa5,0x03,0x01,0x1e,0x50,0x01,0xbc, +0x07,0x01,0xbc,0x07,0x01,0x57,0x05,0x01,0x57,0xab,0x01,0x0c,0x50,0x01,0x5c, +0x07,0x01,0x5c,0x07,0x01,0x01,0xa9,0x01,0x03,0xf7,0xff,0x00,0x01,0x00,0x07, +0x01,0x00,0x07,0x01,0x00,0x56,0x01,0x03,0xae,0x01,0x00,0x08,0x01,0x02,0x0e, +0x01,0x02,0x0e,0x01,0x00,0xf4,0x01,0x05,0x00,0x01,0x02,0x00,0x01,0x04,0x0c, +0x01,0x04,0x0c,0x01,0x5b,0x5a,0x01,0x4a,0x06,0x01,0x3c,0xa0,0x01,0x78,0x0e, +0x01,0x78,0x0e,0x01,0xae,0x0a,0x01,0xaf,0x56,0x01,0x18,0xa0,0x01,0xb8,0x0e, +0x01,0xb8,0x0e,0x01,0x03,0x52,0x01,0x07,0xee,0xff,0x00,0x01,0x00,0x0e,0x01, +0x00,0x0e,0x01,0x00,0xac,0x01,0x03,0x5c,0x01,0x00,0x10,0x01,0x00,0x1c,0x01, +0x00,0x1c,0x01,0x01,0xf0,0x01,0x01,0xf0,0xff,0x00,0x01,0x01,0xf0,0x01,0x01, +0xf0,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00, +0xff,0x00,0xff,0x00,0xff,0x00, }; +#endif diff --git a/rom/usb/trident/MasonIcons/MI_Class_CDCData.c b/rom/usb/trident/MasonIcons/MI_Class_CDCData.c new file mode 100644 index 000000000..d3a1e6f11 --- /dev/null +++ b/rom/usb/trident/MasonIcons/MI_Class_CDCData.c @@ -0,0 +1,67 @@ +#ifdef USE_CLASS_CDCDATA_COLORS +const ULONG Class_CDCData_colors[96] = +{ + 0x96969696,0x96969696,0x96969696, + 0x2d2d2d2d,0x28282828,0x9e9e9e9e, + 0x00000000,0x65656565,0x9a9a9a9a, + 0x35353535,0x75757575,0xaaaaaaaa, + 0x65656565,0x8a8a8a8a,0xbabababa, + 0x0c0c0c0c,0x61616161,0xffffffff, + 0x24242424,0x5d5d5d5d,0x24242424, + 0x35353535,0x8a8a8a8a,0x35353535, + 0x86868686,0xb2b2b2b2,0x3d3d3d3d, + 0x0c0c0c0c,0xe3e3e3e3,0x00000000, + 0x4d4d4d4d,0x9e9e9e9e,0x8e8e8e8e, + 0x82828282,0x00000000,0x00000000, + 0xdfdfdfdf,0x35353535,0x35353535, + 0xdbdbdbdb,0x65656565,0x39393939, + 0xdbdbdbdb,0x8e8e8e8e,0x41414141, + 0xdfdfdfdf,0xbabababa,0x45454545, + 0xefefefef,0xe7e7e7e7,0x14141414, + 0x82828282,0x61616161,0x4d4d4d4d, + 0xa6a6a6a6,0x7e7e7e7e,0x61616161, + 0xcacacaca,0x9a9a9a9a,0x75757575, + 0x9a9a9a9a,0x55555555,0xaaaaaaaa, + 0xffffffff,0x00000000,0xffffffff, + 0xffffffff,0xffffffff,0xffffffff, + 0xdfdfdfdf,0xdfdfdfdf,0xdfdfdfdf, + 0xcacacaca,0xcacacaca,0xcacacaca, + 0xbabababa,0xbabababa,0xbabababa, + 0xaaaaaaaa,0xaaaaaaaa,0xaaaaaaaa, + 0x8a8a8a8a,0x8a8a8a8a,0x8a8a8a8a, + 0x65656565,0x65656565,0x65656565, + 0x4d4d4d4d,0x4d4d4d4d,0x4d4d4d4d, + 0x3c3c3c3c,0x3c3c3c3c,0x3b3b3b3b, + 0x00000000,0x00000000,0x00000000, +}; +#endif + +#define CLASS_CDCDATA_WIDTH 16 +#define CLASS_CDCDATA_HEIGHT 16 +#define CLASS_CDCDATA_DEPTH 5 +#define CLASS_CDCDATA_COMPRESSION 1 +#define CLASS_CDCDATA_MASKING 2 + +#ifdef USE_CLASS_CDCDATA_HEADER +const struct BitMapHeader Class_CDCData_header = +{ 16,16,88,102,5,2,1,0,0,1,1,800,600 }; +#endif + +#ifdef USE_CLASS_CDCDATA_BODY +const UBYTE Class_CDCData_body[218] = { +0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff, +0x00,0xff,0x00,0xff,0x00,0x01,0x01,0x80,0x01,0x21,0x80,0x01,0x1e,0x00,0x01, +0x20,0x80,0x01,0x20,0x80,0x01,0x8a,0xc0,0x01,0x9f,0xc0,0x01,0xa0,0x00,0xff, +0x40,0x01,0xc0,0x40,0x01,0x55,0x6a,0x01,0x00,0xca,0x01,0x2a,0x70,0x01,0xc0, +0x7a,0x01,0xc0,0x7a,0x01,0x40,0xd4,0x01,0x15,0x54,0x01,0x2a,0x60,0x01,0xc0, +0x74,0x01,0xc0,0x74,0x01,0x95,0x60,0x01,0x5e,0xe0,0x01,0x20,0x80,0x01,0xc0, +0xe0,0x01,0xc0,0xe0,0x01,0x40,0x80,0x01,0x70,0x80,0x01,0x0f,0x00,0x01,0x50, +0x00,0x01,0x50,0x00,0x01,0x45,0x40,0x01,0x4f,0xc0,0x01,0x50,0x00,0x01,0x20, +0x00,0x01,0x60,0x00,0x01,0x2a,0xb5,0x01,0x00,0x65,0x01,0x15,0x38,0x01,0x60, +0x3d,0x01,0x60,0x3d,0x01,0x20,0x6a,0x01,0x0a,0xaa,0x01,0x15,0x30,0x01,0x60, +0x3a,0x01,0x60,0x3a,0x01,0x4a,0xb0,0x01,0x2f,0x70,0x01,0x10,0x40,0x01,0x60, +0x70,0x01,0x60,0x70,0x01,0x35,0x40,0x01,0x3a,0xc0,0x01,0x02,0x80,0x01,0x22, +0xc0,0x01,0x22,0xc0,0x01,0x0f,0x80,0x01,0x0f,0x80,0xff,0x00,0x01,0x0f,0x80, +0x01,0x0f,0x80,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00, +0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00, }; +#endif diff --git a/rom/usb/trident/MasonIcons/MI_Class_ChipSmartCard.c b/rom/usb/trident/MasonIcons/MI_Class_ChipSmartCard.c new file mode 100644 index 000000000..b690ea427 --- /dev/null +++ b/rom/usb/trident/MasonIcons/MI_Class_ChipSmartCard.c @@ -0,0 +1,68 @@ +#ifdef USE_CLASS_CHIPSMARTCARD_COLORS +const ULONG Class_ChipSmartCard_colors[96] = +{ + 0x96969696,0x96969696,0x96969696, + 0x2d2d2d2d,0x28282828,0x9e9e9e9e, + 0x00000000,0x65656565,0x9a9a9a9a, + 0x35353535,0x75757575,0xaaaaaaaa, + 0x65656565,0x8a8a8a8a,0xbabababa, + 0x0c0c0c0c,0x61616161,0xffffffff, + 0x24242424,0x5d5d5d5d,0x24242424, + 0x35353535,0x8a8a8a8a,0x35353535, + 0x86868686,0xb2b2b2b2,0x3d3d3d3d, + 0x0c0c0c0c,0xe3e3e3e3,0x00000000, + 0x4d4d4d4d,0x9e9e9e9e,0x8e8e8e8e, + 0x82828282,0x00000000,0x00000000, + 0xdfdfdfdf,0x35353535,0x35353535, + 0xdbdbdbdb,0x65656565,0x39393939, + 0xdbdbdbdb,0x8e8e8e8e,0x41414141, + 0xdfdfdfdf,0xbabababa,0x45454545, + 0xefefefef,0xe7e7e7e7,0x14141414, + 0x82828282,0x61616161,0x4d4d4d4d, + 0xa6a6a6a6,0x7e7e7e7e,0x61616161, + 0xcacacaca,0x9a9a9a9a,0x75757575, + 0x9a9a9a9a,0x55555555,0xaaaaaaaa, + 0xffffffff,0x00000000,0xffffffff, + 0xffffffff,0xffffffff,0xffffffff, + 0xdfdfdfdf,0xdfdfdfdf,0xdfdfdfdf, + 0xcacacaca,0xcacacaca,0xcacacaca, + 0xbabababa,0xbabababa,0xbabababa, + 0xaaaaaaaa,0xaaaaaaaa,0xaaaaaaaa, + 0x8a8a8a8a,0x8a8a8a8a,0x8a8a8a8a, + 0x65656565,0x65656565,0x65656565, + 0x4d4d4d4d,0x4d4d4d4d,0x4d4d4d4d, + 0x3c3c3c3c,0x3c3c3c3c,0x3b3b3b3b, + 0x00000000,0x00000000,0x00000000, +}; +#endif + +#define CLASS_CHIPSMARTCARD_WIDTH 16 +#define CLASS_CHIPSMARTCARD_HEIGHT 16 +#define CLASS_CHIPSMARTCARD_DEPTH 5 +#define CLASS_CHIPSMARTCARD_COMPRESSION 1 +#define CLASS_CHIPSMARTCARD_MASKING 2 + +#ifdef USE_CLASS_CHIPSMARTCARD_HEADER +const struct BitMapHeader Class_ChipSmartCard_header = +{ 16,16,88,45,5,2,1,0,0,1,1,800,600 }; +#endif + +#ifdef USE_CLASS_CHIPSMARTCARD_BODY +const UBYTE Class_ChipSmartCard_body[233] = { +0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0x01,0x06,0x80,0x01,0x07, +0xc0,0x01,0x07,0xc8,0xff,0x38,0x01,0x3f,0xf8,0x01,0x2b,0x4c,0x01,0x2f,0xe4, +0x01,0x2f,0xe8,0x01,0x10,0x1c,0x01,0x3f,0xfc,0x01,0x2e,0x84,0x01,0x2f,0xec, +0x01,0x2f,0xe8,0x01,0x10,0x1c,0x01,0x3f,0xfc,0x01,0x25,0x24,0x01,0x2f,0xec, +0x01,0x2f,0xe8,0x01,0x10,0x1c,0x01,0x3f,0xfc,0x01,0x2a,0x8c,0x01,0x2f,0xec, +0x01,0x2f,0xe8,0x01,0x10,0x1c,0x01,0x3f,0xfc,0x01,0x24,0x2c,0x01,0x2f,0xec, +0x01,0x2f,0xe8,0x01,0x10,0x1c,0x01,0x3f,0xfc,0x01,0x20,0x0c,0x01,0x20,0x0c, +0x01,0x3f,0xf8,0x01,0x1f,0xfc,0x01,0x3f,0xfc,0x01,0x2c,0x0c,0x01,0x23,0x4c, +0x01,0x20,0xb8,0x01,0x1f,0x4c,0x01,0x3f,0x4c,0x01,0x3f,0xfc,0x01,0x3f,0xfc, +0x01,0x20,0x08,0x01,0x00,0x0c,0x01,0x20,0x0c,0x01,0x3f,0xfc,0x01,0x3f,0xfc, +0x01,0x20,0x08,0x01,0x00,0x0c,0x01,0x20,0x0c,0x01,0x3f,0xfc,0x01,0x3f,0xfc, +0x01,0x20,0x08,0x01,0x00,0x0c,0x01,0x20,0x0c,0x01,0x35,0x5c,0x01,0x3a,0xbc, +0x01,0x25,0x48,0x01,0x05,0x4c,0x01,0x25,0x4c,0x01,0x1a,0xac,0x01,0x0f,0xec, +0x01,0x1f,0xf8,0x01,0x3f,0xfc,0x01,0x30,0x1c,0x01,0x0a,0xac,0x01,0x3f,0xfc, +0x01,0x1f,0xf8,0x01,0x3f,0xfc,0x01,0x30,0x1c,0x01,0x1f,0xf8,0x01,0x1f,0xf8, +0xff,0x00,0x01,0x1f,0xf8,0x01,0x1f,0xf8, }; +#endif diff --git a/rom/usb/trident/MasonIcons/MI_Class_CommDevice.c b/rom/usb/trident/MasonIcons/MI_Class_CommDevice.c new file mode 100644 index 000000000..a1098f2fb --- /dev/null +++ b/rom/usb/trident/MasonIcons/MI_Class_CommDevice.c @@ -0,0 +1,66 @@ +#ifdef USE_CLASS_COMMDEVICE_COLORS +const ULONG Class_CommDevice_colors[96] = +{ + 0x96969696,0x96969696,0x96969696, + 0x2d2d2d2d,0x28282828,0x9e9e9e9e, + 0x00000000,0x65656565,0x9a9a9a9a, + 0x35353535,0x75757575,0xaaaaaaaa, + 0x65656565,0x8a8a8a8a,0xbabababa, + 0x0c0c0c0c,0x61616161,0xffffffff, + 0x24242424,0x5d5d5d5d,0x24242424, + 0x35353535,0x8a8a8a8a,0x35353535, + 0x86868686,0xb2b2b2b2,0x3d3d3d3d, + 0x0c0c0c0c,0xe3e3e3e3,0x00000000, + 0x4d4d4d4d,0x9e9e9e9e,0x8e8e8e8e, + 0x82828282,0x00000000,0x00000000, + 0xdfdfdfdf,0x35353535,0x35353535, + 0xdbdbdbdb,0x65656565,0x39393939, + 0xdbdbdbdb,0x8e8e8e8e,0x41414141, + 0xdfdfdfdf,0xbabababa,0x45454545, + 0xefefefef,0xe7e7e7e7,0x14141414, + 0x82828282,0x61616161,0x4d4d4d4d, + 0xa6a6a6a6,0x7e7e7e7e,0x61616161, + 0xcacacaca,0x9a9a9a9a,0x75757575, + 0x9a9a9a9a,0x55555555,0xaaaaaaaa, + 0xffffffff,0x00000000,0xffffffff, + 0xffffffff,0xffffffff,0xffffffff, + 0xdfdfdfdf,0xdfdfdfdf,0xdfdfdfdf, + 0xcacacaca,0xcacacaca,0xcacacaca, + 0xbabababa,0xbabababa,0xbabababa, + 0xaaaaaaaa,0xaaaaaaaa,0xaaaaaaaa, + 0x8a8a8a8a,0x8a8a8a8a,0x8a8a8a8a, + 0x65656565,0x65656565,0x65656565, + 0x4d4d4d4d,0x4d4d4d4d,0x4d4d4d4d, + 0x3c3c3c3c,0x3c3c3c3c,0x3b3b3b3b, + 0x00000000,0x00000000,0x00000000, +}; +#endif + +#define CLASS_COMMDEVICE_WIDTH 16 +#define CLASS_COMMDEVICE_HEIGHT 16 +#define CLASS_COMMDEVICE_DEPTH 5 +#define CLASS_COMMDEVICE_COMPRESSION 1 +#define CLASS_COMMDEVICE_MASKING 2 + +#ifdef USE_CLASS_COMMDEVICE_HEADER +const struct BitMapHeader Class_CommDevice_header = +{ 16,16,88,64,5,2,1,0,0,1,1,800,600 }; +#endif + +#ifdef USE_CLASS_COMMDEVICE_BODY +const UBYTE Class_CommDevice_body[209] = { +0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff, +0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00, +0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0x01,0x01,0x58,0x01,0x1f, +0x38,0x01,0x1f,0x00,0x01,0x20,0xf8,0x01,0x3f,0xf8,0x01,0x1f,0x44,0x01,0x3f, +0x54,0x01,0x3f,0x48,0x01,0x40,0xbc,0x01,0x7f,0xfc,0x01,0x3e,0xaa,0x01,0x7e, +0xae,0x01,0x7e,0xa4,0x01,0x81,0x5e,0x01,0xff,0xfe,0x01,0x50,0xba,0x01,0xaf, +0xfa,0x01,0x00,0x06,0x01,0xff,0xfe,0x01,0xff,0xfe,0x01,0xd5,0x0a,0x01,0x9f, +0xfc,0x01,0x7f,0xfe,0x01,0xff,0xfe,0x01,0xff,0xfe,0x01,0xff,0x1a,0x01,0x6a, +0xf6,0x01,0xbf,0xfe,0x01,0xff,0xfe,0x01,0xea,0xf6,0x01,0xaa,0x87,0x01,0x00, +0x73,0x01,0xff,0xfe,0xff,0xff,0x01,0xea,0xf7,0x01,0x95,0x0a,0x01,0x6a,0xf6, +0x01,0xff,0xfe,0x01,0xff,0xfe,0x01,0xff,0xfe,0x01,0x5f,0xff,0x01,0x3f,0xfd, +0x01,0xff,0xfe,0xff,0xff,0xff,0xff,0x01,0x80,0xb5,0x01,0x80,0x01,0x01,0x7f, +0xfe,0xff,0xff,0xff,0xff,0x01,0x7f,0xfe,0x01,0x7f,0xfe,0xff,0x00,0x01,0x7f, +0xfe,0x01,0x7f,0xfe,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00, }; +#endif diff --git a/rom/usb/trident/MasonIcons/MI_Class_HID.c b/rom/usb/trident/MasonIcons/MI_Class_HID.c new file mode 100644 index 000000000..ef9c05240 --- /dev/null +++ b/rom/usb/trident/MasonIcons/MI_Class_HID.c @@ -0,0 +1,67 @@ +#ifdef USE_CLASS_HID_COLORS +const ULONG Class_HID_colors[96] = +{ + 0x96969696,0x96969696,0x96969696, + 0x2d2d2d2d,0x28282828,0x9e9e9e9e, + 0x00000000,0x65656565,0x9a9a9a9a, + 0x35353535,0x75757575,0xaaaaaaaa, + 0x65656565,0x8a8a8a8a,0xbabababa, + 0x0c0c0c0c,0x61616161,0xffffffff, + 0x24242424,0x5d5d5d5d,0x24242424, + 0x35353535,0x8a8a8a8a,0x35353535, + 0x86868686,0xb2b2b2b2,0x3d3d3d3d, + 0x0c0c0c0c,0xe3e3e3e3,0x00000000, + 0x4d4d4d4d,0x9e9e9e9e,0x8e8e8e8e, + 0x82828282,0x00000000,0x00000000, + 0xdfdfdfdf,0x35353535,0x35353535, + 0xdbdbdbdb,0x65656565,0x39393939, + 0xdbdbdbdb,0x8e8e8e8e,0x41414141, + 0xdfdfdfdf,0xbabababa,0x45454545, + 0xefefefef,0xe7e7e7e7,0x14141414, + 0x82828282,0x61616161,0x4d4d4d4d, + 0xa6a6a6a6,0x7e7e7e7e,0x61616161, + 0xcacacaca,0x9a9a9a9a,0x75757575, + 0x9a9a9a9a,0x55555555,0xaaaaaaaa, + 0xffffffff,0x00000000,0xffffffff, + 0xffffffff,0xffffffff,0xffffffff, + 0xdfdfdfdf,0xdfdfdfdf,0xdfdfdfdf, + 0xcacacaca,0xcacacaca,0xcacacaca, + 0xbabababa,0xbabababa,0xbabababa, + 0xaaaaaaaa,0xaaaaaaaa,0xaaaaaaaa, + 0x8a8a8a8a,0x8a8a8a8a,0x8a8a8a8a, + 0x65656565,0x65656565,0x65656565, + 0x4d4d4d4d,0x4d4d4d4d,0x4d4d4d4d, + 0x3c3c3c3c,0x3c3c3c3c,0x3b3b3b3b, + 0x00000000,0x00000000,0x00000000, +}; +#endif + +#define CLASS_HID_WIDTH 16 +#define CLASS_HID_HEIGHT 16 +#define CLASS_HID_DEPTH 5 +#define CLASS_HID_COMPRESSION 1 +#define CLASS_HID_MASKING 2 + +#ifdef USE_CLASS_HID_HEADER +const struct BitMapHeader Class_HID_header = +{ 16,16,88,140,5,2,1,0,0,1,1,800,600 }; +#endif + +#ifdef USE_CLASS_HID_BODY +const UBYTE Class_HID_body[223] = { +0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff, +0x00,0xff,0x00,0xff,0x00,0x01,0x02,0x80,0x01,0x0b,0x40,0x01,0x03,0x00,0x01, +0x0c,0xc0,0x01,0x0f,0xc0,0x01,0x1f,0xa0,0x01,0x1f,0xf0,0x01,0x1f,0xe0,0x01, +0x20,0x10,0x01,0x3f,0xf0,0x01,0x4d,0x00,0x01,0x79,0xe0,0x01,0x79,0xe0,0x01, +0x06,0x18,0x01,0x7f,0xf8,0x01,0x52,0x0c,0x01,0x73,0xf8,0x01,0x73,0xf8,0x01, +0x8c,0x04,0x01,0xff,0xfc,0x01,0xf8,0x24,0x01,0xff,0xfe,0x01,0xff,0xfc,0x01, +0x00,0x02,0x01,0xff,0xfe,0x01,0xe6,0x71,0x01,0x67,0xf8,0x01,0x67,0xf9,0x01, +0x98,0x05,0x01,0xff,0xfd,0x01,0x81,0xa1,0x01,0x01,0xe5,0x01,0x81,0xe3,0x01, +0xbe,0x1f,0x01,0xbf,0xff,0x01,0x9b,0xd5,0x01,0xd0,0xdc,0x01,0x60,0xd3,0x01, +0xff,0x2f,0xff,0xff,0x01,0x54,0x9a,0x01,0x57,0x78,0x01,0x38,0x07,0x01,0x7f, +0xff,0x01,0x7f,0xff,0x01,0x3a,0xe1,0x01,0x34,0xed,0x01,0x0f,0x1e,0x01,0x3f, +0xff,0x01,0x3f,0xff,0x01,0x09,0x13,0x01,0x08,0xe3,0x01,0x07,0xfc,0x01,0x0f, +0xff,0x01,0x0f,0xff,0x01,0x03,0x0c,0x01,0x03,0x0c,0x01,0x00,0xf0,0x01,0x03, +0xfc,0x01,0x03,0xfc,0x01,0x00,0xf0,0x01,0x00,0xf0,0xff,0x00,0x01,0x00,0xf0, +0x01,0x00,0xf0,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00, }; +#endif diff --git a/rom/usb/trident/MasonIcons/MI_Class_Hub.c b/rom/usb/trident/MasonIcons/MI_Class_Hub.c new file mode 100644 index 000000000..52fd5f905 --- /dev/null +++ b/rom/usb/trident/MasonIcons/MI_Class_Hub.c @@ -0,0 +1,67 @@ +#ifdef USE_CLASS_HUB_COLORS +const ULONG Class_Hub_colors[96] = +{ + 0x96969696,0x96969696,0x96969696, + 0x2d2d2d2d,0x28282828,0x9e9e9e9e, + 0x00000000,0x65656565,0x9a9a9a9a, + 0x35353535,0x75757575,0xaaaaaaaa, + 0x65656565,0x8a8a8a8a,0xbabababa, + 0x0c0c0c0c,0x61616161,0xffffffff, + 0x24242424,0x5d5d5d5d,0x24242424, + 0x35353535,0x8a8a8a8a,0x35353535, + 0x86868686,0xb2b2b2b2,0x3d3d3d3d, + 0x0c0c0c0c,0xe3e3e3e3,0x00000000, + 0x4d4d4d4d,0x9e9e9e9e,0x8e8e8e8e, + 0x82828282,0x00000000,0x00000000, + 0xdfdfdfdf,0x35353535,0x35353535, + 0xdbdbdbdb,0x65656565,0x39393939, + 0xdbdbdbdb,0x8e8e8e8e,0x41414141, + 0xdfdfdfdf,0xbabababa,0x45454545, + 0xefefefef,0xe7e7e7e7,0x14141414, + 0x82828282,0x61616161,0x4d4d4d4d, + 0xa6a6a6a6,0x7e7e7e7e,0x61616161, + 0xcacacaca,0x9a9a9a9a,0x75757575, + 0x9a9a9a9a,0x55555555,0xaaaaaaaa, + 0xffffffff,0x00000000,0xffffffff, + 0xffffffff,0xffffffff,0xffffffff, + 0xdfdfdfdf,0xdfdfdfdf,0xdfdfdfdf, + 0xcacacaca,0xcacacaca,0xcacacaca, + 0xbabababa,0xbabababa,0xbabababa, + 0xaaaaaaaa,0xaaaaaaaa,0xaaaaaaaa, + 0x8a8a8a8a,0x8a8a8a8a,0x8a8a8a8a, + 0x65656565,0x65656565,0x65656565, + 0x4d4d4d4d,0x4d4d4d4d,0x4d4d4d4d, + 0x3c3c3c3c,0x3c3c3c3c,0x3b3b3b3b, + 0x00000000,0x00000000,0x00000000, +}; +#endif + +#define CLASS_HUB_WIDTH 16 +#define CLASS_HUB_HEIGHT 16 +#define CLASS_HUB_DEPTH 5 +#define CLASS_HUB_COMPRESSION 1 +#define CLASS_HUB_MASKING 2 + +#ifdef USE_CLASS_HUB_HEADER +const struct BitMapHeader Class_Hub_header = +{ 16,16,88,159,5,2,1,0,0,1,1,800,600 }; +#endif + +#ifdef USE_CLASS_HUB_BODY +const UBYTE Class_Hub_body[212] = { +0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff, +0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00, +0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0x01,0x01,0x58,0x01,0x0f, +0x38,0x01,0x0f,0x00,0x01,0x10,0xf8,0x01,0x1f,0xf8,0x01,0x0f,0x44,0x01,0x1f, +0x54,0x01,0x1f,0x48,0x01,0x20,0xbc,0x01,0x3f,0xfc,0x01,0x1e,0xaa,0x01,0x3e, +0xae,0x01,0x3e,0xa4,0x01,0x41,0x5e,0x01,0x7f,0xfe,0x01,0x28,0xba,0x01,0x57, +0xfa,0x01,0x00,0x06,0x01,0x7f,0xfe,0x01,0x7f,0xfe,0x01,0x59,0x9a,0xff,0x44, +0x01,0x7b,0xba,0x01,0x3f,0xfe,0x01,0x7f,0xfe,0x01,0x55,0x56,0x01,0x7f,0xfe, +0x01,0x5d,0xde,0xff,0x22,0x01,0x7f,0xfe,0x01,0x59,0x9b,0x01,0x44,0x47,0x01, +0x7b,0xba,0x01,0x3f,0xff,0x01,0x7f,0xff,0x01,0x15,0x56,0x01,0x3f,0xfe,0x01, +0x1d,0xde,0x01,0x62,0x22,0x01,0x7f,0xfe,0x01,0x2f,0xff,0x01,0x1f,0xfd,0x01, +0x7f,0xfe,0x01,0x7f,0xff,0x01,0x7f,0xff,0x01,0x40,0xb5,0x01,0x40,0x01,0x01, +0x3f,0xfe,0x01,0x7f,0xff,0x01,0x7f,0xff,0x01,0x3f,0xfe,0x01,0x3f,0xfe,0xff, +0x00,0x01,0x3f,0xfe,0x01,0x3f,0xfe,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00, +0xff,0x00, }; +#endif diff --git a/rom/usb/trident/MasonIcons/MI_Class_MassStorage.c b/rom/usb/trident/MasonIcons/MI_Class_MassStorage.c new file mode 100644 index 000000000..5c921a34b --- /dev/null +++ b/rom/usb/trident/MasonIcons/MI_Class_MassStorage.c @@ -0,0 +1,67 @@ +#ifdef USE_CLASS_MASSSTORAGE_COLORS +const ULONG Class_MassStorage_colors[96] = +{ + 0x96969696,0x96969696,0x96969696, + 0x2d2d2d2d,0x28282828,0x9e9e9e9e, + 0x00000000,0x65656565,0x9a9a9a9a, + 0x35353535,0x75757575,0xaaaaaaaa, + 0x65656565,0x8a8a8a8a,0xbabababa, + 0x0c0c0c0c,0x61616161,0xffffffff, + 0x24242424,0x5d5d5d5d,0x24242424, + 0x35353535,0x8a8a8a8a,0x35353535, + 0x86868686,0xb2b2b2b2,0x3d3d3d3d, + 0x0c0c0c0c,0xe3e3e3e3,0x00000000, + 0x4d4d4d4d,0x9e9e9e9e,0x8e8e8e8e, + 0x82828282,0x00000000,0x00000000, + 0xdfdfdfdf,0x35353535,0x35353535, + 0xdbdbdbdb,0x65656565,0x39393939, + 0xdbdbdbdb,0x8e8e8e8e,0x41414141, + 0xdfdfdfdf,0xbabababa,0x45454545, + 0xefefefef,0xe7e7e7e7,0x14141414, + 0x82828282,0x61616161,0x4d4d4d4d, + 0xa6a6a6a6,0x7e7e7e7e,0x61616161, + 0xcacacaca,0x9a9a9a9a,0x75757575, + 0x9a9a9a9a,0x55555555,0xaaaaaaaa, + 0xffffffff,0x00000000,0xffffffff, + 0xffffffff,0xffffffff,0xffffffff, + 0xdfdfdfdf,0xdfdfdfdf,0xdfdfdfdf, + 0xcacacaca,0xcacacaca,0xcacacaca, + 0xbabababa,0xbabababa,0xbabababa, + 0xaaaaaaaa,0xaaaaaaaa,0xaaaaaaaa, + 0x8a8a8a8a,0x8a8a8a8a,0x8a8a8a8a, + 0x65656565,0x65656565,0x65656565, + 0x4d4d4d4d,0x4d4d4d4d,0x4d4d4d4d, + 0x3c3c3c3c,0x3c3c3c3c,0x3b3b3b3b, + 0x00000000,0x00000000,0x00000000, +}; +#endif + +#define CLASS_MASSSTORAGE_WIDTH 16 +#define CLASS_MASSSTORAGE_HEIGHT 16 +#define CLASS_MASSSTORAGE_DEPTH 5 +#define CLASS_MASSSTORAGE_COMPRESSION 1 +#define CLASS_MASSSTORAGE_MASKING 2 + +#ifdef USE_CLASS_MASSSTORAGE_HEADER +const struct BitMapHeader Class_MassStorage_header = +{ 16,16,88,178,5,2,1,0,0,1,1,800,600 }; +#endif + +#ifdef USE_CLASS_MASSSTORAGE_BODY +const UBYTE Class_MassStorage_body[215] = { +0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff, +0x00,0xff,0x00,0xff,0x00,0x01,0x01,0x58,0x01,0x1f,0x38,0x01,0x1f,0x00,0x01, +0x20,0xf8,0x01,0x3f,0xf8,0x01,0x1f,0x44,0x01,0x3f,0x54,0x01,0x3f,0x48,0x01, +0x40,0xbc,0x01,0x7f,0xfc,0x01,0x3e,0xaa,0x01,0x7e,0xae,0x01,0x7e,0xa4,0x01, +0x81,0x5e,0x01,0xff,0xfe,0x01,0x68,0xba,0x01,0x97,0xfa,0x01,0x80,0x06,0x01, +0x7f,0xfe,0x01,0xff,0xfe,0x01,0x16,0x30,0x01,0xfe,0x0e,0x01,0x81,0xfe,0x01, +0x7f,0xfe,0x01,0xff,0xfe,0x01,0x2b,0xd2,0x01,0xff,0xd4,0x01,0xff,0xd2,0x01, +0x00,0x2e,0x01,0xff,0xfe,0x01,0x11,0xd6,0x01,0x90,0x2e,0x01,0x90,0x02,0x01, +0x7f,0xfe,0x01,0xaf,0xfe,0x01,0x40,0xe7,0x01,0xa8,0x1f,0x01,0xa8,0x02,0x01, +0x47,0xff,0x01,0xbf,0xff,0x01,0x79,0x78,0x01,0x87,0xfa,0x01,0x80,0x06,0x01, +0x7f,0xfe,0x01,0xff,0xfe,0x01,0x59,0xfb,0x01,0xc7,0xfd,0x01,0x3f,0xfe,0xff, +0xff,0xff,0xff,0x01,0x80,0xb5,0x01,0x80,0x01,0x01,0x7f,0xfe,0xff,0xff,0xff, +0xff,0x01,0x7f,0xfe,0x01,0x7f,0xfe,0xff,0x00,0x01,0x7f,0xfe,0x01,0x7f,0xfe, +0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff, +0x00,0xff,0x00,0xff,0x00, }; +#endif diff --git a/rom/usb/trident/MasonIcons/MI_Class_None.c b/rom/usb/trident/MasonIcons/MI_Class_None.c new file mode 100644 index 000000000..28189460c --- /dev/null +++ b/rom/usb/trident/MasonIcons/MI_Class_None.c @@ -0,0 +1,68 @@ +#ifdef USE_CLASS_NONE_COLORS +const ULONG Class_None_colors[96] = +{ + 0x96969696,0x96969696,0x96969696, + 0x2d2d2d2d,0x28282828,0x9e9e9e9e, + 0x00000000,0x65656565,0x9a9a9a9a, + 0x35353535,0x75757575,0xaaaaaaaa, + 0x65656565,0x8a8a8a8a,0xbabababa, + 0x0c0c0c0c,0x61616161,0xffffffff, + 0x24242424,0x5d5d5d5d,0x24242424, + 0x35353535,0x8a8a8a8a,0x35353535, + 0x86868686,0xb2b2b2b2,0x3d3d3d3d, + 0x0c0c0c0c,0xe3e3e3e3,0x00000000, + 0x4d4d4d4d,0x9e9e9e9e,0x8e8e8e8e, + 0x82828282,0x00000000,0x00000000, + 0xdfdfdfdf,0x35353535,0x35353535, + 0xdbdbdbdb,0x65656565,0x39393939, + 0xdbdbdbdb,0x8e8e8e8e,0x41414141, + 0xdfdfdfdf,0xbabababa,0x45454545, + 0xefefefef,0xe7e7e7e7,0x14141414, + 0x82828282,0x61616161,0x4d4d4d4d, + 0xa6a6a6a6,0x7e7e7e7e,0x61616161, + 0xcacacaca,0x9a9a9a9a,0x75757575, + 0x9a9a9a9a,0x55555555,0xaaaaaaaa, + 0xffffffff,0x00000000,0xffffffff, + 0xffffffff,0xffffffff,0xffffffff, + 0xdfdfdfdf,0xdfdfdfdf,0xdfdfdfdf, + 0xcacacaca,0xcacacaca,0xcacacaca, + 0xbabababa,0xbabababa,0xbabababa, + 0xaaaaaaaa,0xaaaaaaaa,0xaaaaaaaa, + 0x8a8a8a8a,0x8a8a8a8a,0x8a8a8a8a, + 0x65656565,0x65656565,0x65656565, + 0x4d4d4d4d,0x4d4d4d4d,0x4d4d4d4d, + 0x3c3c3c3c,0x3c3c3c3c,0x3b3b3b3b, + 0x00000000,0x00000000,0x00000000, +}; +#endif + +#define CLASS_NONE_WIDTH 16 +#define CLASS_NONE_HEIGHT 16 +#define CLASS_NONE_DEPTH 5 +#define CLASS_NONE_COMPRESSION 1 +#define CLASS_NONE_MASKING 2 + +#ifdef USE_CLASS_NONE_HEADER +const struct BitMapHeader Class_None_header = +{ 16,16,88,254,5,2,1,0,0,1,1,800,600 }; +#endif + +#ifdef USE_CLASS_NONE_BODY +const UBYTE Class_None_body[234] = { +0x01,0x06,0xa0,0x01,0x00,0x60,0xff,0x00,0x01,0x07,0xe0,0x01,0x07,0xe0,0x01, +0x0d,0x40,0x01,0x10,0x00,0x01,0x07,0xf0,0x01,0x1f,0xf0,0x01,0x18,0x30,0x01, +0x29,0x10,0x01,0x12,0x50,0x01,0x1c,0x68,0x01,0x3f,0xf8,0x01,0x23,0x88,0x01, +0x11,0xec,0x01,0x65,0x88,0x01,0x39,0xb4,0x01,0x7e,0x7c,0x01,0x47,0xc4,0x01, +0x6e,0x22,0x01,0x03,0x86,0x01,0x3b,0xbc,0x01,0x7c,0x7e,0x01,0x47,0xc6,0x01, +0xd0,0x94,0x01,0x05,0xd6,0x01,0x7d,0xea,0x01,0xfe,0x7e,0x01,0x83,0x82,0x01, +0xaa,0xc7,0x01,0x01,0x05,0x01,0x7d,0x7a,0x01,0xfe,0xff,0xff,0x83,0x01,0x50, +0xaf,0x01,0x02,0x2f,0x01,0x7e,0xd2,0xff,0xff,0x01,0x81,0x03,0x01,0xa4,0x97, +0x01,0x00,0x97,0x01,0x7f,0x6a,0xff,0xff,0x01,0x80,0x03,0x01,0x51,0x2d,0x01, +0x80,0x2f,0x01,0x7e,0xd2,0xff,0xff,0x01,0x81,0x03,0x01,0x81,0x5d,0x01,0x83, +0x5d,0x01,0x7d,0x26,0x01,0xfe,0xff,0x01,0xc3,0x87,0x01,0x24,0xba,0x01,0x24, +0xbe,0x01,0x5a,0x44,0x01,0x7f,0xfe,0x01,0x41,0x06,0x01,0x11,0x7a,0x01,0x11, +0x7a,0x01,0x2e,0x8c,0x01,0x3f,0xfe,0x01,0x20,0x0e,0x01,0x17,0xe4,0x01,0x0f, +0xf4,0x01,0x18,0x38,0x01,0x1f,0xfc,0x01,0x18,0x3c,0x01,0x0b,0x98,0x01,0x0d, +0xd8,0x01,0x07,0xe0,0x01,0x0f,0xf8,0x01,0x0f,0xf8,0x01,0x03,0xe0,0x01,0x03, +0xe0,0xff,0x00,0x01,0x03,0xe0,0x01,0x03,0xe0, }; +#endif diff --git a/rom/usb/trident/MasonIcons/MI_Class_Physical.c b/rom/usb/trident/MasonIcons/MI_Class_Physical.c new file mode 100644 index 000000000..373ba7207 --- /dev/null +++ b/rom/usb/trident/MasonIcons/MI_Class_Physical.c @@ -0,0 +1,67 @@ +#ifdef USE_CLASS_PHYSICAL_COLORS +const ULONG Class_Physical_colors[96] = +{ + 0x96969696,0x96969696,0x96969696, + 0x2d2d2d2d,0x28282828,0x9e9e9e9e, + 0x00000000,0x65656565,0x9a9a9a9a, + 0x35353535,0x75757575,0xaaaaaaaa, + 0x65656565,0x8a8a8a8a,0xbabababa, + 0x0c0c0c0c,0x61616161,0xffffffff, + 0x24242424,0x5d5d5d5d,0x24242424, + 0x35353535,0x8a8a8a8a,0x35353535, + 0x86868686,0xb2b2b2b2,0x3d3d3d3d, + 0x0c0c0c0c,0xe3e3e3e3,0x00000000, + 0x4d4d4d4d,0x9e9e9e9e,0x8e8e8e8e, + 0x82828282,0x00000000,0x00000000, + 0xdfdfdfdf,0x35353535,0x35353535, + 0xdbdbdbdb,0x65656565,0x39393939, + 0xdbdbdbdb,0x8e8e8e8e,0x41414141, + 0xdfdfdfdf,0xbabababa,0x45454545, + 0xefefefef,0xe7e7e7e7,0x14141414, + 0x82828282,0x61616161,0x4d4d4d4d, + 0xa6a6a6a6,0x7e7e7e7e,0x61616161, + 0xcacacaca,0x9a9a9a9a,0x75757575, + 0x9a9a9a9a,0x55555555,0xaaaaaaaa, + 0xffffffff,0x00000000,0xffffffff, + 0xffffffff,0xffffffff,0xffffffff, + 0xdfdfdfdf,0xdfdfdfdf,0xdfdfdfdf, + 0xcacacaca,0xcacacaca,0xcacacaca, + 0xbabababa,0xbabababa,0xbabababa, + 0xaaaaaaaa,0xaaaaaaaa,0xaaaaaaaa, + 0x8a8a8a8a,0x8a8a8a8a,0x8a8a8a8a, + 0x65656565,0x65656565,0x65656565, + 0x4d4d4d4d,0x4d4d4d4d,0x4d4d4d4d, + 0x3c3c3c3c,0x3c3c3c3c,0x3b3b3b3b, + 0x00000000,0x00000000,0x00000000, +}; +#endif + +#define CLASS_PHYSICAL_WIDTH 16 +#define CLASS_PHYSICAL_HEIGHT 16 +#define CLASS_PHYSICAL_DEPTH 5 +#define CLASS_PHYSICAL_COMPRESSION 1 +#define CLASS_PHYSICAL_MASKING 2 + +#ifdef USE_CLASS_PHYSICAL_HEADER +const struct BitMapHeader Class_Physical_header = +{ 16,16,88,197,5,2,1,0,0,1,1,800,600 }; +#endif + +#ifdef USE_CLASS_PHYSICAL_BODY +const UBYTE Class_Physical_body[217] = { +0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff, +0x00,0xff,0x00,0xff,0x00,0x01,0x01,0x00,0x01,0x21,0x00,0x01,0x1e,0x00,0x01, +0x20,0x00,0x01,0x20,0x00,0x01,0x8a,0x80,0x01,0x9f,0x80,0x01,0xa0,0x00,0x01, +0x40,0x00,0x01,0xc0,0x00,0x01,0x55,0x6a,0x01,0x00,0xca,0x01,0x2a,0x70,0x01, +0xc0,0x7a,0x01,0xc0,0x7a,0x01,0x40,0xd4,0x01,0x15,0x54,0x01,0x2a,0x60,0x01, +0xc0,0x74,0x01,0xc0,0x74,0x01,0x95,0x60,0x01,0x5e,0xe0,0x01,0x20,0x80,0x01, +0xc0,0xe0,0x01,0xc0,0xe0,0x01,0x6a,0x08,0x01,0x75,0x08,0x01,0x04,0xf0,0x01, +0x45,0x00,0x01,0x45,0x00,0x01,0x1c,0x52,0x01,0x1e,0xf8,0x01,0x01,0x00,0x01, +0x1e,0x06,0x01,0x1e,0x06,0xff,0xad,0x01,0xa5,0x03,0x01,0x1e,0x50,0x01,0xbc, +0x07,0x01,0xbc,0x07,0x01,0x57,0x05,0x01,0x57,0xab,0x01,0x0c,0x50,0x01,0x5c, +0x07,0x01,0x5c,0x07,0x01,0x01,0xa9,0x01,0x03,0xf7,0xff,0x00,0x01,0x00,0x07, +0x01,0x00,0x07,0x01,0x00,0x56,0x01,0x01,0xae,0x01,0x00,0x08,0x01,0x00,0x0e, +0x01,0x00,0x0e,0x01,0x00,0xf8,0x01,0x00,0xf8,0xff,0x00,0x01,0x00,0xf8,0x01, +0x00,0xf8,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff, +0x00,0xff,0x00,0xff,0x00,0xff,0x00, }; +#endif diff --git a/rom/usb/trident/MasonIcons/MI_Class_Printer.c b/rom/usb/trident/MasonIcons/MI_Class_Printer.c new file mode 100644 index 000000000..a00477224 --- /dev/null +++ b/rom/usb/trident/MasonIcons/MI_Class_Printer.c @@ -0,0 +1,68 @@ +#ifdef USE_CLASS_PRINTER_COLORS +const ULONG Class_Printer_colors[96] = +{ + 0x96969696,0x96969696,0x96969696, + 0x2d2d2d2d,0x28282828,0x9e9e9e9e, + 0x00000000,0x65656565,0x9a9a9a9a, + 0x35353535,0x75757575,0xaaaaaaaa, + 0x65656565,0x8a8a8a8a,0xbabababa, + 0x0c0c0c0c,0x61616161,0xffffffff, + 0x24242424,0x5d5d5d5d,0x24242424, + 0x35353535,0x8a8a8a8a,0x35353535, + 0x86868686,0xb2b2b2b2,0x3d3d3d3d, + 0x0c0c0c0c,0xe3e3e3e3,0x00000000, + 0x4d4d4d4d,0x9e9e9e9e,0x8e8e8e8e, + 0x82828282,0x00000000,0x00000000, + 0xdfdfdfdf,0x35353535,0x35353535, + 0xdbdbdbdb,0x65656565,0x39393939, + 0xdbdbdbdb,0x8e8e8e8e,0x41414141, + 0xdfdfdfdf,0xbabababa,0x45454545, + 0xefefefef,0xe7e7e7e7,0x14141414, + 0x82828282,0x61616161,0x4d4d4d4d, + 0xa6a6a6a6,0x7e7e7e7e,0x61616161, + 0xcacacaca,0x9a9a9a9a,0x75757575, + 0x9a9a9a9a,0x55555555,0xaaaaaaaa, + 0xffffffff,0x00000000,0xffffffff, + 0xffffffff,0xffffffff,0xffffffff, + 0xdfdfdfdf,0xdfdfdfdf,0xdfdfdfdf, + 0xcacacaca,0xcacacaca,0xcacacaca, + 0xbabababa,0xbabababa,0xbabababa, + 0xaaaaaaaa,0xaaaaaaaa,0xaaaaaaaa, + 0x8a8a8a8a,0x8a8a8a8a,0x8a8a8a8a, + 0x65656565,0x65656565,0x65656565, + 0x4d4d4d4d,0x4d4d4d4d,0x4d4d4d4d, + 0x3c3c3c3c,0x3c3c3c3c,0x3b3b3b3b, + 0x00000000,0x00000000,0x00000000, +}; +#endif + +#define CLASS_PRINTER_WIDTH 16 +#define CLASS_PRINTER_HEIGHT 16 +#define CLASS_PRINTER_DEPTH 5 +#define CLASS_PRINTER_COMPRESSION 1 +#define CLASS_PRINTER_MASKING 2 + +#ifdef USE_CLASS_PRINTER_HEADER +const struct BitMapHeader Class_Printer_header = +{ 16,16,88,216,5,2,1,0,0,1,1,800,600 }; +#endif + +#ifdef USE_CLASS_PRINTER_BODY +const UBYTE Class_Printer_body[233] = { +0x01,0x00,0x80,0x01,0x00,0xa0,0x01,0x00,0x80,0x01,0x00,0x60,0x01,0x00,0xe0, +0x01,0x01,0x20,0x01,0x01,0x68,0x01,0x01,0x60,0x01,0x00,0x18,0x01,0x01,0xf8, +0x01,0x02,0x08,0x01,0x02,0xaa,0x01,0x02,0xa8,0x01,0x00,0x06,0x01,0x03,0xfe, +0x01,0x14,0x06,0x01,0x05,0x56,0x01,0x05,0x54,0x01,0x18,0x02,0x01,0x1f,0xfe, +0x01,0x02,0x0c,0x01,0x2a,0xac,0x01,0x22,0xa8,0x01,0x1c,0x04,0x01,0x3f,0xfc, +0x01,0x12,0x99,0x01,0x44,0xd9,0x01,0x40,0xd6,0x01,0x3f,0x0f,0x01,0x67,0xff, +0x01,0xab,0x14,0x01,0x10,0xb0,0x01,0x00,0x0f,0xff,0xff,0x01,0xf7,0xff,0x01, +0x56,0x46,0x01,0x49,0xc1,0x01,0x40,0x3f,0x01,0xbf,0xff,0xff,0xff,0x01,0xb4, +0x96,0x01,0x33,0x81,0x01,0x30,0x7f,0x01,0xcf,0xff,0xff,0xff,0x01,0x8d,0x2e, +0x01,0x0d,0x01,0x01,0x0c,0xff,0x01,0xf3,0xff,0xff,0xff,0x01,0x5f,0x18,0x01, +0x83,0x07,0x01,0x02,0xff,0x01,0xfd,0xff,0xff,0xff,0x01,0xd9,0xa4,0x01,0xe7, +0x1a,0x01,0x00,0xff,0xff,0xff,0xff,0xff,0x01,0x10,0x15,0x01,0x1e,0x69,0x01, +0x61,0xfe,0x01,0x7f,0xff,0x01,0x7f,0xff,0x01,0x2d,0x54,0x01,0x26,0xa4,0x01, +0x19,0xf8,0x01,0x3f,0xfc,0x01,0x3f,0xfc,0x01,0x0b,0x50,0x01,0x08,0x90,0x01, +0x07,0xe0,0x01,0x0f,0xf0,0x01,0x0f,0xf0,0x01,0x02,0x40,0x01,0x02,0x40,0x01, +0x01,0x80,0x01,0x03,0xc0,0x01,0x03,0xc0, }; +#endif diff --git a/rom/usb/trident/MasonIcons/MI_Class_Security.c b/rom/usb/trident/MasonIcons/MI_Class_Security.c new file mode 100644 index 000000000..07b7a6eba --- /dev/null +++ b/rom/usb/trident/MasonIcons/MI_Class_Security.c @@ -0,0 +1,68 @@ +#ifdef USE_CLASS_SECURITY_COLORS +const ULONG Class_Security_colors[96] = +{ + 0x96969696,0x96969696,0x96969696, + 0x2d2d2d2d,0x28282828,0x9e9e9e9e, + 0x00000000,0x65656565,0x9a9a9a9a, + 0x35353535,0x75757575,0xaaaaaaaa, + 0x65656565,0x8a8a8a8a,0xbabababa, + 0x0c0c0c0c,0x61616161,0xffffffff, + 0x24242424,0x5d5d5d5d,0x24242424, + 0x35353535,0x8a8a8a8a,0x35353535, + 0x86868686,0xb2b2b2b2,0x3d3d3d3d, + 0x0c0c0c0c,0xe3e3e3e3,0x00000000, + 0x4d4d4d4d,0x9e9e9e9e,0x8e8e8e8e, + 0x82828282,0x00000000,0x00000000, + 0xdfdfdfdf,0x35353535,0x35353535, + 0xdbdbdbdb,0x65656565,0x39393939, + 0xdbdbdbdb,0x8e8e8e8e,0x41414141, + 0xdfdfdfdf,0xbabababa,0x45454545, + 0xefefefef,0xe7e7e7e7,0x14141414, + 0x82828282,0x61616161,0x4d4d4d4d, + 0xa6a6a6a6,0x7e7e7e7e,0x61616161, + 0xcacacaca,0x9a9a9a9a,0x75757575, + 0x9a9a9a9a,0x55555555,0xaaaaaaaa, + 0xffffffff,0x00000000,0xffffffff, + 0xffffffff,0xffffffff,0xffffffff, + 0xdfdfdfdf,0xdfdfdfdf,0xdfdfdfdf, + 0xcacacaca,0xcacacaca,0xcacacaca, + 0xbabababa,0xbabababa,0xbabababa, + 0xaaaaaaaa,0xaaaaaaaa,0xaaaaaaaa, + 0x8a8a8a8a,0x8a8a8a8a,0x8a8a8a8a, + 0x65656565,0x65656565,0x65656565, + 0x4d4d4d4d,0x4d4d4d4d,0x4d4d4d4d, + 0x3c3c3c3c,0x3c3c3c3c,0x3b3b3b3b, + 0x00000000,0x00000000,0x00000000, +}; +#endif + +#define CLASS_SECURITY_WIDTH 16 +#define CLASS_SECURITY_HEIGHT 16 +#define CLASS_SECURITY_DEPTH 5 +#define CLASS_SECURITY_COMPRESSION 1 +#define CLASS_SECURITY_MASKING 2 + +#ifdef USE_CLASS_SECURITY_HEADER +const struct BitMapHeader Class_Security_header = +{ 16,16,88,121,5,2,1,0,0,1,1,800,600 }; +#endif + +#ifdef USE_CLASS_SECURITY_BODY +const UBYTE Class_Security_body[228] = { +0x01,0x00,0x01,0x01,0x7f,0xfd,0x01,0x7f,0xfc,0x01,0x80,0x03,0xff,0xff,0x01, +0x9d,0x40,0x01,0xfd,0x40,0x01,0xfd,0x41,0x01,0x02,0xbf,0xff,0xff,0x01,0x3f, +0xf9,0x01,0xdf,0xfc,0x01,0xff,0xf9,0x01,0x3f,0xff,0xff,0xff,0xff,0x70,0x01, +0xe0,0x0d,0x01,0xff,0xfd,0x01,0x3f,0xfb,0xff,0xff,0x01,0x65,0x29,0x01,0xe5, +0x05,0x01,0xfa,0xfd,0x01,0x3f,0xfb,0xff,0xff,0x01,0x6a,0xa9,0x01,0xea,0xd5, +0x01,0xf5,0x0d,0x01,0x3f,0xfb,0xff,0xff,0x01,0x67,0x1d,0x01,0xe7,0x55,0x01, +0xf8,0x25,0x01,0x3f,0x8b,0x01,0xff,0x8f,0x01,0x16,0x69,0x01,0xac,0xdd,0x01, +0x8c,0x21,0x01,0x73,0x27,0x01,0xff,0x27,0x01,0x21,0x11,0x01,0x8a,0xc2,0x01, +0xc1,0x3d,0x01,0x7f,0x77,0x01,0xff,0x77,0x01,0x6a,0x91,0x01,0xbf,0x7b,0x01, +0xc1,0x05,0x01,0x7f,0x27,0x01,0xff,0x27,0x01,0xbf,0x45,0x01,0x94,0xb6,0x01, +0xab,0x89,0x01,0x7f,0x8f,0x01,0xff,0x8f,0x01,0x54,0x2b,0x01,0x81,0x4e,0x01, +0x16,0x71,0xff,0xff,0x01,0xf7,0xff,0x01,0xd5,0xb6,0x01,0x9a,0x70,0x01,0x60, +0x0f,0xff,0xff,0xff,0xff,0x01,0xa2,0x75,0x01,0x9d,0x89,0x01,0x7f,0xfe,0xff, +0xff,0xff,0xff,0x01,0x4a,0xca,0x01,0x41,0xd2,0x01,0x30,0x3c,0x01,0x7f,0xfe, +0x01,0x7f,0xfe,0x01,0x30,0x0c,0x01,0x30,0x0c,0x01,0x0f,0xf0,0x01,0x3f,0xfc, +0x01,0x3f,0xfc, }; +#endif diff --git a/rom/usb/trident/MasonIcons/MI_Class_StillImage.c b/rom/usb/trident/MasonIcons/MI_Class_StillImage.c new file mode 100644 index 000000000..cec2f81ac --- /dev/null +++ b/rom/usb/trident/MasonIcons/MI_Class_StillImage.c @@ -0,0 +1,68 @@ +#ifdef USE_CLASS_STILLIMAGE_COLORS +const ULONG Class_StillImage_colors[96] = +{ + 0x96969696,0x96969696,0x96969696, + 0x2d2d2d2d,0x28282828,0x9e9e9e9e, + 0x00000000,0x65656565,0x9a9a9a9a, + 0x35353535,0x75757575,0xaaaaaaaa, + 0x65656565,0x8a8a8a8a,0xbabababa, + 0x0c0c0c0c,0x61616161,0xffffffff, + 0x24242424,0x5d5d5d5d,0x24242424, + 0x35353535,0x8a8a8a8a,0x35353535, + 0x86868686,0xb2b2b2b2,0x3d3d3d3d, + 0x0c0c0c0c,0xe3e3e3e3,0x00000000, + 0x4d4d4d4d,0x9e9e9e9e,0x8e8e8e8e, + 0x82828282,0x00000000,0x00000000, + 0xdfdfdfdf,0x35353535,0x35353535, + 0xdbdbdbdb,0x65656565,0x39393939, + 0xdbdbdbdb,0x8e8e8e8e,0x41414141, + 0xdfdfdfdf,0xbabababa,0x45454545, + 0xefefefef,0xe7e7e7e7,0x14141414, + 0x82828282,0x61616161,0x4d4d4d4d, + 0xa6a6a6a6,0x7e7e7e7e,0x61616161, + 0xcacacaca,0x9a9a9a9a,0x75757575, + 0x9a9a9a9a,0x55555555,0xaaaaaaaa, + 0xffffffff,0x00000000,0xffffffff, + 0xffffffff,0xffffffff,0xffffffff, + 0xdfdfdfdf,0xdfdfdfdf,0xdfdfdfdf, + 0xcacacaca,0xcacacaca,0xcacacaca, + 0xbabababa,0xbabababa,0xbabababa, + 0xaaaaaaaa,0xaaaaaaaa,0xaaaaaaaa, + 0x8a8a8a8a,0x8a8a8a8a,0x8a8a8a8a, + 0x65656565,0x65656565,0x65656565, + 0x4d4d4d4d,0x4d4d4d4d,0x4d4d4d4d, + 0x3c3c3c3c,0x3c3c3c3c,0x3b3b3b3b, + 0x00000000,0x00000000,0x00000000, +}; +#endif + +#define CLASS_STILLIMAGE_WIDTH 16 +#define CLASS_STILLIMAGE_HEIGHT 16 +#define CLASS_STILLIMAGE_DEPTH 5 +#define CLASS_STILLIMAGE_COMPRESSION 1 +#define CLASS_STILLIMAGE_MASKING 0 + +#ifdef USE_CLASS_STILLIMAGE_HEADER +const struct BitMapHeader Class_StillImage_header = +{ 16,16,0,0,5,0,1,0,0,11,10,16,16 }; +#endif + +#ifdef USE_CLASS_STILLIMAGE_BODY +const UBYTE Class_StillImage_body[235] = { +0x01,0x30,0x28,0x01,0x30,0x04,0xff,0x00,0x01,0x30,0x3c,0x01,0x30,0x3c,0x01, +0x70,0x42,0x01,0x44,0xbe,0x01,0x3a,0x00,0x01,0x7e,0xfe,0x01,0x7e,0xfe,0x01, +0x29,0xa9,0x01,0x16,0x8b,0x01,0x38,0x80,0x01,0x3f,0x6b,0x01,0x3f,0xeb,0x01, +0x85,0x60,0x01,0x49,0x16,0x01,0xf9,0x01,0x01,0xfe,0xf7,0x01,0xff,0xf7,0x01, +0x97,0x0b,0x01,0x02,0xfa,0x01,0xfa,0x01,0x01,0xfd,0xfb,0x01,0xff,0xfb,0x01, +0x26,0x66,0x01,0x91,0x86,0x01,0xf8,0x09,0x01,0xff,0xef,0x01,0xff,0xef,0x01, +0xa6,0x05,0x01,0x12,0xb4,0x01,0xfa,0x03,0x01,0xfd,0xb7,0x01,0xff,0xb7,0x01, +0x36,0x85,0x01,0x82,0x64,0x01,0xfb,0xf3,0x01,0xfd,0xff,0xff,0xff,0x01,0xa5, +0x68,0x01,0x12,0xf8,0x01,0xf9,0xf3,0x01,0xff,0xfb,0x01,0xff,0xfb,0x01,0x34, +0xd1,0x01,0x83,0xf0,0x01,0xf9,0xfb,0x01,0xff,0xfb,0x01,0xff,0xfb,0x01,0xa4, +0x84,0x01,0x13,0xd5,0x01,0xf9,0xfb,0xff,0xff,0xff,0xff,0x01,0xb3,0xc9,0x01, +0x98,0x7a,0x01,0x79,0xf7,0x01,0xfb,0xff,0x01,0xfb,0xff,0x01,0xa4,0x96,0x01, +0xb8,0x91,0x01,0x7c,0x6f,0x01,0xfd,0xff,0x01,0xfd,0xff,0x01,0x23,0x0d,0x01, +0x23,0xe3,0x01,0x1c,0x1e,0x01,0x3f,0xff,0x01,0x3f,0xff,0x01,0x08,0x2f,0x01, +0x08,0x0f,0x01,0x03,0xf0,0x01,0x0b,0xff,0x01,0x0b,0xff,0x01,0x01,0xf0,0x01, +0x01,0xf0,0xff,0x00,0x01,0x01,0xf0,0x01,0x01,0xf0, }; +#endif diff --git a/rom/usb/trident/MasonIcons/MI_Class_Vendor.c b/rom/usb/trident/MasonIcons/MI_Class_Vendor.c new file mode 100644 index 000000000..159bd0c4f --- /dev/null +++ b/rom/usb/trident/MasonIcons/MI_Class_Vendor.c @@ -0,0 +1,68 @@ +#ifdef USE_CLASS_VENDOR_COLORS +const ULONG Class_Vendor_colors[96] = +{ + 0x96969696,0x96969696,0x96969696, + 0x2d2d2d2d,0x28282828,0x9e9e9e9e, + 0x00000000,0x65656565,0x9a9a9a9a, + 0x35353535,0x75757575,0xaaaaaaaa, + 0x65656565,0x8a8a8a8a,0xbabababa, + 0x0c0c0c0c,0x61616161,0xffffffff, + 0x24242424,0x5d5d5d5d,0x24242424, + 0x35353535,0x8a8a8a8a,0x35353535, + 0x86868686,0xb2b2b2b2,0x3d3d3d3d, + 0x0c0c0c0c,0xe3e3e3e3,0x00000000, + 0x4d4d4d4d,0x9e9e9e9e,0x8e8e8e8e, + 0x82828282,0x00000000,0x00000000, + 0xdfdfdfdf,0x35353535,0x35353535, + 0xdbdbdbdb,0x65656565,0x39393939, + 0xdbdbdbdb,0x8e8e8e8e,0x41414141, + 0xdfdfdfdf,0xbabababa,0x45454545, + 0xefefefef,0xe7e7e7e7,0x14141414, + 0x82828282,0x61616161,0x4d4d4d4d, + 0xa6a6a6a6,0x7e7e7e7e,0x61616161, + 0xcacacaca,0x9a9a9a9a,0x75757575, + 0x9a9a9a9a,0x55555555,0xaaaaaaaa, + 0xffffffff,0x00000000,0xffffffff, + 0xffffffff,0xffffffff,0xffffffff, + 0xdfdfdfdf,0xdfdfdfdf,0xdfdfdfdf, + 0xcacacaca,0xcacacaca,0xcacacaca, + 0xbabababa,0xbabababa,0xbabababa, + 0xaaaaaaaa,0xaaaaaaaa,0xaaaaaaaa, + 0x8a8a8a8a,0x8a8a8a8a,0x8a8a8a8a, + 0x65656565,0x65656565,0x65656565, + 0x4d4d4d4d,0x4d4d4d4d,0x4d4d4d4d, + 0x3c3c3c3c,0x3c3c3c3c,0x3b3b3b3b, + 0x00000000,0x00000000,0x00000000, +}; +#endif + +#define CLASS_VENDOR_WIDTH 16 +#define CLASS_VENDOR_HEIGHT 16 +#define CLASS_VENDOR_DEPTH 5 +#define CLASS_VENDOR_COMPRESSION 1 +#define CLASS_VENDOR_MASKING 2 + +#ifdef USE_CLASS_VENDOR_HEADER +const struct BitMapHeader Class_Vendor_header = +{ 16,16,88,235,5,2,1,0,0,1,1,800,600 }; +#endif + +#ifdef USE_CLASS_VENDOR_BODY +const UBYTE Class_Vendor_body[229] = { +0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0x01,0x02,0x00,0x01,0x1a, +0x00,0x01,0x18,0x00,0x01,0x06,0x00,0x01,0x1e,0x00,0x01,0x13,0x00,0x01,0x2b, +0x00,0x01,0x26,0x00,0x01,0x1f,0x00,0x01,0x3f,0x00,0x01,0x25,0x00,0x01,0x57, +0x00,0x01,0x4e,0x00,0x01,0x3f,0x00,0x01,0x7e,0x00,0x01,0x0a,0x80,0x01,0x6c, +0x80,0x01,0x5f,0x00,0x01,0x3f,0x80,0x01,0x7c,0x00,0x01,0x54,0xc0,0x01,0x38, +0xc0,0x01,0x0f,0x00,0x01,0x7f,0xc0,0x01,0x78,0x40,0x01,0x19,0x40,0x01,0x21, +0x40,0x01,0x5e,0x80,0x01,0x7f,0xc0,0x01,0x70,0x00,0x01,0x7b,0xa0,0x01,0x0c, +0xa0,0x01,0x71,0x40,0x01,0x75,0xe0,0x01,0x6e,0x00,0x01,0x4e,0xd0,0x01,0x7a, +0x50,0x01,0x35,0xa0,0x01,0x7f,0xf0,0x01,0x7c,0x00,0x01,0x33,0x68,0x01,0x3f, +0x28,0x01,0x0c,0xd0,0x01,0x3f,0xf8,0x01,0x2e,0x00,0x01,0x0c,0xac,0x01,0x0b, +0x8c,0x01,0x14,0x70,0x01,0x1f,0xfc,0x01,0x17,0x00,0x01,0x12,0x5a,0x01,0x1c, +0xde,0x01,0x0f,0xa4,0x01,0x1f,0xfe,0x01,0x1f,0x86,0x01,0x0b,0x3a,0x01,0x08, +0xfe,0x01,0x07,0xcc,0x01,0x0f,0xfe,0x01,0x0f,0xce,0x01,0x06,0xb4,0x01,0x06, +0xdc,0x01,0x01,0x78,0x01,0x07,0xfc,0x01,0x07,0xfc,0x01,0x01,0x78,0x01,0x01, +0x78,0xff,0x00,0x01,0x01,0x78,0x01,0x01,0x78,0xff,0x00,0xff,0x00,0xff,0x00, +0xff,0x00,0xff,0x00, }; +#endif diff --git a/rom/usb/trident/MasonIcons/MI_Classes.c b/rom/usb/trident/MasonIcons/MI_Classes.c new file mode 100644 index 000000000..128ee88d0 --- /dev/null +++ b/rom/usb/trident/MasonIcons/MI_Classes.c @@ -0,0 +1,68 @@ +#ifdef USE_CLASSES_COLORS +const ULONG Classes_colors[96] = +{ + 0x96969696,0x96969696,0x96969696, + 0x2d2d2d2d,0x28282828,0x9e9e9e9e, + 0x00000000,0x65656565,0x9a9a9a9a, + 0x35353535,0x75757575,0xaaaaaaaa, + 0x65656565,0x8a8a8a8a,0xbabababa, + 0x0c0c0c0c,0x61616161,0xffffffff, + 0x24242424,0x5d5d5d5d,0x24242424, + 0x35353535,0x8a8a8a8a,0x35353535, + 0x86868686,0xb2b2b2b2,0x3d3d3d3d, + 0x0c0c0c0c,0xe3e3e3e3,0x00000000, + 0x4d4d4d4d,0x9e9e9e9e,0x8e8e8e8e, + 0x82828282,0x00000000,0x00000000, + 0xdfdfdfdf,0x35353535,0x35353535, + 0xdbdbdbdb,0x65656565,0x39393939, + 0xdbdbdbdb,0x8e8e8e8e,0x41414141, + 0xdfdfdfdf,0xbabababa,0x45454545, + 0xefefefef,0xe7e7e7e7,0x14141414, + 0x82828282,0x61616161,0x4d4d4d4d, + 0xa6a6a6a6,0x7e7e7e7e,0x61616161, + 0xcacacaca,0x9a9a9a9a,0x75757575, + 0x9a9a9a9a,0x55555555,0xaaaaaaaa, + 0xffffffff,0x00000000,0xffffffff, + 0xffffffff,0xffffffff,0xffffffff, + 0xdfdfdfdf,0xdfdfdfdf,0xdfdfdfdf, + 0xcacacaca,0xcacacaca,0xcacacaca, + 0xbabababa,0xbabababa,0xbabababa, + 0xaaaaaaaa,0xaaaaaaaa,0xaaaaaaaa, + 0x8a8a8a8a,0x8a8a8a8a,0x8a8a8a8a, + 0x65656565,0x65656565,0x65656565, + 0x4d4d4d4d,0x4d4d4d4d,0x4d4d4d4d, + 0x3c3c3c3c,0x3c3c3c3c,0x3b3b3b3b, + 0x00000000,0x00000000,0x00000000, +}; +#endif + +#define CLASSES_WIDTH 16 +#define CLASSES_HEIGHT 16 +#define CLASSES_DEPTH 5 +#define CLASSES_COMPRESSION 1 +#define CLASSES_MASKING 2 + +#ifdef USE_CLASSES_HEADER +const struct BitMapHeader Classes_header = +{ 16,16,69,83,5,2,1,0,0,1,1,800,600 }; +#endif + +#ifdef USE_CLASSES_BODY +const UBYTE Classes_body[230] = { +0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0x01,0x02,0x60,0x01,0x02, +0x60,0x01,0x01,0x80,0x01,0x02,0x20,0x01,0x02,0x20,0x01,0x08,0x98,0x01,0x08, +0xb8,0x01,0x07,0x40,0xff,0x08,0xff,0x08,0x01,0x25,0xf6,0x01,0x25,0xfe,0x01, +0x1a,0x00,0x01,0x20,0x02,0x01,0x20,0x02,0x01,0x0b,0x7c,0x01,0x0b,0x7e,0x01, +0x74,0x80,0xff,0x00,0xff,0x00,0x01,0x25,0xf4,0x01,0x25,0xfa,0x01,0x5a,0x02, +0x01,0x00,0x02,0x01,0x00,0x02,0x01,0x39,0xde,0x01,0x39,0xe2,0x01,0x46,0x02, +0x01,0x00,0x02,0x01,0x00,0x02,0x01,0x3c,0x74,0x01,0x3e,0x0a,0x01,0x41,0x8a, +0x01,0x00,0x0a,0x01,0x00,0x0a,0x01,0x36,0x5b,0x01,0x3f,0xa7,0x01,0x40,0x26, +0x01,0x00,0x27,0x01,0x00,0x27,0x01,0x3d,0x76,0x01,0x3f,0x8a,0x01,0x40,0x0a, +0x01,0x00,0x0a,0x01,0x00,0x0a,0x01,0x6a,0x2b,0x01,0x7f,0xd7,0x01,0x00,0x56, +0x01,0x00,0x57,0x01,0x00,0x57,0x01,0x54,0x53,0x01,0x5f,0xad,0x01,0x20,0x2e, +0x01,0x60,0x2f,0x01,0x60,0x2f,0x01,0x29,0x2a,0x01,0x27,0xd2,0x01,0x18,0x5c, +0x01,0x38,0x5e,0x01,0x38,0x5e,0x01,0x1e,0x2c,0x01,0x19,0xcc,0x01,0x06,0x70, +0x01,0x1e,0x7c,0x01,0x1e,0x7c,0x01,0x07,0xb0,0x01,0x06,0x30,0x01,0x01,0xc0, +0x01,0x07,0xf0,0x01,0x07,0xf0,0x01,0x01,0xc0,0x01,0x01,0xc0,0xff,0x00,0x01, +0x01,0xc0,0x01,0x01,0xc0, }; +#endif diff --git a/rom/usb/trident/MasonIcons/MI_Devices.c b/rom/usb/trident/MasonIcons/MI_Devices.c new file mode 100644 index 000000000..e1aaebbd1 --- /dev/null +++ b/rom/usb/trident/MasonIcons/MI_Devices.c @@ -0,0 +1,68 @@ +#ifdef USE_DEVICES_COLORS +const ULONG Devices_colors[96] = +{ + 0x96969696,0x96969696,0x96969696, + 0x2d2d2d2d,0x28282828,0x9e9e9e9e, + 0x00000000,0x65656565,0x9a9a9a9a, + 0x35353535,0x75757575,0xaaaaaaaa, + 0x65656565,0x8a8a8a8a,0xbabababa, + 0x0c0c0c0c,0x61616161,0xffffffff, + 0x24242424,0x5d5d5d5d,0x24242424, + 0x35353535,0x8a8a8a8a,0x35353535, + 0x86868686,0xb2b2b2b2,0x3d3d3d3d, + 0x0c0c0c0c,0xe3e3e3e3,0x00000000, + 0x4d4d4d4d,0x9e9e9e9e,0x8e8e8e8e, + 0x82828282,0x00000000,0x00000000, + 0xdfdfdfdf,0x35353535,0x35353535, + 0xdbdbdbdb,0x65656565,0x39393939, + 0xdbdbdbdb,0x8e8e8e8e,0x41414141, + 0xdfdfdfdf,0xbabababa,0x45454545, + 0xefefefef,0xe7e7e7e7,0x14141414, + 0x82828282,0x61616161,0x4d4d4d4d, + 0xa6a6a6a6,0x7e7e7e7e,0x61616161, + 0xcacacaca,0x9a9a9a9a,0x75757575, + 0x9a9a9a9a,0x55555555,0xaaaaaaaa, + 0xffffffff,0x00000000,0xffffffff, + 0xffffffff,0xffffffff,0xffffffff, + 0xdfdfdfdf,0xdfdfdfdf,0xdfdfdfdf, + 0xcacacaca,0xcacacaca,0xcacacaca, + 0xbabababa,0xbabababa,0xbabababa, + 0xaaaaaaaa,0xaaaaaaaa,0xaaaaaaaa, + 0x8a8a8a8a,0x8a8a8a8a,0x8a8a8a8a, + 0x65656565,0x65656565,0x65656565, + 0x4d4d4d4d,0x4d4d4d4d,0x4d4d4d4d, + 0x3c3c3c3c,0x3c3c3c3c,0x3b3b3b3b, + 0x00000000,0x00000000,0x00000000, +}; +#endif + +#define DEVICES_WIDTH 16 +#define DEVICES_HEIGHT 16 +#define DEVICES_DEPTH 5 +#define DEVICES_COMPRESSION 1 +#define DEVICES_MASKING 2 + +#ifdef USE_DEVICES_HEADER +const struct BitMapHeader Devices_header = +{ 16,16,69,64,5,2,1,0,0,1,1,800,600 }; +#endif + +#ifdef USE_DEVICES_BODY +const UBYTE Devices_body[235] = { +0x01,0x0e,0xe0,0x01,0x08,0x80,0x01,0x0e,0xe0,0x01,0x0e,0xe0,0xff,0x00,0x01, +0x3b,0xf8,0x01,0x0a,0xd0,0x01,0x3b,0xe8,0x01,0x3b,0xf8,0x01,0x04,0x00,0x01, +0x48,0x3c,0x01,0x00,0x2c,0x01,0x48,0x38,0x01,0x48,0x3c,0x01,0x37,0xc0,0x01, +0xe7,0x7e,0x01,0x07,0x32,0x01,0xe6,0xfc,0x01,0xe7,0xfe,0x01,0x1a,0x00,0x01, +0x8f,0x3e,0x01,0x0f,0x0a,0x01,0x8c,0xfe,0x01,0x8f,0xfe,0x01,0x74,0x02,0x01, +0x6f,0x7e,0x01,0x6f,0x16,0x01,0xae,0xfa,0x01,0xef,0xfe,0x01,0x16,0x02,0x01, +0x07,0xfe,0x01,0x04,0x22,0x01,0x87,0xfe,0x01,0x87,0xfe,0x01,0x78,0x02,0x01, +0x6f,0xfe,0x01,0x4f,0x4e,0x01,0xaf,0xf6,0x01,0xef,0xfe,0x01,0x10,0x06,0x01, +0x5f,0xfe,0x01,0x1b,0x5e,0x01,0xdf,0xee,0x01,0xdf,0xfe,0x01,0x28,0x0e,0x01, +0x7f,0xff,0x01,0x3b,0x7f,0x01,0xdd,0xbe,0xff,0xff,0x01,0x19,0x3f,0x01,0xff, +0xfe,0x01,0xbb,0x7e,0x01,0x4f,0x9c,0x01,0xff,0xfe,0x01,0x0b,0x1c,0xff,0xff, +0x01,0xbb,0x7d,0x01,0x5d,0xba,0xff,0xff,0x01,0x99,0x3b,0x01,0x7f,0xfd,0x01, +0x3b,0x7d,0x01,0x4f,0x9a,0x01,0x7f,0xff,0x01,0x0b,0x1b,0x01,0x3f,0xfa,0x01, +0x33,0x7a,0x01,0x1d,0xb4,0x01,0x3f,0xfe,0x01,0x19,0xb6,0x01,0x1f,0x75,0x01, +0x1b,0x65,0x01,0x07,0xf8,0x01,0x1f,0xfd,0x01,0x1f,0xfd,0x01,0x07,0xfa,0x01, +0x07,0xfa,0xff,0x00,0x01,0x07,0xfa,0x01,0x07,0xfa, }; +#endif diff --git a/rom/usb/trident/MasonIcons/MI_General.c b/rom/usb/trident/MasonIcons/MI_General.c new file mode 100644 index 000000000..7750d9047 --- /dev/null +++ b/rom/usb/trident/MasonIcons/MI_General.c @@ -0,0 +1,68 @@ +#ifdef USE_GENERAL_COLORS +const ULONG General_colors[96] = +{ + 0x96969696,0x96969696,0x96969696, + 0x2d2d2d2d,0x28282828,0x9e9e9e9e, + 0x00000000,0x65656565,0x9a9a9a9a, + 0x35353535,0x75757575,0xaaaaaaaa, + 0x65656565,0x8a8a8a8a,0xbabababa, + 0x0c0c0c0c,0x61616161,0xffffffff, + 0x24242424,0x5d5d5d5d,0x24242424, + 0x35353535,0x8a8a8a8a,0x35353535, + 0x86868686,0xb2b2b2b2,0x3d3d3d3d, + 0x0c0c0c0c,0xe3e3e3e3,0x00000000, + 0x4d4d4d4d,0x9e9e9e9e,0x8e8e8e8e, + 0x82828282,0x00000000,0x00000000, + 0xdfdfdfdf,0x35353535,0x35353535, + 0xdbdbdbdb,0x65656565,0x39393939, + 0xdbdbdbdb,0x8e8e8e8e,0x41414141, + 0xdfdfdfdf,0xbabababa,0x45454545, + 0xefefefef,0xe7e7e7e7,0x14141414, + 0x82828282,0x61616161,0x4d4d4d4d, + 0xa6a6a6a6,0x7e7e7e7e,0x61616161, + 0xcacacaca,0x9a9a9a9a,0x75757575, + 0x9a9a9a9a,0x55555555,0xaaaaaaaa, + 0xffffffff,0x00000000,0xffffffff, + 0xffffffff,0xffffffff,0xffffffff, + 0xdfdfdfdf,0xdfdfdfdf,0xdfdfdfdf, + 0xcacacaca,0xcacacaca,0xcacacaca, + 0xbabababa,0xbabababa,0xbabababa, + 0xaaaaaaaa,0xaaaaaaaa,0xaaaaaaaa, + 0x8a8a8a8a,0x8a8a8a8a,0x8a8a8a8a, + 0x65656565,0x65656565,0x65656565, + 0x4d4d4d4d,0x4d4d4d4d,0x4d4d4d4d, + 0x3c3c3c3c,0x3c3c3c3c,0x3b3b3b3b, + 0x00000000,0x00000000,0x00000000, +}; +#endif + +#define GENERAL_WIDTH 16 +#define GENERAL_HEIGHT 16 +#define GENERAL_DEPTH 5 +#define GENERAL_COMPRESSION 1 +#define GENERAL_MASKING 2 + +#ifdef USE_GENERAL_HEADER +const struct BitMapHeader General_header = +{ 16,16,69,26,5,2,1,0,0,1,1,800,600 }; +#endif + +#ifdef USE_GENERAL_BODY +const UBYTE General_body[235] = { +0x01,0x06,0xa0,0x01,0x00,0x60,0xff,0x00,0x01,0x07,0xe0,0x01,0x07,0xe0,0x01, +0x0e,0x80,0x01,0x17,0xc0,0x01,0x00,0x30,0x01,0x18,0x30,0x01,0x18,0x30,0x01, +0x2e,0x70,0x01,0x0f,0xe0,0x01,0x13,0xc8,0x01,0x20,0x08,0x01,0x23,0xc8,0x01, +0x1c,0xac,0x01,0x5e,0xb0,0x01,0x27,0x24,0x01,0x40,0xc4,0x01,0x46,0xe4,0x01, +0x79,0x12,0x01,0x37,0x7e,0x01,0x04,0xa4,0x01,0x4a,0x46,0x01,0x4e,0x66,0x01, +0xd2,0x94,0x01,0x7e,0xba,0x01,0x07,0x22,0x01,0x88,0x42,0x01,0x8e,0x62,0x01, +0xf5,0x9f,0x01,0x75,0x51,0x01,0x0c,0x42,0x01,0x82,0xa3,0x01,0x86,0xe3,0x01, +0x2a,0x67,0x01,0x7b,0xbb,0x01,0x04,0x82,0x01,0x81,0x43,0x01,0x81,0xc3,0x01, +0xd6,0x4f,0x01,0x7f,0xf3,0x01,0x01,0x02,0x01,0x82,0x83,0xff,0x83,0x01,0x24, +0xd5,0x01,0xff,0xeb,0x01,0x00,0x02,0xff,0x83,0xff,0x83,0x01,0x8a,0xad,0x01, +0xbe,0xd5,0x01,0x40,0x06,0x01,0xc1,0x07,0x01,0xc1,0x07,0x01,0x24,0x5a,0x01, +0x1d,0xe6,0x01,0x41,0x04,0x01,0x42,0x86,0x01,0x43,0x86,0x01,0x12,0x3a,0x01, +0x0f,0xca,0x01,0x20,0x0c,0x01,0x21,0x0e,0x01,0x21,0x0e,0x01,0x17,0xe4,0x01, +0x08,0x34,0x01,0x18,0x38,0x01,0x18,0x3c,0x01,0x18,0x3c,0x01,0x0b,0x98,0x01, +0x0d,0xd8,0x01,0x07,0xe0,0x01,0x0f,0xf8,0x01,0x0f,0xf8,0x01,0x03,0xe0,0x01, +0x03,0xe0,0xff,0x00,0x01,0x03,0xe0,0x01,0x03,0xe0, }; +#endif diff --git a/rom/usb/trident/MasonIcons/MI_GreenLED.c b/rom/usb/trident/MasonIcons/MI_GreenLED.c new file mode 100644 index 000000000..d6b068893 --- /dev/null +++ b/rom/usb/trident/MasonIcons/MI_GreenLED.c @@ -0,0 +1,68 @@ +#ifdef USE_GREENLED_COLORS +const ULONG GreenLED_colors[96] = +{ + 0x96969696,0x96969696,0x96969696, + 0x2d2d2d2d,0x28282828,0x9e9e9e9e, + 0x00000000,0x65656565,0x9a9a9a9a, + 0x35353535,0x75757575,0xaaaaaaaa, + 0x65656565,0x8a8a8a8a,0xbabababa, + 0x0c0c0c0c,0x61616161,0xffffffff, + 0x24242424,0x5d5d5d5d,0x24242424, + 0x35353535,0x8a8a8a8a,0x35353535, + 0x86868686,0xb2b2b2b2,0x3d3d3d3d, + 0x0c0c0c0c,0xe3e3e3e3,0x00000000, + 0x4d4d4d4d,0x9e9e9e9e,0x8e8e8e8e, + 0x82828282,0x00000000,0x00000000, + 0xdfdfdfdf,0x35353535,0x35353535, + 0xdbdbdbdb,0x65656565,0x39393939, + 0xdbdbdbdb,0x8e8e8e8e,0x41414141, + 0xdfdfdfdf,0xbabababa,0x45454545, + 0xefefefef,0xe7e7e7e7,0x14141414, + 0x82828282,0x61616161,0x4d4d4d4d, + 0xa6a6a6a6,0x7e7e7e7e,0x61616161, + 0xcacacaca,0x9a9a9a9a,0x75757575, + 0x9a9a9a9a,0x55555555,0xaaaaaaaa, + 0xffffffff,0x00000000,0xffffffff, + 0xffffffff,0xffffffff,0xffffffff, + 0xdfdfdfdf,0xdfdfdfdf,0xdfdfdfdf, + 0xcacacaca,0xcacacaca,0xcacacaca, + 0xbabababa,0xbabababa,0xbabababa, + 0xaaaaaaaa,0xaaaaaaaa,0xaaaaaaaa, + 0x8a8a8a8a,0x8a8a8a8a,0x8a8a8a8a, + 0x65656565,0x65656565,0x65656565, + 0x4d4d4d4d,0x4d4d4d4d,0x4d4d4d4d, + 0x3c3c3c3c,0x3c3c3c3c,0x3b3b3b3b, + 0x00000000,0x00000000,0x00000000, +}; +#endif + +#define GREENLED_WIDTH 16 +#define GREENLED_HEIGHT 16 +#define GREENLED_DEPTH 5 +#define GREENLED_COMPRESSION 1 +#define GREENLED_MASKING 0 + +#ifdef USE_GREENLED_HEADER +const struct BitMapHeader GreenLED_header = +{ 16,16,0,0,5,0,1,0,0,11,10,16,16 }; +#endif + +#ifdef USE_GREENLED_BODY +const UBYTE GreenLED_body[238] = { +0x01,0x06,0xa0,0x01,0x00,0x60,0xff,0x00,0x01,0x07,0xe0,0x01,0x07,0xe0,0x01, +0x0a,0x80,0x01,0x12,0x80,0x01,0x02,0xb0,0x01,0x1d,0x70,0x01,0x18,0x30,0x01, +0x25,0x40,0x01,0x15,0x50,0x01,0x05,0x58,0x01,0x3a,0xa8,0x01,0x20,0x08,0x01, +0x0a,0xf4,0x01,0x6a,0xf8,0x01,0x0a,0xfc,0x01,0x75,0x04,0x01,0x40,0x04,0x01, +0x55,0xba,0x01,0x15,0xbe,0x01,0x15,0xbc,0x01,0x6a,0x46,0x01,0x40,0x06,0x01, +0xab,0xe8,0x01,0x2b,0xfe,0x01,0x2b,0xfe,0x01,0xd4,0x02,0x01,0x80,0x02,0x01, +0xd6,0xfb,0x01,0x56,0xfd,0x01,0x56,0xfe,0x01,0xa9,0x03,0x01,0x80,0x03,0x01, +0x2f,0xd3,0x01,0x2f,0xff,0x01,0x2f,0xfe,0x01,0xd0,0x03,0x01,0x80,0x03,0x01, +0xdb,0x6b,0x01,0x5b,0xff,0x01,0x5b,0xfe,0x01,0xa4,0x03,0x01,0x80,0x03,0x01, +0x2f,0xd1,0x01,0xaf,0xff,0x01,0x2f,0xfe,0x01,0xd0,0x03,0x01,0x80,0x03,0x01, +0xbe,0xa5,0x01,0xbf,0xfd,0x01,0x7f,0xfe,0x01,0xc0,0x07,0x01,0xc0,0x07,0x01, +0x1b,0x42,0x01,0x3f,0xfe,0x01,0x7f,0xfc,0x01,0x40,0x06,0x01,0x40,0x06,0x01, +0x0e,0x8a,0x01,0x1f,0xfa,0x01,0x3f,0xfc,0x01,0x20,0x0e,0x01,0x20,0x0e,0x01, +0x10,0x24,0x01,0x0f,0xf4,0x01,0x1f,0xf8,0x01,0x18,0x3c,0x01,0x18,0x3c,0x01, +0x0b,0x98,0x01,0x0d,0xd8,0x01,0x07,0xe0,0x01,0x0f,0xf8,0x01,0x0f,0xf8,0x01, +0x03,0xe0,0x01,0x03,0xe0,0xff,0x00,0x01,0x03,0xe0,0x01,0x03,0xe0, }; +#endif diff --git a/rom/usb/trident/MasonIcons/MI_Hardware.c b/rom/usb/trident/MasonIcons/MI_Hardware.c new file mode 100644 index 000000000..738968ea5 --- /dev/null +++ b/rom/usb/trident/MasonIcons/MI_Hardware.c @@ -0,0 +1,68 @@ +#ifdef USE_HARDWARE_COLORS +const ULONG Hardware_colors[96] = +{ + 0x96969696,0x96969696,0x96969696, + 0x2d2d2d2d,0x28282828,0x9e9e9e9e, + 0x00000000,0x65656565,0x9a9a9a9a, + 0x35353535,0x75757575,0xaaaaaaaa, + 0x65656565,0x8a8a8a8a,0xbabababa, + 0x0c0c0c0c,0x61616161,0xffffffff, + 0x24242424,0x5d5d5d5d,0x24242424, + 0x35353535,0x8a8a8a8a,0x35353535, + 0x86868686,0xb2b2b2b2,0x3d3d3d3d, + 0x0c0c0c0c,0xe3e3e3e3,0x00000000, + 0x4d4d4d4d,0x9e9e9e9e,0x8e8e8e8e, + 0x82828282,0x00000000,0x00000000, + 0xdfdfdfdf,0x35353535,0x35353535, + 0xdbdbdbdb,0x65656565,0x39393939, + 0xdbdbdbdb,0x8e8e8e8e,0x41414141, + 0xdfdfdfdf,0xbabababa,0x45454545, + 0xefefefef,0xe7e7e7e7,0x14141414, + 0x82828282,0x61616161,0x4d4d4d4d, + 0xa6a6a6a6,0x7e7e7e7e,0x61616161, + 0xcacacaca,0x9a9a9a9a,0x75757575, + 0x9a9a9a9a,0x55555555,0xaaaaaaaa, + 0xffffffff,0x00000000,0xffffffff, + 0xffffffff,0xffffffff,0xffffffff, + 0xdfdfdfdf,0xdfdfdfdf,0xdfdfdfdf, + 0xcacacaca,0xcacacaca,0xcacacaca, + 0xbabababa,0xbabababa,0xbabababa, + 0xaaaaaaaa,0xaaaaaaaa,0xaaaaaaaa, + 0x8a8a8a8a,0x8a8a8a8a,0x8a8a8a8a, + 0x65656565,0x65656565,0x65656565, + 0x4d4d4d4d,0x4d4d4d4d,0x4d4d4d4d, + 0x3c3c3c3c,0x3c3c3c3c,0x3b3b3b3b, + 0x00000000,0x00000000,0x00000000, +}; +#endif + +#define HARDWARE_WIDTH 16 +#define HARDWARE_HEIGHT 16 +#define HARDWARE_DEPTH 5 +#define HARDWARE_COMPRESSION 1 +#define HARDWARE_MASKING 2 + +#ifdef USE_HARDWARE_HEADER +const struct BitMapHeader Hardware_header = +{ 16,16,69,45,5,2,1,0,0,1,1,800,600 }; +#endif + +#ifdef USE_HARDWARE_BODY +const UBYTE Hardware_body[231] = { +0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0x01,0x7f,0xfc,0x01,0xff, +0xfe,0x01,0xff,0xfe,0xff,0x00,0xff,0x00,0x01,0xb7,0x31,0x01,0x92,0x67,0x01, +0x93,0xfe,0x01,0x6d,0xdf,0x01,0x6d,0xdf,0x01,0xc8,0x45,0x01,0xb6,0xef,0x01, +0x93,0xfe,0x01,0x6d,0xdf,0x01,0x6d,0xdf,0x01,0xc9,0x55,0x01,0xfe,0xef,0x01, +0xff,0xfe,0x01,0x01,0xdf,0x01,0x01,0xdf,0x01,0xdb,0x55,0x01,0x86,0xef,0x01, +0xff,0xfe,0x01,0x7d,0xdf,0x01,0x7d,0xdf,0x01,0x84,0x89,0x01,0xbf,0xff,0x01, +0xff,0xfe,0x01,0x7d,0xdf,0x01,0x7d,0xdf,0x01,0xc5,0x11,0x01,0xbf,0xff,0x01, +0xff,0xfe,0x01,0x7c,0x03,0x01,0x7c,0x03,0x01,0xc5,0x75,0x01,0xbe,0xb7,0x01, +0xff,0xe2,0x01,0x7d,0xdf,0x01,0x7c,0x1f,0x01,0xb9,0x09,0x01,0xff,0xe7,0x01, +0xff,0xe2,0x01,0x7c,0x1f,0x01,0x7c,0x1f,0x01,0xc1,0x69,0x01,0xfe,0xa7,0x01, +0xff,0xe2,0x01,0x01,0xdf,0x01,0x00,0x1f,0x01,0xff,0x15,0x01,0xab,0xff,0x01, +0xff,0xe2,0x01,0x54,0x1f,0x01,0x00,0x1f,0x01,0x80,0x01,0xff,0xff,0x01,0xff, +0xfe,0x01,0x00,0x03,0x01,0x00,0x03,0x01,0xaa,0xa9,0x01,0xd5,0x57,0x01,0xff, +0xfe,0x01,0x7f,0xfd,0x01,0x00,0x01,0x01,0x55,0x57,0x01,0x7f,0xff,0x01,0x7f, +0xfc,0x01,0x7f,0xff,0x01,0x00,0x03,0x01,0x3f,0xfe,0x01,0x3f,0xfe,0xff,0x00, +0x01,0x3f,0xfe,0x01,0x3f,0xfe, }; +#endif diff --git a/rom/usb/trident/MasonIcons/MI_Online.c b/rom/usb/trident/MasonIcons/MI_Online.c new file mode 100644 index 000000000..47d571ad5 --- /dev/null +++ b/rom/usb/trident/MasonIcons/MI_Online.c @@ -0,0 +1,68 @@ +#ifdef USE_ONLINE_COLORS +const ULONG Online_colors[96] = +{ + 0x96969696,0x96969696,0x96969696, + 0x2d2d2d2d,0x28282828,0x9e9e9e9e, + 0x00000000,0x65656565,0x9a9a9a9a, + 0x35353535,0x75757575,0xaaaaaaaa, + 0x65656565,0x8a8a8a8a,0xbabababa, + 0x0c0c0c0c,0x61616161,0xffffffff, + 0x24242424,0x5d5d5d5d,0x24242424, + 0x35353535,0x8a8a8a8a,0x35353535, + 0x86868686,0xb2b2b2b2,0x3d3d3d3d, + 0x0c0c0c0c,0xe3e3e3e3,0x00000000, + 0x4d4d4d4d,0x9e9e9e9e,0x8e8e8e8e, + 0x82828282,0x00000000,0x00000000, + 0xdfdfdfdf,0x35353535,0x35353535, + 0xdbdbdbdb,0x65656565,0x39393939, + 0xdbdbdbdb,0x8e8e8e8e,0x41414141, + 0xdfdfdfdf,0xbabababa,0x45454545, + 0xefefefef,0xe7e7e7e7,0x14141414, + 0x82828282,0x61616161,0x4d4d4d4d, + 0xa6a6a6a6,0x7e7e7e7e,0x61616161, + 0xcacacaca,0x9a9a9a9a,0x75757575, + 0x9a9a9a9a,0x55555555,0xaaaaaaaa, + 0xffffffff,0x00000000,0xffffffff, + 0xffffffff,0xffffffff,0xffffffff, + 0xdfdfdfdf,0xdfdfdfdf,0xdfdfdfdf, + 0xcacacaca,0xcacacaca,0xcacacaca, + 0xbabababa,0xbabababa,0xbabababa, + 0xaaaaaaaa,0xaaaaaaaa,0xaaaaaaaa, + 0x8a8a8a8a,0x8a8a8a8a,0x8a8a8a8a, + 0x65656565,0x65656565,0x65656565, + 0x4d4d4d4d,0x4d4d4d4d,0x4d4d4d4d, + 0x3c3c3c3c,0x3c3c3c3c,0x3b3b3b3b, + 0x00000000,0x00000000,0x00000000, +}; +#endif + +#define ONLINE_WIDTH 16 +#define ONLINE_HEIGHT 16 +#define ONLINE_DEPTH 5 +#define ONLINE_COMPRESSION 1 +#define ONLINE_MASKING 0 + +#ifdef USE_ONLINE_HEADER +const struct BitMapHeader Online_header = +{ 16,16,0,0,5,0,1,0,0,11,10,16,16 }; +#endif + +#ifdef USE_ONLINE_BODY +const UBYTE Online_body[239] = { +0x01,0x02,0xc4,0x01,0x02,0xc4,0x01,0x01,0x44,0x01,0x00,0x44,0x01,0x00,0x38, +0x01,0x01,0x82,0x01,0x09,0x82,0x01,0x06,0x82,0x01,0x00,0x82,0x01,0x00,0x7c, +0x01,0x11,0x61,0x01,0x19,0x61,0x01,0x07,0x61,0x01,0x01,0x61,0x01,0x18,0x9e, +0x01,0x2a,0x90,0x01,0x3a,0xf0,0x01,0x04,0xf0,0x01,0x00,0x90,0x01,0x33,0x6f, +0x01,0x1f,0x61,0x01,0x7f,0x61,0x01,0x01,0x61,0x01,0x01,0x61,0x01,0x62,0x9e, +0x01,0x7b,0x00,0x01,0x7b,0x01,0x01,0x05,0x01,0xff,0x01,0x01,0x00,0xfe,0x01, +0x50,0x82,0x01,0x50,0x82,0x01,0xaf,0x82,0x01,0x01,0x82,0x01,0x01,0x7c,0x01, +0x83,0x06,0x01,0x83,0x04,0x01,0x7c,0x86,0x01,0x00,0x86,0x01,0x03,0xfa,0x01, +0x94,0x1e,0x01,0xd7,0x9c,0x01,0x28,0x58,0x01,0x00,0x58,0x01,0xc3,0xe6,0x01, +0x9e,0x96,0x01,0x7f,0x48,0x01,0x00,0x3e,0x01,0x00,0x3e,0x01,0xc1,0xfe,0x01, +0x3f,0x52,0x01,0xfe,0x8c,0x01,0x00,0x3a,0x01,0x00,0x3a,0x01,0x81,0xfa,0x01, +0x13,0x68,0x01,0x7e,0x9c,0x01,0x00,0x38,0x01,0x00,0x38,0x01,0x41,0xf8,0x01, +0x69,0xdc,0x01,0x3e,0x60,0x01,0x00,0x1c,0x01,0x00,0x1c,0x01,0x41,0x9c,0x01, +0x21,0xa8,0x01,0x1e,0x50,0x01,0x00,0x28,0x01,0x00,0x28,0x01,0x21,0xa8,0x01, +0x01,0xb0,0x01,0x0e,0x40,0x01,0x10,0xb0,0x01,0x10,0xb0,0x01,0x11,0xb0,0x01, +0x0b,0xc0,0x01,0x0c,0x00,0x01,0x03,0xe0,0x01,0x0b,0xe0,0x01,0x0b,0xe0, }; +#endif diff --git a/rom/usb/trident/MasonIcons/MI_OrangeLED.c b/rom/usb/trident/MasonIcons/MI_OrangeLED.c new file mode 100644 index 000000000..70f6c0036 --- /dev/null +++ b/rom/usb/trident/MasonIcons/MI_OrangeLED.c @@ -0,0 +1,68 @@ +#ifdef USE_ORANGELED_COLORS +const ULONG OrangeLED_colors[96] = +{ + 0x96969696,0x96969696,0x96969696, + 0x2d2d2d2d,0x28282828,0x9e9e9e9e, + 0x00000000,0x65656565,0x9a9a9a9a, + 0x35353535,0x75757575,0xaaaaaaaa, + 0x65656565,0x8a8a8a8a,0xbabababa, + 0x0c0c0c0c,0x61616161,0xffffffff, + 0x24242424,0x5d5d5d5d,0x24242424, + 0x35353535,0x8a8a8a8a,0x35353535, + 0x86868686,0xb2b2b2b2,0x3d3d3d3d, + 0x0c0c0c0c,0xe3e3e3e3,0x00000000, + 0x4d4d4d4d,0x9e9e9e9e,0x8e8e8e8e, + 0x82828282,0x00000000,0x00000000, + 0xdfdfdfdf,0x35353535,0x35353535, + 0xdbdbdbdb,0x65656565,0x39393939, + 0xdbdbdbdb,0x8e8e8e8e,0x41414141, + 0xdfdfdfdf,0xbabababa,0x45454545, + 0xefefefef,0xe7e7e7e7,0x14141414, + 0x82828282,0x61616161,0x4d4d4d4d, + 0xa6a6a6a6,0x7e7e7e7e,0x61616161, + 0xcacacaca,0x9a9a9a9a,0x75757575, + 0x9a9a9a9a,0x55555555,0xaaaaaaaa, + 0xffffffff,0x00000000,0xffffffff, + 0xffffffff,0xffffffff,0xffffffff, + 0xdfdfdfdf,0xdfdfdfdf,0xdfdfdfdf, + 0xcacacaca,0xcacacaca,0xcacacaca, + 0xbabababa,0xbabababa,0xbabababa, + 0xaaaaaaaa,0xaaaaaaaa,0xaaaaaaaa, + 0x8a8a8a8a,0x8a8a8a8a,0x8a8a8a8a, + 0x65656565,0x65656565,0x65656565, + 0x4d4d4d4d,0x4d4d4d4d,0x4d4d4d4d, + 0x3c3c3c3c,0x3c3c3c3c,0x3b3b3b3b, + 0x00000000,0x00000000,0x00000000, +}; +#endif + +#define ORANGELED_WIDTH 16 +#define ORANGELED_HEIGHT 16 +#define ORANGELED_DEPTH 5 +#define ORANGELED_COMPRESSION 1 +#define ORANGELED_MASKING 0 + +#ifdef USE_ORANGELED_HEADER +const struct BitMapHeader OrangeLED_header = +{ 16,16,0,0,5,0,1,0,0,11,10,16,16 }; +#endif + +#ifdef USE_ORANGELED_BODY +const UBYTE OrangeLED_body[233] = { +0x01,0x06,0xa0,0x01,0x00,0x60,0xff,0x00,0x01,0x07,0xe0,0x01,0x07,0xe0,0x01, +0x0d,0x40,0x01,0x17,0xc0,0x01,0x07,0xf0,0x01,0x1f,0xf0,0x01,0x18,0x30,0x01, +0x2a,0xb0,0x01,0x0f,0xe0,0x01,0x0f,0xf8,0x01,0x2f,0xf8,0x01,0x30,0x08,0x01, +0x15,0x0c,0x01,0x5f,0xf0,0x01,0x1f,0xfc,0x01,0x5f,0xfc,0x01,0x60,0x04,0x01, +0x6a,0x42,0x01,0x3f,0xfe,0x01,0x3f,0xfc,0x01,0x7f,0xfe,0x01,0x40,0x06,0x01, +0xd4,0x14,0x01,0x7f,0xea,0x01,0x7f,0xfe,0x01,0xff,0xfe,0x01,0x80,0x02,0x01, +0xa9,0x07,0x01,0x7f,0xf9,0x01,0x7f,0xfe,0xff,0xff,0x01,0x80,0x03,0x01,0x50, +0x2f,0x01,0x7f,0xd3,0x01,0x7f,0xfe,0xff,0xff,0x01,0x80,0x03,0x01,0xa4,0x97, +0x01,0x7f,0x6b,0x01,0x7f,0xfe,0xff,0xff,0x01,0x80,0x03,0x01,0x50,0x2d,0x01, +0xff,0xd3,0x01,0x7f,0xfe,0xff,0xff,0x01,0x80,0x03,0x01,0x81,0x5d,0x01,0xbe, +0xa5,0x01,0x7f,0xfe,0xff,0xff,0x01,0xc0,0x07,0x01,0x24,0xba,0x01,0x1b,0x46, +0x01,0x7f,0xfc,0x01,0x7f,0xfe,0x01,0x40,0x06,0x01,0x11,0x7a,0x01,0x0e,0x8a, +0x01,0x3f,0xfc,0x01,0x3f,0xfe,0x01,0x20,0x0e,0x01,0x17,0xe4,0x01,0x08,0x34, +0x01,0x1f,0xf8,0x01,0x1f,0xfc,0x01,0x18,0x3c,0x01,0x0b,0x98,0x01,0x0d,0xd8, +0x01,0x07,0xe0,0x01,0x0f,0xf8,0x01,0x0f,0xf8,0x01,0x03,0xe0,0x01,0x03,0xe0, +0xff,0x00,0x01,0x03,0xe0,0x01,0x03,0xe0, }; +#endif diff --git a/rom/usb/trident/MasonIcons/MI_OrangeLEDQ.c b/rom/usb/trident/MasonIcons/MI_OrangeLEDQ.c new file mode 100644 index 000000000..2c668ad8d --- /dev/null +++ b/rom/usb/trident/MasonIcons/MI_OrangeLEDQ.c @@ -0,0 +1,68 @@ +#ifdef USE_ORANGELEDQ_COLORS +const ULONG OrangeLEDQ_colors[96] = +{ + 0x96969696,0x96969696,0x96969696, + 0x2d2d2d2d,0x28282828,0x9e9e9e9e, + 0x00000000,0x65656565,0x9a9a9a9a, + 0x35353535,0x75757575,0xaaaaaaaa, + 0x65656565,0x8a8a8a8a,0xbabababa, + 0x0c0c0c0c,0x61616161,0xffffffff, + 0x24242424,0x5d5d5d5d,0x24242424, + 0x35353535,0x8a8a8a8a,0x35353535, + 0x86868686,0xb2b2b2b2,0x3d3d3d3d, + 0x0c0c0c0c,0xe3e3e3e3,0x00000000, + 0x4d4d4d4d,0x9e9e9e9e,0x8e8e8e8e, + 0x82828282,0x00000000,0x00000000, + 0xdfdfdfdf,0x35353535,0x35353535, + 0xdbdbdbdb,0x65656565,0x39393939, + 0xdbdbdbdb,0x8e8e8e8e,0x41414141, + 0xdfdfdfdf,0xbabababa,0x45454545, + 0xefefefef,0xe7e7e7e7,0x14141414, + 0x82828282,0x61616161,0x4d4d4d4d, + 0xa6a6a6a6,0x7e7e7e7e,0x61616161, + 0xcacacaca,0x9a9a9a9a,0x75757575, + 0x9a9a9a9a,0x55555555,0xaaaaaaaa, + 0xffffffff,0x00000000,0xffffffff, + 0xffffffff,0xffffffff,0xffffffff, + 0xdfdfdfdf,0xdfdfdfdf,0xdfdfdfdf, + 0xcacacaca,0xcacacaca,0xcacacaca, + 0xbabababa,0xbabababa,0xbabababa, + 0xaaaaaaaa,0xaaaaaaaa,0xaaaaaaaa, + 0x8a8a8a8a,0x8a8a8a8a,0x8a8a8a8a, + 0x65656565,0x65656565,0x65656565, + 0x4d4d4d4d,0x4d4d4d4d,0x4d4d4d4d, + 0x3c3c3c3c,0x3c3c3c3c,0x3b3b3b3b, + 0x00000000,0x00000000,0x00000000, +}; +#endif + +#define ORANGELEDQ_WIDTH 16 +#define ORANGELEDQ_HEIGHT 16 +#define ORANGELEDQ_DEPTH 5 +#define ORANGELEDQ_COMPRESSION 1 +#define ORANGELEDQ_MASKING 0 + +#ifdef USE_ORANGELEDQ_HEADER +const struct BitMapHeader OrangeLEDQ_header = +{ 16,16,0,0,5,0,1,0,0,11,10,16,16 }; +#endif + +#ifdef USE_ORANGELEDQ_BODY +const UBYTE OrangeLEDQ_body[236] = { +0x01,0x06,0xa0,0x01,0x00,0x60,0xff,0x00,0x01,0x07,0xe0,0x01,0x07,0xe0,0x01, +0x0d,0xc0,0x01,0x16,0x00,0x01,0x07,0xf0,0x01,0x1f,0xf0,0x01,0x18,0x30,0x01, +0x2a,0x70,0x01,0x0f,0xe0,0x01,0x0f,0xf8,0x01,0x2c,0x38,0x01,0x33,0xc8,0x01, +0x15,0xac,0x01,0x5f,0x30,0x01,0x1f,0xbc,0x01,0x59,0xdc,0x01,0x66,0x64,0x01, +0x68,0x12,0x01,0x37,0xee,0x01,0x35,0xbc,0x01,0x7b,0xde,0x01,0x4e,0x66,0x01, +0xd2,0x14,0x01,0x7f,0xaa,0x01,0x77,0xbe,0x01,0xf9,0xde,0x01,0x8e,0x62,0x01, +0xad,0x87,0x01,0x7f,0x59,0x01,0x7f,0x5e,0x01,0xfb,0xbf,0x01,0x84,0xe3,0x01, +0x50,0x6f,0x01,0x7f,0x93,0x01,0x7e,0xbe,0x01,0xff,0x7f,0x01,0x81,0xc3,0x01, +0xa6,0x17,0x01,0x7d,0xeb,0x01,0x7f,0x7e,0x01,0xfe,0xff,0x01,0x81,0x83,0x01, +0x50,0xad,0x01,0xff,0x53,0x01,0x7c,0xfe,0xff,0xff,0x01,0x83,0x03,0x01,0x80, +0x5d,0x01,0xbe,0xa5,0x01,0x7e,0xfe,0xff,0xff,0x01,0xc1,0x07,0x01,0x24,0x3a, +0x01,0x19,0xc6,0x01,0x7d,0x7c,0x01,0x7e,0xfe,0x01,0x43,0x86,0x01,0x10,0x7a, +0x01,0x0f,0x8a,0x01,0x3e,0xfc,0x01,0x3f,0xfe,0x01,0x21,0x0e,0x01,0x17,0xe4, +0x01,0x08,0x34,0x01,0x1f,0xf8,0x01,0x1f,0xfc,0x01,0x18,0x3c,0x01,0x0b,0x98, +0x01,0x0d,0xd8,0x01,0x07,0xe0,0x01,0x0f,0xf8,0x01,0x0f,0xf8,0x01,0x03,0xe0, +0x01,0x03,0xe0,0xff,0x00,0x01,0x03,0xe0,0x01,0x03,0xe0, }; +#endif diff --git a/rom/usb/trident/MasonIcons/MI_Popup.c b/rom/usb/trident/MasonIcons/MI_Popup.c new file mode 100644 index 000000000..f9936e54d --- /dev/null +++ b/rom/usb/trident/MasonIcons/MI_Popup.c @@ -0,0 +1,67 @@ +#ifdef USE_POPUP_COLORS +const ULONG Popup_colors[96] = +{ + 0x96969696,0x96969696,0x96969696, + 0x2d2d2d2d,0x28282828,0x9e9e9e9e, + 0x00000000,0x65656565,0x9a9a9a9a, + 0x35353535,0x75757575,0xaaaaaaaa, + 0x65656565,0x8a8a8a8a,0xbabababa, + 0x0c0c0c0c,0x61616161,0xffffffff, + 0x24242424,0x5d5d5d5d,0x24242424, + 0x35353535,0x8a8a8a8a,0x35353535, + 0x86868686,0xb2b2b2b2,0x3d3d3d3d, + 0x0c0c0c0c,0xe3e3e3e3,0x00000000, + 0x4d4d4d4d,0x9e9e9e9e,0x8e8e8e8e, + 0x82828282,0x00000000,0x00000000, + 0xdfdfdfdf,0x35353535,0x35353535, + 0xdbdbdbdb,0x65656565,0x39393939, + 0xdbdbdbdb,0x8e8e8e8e,0x41414141, + 0xdfdfdfdf,0xbabababa,0x45454545, + 0xefefefef,0xe7e7e7e7,0x14141414, + 0x82828282,0x61616161,0x4d4d4d4d, + 0xa6a6a6a6,0x7e7e7e7e,0x61616161, + 0xcacacaca,0x9a9a9a9a,0x75757575, + 0x9a9a9a9a,0x55555555,0xaaaaaaaa, + 0xffffffff,0x00000000,0xffffffff, + 0xffffffff,0xffffffff,0xffffffff, + 0xdfdfdfdf,0xdfdfdfdf,0xdfdfdfdf, + 0xcacacaca,0xcacacaca,0xcacacaca, + 0xbabababa,0xbabababa,0xbabababa, + 0xaaaaaaaa,0xaaaaaaaa,0xaaaaaaaa, + 0x8a8a8a8a,0x8a8a8a8a,0x8a8a8a8a, + 0x65656565,0x65656565,0x65656565, + 0x4d4d4d4d,0x4d4d4d4d,0x4d4d4d4d, + 0x3c3c3c3c,0x3c3c3c3c,0x3b3b3b3b, + 0x00000000,0x00000000,0x00000000, +}; +#endif + +#define POPUP_WIDTH 16 +#define POPUP_HEIGHT 16 +#define POPUP_DEPTH 5 +#define POPUP_COMPRESSION 1 +#define POPUP_MASKING 0 + +#ifdef USE_POPUP_HEADER +const struct BitMapHeader Popup_header = +{ 16,16,0,0,5,0,1,0,0,11,10,16,16 }; +#endif + +#ifdef USE_POPUP_BODY +const UBYTE Popup_body[221] = { +0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0x01,0x00,0x04,0x01,0xff, +0xfe,0x01,0xff,0xfc,0x01,0x00,0x02,0x01,0xff,0xfe,0x01,0x2a,0xad,0x01,0xaa, +0xad,0x01,0xd5,0x52,0x01,0x00,0x03,0x01,0x80,0x03,0x01,0x05,0x7f,0x01,0x85, +0x7f,0x01,0xfa,0x82,0x01,0x00,0x03,0x01,0x80,0x03,0x01,0x7f,0xf3,0x01,0xff, +0xf7,0x01,0xff,0xfa,0x01,0x7f,0xff,0xff,0xff,0x01,0x5f,0xd7,0x01,0xf8,0xef, +0x01,0xd8,0xc6,0x01,0x7f,0xfb,0xff,0xff,0x01,0x77,0xbb,0x01,0xd6,0xb7,0x01, +0xde,0xf6,0x01,0x7f,0xfb,0xff,0xff,0x01,0x7e,0xfb,0x01,0xd6,0xb7,0x01,0xd6, +0xb6,0x01,0x7f,0xfb,0xff,0xff,0x01,0x45,0x7b,0x01,0xe0,0x07,0x01,0xc0,0x06, +0x01,0x7f,0xfb,0xff,0xff,0x01,0x6b,0xf3,0x01,0xc0,0x0f,0x01,0xc0,0x06,0x01, +0x7f,0xfb,0xff,0xff,0x01,0x6f,0x7b,0x01,0xde,0xf7,0x01,0xde,0xf6,0x01,0x61, +0x0b,0xff,0xff,0x01,0x51,0x83,0x01,0xf2,0x9f,0x01,0xde,0xf6,0x01,0x6f,0x7b, +0xff,0xff,0x01,0x3f,0xab,0x01,0x80,0x57,0x01,0xc0,0x06,0x01,0x7f,0xfb,0xff, +0xff,0x01,0xa0,0x03,0xff,0xff,0x01,0xbf,0xfe,0x01,0x40,0x03,0xff,0xff,0x01, +0x3f,0xff,0x01,0xbf,0xff,0x01,0x7f,0xfe,0xff,0xff,0xff,0xff,0x01,0x7f,0xff, +0x01,0x7f,0xff,0xff,0x00,0x01,0x7f,0xff,0x01,0x7f,0xff, }; +#endif diff --git a/rom/usb/trident/MasonIcons/MI_Settings.c b/rom/usb/trident/MasonIcons/MI_Settings.c new file mode 100644 index 000000000..9845581bd --- /dev/null +++ b/rom/usb/trident/MasonIcons/MI_Settings.c @@ -0,0 +1,68 @@ +#ifdef USE_SETTINGS_COLORS +const ULONG Settings_colors[96] = +{ + 0x96969696,0x96969696,0x96969696, + 0x2d2d2d2d,0x28282828,0x9e9e9e9e, + 0x00000000,0x65656565,0x9a9a9a9a, + 0x35353535,0x75757575,0xaaaaaaaa, + 0x65656565,0x8a8a8a8a,0xbabababa, + 0x0c0c0c0c,0x61616161,0xffffffff, + 0x24242424,0x5d5d5d5d,0x24242424, + 0x35353535,0x8a8a8a8a,0x35353535, + 0x86868686,0xb2b2b2b2,0x3d3d3d3d, + 0x0c0c0c0c,0xe3e3e3e3,0x00000000, + 0x4d4d4d4d,0x9e9e9e9e,0x8e8e8e8e, + 0x82828282,0x00000000,0x00000000, + 0xdfdfdfdf,0x35353535,0x35353535, + 0xdbdbdbdb,0x65656565,0x39393939, + 0xdbdbdbdb,0x8e8e8e8e,0x41414141, + 0xdfdfdfdf,0xbabababa,0x45454545, + 0xefefefef,0xe7e7e7e7,0x14141414, + 0x82828282,0x61616161,0x4d4d4d4d, + 0xa6a6a6a6,0x7e7e7e7e,0x61616161, + 0xcacacaca,0x9a9a9a9a,0x75757575, + 0x9a9a9a9a,0x55555555,0xaaaaaaaa, + 0xffffffff,0x00000000,0xffffffff, + 0xffffffff,0xffffffff,0xffffffff, + 0xdfdfdfdf,0xdfdfdfdf,0xdfdfdfdf, + 0xcacacaca,0xcacacaca,0xcacacaca, + 0xbabababa,0xbabababa,0xbabababa, + 0xaaaaaaaa,0xaaaaaaaa,0xaaaaaaaa, + 0x8a8a8a8a,0x8a8a8a8a,0x8a8a8a8a, + 0x65656565,0x65656565,0x65656565, + 0x4d4d4d4d,0x4d4d4d4d,0x4d4d4d4d, + 0x3c3c3c3c,0x3c3c3c3c,0x3b3b3b3b, + 0x00000000,0x00000000,0x00000000, +}; +#endif + +#define SETTINGS_WIDTH 16 +#define SETTINGS_HEIGHT 16 +#define SETTINGS_DEPTH 5 +#define SETTINGS_COMPRESSION 1 +#define SETTINGS_MASKING 2 + +#ifdef USE_SETTINGS_HEADER +const struct BitMapHeader Settings_header = +{ 16,16,69,102,5,2,1,0,0,1,1,800,600 }; +#endif + +#ifdef USE_SETTINGS_BODY +const UBYTE Settings_body[239] = { +0x01,0x40,0x04,0x01,0x7f,0xfe,0x01,0x7f,0xfc,0x01,0x00,0x02,0x01,0x7f,0xfe, +0x01,0x08,0xdf,0x01,0x7c,0xdf,0x01,0x40,0xdc,0x01,0x03,0x23,0x01,0x43,0xff, +0x01,0x3d,0xfd,0x01,0x6e,0xfd,0x01,0x50,0xfe,0x01,0x1b,0x03,0x01,0x5b,0xff, +0x01,0x11,0xff,0x01,0x65,0xfd,0x01,0x51,0xfe,0x01,0x1a,0x03,0x01,0x5b,0xff, +0x01,0x15,0xf9,0x01,0x66,0xff,0x01,0x50,0xfe,0x01,0x1b,0x03,0x01,0x5b,0xff, +0x01,0x31,0xef,0x01,0x65,0xff,0x01,0x51,0xfe,0x01,0x1a,0x03,0x01,0x5b,0xff, +0x01,0x15,0xfb,0x01,0x66,0xff,0x01,0x50,0xfe,0x01,0x1b,0x03,0x01,0x5b,0xff, +0x01,0x35,0xd7,0x01,0x65,0xff,0x01,0x51,0xfe,0x01,0x1a,0x03,0x01,0x5b,0xff, +0x01,0x15,0xeb,0x01,0x66,0xff,0x01,0x50,0xfe,0x01,0x1b,0x03,0x01,0x5b,0xff, +0x01,0x3d,0x87,0x01,0x79,0xff,0x01,0x79,0xfe,0x01,0x06,0x03,0x01,0x7f,0xff, +0x01,0x21,0xb7,0x01,0x5f,0xf5,0x01,0x43,0xf2,0x01,0x3f,0x0f,0x01,0x7c,0xff, +0x01,0x0a,0x36,0x01,0x74,0xee,0x01,0x50,0xe4,0x01,0x1b,0x1e,0x01,0x5b,0xfe, +0x01,0x35,0x86,0x01,0x77,0xd2,0x01,0x43,0xcc,0x01,0x1b,0x3e,0x01,0x58,0xfe, +0x01,0x75,0x7c,0x01,0x75,0xf4,0x01,0x49,0xd8,0x01,0x02,0x3c,0x01,0x43,0xfc, +0x01,0x2b,0xf8,0x01,0x67,0xd8,0x01,0x1f,0xe0,0x01,0x7f,0xf8,0x01,0x7f,0xf8, +0x01,0x3f,0xe0,0x01,0x3f,0xe0,0xff,0x00,0x01,0x3f,0xe0,0x01,0x3f,0xe0, }; +#endif diff --git a/rom/usb/trident/MasonIcons/Online b/rom/usb/trident/MasonIcons/Online new file mode 100644 index 0000000000000000000000000000000000000000..ee7a7a2aad04518ec9d111e02d1679bffb68b4e9 GIT binary patch literal 404 zcwQaOze@sP7zgm@n?ItIP;w{;BXE$QDGtiaI<+$BMG=A;0xvkIsmV!EI>F%(aflm4 zZj87kX}qbZ$$y~1;DVq=9mB!veS4k{@AEu7@V@V1zQ~BsIzCCWG|Od)C_*8gJbVOx z2Ij?_k=YR+yo3;Cm|Wm}$uNwKxJhbPDqE^<2NgGV5tDSO`LrASB4)NVB1e*j>h`cL zJNCioC!#6rzNQSi5WI@~( zpkYpfUjuPfgcU3+m{kA;OD5JkNQ~hfgF4u}!K#A#|BAabQ6W?SA6$T@C}_f?Cay#k z4L=%QRGXkCJQLhS@!muH40MLqZTpZVE)AVIINac9;UEna zbW=3m5YD&O5ICGr5VhoJAYR`U<@-H+@B8B!p7+fc_8AeHyL%Fo*iMd!LKNhW*DQhm zo;jPd8Me*AN$wzJS*FP6O1s@&UG9?H5o?;P>fWjqE5$@rY~F8rUx;;E4I)z%`|^6f zl`-|L&$m#c%5F}pMyJ*}&@8fenWkwNhOXh0Rkh$M@YD_;6<5RW0c3JIB_H)H9=|&WrDN|Pa!BD_H0d1 zpTVsF<%^?bq3%F24(0KmuFjzxPrX%GQ}3*VhwESJ35e-f%tQIhm_LDEwIg}(k{{t$ dxYrOJ**is&@La(6Y@fk5=5h?U_-Q|#z5yaAhg|>w literal 0 HcwPel00001 diff --git a/rom/usb/trident/MasonIcons/OrangeLEDQ b/rom/usb/trident/MasonIcons/OrangeLEDQ new file mode 100644 index 0000000000000000000000000000000000000000..57b5a1532e6ca6c874feb3d90f6595575c86b962 GIT binary patch literal 400 zcwQZkJxE(&6o$VCt%`pM5`Q`cAw!WC1iffAwj{Bwg?<_ohYbEiywa^MQt&6&pJL?> zS%gqBNS8WXbaA{$+9HT#bP_DyfCUFjbySpme(^mo=Y8L^oO9j|4ND=|c>f_PqjI2M z2oVr|T^dgWy4O^fax5a>=}<1J{30eJaqTBFnaqo4Tf)p5bB<}dwMi8k3mLYtzSmcK zF635vRS3^8PR*C6>4@jPxw;6fCgpZ2na|E;M;#@UhUaNm-tP$Tu zjj&i$inTJ9$H@I4RZ71r3H9*wkflXEAhwQw9-qytdtMi5t*7}fRh>IW^p#1(FvuGztkB8eZ?06WenrZvxGAc3EnnL+U2-`b$FXhOvMkdy4a3khO$ZT z{(+{XS!}>;;3W(4q2xnA$AykTd5n4wZXfOdI`6^JD}K9pdxkz_I(J;(Qzq+Ee1c8k*fr1RRxh*&J`rnF%S5^$wB_}7HLPo~ z?u)yeW!LA~W<6iuQ#o;SbX{*Yo0_Jns;Vf8EX#~BzkkClh^N94(`@7*hZtt@VV3MJ zib@IZ=nq098QnK?7a +** +** Project started: 08-Mar-02 +** Releases : +*/ + +#include "debug.h" + +#define USE_INLINE_STDARG +#define __NOLIBBASE__ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "Trident.h" +#include "ActionClass.h" +#include "IconListClass.h" +#include "DevWinClass.h" +#include "CfgListClass.h" + +#define TMPL_SWITCH 1 +#define TMPL_NUMERIC 2 +#define TMPL_ARGUMENT 4 + + +#include + + +/* defines */ + +struct WBStartup *_WBenchMsg; + +extern struct ExecBase *SysBase; +extern struct DosLibrary *DOSBase; +extern struct IntuitionBase *IntuitionBase; +extern struct Library *UtilityBase; +extern struct Library *MUIMasterBase; +struct Library *ps; +extern struct Library *IconBase; + +struct MUI_CustomClass *ActionClass = NULL; +struct MUI_CustomClass *IconListClass = NULL; +struct MUI_CustomClass *DevWinClass = NULL; +struct MUI_CustomClass *CfgListClass = NULL; + +Object *appobj = NULL; +Object *mainwinobj = NULL; +Object *actionobj = NULL; +BOOL registermode = FALSE; + +static Object *mi_about; +static Object *mi_aboutmui; +static Object *mi_help; +static Object *mi_online; +static Object *mi_offline; +static Object *mi_iconify; +static Object *mi_quit; +static Object *mi_saveerrors; +static Object *mi_flusherrors; +static Object *mi_savedevlist; +static Object *mi_loadprefs; +static Object *mi_saveprefs; +static Object *mi_saveprefsas; +static Object *mi_muiprefs; + +#define ARGS_REGMODE 0 +#define ARGS_NOGUI 1 +#define ARGS_SAVE 2 +#define ARGS_SIZEOF 3 + +static char *template = "REGISTERMODE/S,NOGUI/S,SAVE/S"; +static IPTR ArgsArray[ARGS_SIZEOF]; +static struct RDArgs *ArgsHook = NULL; +static struct DiskObject *IconObject = NULL; +static LONG NumericArgsBuffer[32]; + +/* /// "GetToolTypes()" */ +BOOL GetToolTypes(void) +{ + BPTR dir; + struct WBArg *wba; + char currtemp[512]; + char currkey[128]; + LONG currtype; + char *templatepos = template; + char *bufpos; + char *bufpos2; + BOOL valid = FALSE; + IPTR *argsptr = ArgsArray; + LONG *numargsptr = NumericArgsBuffer; + + if(!_WBenchMsg) return(0); + wba = _WBenchMsg->sm_ArgList; + + dir = CurrentDir(wba->wa_Lock); + if((IconObject = GetDiskObject(wba->wa_Name))) + { + valid = TRUE; + if(IconObject->do_ToolTypes) + { + while(*templatepos) + { + bufpos = currtemp; + while(*templatepos) + { + if(*templatepos == ',') + { + templatepos++; + break; + } + *bufpos++ = *templatepos++; + } + *bufpos = 0; + bufpos = currtemp; + currtype = 0; + while(*bufpos) + { + if(*bufpos++ == '/') + { + switch(*bufpos++) + { + case 'S': + currtype |= TMPL_SWITCH; + break; + case 'A': + currtype |= TMPL_ARGUMENT; + break; + case 'N': + currtype |= TMPL_NUMERIC; + break; + } + } + } + bufpos2 = currtemp; + *argsptr = 0L; + while(*bufpos2) + { + bufpos = currkey; + while(*bufpos2) + { + if(*bufpos2 == '/') + { + bufpos2 = currtemp + strlen(currtemp); + break; + } + if(*bufpos2 == '=') + { + bufpos2++; + break; + } + *bufpos++ = *bufpos2++; + } + *bufpos = 0; + if((bufpos = FindToolType(IconObject->do_ToolTypes, currkey))) + { + if(currtype & TMPL_SWITCH) + { + *argsptr = -1; + } else { + if(currtype & TMPL_NUMERIC) + { + *numargsptr = atoi(bufpos); + *argsptr = (LONG) numargsptr++; + } else { + *argsptr = (LONG) bufpos; + } + } + } + } + if((currtype & TMPL_ARGUMENT) && (*argsptr == 0L)) + { + valid = FALSE; + break; + } + argsptr++; + } + } + } + CurrentDir(dir); + return(valid); +} +/* \\\ */ + +/* /// "CleanupClasses()" */ +void CleanupClasses(void) +{ + if(DevWinClass) + { + MUI_DeleteCustomClass(DevWinClass); + DevWinClass = NULL; + } + if(ActionClass) + { + MUI_DeleteCustomClass(ActionClass); + ActionClass = NULL; + } + if(IconListClass) + { + MUI_DeleteCustomClass(IconListClass); + IconListClass = NULL; + } + if(CfgListClass) + { + MUI_DeleteCustomClass(CfgListClass); + CfgListClass = NULL; + } +} +/* \\\ */ + +/* /// "SetupClasses()" */ +BOOL SetupClasses(void) +{ + DevWinClass = MUI_CreateCustomClass(NULL, MUIC_Window, NULL, sizeof(struct DevWinData) , DevWinDispatcher); + ActionClass = MUI_CreateCustomClass(NULL, MUIC_Group , NULL, sizeof(struct ActionData) , ActionDispatcher); + IconListClass = MUI_CreateCustomClass(NULL, MUIC_List , NULL, sizeof(struct IconListData) , IconListDispatcher); + CfgListClass = MUI_CreateCustomClass(NULL, MUIC_List , NULL, sizeof(struct CfgListData) , CfgListDispatcher); + + if(ActionClass && IconListClass && DevWinClass && CfgListClass) + return(TRUE); + + return(FALSE); +} +/* \\\ */ + +/* /// "fail()" */ +void fail(char *str) +{ + if(appobj) + { + MUI_DisposeObject(appobj); + appobj = NULL; + } + CleanupClasses(); + + if(ArgsHook) + { + FreeArgs(ArgsHook); + ArgsHook = NULL; + } + + if(ps) + { + CloseLibrary(ps); + ps = NULL; + } + + if(IconObject) + { + FreeDiskObject(IconObject); + IconObject = NULL; + } + + if(_WBenchMsg && str) + { + struct EasyStruct errorReq = { sizeof(struct EasyStruct), 0, "Trident", NULL, "Cancel" }; + errorReq.es_TextFormat = str; + EasyRequest(NULL, &errorReq, NULL, NULL); + } + + if(MUIMasterBase) + { + CloseLibrary(MUIMasterBase); + MUIMasterBase = NULL; + } + + if(str) + { + PutStr(str); + exit(20); + } + exit(0); +} +/* \\\ */ + +/* /// "main()" */ +int main(int argc, char *argv[]) +{ + if(!argc) + { + _WBenchMsg = (struct WBStartup *) argv; + if(!GetToolTypes()) + { + fail("Wrong or missing ToolTypes!"); + } + } else { + if(!(ArgsHook = ReadArgs(template, ArgsArray, NULL))) + { + fail("Wrong arguments!\n"); + } + } + + if(!(ps = OpenLibrary("poseidon.library", 4))) + { + fail("Failed to open version 4 of poseidon.library.\n"); + } + + if(ArgsArray[ARGS_NOGUI]) + { + if(ArgsArray[ARGS_SAVE]) + { + InternalCreateConfig(); + psdSaveCfgToDisk(NULL, FALSE); + } else { + IPTR cfgread = FALSE; + psdGetAttrs(PGA_STACK, NULL, PA_ConfigRead, &cfgread, TAG_DONE); + if(!cfgread) + { + psdLoadCfgFromDisk(NULL); + } else { + psdParseCfg(); + } + } + fail(NULL); + } + + if((ps->lib_Version == 4) && (ps->lib_Revision < 3)) + { + fail("Sorry, this version of Trident requires at least version 4.3 of poseidon.library!\n"); + } + + { + struct Task *thistask; + IPTR stackfree; + thistask = FindTask(NULL); + stackfree = ((IPTR) thistask->tc_SPUpper) - ((IPTR) thistask->tc_SPLower); + if(stackfree < 16000) + { + fail("Trident needs at least 16KB of stack! Please change the tooltypes accordingly!\n"); + } + } + + { + IPTR cfgread = FALSE; + psdGetAttrs(PGA_STACK, NULL, PA_ConfigRead, &cfgread, TAG_DONE); + if(!cfgread) + { + psdLoadCfgFromDisk(NULL); + } else { + psdParseCfg(); + } + } + registermode = ArgsArray[ARGS_REGMODE]; + + if(!(MUIMasterBase = OpenLibrary(MUIMASTER_NAME,MUIMASTER_VMIN))) + fail("Failed to open "MUIMASTER_NAME". This application requires MUI!\n"); + + if(!SetupClasses()) + fail("Could not create custom classes.\n"); + + appobj = ApplicationObject, + MUIA_Application_Title , "Trident", + MUIA_Application_Version , "4.3 (27-May-09)", + MUIA_Application_Copyright , "©2002-2009 Chris Hodges", + MUIA_Application_Author , "Chris Hodges ", + MUIA_Application_Description, "Poseidon USB Stack GUI", + MUIA_Application_Base , "TRIDENT", + MUIA_Application_SingleTask , TRUE, + MUIA_Application_DiskObject , IconObject, + MUIA_Application_HelpFile , "HELP:Poseidon.guide", + MUIA_Application_Menustrip , MenustripObject, + Child, MenuObjectT("Project"), + Child, mi_about = MenuitemObject, + MUIA_Menuitem_Title, "About...", + MUIA_Menuitem_Shortcut, "?", + End, + Child, mi_aboutmui = MenuitemObject, + MUIA_Menuitem_Title, "About MUI...", + End, + Child, mi_help = MenuitemObject, + MUIA_Menuitem_Title, "Help", + End, + Child, MenuitemObject, + MUIA_Menuitem_Title, NM_BARLABEL, + End, + Child, mi_online = MenuitemObject, + MUIA_Menuitem_Title, "Online", + MUIA_Menuitem_Shortcut, "O", + End, + Child, mi_offline = MenuitemObject, + MUIA_Menuitem_Title, "Offline", + MUIA_Menuitem_Shortcut, "F", + End, + Child, MenuitemObject, + MUIA_Menuitem_Title, NM_BARLABEL, + End, + Child, mi_iconify = MenuitemObject, + MUIA_Menuitem_Title, "Iconify", + MUIA_Menuitem_Shortcut, "H", + End, + Child, MenuitemObject, + MUIA_Menuitem_Title, NM_BARLABEL, + End, + Child, mi_quit = MenuitemObject, + MUIA_Menuitem_Title, "Quit", + MUIA_Menuitem_Shortcut, "Q", + End, + End, + Child, MenuObjectT("Information"), + Child, mi_saveerrors = MenuitemObject, + MUIA_Menuitem_Title, "Save error log...", + End, + Child, mi_flusherrors = MenuitemObject, + MUIA_Menuitem_Title, "Flush errors", + End, + Child, MenuitemObject, + MUIA_Menuitem_Title, NM_BARLABEL, + End, + Child, mi_savedevlist = MenuitemObject, + MUIA_Menuitem_Title, "Save device list...", + End, + End, + Child, MenuObjectT("Settings"), + Child, mi_loadprefs = MenuitemObject, + MUIA_Menuitem_Title, "Load...", + MUIA_Menuitem_Shortcut, "L", + End, + Child, mi_saveprefs = MenuitemObject, + MUIA_Menuitem_Title, "Save", + MUIA_Menuitem_Shortcut, "S", + End, + Child, mi_saveprefsas = MenuitemObject, + MUIA_Menuitem_Title, "Save as...", + MUIA_Menuitem_Shortcut, "A", + End, + Child, MenuitemObject, + MUIA_Menuitem_Title, NM_BARLABEL, + End, + Child, mi_muiprefs = MenuitemObject, + MUIA_Menuitem_Title, "MUI Settings", + MUIA_Menuitem_Shortcut, "M", + End, + End, + End, + + SubWindow, mainwinobj = WindowObject, + MUIA_Window_ID , MAKE_ID('M','A','I','N'), + MUIA_Window_Title, "Trident 4.3", + MUIA_HelpNode, "usingtrident", + + WindowContents, actionobj = NewObject(ActionClass->mcc_Class, 0, TAG_END), + End, + End; + + if(!appobj) fail("Failed to create Application. Already running?\n"); + +/* +** Add notifications +*/ + DoMethod(mi_aboutmui, MUIM_Notify, MUIA_Menuitem_Trigger, MUIV_EveryTime, + appobj, 2, MUIM_Application_AboutMUI, mainwinobj); + DoMethod(mi_about, MUIM_Notify, MUIA_Menuitem_Trigger, MUIV_EveryTime, + actionobj, 1, MUIM_Action_About); + DoMethod(mi_online, MUIM_Notify, MUIA_Menuitem_Trigger, MUIV_EveryTime, + actionobj, 1, MUIM_Action_Online); + DoMethod(mi_offline, MUIM_Notify, MUIA_Menuitem_Trigger, MUIV_EveryTime, + actionobj, 1, MUIM_Action_Offline); + DoMethod(mi_help, MUIM_Notify, MUIA_Menuitem_Trigger, MUIV_EveryTime, + appobj, 5, MUIM_Application_ShowHelp, mainwinobj, NULL, "main", 0); + DoMethod(mi_iconify, MUIM_Notify, MUIA_Menuitem_Trigger, MUIV_EveryTime, + appobj, 3, MUIM_Set, MUIA_Application_Iconified, TRUE); + DoMethod(mi_quit, MUIM_Notify, MUIA_Menuitem_Trigger, MUIV_EveryTime, + appobj, 2, MUIM_Application_ReturnID, MUIV_Application_ReturnID_Quit); + + DoMethod(mi_saveerrors, MUIM_Notify, MUIA_Menuitem_Trigger, MUIV_EveryTime, + actionobj, 1, MUIM_Action_SaveErrors); + DoMethod(mi_flusherrors, MUIM_Notify, MUIA_Menuitem_Trigger, MUIV_EveryTime, + actionobj, 1, MUIM_Action_FlushErrors); + DoMethod(mi_savedevlist, MUIM_Notify, MUIA_Menuitem_Trigger, MUIV_EveryTime, + actionobj, 1, MUIM_Action_SaveDeviceList); + + DoMethod(mi_loadprefs, MUIM_Notify, MUIA_Menuitem_Trigger, MUIV_EveryTime, + actionobj, 1, MUIM_Action_LoadPrefs); + DoMethod(mi_saveprefs, MUIM_Notify, MUIA_Menuitem_Trigger, MUIV_EveryTime, + actionobj, 1, MUIM_Action_SavePrefs); + DoMethod(mi_saveprefsas, MUIM_Notify, MUIA_Menuitem_Trigger, MUIV_EveryTime, + actionobj, 1, MUIM_Action_SavePrefsAs); + DoMethod(mi_muiprefs, MUIM_Notify, MUIA_Menuitem_Trigger, MUIV_EveryTime, + appobj, 2, MUIM_Application_OpenConfigWindow, 0); + + DoMethod(mainwinobj, MUIM_Notify, MUIA_Window_CloseRequest, TRUE, + actionobj, 1, MUIM_Action_UseQuit); + DoMethod(appobj, MUIM_Notify, MUIA_Application_DoubleStart, MUIV_EveryTime, + actionobj, 1, MUIM_Action_WakeUp); + + DoMethod(appobj, MUIM_Application_Load, MUIV_Application_Load_ENVARC); + +/* +** This is the ideal input loop for an object oriented MUI application. +** Everything is encapsulated in classes, no return ids need to be used, +** we just check if the program shall terminate. +** Note that MUIM_Application_NewInput expects sigs to contain the result +** from Wait() (or 0). This makes the input loop significantly faster. +*/ + + { + ULONG sigs = 0; + ULONG sigmask; + LONG isopen; + LONG iconify; + + get(appobj, MUIA_Application_Iconified, &iconify); + set(mainwinobj, MUIA_Window_Open, TRUE); + get(mainwinobj, MUIA_Window_Open, &isopen); + if(!(isopen || iconify)) + fail("Couldn't open window! Maybe screen is too small. Try a higher resolution!\n"); + + sigmask = 0;// FIXME 1L<mp_SigBit; + while(DoMethod(appobj, MUIM_Application_NewInput, &sigs) != MUIV_Application_ReturnID_Quit) + { + if(sigs) + { + sigs = Wait(sigs | sigmask | SIGBREAKF_CTRL_C); + if(sigs & SIGBREAKF_CTRL_C) + break; + } + } + set(mainwinobj, MUIA_Window_Open, FALSE); + } + DoMethod(appobj, MUIM_Application_Save, MUIV_Application_Save_ENVARC); + +/* +** Shut down... +*/ + fail(NULL); + return(0); // never gets here, just to shut the compiler up +} +/* \\\ */ + diff --git a/rom/usb/trident/Trident.h b/rom/usb/trident/Trident.h new file mode 100644 index 000000000..0d5a95aeb --- /dev/null +++ b/rom/usb/trident/Trident.h @@ -0,0 +1,72 @@ +/*************************************************************/ +/* Includes and other common stuff for the Audex Project */ +/*************************************************************/ + +/* MUI */ +#include +#include +#include +#include + +/* System */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* ANSI C */ +#include +#include +#include + +extern struct ExecBase *SysBase; + +#ifndef MAKE_ID +#define MAKE_ID(a,b,c,d) ((ULONG) (a)<<24 | (ULONG) (b)<<16 | (ULONG) (c)<<8 | (ULONG) (d)) +#endif + +#define LabelB(label) (void *)MUI_NewObject(MUIC_Text,MUIA_Text_PreParse,"\33r",\ + MUIA_Text_Contents,label,TextFrame,MUIA_FramePhantomHoriz,\ + TRUE,MUIA_Weight,0,MUIA_InnerLeft,0,MUIA_InnerRight,0,TAG_DONE) + +#ifndef min +#define min(x,y) (((x) < (y)) ? (x) : (y)) +#define max(x,y) (((x) > (y)) ? (x) : (y)) +#endif + +/* prototypes */ + +BOOL WriteConfig(STRPTR name); +void LoadPsdStackloader(void); +BOOL GetToolTypes(void); + +void CleanupClasses(void); +BOOL SetupClasses(void); +void fail(char *str); +int main(int argc, char *argv[]); + +/* extern variables */ + +extern struct MUI_CustomClass *ActionClass; +extern struct MUI_CustomClass *IconListClass; +extern struct MUI_CustomClass *DevWinClass; +extern struct MUI_CustomClass *CfgListClass; +extern BOOL registermode; + +extern struct Library *MUIMasterBase; +extern struct Library *PsdBase; +extern struct WBStartup *_WBenchMsg; + diff --git a/rom/usb/trident/debug.c b/rom/usb/trident/debug.c new file mode 100644 index 000000000..f29021b6b --- /dev/null +++ b/rom/usb/trident/debug.c @@ -0,0 +1,38 @@ +#include "debug.h" + +#ifdef DEBUG +void dumpmem(void *mem, unsigned long int len) +{ + unsigned char *p; + + if (!mem || !len) { return; } + + p = (unsigned char *) mem; + + bug("\n"); + + do + { + unsigned char b, c, str[17]; + + for (b = 0; b < 16; b++) + { + c = *p++; + str[b] = ((c >= ' ') && (c <= 'z')) ? c : '.'; + str[b + 1] = 0; + bug("%02lx ", c); + if (--len == 0) break; + } + + while (++b < 16) + { + bug(" "); + } + + bug(" %s\n", str); + } while (len); + + bug("\n\n"); +} + +#endif /* DEBUG */ diff --git a/rom/usb/trident/debug.h b/rom/usb/trident/debug.h new file mode 100644 index 000000000..6d5cb840e --- /dev/null +++ b/rom/usb/trident/debug.h @@ -0,0 +1,22 @@ +#ifndef __DEBUG_H__ +#define __DEBUG_H__ + +#define DB_LEVEL 1 + +#define DEBUG 1 + +#include + +#ifdef DEBUG +#define KPRINTF(l, x) do { if ((l) >= DB_LEVEL) \ + { bug("%s:%s/%lu: ", __FILE__, __FUNCTION__, __LINE__); bug x;} } while (0) +#define DB(x) x + void dumpmem(void *mem, unsigned long int len); +#else /* !DEBUG */ + +#define KPRINTF(l, x) ((void) 0) +#define DB(x) + +#endif /* DEBUG */ + +#endif /* __DEBUG_H__ */ diff --git a/rom/usb/trident/mmakefile.src b/rom/usb/trident/mmakefile.src new file mode 100644 index 000000000..3532c3d03 --- /dev/null +++ b/rom/usb/trident/mmakefile.src @@ -0,0 +1,13 @@ +# $Id: mmakefile.src $ +include $(TOP)/config/make.cfg + +FILES := Trident ActionClass CfgListClass DevWinClass IconListClass debug + +#MM- rom-usb-trident : rom-usb-poseidon linklibs + +%build_prog progname="Trident" mmake=rom-usb-trident \ + files=$(FILES) targetdir=$(AROS_PREFS) \ + uselibs="arossupport amiga mui arosc m" + + +%common diff --git a/rom/usb/trident/neptune8logo.c b/rom/usb/trident/neptune8logo.c new file mode 100644 index 000000000..938091dfb --- /dev/null +++ b/rom/usb/trident/neptune8logo.c @@ -0,0 +1,828 @@ +#ifdef USE_NEPTUNE8_COLORS +const ULONG neptune8_colors[24] = +{ + 0xf6f6f6f6,0x06060606,0xf6f6f6f6, + 0x00000000,0x00000000,0x00000000, + 0x2c2c2c2c,0x2c2c2c2c,0x2c2c2c2c, + 0x4e4e4e4e,0x4e4e4e4e,0x4e4e4e4e, + 0x95959595,0x95959595,0x95959595, + 0xafafafaf,0xafafafaf,0xafafafaf, + 0xc7c7c7c7,0xc7c7c7c7,0xc7c7c7c7, + 0xffffffff,0xffffffff,0xffffffff, +}; +#endif + +#define NEPTUNE8_WIDTH 160 +#define NEPTUNE8_HEIGHT 216 +#define NEPTUNE8_DEPTH 3 +#define NEPTUNE8_COMPRESSION 1 +#define NEPTUNE8_MASKING 0 + +#ifdef USE_NEPTUNE8_HEADER +const struct BitMapHeader neptune8_header = +{ 160,216,0,0,3,0,1,0,0,17,20,640,512 }; +#endif + +#ifdef USE_NEPTUNE8_BODY +const UBYTE neptune8_body[11996] = { +0xfd,0x00,0x01,0x14,0x40,0xf3,0x00,0xfd,0x00,0x01,0x0b,0x80,0xf3,0x00,0xfe, +0x00,0x02,0x07,0xff,0xc0,0xf3,0x00,0xfe,0x00,0x02,0x03,0x14,0x80,0xf3,0x00, +0xfe,0x00,0x01,0x01,0xeb,0xf2,0x00,0xfe,0x00,0x02,0x07,0xff,0xc0,0xf3,0x00, +0xfe,0x00,0x02,0x03,0xb4,0x80,0xfc,0x00,0x01,0x01,0x2a,0xfa,0x00,0xfe,0x00, +0x01,0x01,0xfb,0xfb,0x00,0x01,0x01,0x0c,0xfa,0x00,0xfe,0x00,0x02,0x07,0xff, +0xc0,0xfc,0x00,0x01,0x01,0xfe,0xfa,0x00,0xfe,0x00,0x02,0x02,0x68,0xe0,0xfc, +0x00,0x01,0x01,0xd8,0xfa,0x00,0xfe,0x00,0x02,0x01,0xff,0xc0,0xfc,0x00,0x01, +0x05,0x5d,0xfa,0x00,0xfe,0x00,0x02,0x07,0xff,0xe0,0xfc,0x00,0x02,0x06,0xa3, +0x80,0xfb,0x00,0xfe,0x00,0x02,0x07,0x2c,0x40,0xfc,0x00,0x02,0x09,0x22,0xc0, +0xfb,0x00,0xfd,0x00,0x01,0xff,0xe0,0xfc,0x00,0x01,0x32,0x82,0xfa,0x00,0xfe, +0x00,0x02,0x0f,0xff,0xe0,0xfc,0x00,0x02,0x7f,0xfd,0xe0,0xfb,0x00,0xfe,0x00, +0x02,0x0b,0x92,0x20,0xfd,0x00,0x03,0x02,0xa0,0x2f,0x58,0xfb,0x00,0xfe,0x00, +0x02,0x04,0x7f,0xc0,0xfd,0x00,0x03,0x01,0x7f,0xd0,0xb0,0xfb,0x00,0xfe,0x00, +0x02,0x1f,0xff,0xf0,0xfd,0x00,0x03,0x03,0xff,0xff,0xf8,0xfb,0x00,0xfe,0x00, +0x02,0x04,0x8c,0x40,0xfd,0x00,0x03,0x07,0x6f,0x6d,0x4c,0xfb,0x00,0xfe,0x00, +0x02,0x01,0xfe,0x90,0xfd,0x00,0x03,0x07,0xff,0xff,0xfc,0xfb,0x00,0xfe,0x00, +0x02,0x3f,0xff,0xf8,0xfd,0x00,0x03,0x07,0xff,0xff,0xfc,0xfb,0x00,0xfe,0x00, +0x02,0x30,0x4a,0x08,0xfc,0x00,0x02,0x2a,0xd7,0xfc,0xfb,0x00,0xfe,0x00,0x01, +0x17,0xff,0xfc,0x00,0x00,0x0f,0xfe,0xff,0xfb,0x00,0xfe,0x00,0x02,0x6f,0xff, +0xfc,0xfd,0x00,0x00,0x0f,0xfe,0xff,0xfb,0x00,0xfe,0x00,0x02,0x5a,0x9d,0xc8, +0xfd,0x00,0x04,0x02,0xa5,0xfe,0xff,0x10,0xfc,0x00,0xfe,0x00,0x02,0x15,0xff, +0x44,0xfd,0x00,0x04,0x0d,0x5f,0xfd,0xff,0xe0,0xfc,0x00,0xfe,0x00,0x02,0x6f, +0xff,0xbc,0xfd,0x00,0x00,0x0f,0xfe,0xff,0x00,0xf0,0xfc,0x00,0xfe,0x00,0x02, +0x62,0x21,0x60,0xfd,0x00,0x04,0x20,0x34,0x2c,0x40,0xa8,0xfc,0x00,0xfe,0x00, +0x02,0x1c,0x7e,0x60,0xfd,0x00,0x04,0x40,0x08,0xb1,0xff,0xf8,0xfc,0x00,0xfe, +0x00,0x02,0xff,0xff,0x9c,0xfd,0x00,0x04,0x7f,0xff,0x7f,0xff,0xf8,0xfc,0x00, +0xfe,0x00,0x02,0x57,0x1d,0xf0,0xfe,0x00,0x05,0x03,0x07,0xbd,0x76,0x9b,0x5c, +0xfc,0x00,0xfe,0x00,0x02,0x20,0xfe,0x70,0xfe,0x00,0x05,0x07,0x8f,0xbd,0xfe, +0x84,0xb8,0xfc,0x00,0xfe,0x00,0x02,0xff,0xff,0x8c,0xfe,0x00,0x05,0x07,0xf0, +0x42,0x31,0x7f,0xfc,0xfc,0x00,0xfe,0x00,0x02,0x64,0x30,0x7c,0xfd,0x00,0x04, +0x87,0xfe,0x6a,0xf2,0xa8,0xfc,0x00,0xfe,0x00,0x02,0x83,0xcf,0xfc,0xfe,0x00, +0x05,0x07,0x2f,0xff,0xf6,0xf2,0x9c,0xfc,0x00,0x05,0x00,0x00,0x01,0xff,0xff, +0x80,0xfe,0x00,0x05,0x07,0xf0,0x01,0xfd,0x0d,0x7c,0xfc,0x00,0x05,0x00,0x00, +0x01,0xca,0xa0,0xe8,0xfe,0x00,0x05,0x05,0xfa,0x76,0x3b,0x6e,0xf7,0xfc,0x00, +0xfe,0x00,0x02,0x05,0xff,0xf8,0xfe,0x00,0x05,0x06,0x19,0xfc,0xfd,0x0f,0xf3, +0xfc,0x00,0x05,0x00,0x00,0x03,0xff,0xff,0xc4,0xfe,0x00,0x05,0x07,0xe7,0xfb, +0xfe,0xf0,0x1f,0xfc,0x00,0x05,0x00,0x00,0x03,0xe3,0x10,0x38,0xfd,0x00,0x05, +0x10,0x6f,0x16,0xfc,0x56,0x80,0xfd,0x00,0xfe,0x00,0x02,0x0c,0xff,0xd0,0xfe, +0x00,0x06,0x0f,0xf7,0x9e,0x57,0xfe,0x61,0xc0,0xfd,0x00,0x05,0x00,0x00,0x03, +0xff,0xff,0xe8,0xfe,0x00,0x06,0x0f,0xef,0xff,0xaf,0xff,0x9f,0xc0,0xfd,0x00, +0x05,0x00,0x00,0x03,0x12,0x18,0x98,0xfd,0x00,0x05,0xe4,0x75,0xb4,0x23,0x48, +0x60,0xfd,0x00,0xfe,0x00,0x02,0xed,0xff,0xc8,0xfe,0x00,0x06,0x0e,0xf7,0x1f, +0xaf,0xff,0x87,0x80,0xfd,0x00,0x05,0x00,0x00,0x03,0xff,0xff,0xf0,0xfe,0x00, +0x06,0x0f,0xfb,0xff,0xdf,0xff,0xff,0xe0,0xfd,0x00,0xfe,0x00,0x02,0x18,0xe0, +0x80,0xfe,0x00,0x06,0x04,0x19,0x11,0x4e,0x35,0x42,0xd0,0xfd,0x00,0x04,0x00, +0x00,0x01,0xe7,0xff,0xfd,0x00,0x06,0x09,0x73,0x0f,0xfd,0xf9,0xbf,0xe0,0xfd, +0x00,0x05,0x00,0x00,0x03,0xff,0xff,0xf8,0xfe,0x00,0x06,0x0e,0xfc,0xff,0xff, +0xfe,0x7f,0xf0,0xfd,0x00,0xfe,0x00,0x02,0x10,0x24,0x68,0xfe,0x00,0x05,0x0f, +0x68,0x99,0xdd,0x34,0xb9,0xfc,0x00,0x05,0x00,0x00,0x01,0xef,0xff,0xb0,0xfe, +0x00,0x06,0x0f,0x18,0xf9,0xbc,0x3c,0x7d,0xf0,0xfd,0x00,0x05,0x00,0x00,0x03, +0xff,0xff,0xd8,0xfd,0x00,0x05,0xff,0x07,0xff,0xc3,0xff,0xf8,0xfd,0x00,0x05, +0x00,0x00,0x02,0x0f,0x59,0xb8,0xfe,0x00,0x06,0x0d,0x80,0x11,0x24,0xa0,0x88, +0x40,0xfd,0x00,0x05,0x00,0x00,0x01,0xf0,0xff,0xf0,0xfe,0x00,0x06,0x0f,0xcd, +0x6f,0x8f,0x59,0xce,0xe8,0xfd,0x00,0x05,0x00,0x00,0x03,0xff,0xff,0xd8,0xfd, +0x00,0x00,0x3e,0xfe,0xff,0x01,0xfd,0xfc,0xfd,0x00,0x05,0x00,0x00,0x03,0xa0, +0x10,0xd8,0xfe,0x00,0x06,0x05,0xe3,0xe2,0xca,0x2e,0x2d,0xe8,0xfd,0x00,0x04, +0x00,0x00,0x01,0xc0,0x0f,0xfd,0x00,0x06,0x07,0xaf,0xef,0x36,0xcb,0x9f,0x80, +0xfd,0x00,0x05,0x00,0x00,0x03,0xff,0xff,0xf8,0xfe,0x00,0x06,0x02,0x5f,0x1f, +0xff,0xf7,0xfe,0x7c,0xfd,0x00,0x05,0x00,0x00,0x01,0x49,0xeb,0x90,0xfe,0x00, +0x06,0x03,0x1c,0xf2,0x57,0x89,0x3c,0x40,0xfd,0x00,0xfe,0x00,0x01,0x81,0xe4, +0xfd,0x00,0x06,0x06,0x3f,0xec,0x09,0x9f,0xf4,0xc0,0xfd,0x00,0x05,0x00,0x00, +0x03,0xfe,0x1f,0xf8,0xfe,0x00,0x00,0x0f,0xfd,0xff,0x01,0xfb,0x3c,0xfd,0x00, +0xfe,0x00,0x01,0xe1,0xfc,0xfd,0x00,0x06,0x0f,0x42,0x62,0x86,0xf4,0x54,0x68, +0xfd,0x00,0x04,0x00,0x00,0x01,0x01,0xfc,0xfd,0x00,0x06,0x05,0x06,0xd2,0xc0, +0xff,0x72,0xa8,0xfd,0x00,0x05,0x00,0x00,0x03,0xfe,0x03,0xf8,0xfe,0x00,0x06, +0x0f,0xff,0x3d,0x7f,0xff,0xff,0x14,0xfd,0x00,0xfe,0x00,0x02,0x50,0x4e,0xe0, +0xfe,0x00,0x06,0x07,0x93,0xb6,0xb7,0x8b,0x44,0x90,0xfd,0x00,0x05,0x00,0x00, +0x01,0x20,0xfe,0x80,0xfe,0x00,0x06,0x03,0xe9,0xc6,0x55,0x95,0xad,0xf0,0xfd, +0x00,0x05,0x00,0x00,0x03,0xff,0x01,0x78,0xfe,0x00,0x06,0x0e,0x07,0xf9,0xea, +0x7e,0xff,0x8c,0xfd,0x00,0x05,0x00,0x00,0x01,0x0a,0x09,0x60,0xfe,0x00,0x06, +0x0d,0xa8,0xb9,0x36,0x21,0x2d,0x58,0xfd,0x00,0x04,0x00,0x00,0x01,0x0b,0x6f, +0xfd,0x00,0x06,0x0f,0xd6,0x5d,0xf6,0x21,0x2a,0x78,0xfd,0x00,0x05,0x00,0x00, +0x02,0xf4,0xf0,0xf8,0xfe,0x00,0x06,0x03,0x01,0xe2,0xe9,0xdf,0xff,0x80,0xfd, +0x00,0x05,0x00,0x00,0x01,0x12,0xd8,0xb0,0xfe,0x00,0x06,0x07,0xcc,0x70,0x05, +0x95,0x46,0x50,0xfd,0x00,0x05,0x00,0x00,0x01,0x0a,0x23,0xa0,0xfe,0x00,0x06, +0x3f,0xb3,0xfd,0xff,0x9f,0x79,0xf0,0xfd,0x00,0x05,0x00,0x00,0x02,0xfd,0xfc, +0x58,0xfe,0x00,0x06,0x30,0x00,0x03,0xf0,0x7e,0xfe,0x08,0xfd,0x00,0xfe,0x00, +0x01,0x74,0x9f,0xfd,0x00,0x06,0x3a,0x1b,0x12,0x18,0x30,0x8b,0x20,0xfd,0x00, +0x05,0x00,0x00,0x01,0xf1,0x62,0xc0,0xfe,0x00,0x06,0xef,0x6c,0xe8,0xfb,0xce, +0xd0,0xb0,0xfd,0x00,0xfe,0x00,0x02,0x0f,0xfc,0x38,0xfe,0x00,0x06,0xf0,0xf0, +0x07,0xfc,0x01,0xfc,0x40,0xfd,0x00,0x0f,0x00,0x00,0x01,0xe3,0x15,0x48,0x00, +0x00,0x01,0x15,0xe0,0x00,0x84,0x02,0x0c,0x90,0xfd,0x00,0x05,0x00,0x00,0x01, +0xe0,0xe2,0xc8,0xfe,0x00,0x06,0xf6,0x7f,0xe0,0x81,0xe1,0x0a,0xd0,0xfd,0x00, +0xfe,0x00,0x0c,0x1f,0xfc,0x30,0x00,0x00,0x01,0xf9,0x80,0x1f,0x7e,0x1f,0xf1, +0x20,0xfd,0x00,0xfe,0x00,0x0c,0xbc,0x0a,0x08,0x00,0x00,0x01,0x80,0xdf,0xb3, +0xd0,0x18,0x60,0xc0,0xfd,0x00,0xfe,0x00,0x02,0xfd,0xf3,0x88,0xfe,0x00,0x06, +0xbe,0xe1,0x8d,0xf7,0x78,0x7b,0x70,0xfd,0x00,0xfe,0x00,0x0c,0x03,0xfc,0x70, +0x00,0x00,0x01,0xff,0x00,0x7e,0x0f,0x87,0x87,0x80,0xfd,0x00,0xfe,0x00,0x02, +0xda,0xc8,0x50,0xfe,0x00,0x06,0x05,0x0a,0x1e,0x37,0xf2,0xb1,0xa0,0xfd,0x00, +0xfe,0x00,0x02,0xfb,0x33,0xd0,0xfe,0x00,0x06,0x89,0x77,0xf5,0xff,0xed,0x57, +0xb0,0xfd,0x00,0xfe,0x00,0x0c,0x05,0xfc,0x28,0x00,0x00,0x01,0xfe,0x81,0xff, +0xff,0xc0,0x0e,0x50,0xfd,0x00,0xfe,0x00,0x0c,0x69,0x08,0x70,0x00,0x00,0x01, +0x0d,0x98,0x10,0xe0,0x19,0xa8,0xd0,0xfd,0x00,0xfe,0x00,0x0c,0x7c,0xf3,0xf0, +0x00,0x00,0x01,0x41,0xa0,0x7e,0x1f,0xf6,0x6d,0x50,0xfd,0x00,0xfe,0x00,0x02, +0x03,0xfc,0x08,0xfe,0x00,0x06,0xfe,0x47,0xff,0xff,0xe0,0x1e,0x30,0xfd,0x00, +0xfe,0x00,0x02,0x15,0x89,0x30,0xfe,0x00,0x06,0xd6,0x90,0xef,0x65,0x2b,0x01, +0xc0,0xfd,0x00,0xfe,0x00,0x02,0x7c,0x73,0xf0,0xfe,0x00,0x06,0xc7,0xa0,0x9c, +0xcf,0xcc,0xdf,0xc0,0xfd,0x00,0xfe,0x00,0x01,0x03,0xfc,0xfd,0x00,0x06,0x38, +0x4f,0x7f,0xff,0xf0,0x20,0x38,0xfd,0x00,0xfe,0x00,0x02,0x61,0x89,0xe0,0xfe, +0x00,0x06,0xa6,0x80,0x56,0xc0,0x06,0xef,0x08,0xfd,0x00,0xfe,0x00,0x02,0x7c, +0x73,0xe0,0xfe,0x00,0x06,0xfe,0xf0,0x48,0x0f,0x8b,0x1d,0x90,0xfd,0x00,0xfe, +0x00,0x02,0x03,0xfc,0x10,0xfe,0x00,0x06,0x01,0x0f,0xbf,0xff,0xfc,0x13,0xfc, +0xfd,0x00,0xfe,0x00,0x02,0x6b,0x1b,0x20,0xfe,0x00,0x06,0x89,0xb3,0xdd,0x8a, +0x99,0xb4,0x38,0xfd,0x00,0xfe,0x00,0x02,0x7c,0xe3,0xe0,0xfe,0x00,0x06,0xf9, +0xd2,0x10,0x44,0x85,0x6e,0x5c,0xfd,0x00,0xfe,0x00,0x01,0x03,0xfc,0xfd,0x00, +0x06,0x06,0x0d,0xef,0xff,0x7e,0x1f,0xfc,0xfd,0x00,0xfe,0x00,0x02,0x23,0x0b, +0xc0,0xfe,0x00,0x06,0x08,0xb9,0x45,0x07,0x02,0xc7,0x34,0xfd,0x00,0xfe,0x00, +0x0c,0x3c,0xf3,0xc0,0x00,0x00,0x01,0xff,0x5f,0xe0,0x01,0x7c,0x47,0x9c,0xfd, +0x00,0xfe,0x00,0x01,0x03,0xfc,0xfb,0x00,0x04,0x1f,0xfe,0xff,0x38,0xf8,0xfd, +0x00,0xfe,0x00,0x0c,0x33,0x0a,0xc0,0x00,0x00,0x01,0x00,0x59,0xa4,0x0b,0x8a, +0xc6,0xd0,0xfd,0x00,0xfe,0x00,0x0c,0x3c,0xf3,0xc0,0x00,0x00,0x01,0xff,0xbe, +0x58,0xdb,0xfe,0xb7,0xd8,0xfd,0x00,0xfe,0x00,0x01,0x03,0xfc,0xfb,0x00,0x04, +0x03,0xe4,0x01,0x09,0x38,0xfd,0x00,0xfe,0x00,0x0b,0x03,0x0e,0x80,0x00,0x00, +0x01,0x09,0xfc,0x10,0xd2,0xe1,0x67,0xfc,0x00,0xfe,0x00,0x0c,0x1c,0xf7,0x80, +0x00,0x00,0x01,0xfe,0x1b,0xed,0xcd,0x21,0x1f,0xd0,0xfd,0x00,0xfe,0x00,0x01, +0x23,0xf8,0xfb,0x00,0x04,0x03,0xe0,0x1e,0x80,0x38,0xfd,0x00,0xfe,0x00,0x0c, +0x04,0x0d,0x80,0x00,0x00,0x01,0x04,0x08,0xde,0xae,0x6f,0x57,0xa8,0xfd,0x00, +0xfe,0x00,0x0c,0x1f,0xf7,0x80,0x00,0x00,0x01,0xfb,0x57,0xe1,0xd1,0xdf,0x28, +0x70,0xfd,0x00,0xfe,0x00,0x01,0x03,0xf8,0xfd,0x00,0x06,0x0f,0xa0,0x03,0xe0, +0x00,0x80,0x04,0xfd,0x00,0xfe,0x00,0x02,0x04,0x09,0x80,0xfe,0x00,0x06,0x31, +0x9b,0xe2,0xf3,0x1b,0x04,0xa8,0xfd,0x00,0xfe,0x00,0x02,0x1f,0xf7,0x80,0xfe, +0x00,0x06,0xce,0x5f,0xf9,0xdd,0x07,0x7f,0x74,0xfd,0x00,0xfe,0x00,0x01,0x03, +0xf8,0xfd,0x00,0x06,0x0f,0xe0,0x07,0xe0,0xe0,0x80,0x0c,0xfd,0x00,0xfe,0x00, +0x01,0x12,0x01,0xfd,0x00,0x06,0x9c,0x03,0xae,0xa7,0x86,0x61,0x04,0xfd,0x00, +0xfe,0x00,0x01,0x19,0xf7,0xfd,0x00,0x06,0xeb,0x03,0xb9,0xc9,0xf9,0x65,0xf4, +0xfd,0x00,0xfe,0x00,0x01,0x07,0xf8,0xfd,0x00,0x06,0x07,0xfc,0x47,0xf0,0x00, +0x9e,0x0c,0xfd,0x00,0xfe,0x00,0x01,0x03,0x01,0xfd,0x00,0x06,0x25,0xa2,0x0a, +0xc7,0xbd,0xa9,0x14,0xfd,0x00,0xfe,0x00,0x01,0x18,0xf7,0xfd,0x00,0x06,0x5c, +0xe5,0xf1,0xc7,0x5e,0x2e,0xe4,0xfd,0x00,0xfe,0x00,0x01,0x07,0xf8,0xfd,0x00, +0x06,0x03,0x1f,0xff,0xf8,0xe3,0xdf,0x0c,0xfd,0x00,0xfe,0x00,0x01,0x33,0x30, +0xfd,0x00,0x06,0x10,0xe1,0x63,0x1a,0xcc,0x59,0x48,0xfd,0x00,0xfe,0x00,0x01, +0x38,0xc7,0xfd,0x00,0x06,0x6f,0x26,0x90,0xd6,0xd4,0x78,0x78,0xfd,0x00,0xfe, +0x00,0x01,0x07,0xf8,0xfc,0x00,0x05,0x1f,0xff,0xef,0x3f,0x87,0xb8,0xfd,0x00, +0xfe,0x00,0x01,0x3a,0x21,0xfd,0x00,0x06,0x33,0xb0,0x62,0x8a,0x00,0xfd,0x48, +0xfd,0x00,0xfe,0x00,0x01,0x39,0xd7,0xfd,0x00,0x06,0x3c,0x70,0x01,0xc5,0xfc, +0xc3,0xf8,0xfd,0x00,0xfe,0x00,0x01,0x07,0xf8,0xfc,0x00,0x00,0x0f,0xfe,0xff, +0x01,0x00,0xf0,0xfd,0x00,0xfe,0x00,0x02,0x3f,0x40,0x80,0xfe,0x00,0x06,0x02, +0x98,0x1a,0x93,0xe0,0xe1,0x48,0xfd,0x00,0xfe,0x00,0x02,0x38,0xb7,0x80,0xfe, +0x00,0x06,0x05,0x78,0x09,0xd0,0x18,0xd9,0x20,0xfd,0x00,0xfe,0x00,0x01,0x07, +0xf8,0xfc,0x00,0x05,0x07,0xf7,0xef,0xff,0x06,0xf8,0xfd,0x00,0xfe,0x00,0x02, +0x3f,0x78,0x80,0xfd,0x00,0x05,0x1e,0x0a,0x09,0x03,0xb9,0xb0,0xfd,0x00,0xfe, +0x00,0x02,0x38,0x8f,0x80,0xfd,0x00,0x05,0x3e,0x03,0xc8,0x03,0xc5,0x70,0xfd, +0x00,0xfe,0x00,0x01,0x47,0xf0,0xfc,0x00,0x04,0x01,0xff,0xf7,0xfc,0x0e,0xfc, +0x00,0xfe,0x00,0x02,0x6f,0x18,0x80,0xfe,0x00,0x06,0x3d,0x5c,0x46,0x73,0x1f, +0x9a,0xc0,0xfd,0x00,0xfe,0x00,0x02,0x78,0xef,0x80,0xfe,0x00,0x06,0x3e,0xfc, +0x05,0xa0,0x1f,0xeb,0x30,0xfd,0x00,0xfe,0x00,0x01,0x07,0xf0,0xfc,0x00,0x04, +0x03,0xfb,0xdf,0xe0,0x04,0xfc,0x00,0xfe,0x00,0x01,0x6e,0x3e,0xfe,0x00,0x07, +0x03,0xd9,0xf4,0x2f,0xc5,0x0f,0xe9,0x20,0xfd,0x00,0xfe,0x00,0x01,0x79,0xcf, +0xfe,0x00,0x07,0x03,0xf6,0x3c,0x2f,0xc4,0x0f,0x96,0xe0,0xfd,0x00,0xfe,0x00, +0x02,0x07,0xf0,0x80,0xfd,0x00,0x03,0x43,0xd0,0x3b,0xf0,0xfb,0x00,0xfe,0x00, +0x01,0x4a,0x1f,0xfe,0x00,0x07,0x03,0x0a,0x39,0x67,0xe1,0x1f,0xd9,0x80,0xfd, +0x00,0xfe,0x00,0x01,0x7d,0xef,0xfe,0x00,0x07,0x03,0xfe,0xf9,0x3f,0xf8,0x1f, +0xef,0xc0,0xfd,0x00,0xfe,0x00,0x01,0x87,0xf0,0xfd,0x00,0x04,0x01,0xc6,0xf0, +0x0f,0xe0,0xfb,0x00,0xfe,0x00,0x01,0xe6,0x6f,0xfe,0x00,0x06,0x01,0xba,0x7d, +0x07,0xb0,0x86,0x60,0xfc,0x00,0xfe,0x00,0x01,0xf1,0x8f,0xfe,0x00,0x06,0x03, +0xf9,0x94,0xc4,0x4f,0x06,0x50,0xfc,0x00,0xfe,0x00,0x01,0x0f,0xf0,0xfe,0x00, +0x06,0x0c,0x07,0xfb,0xf8,0x3f,0xf9,0x80,0xfc,0x00,0xfe,0x00,0x01,0xc6,0x2f, +0xfe,0x00,0x06,0x05,0xe3,0x4e,0x2e,0xac,0x30,0x80,0xfc,0x00,0xfe,0x00,0x01, +0xf1,0xcf,0xfe,0x00,0x06,0x07,0xf0,0xb9,0x16,0x19,0xb0,0x50,0xfc,0x00,0xfe, +0x00,0x01,0x0f,0xf0,0xfe,0x00,0x06,0x08,0x0f,0xff,0xd9,0xf7,0xcf,0xe0,0xfc, +0x00,0x04,0x00,0x00,0x01,0xc6,0x2f,0xfe,0x00,0x06,0x01,0x4e,0x69,0x04,0x50, +0x88,0x0e,0xfc,0x00,0x04,0x00,0x00,0x01,0xf1,0xcf,0xfe,0x00,0x06,0x07,0xfe, +0xa6,0x3c,0x56,0x49,0x1e,0xfc,0x00,0xfe,0x00,0x01,0x0f,0xf0,0xfe,0x00,0x06, +0x18,0x01,0xdf,0xc3,0xab,0xf7,0xe0,0xfc,0x00,0x04,0x00,0x00,0x01,0xf4,0x3f, +0xfe,0x00,0x06,0x21,0x90,0x1e,0x79,0x14,0x18,0x8a,0xfc,0x00,0x04,0x00,0x00, +0x01,0xf3,0xdf,0xfe,0x00,0x07,0x27,0x3f,0x80,0x6a,0xe8,0x56,0x15,0x80,0xfd, +0x00,0xfe,0x00,0x01,0x0f,0xe0,0xfe,0x00,0x07,0x58,0x40,0xff,0x84,0x03,0xef, +0xe0,0x60,0xfd,0x00,0x04,0x00,0x00,0x03,0xec,0x3f,0xfe,0x00,0x07,0x0f,0x55, +0xd0,0x24,0x94,0x03,0x8a,0x40,0xfd,0x00,0x04,0x00,0x00,0x03,0xe3,0xdf,0xfe, +0x00,0x07,0x2b,0x7a,0x70,0x02,0x63,0x3d,0x67,0xb8,0xfd,0x00,0xfe,0x00,0x0c, +0x1f,0xe0,0x80,0x00,0x00,0xd0,0x81,0xbf,0xff,0xf9,0xfe,0xf0,0x78,0xfd,0x00, +0x0f,0x00,0x00,0x01,0xfe,0x2f,0x80,0x00,0x00,0x4e,0xc4,0x9f,0xfe,0x30,0xc8, +0x34,0x7b,0xfd,0x00,0x0f,0x00,0x00,0x01,0xf1,0xcf,0x80,0x00,0x00,0x7e,0xfd, +0x1f,0xde,0x36,0xc2,0x47,0xff,0xfd,0x00,0x04,0x00,0x00,0x02,0x0f,0xf0,0xfe, +0x00,0x07,0x81,0x03,0xe0,0x21,0xc9,0x3f,0xf8,0x3f,0xfd,0x00,0x10,0x00,0x00, +0x03,0x98,0x3f,0x00,0x01,0x00,0x38,0xce,0x15,0x85,0xfc,0x06,0x5b,0x80,0x80, +0xfe,0x00,0x10,0x00,0x00,0x03,0x97,0xdf,0x00,0x01,0x00,0x3e,0x7b,0xf7,0xa7, +0xe6,0xee,0x6b,0xbf,0xe0,0xfe,0x00,0xfe,0x00,0x0d,0x6f,0xe0,0x80,0x1e,0x01, +0xc1,0x87,0xc8,0x78,0x19,0x19,0x84,0x7f,0xe0,0xfe,0x00,0x10,0x00,0x00,0x07, +0x69,0xbf,0xf8,0xd0,0x41,0xf8,0x16,0xdd,0x00,0xef,0x09,0x7b,0xb6,0x88,0xfe, +0x00,0x10,0x00,0x00,0x07,0x66,0x5f,0xf8,0x3f,0x81,0x3f,0xdf,0xfd,0x7f,0x03, +0x33,0x13,0xb9,0xfe,0xfe,0x00,0xfe,0x00,0x0d,0x9f,0xe0,0x01,0xff,0xc8,0xc0, +0xe2,0x02,0xff,0xfc,0xfc,0x8c,0x7f,0xfe,0xfe,0x00,0x10,0x00,0x00,0x0e,0xd7, +0xff,0x7b,0xca,0xd7,0xf8,0x4c,0xf5,0x04,0xa1,0x4a,0xe3,0xe6,0x10,0xfe,0x00, +0x13,0x00,0x00,0x0e,0xc8,0x1f,0xf8,0x05,0x22,0x1f,0x06,0xfc,0xff,0xfd,0xc9, +0x43,0xff,0xff,0x80,0x00,0x00,0x13,0x00,0x00,0x01,0x3f,0xe0,0x07,0xff,0xfd, +0xe0,0xf3,0x23,0xff,0xfe,0x37,0x9c,0x3f,0xff,0x80,0x00,0x00,0x13,0x00,0x00, +0x05,0xdb,0x6a,0x65,0xe1,0xec,0x0c,0xe0,0x4a,0x40,0x09,0x97,0xc4,0xd2,0x6d, +0x80,0x00,0x00,0x13,0x00,0x00,0x0d,0xa0,0x8b,0xe2,0x1e,0x13,0xff,0x7b,0xaf, +0xff,0xfe,0xf8,0x7d,0xdf,0xff,0xc0,0x00,0x00,0x13,0x00,0x00,0x02,0x7f,0xf4, +0x1f,0xff,0xff,0xf0,0x07,0xf7,0xff,0xff,0x07,0x02,0x3f,0xff,0xc0,0x00,0x00, +0x13,0x00,0x00,0x1d,0x2d,0xb7,0xf0,0xa9,0xde,0x64,0x41,0x38,0xdc,0x01,0xc8, +0x10,0xc0,0x44,0x60,0x00,0x00,0x13,0x00,0x00,0x0d,0x42,0x07,0xef,0x06,0x21, +0xbb,0xf0,0x17,0x27,0xff,0x7f,0x2f,0xdb,0xff,0xf8,0x00,0x00,0x13,0x00,0x00, +0x02,0xff,0xf8,0x1f,0xff,0xff,0xfc,0x0f,0xef,0xff,0xff,0x87,0xc0,0x3f,0xff, +0xf8,0x00,0x00,0x13,0x00,0x00,0x03,0x0d,0xc3,0xc1,0x7c,0xf3,0x7e,0xbf,0xb9, +0x9e,0x8c,0xc8,0x98,0xe0,0x06,0xac,0x00,0x00,0x13,0x00,0x00,0x13,0xc2,0x03, +0xfe,0x83,0x0c,0x9f,0xff,0xb6,0x4e,0x3a,0x4e,0x13,0xdf,0xff,0xfe,0x00,0x00, +0x13,0x00,0x00,0x0c,0xff,0xfc,0x3f,0xff,0xff,0xfc,0x00,0x4f,0xf1,0xff,0xff, +0xe4,0x3f,0xff,0xfe,0x00,0x00,0x13,0x00,0x00,0x17,0x90,0xc7,0x80,0x0e,0x5f, +0x00,0x41,0x8c,0x05,0x12,0xa6,0x6f,0x63,0xe8,0x12,0x00,0x00,0x13,0x00,0x00, +0x37,0x0f,0x07,0xbf,0xf0,0x00,0xfd,0xcf,0xe4,0xf1,0x6c,0x86,0x5f,0x3f,0xff, +0xff,0x00,0x00,0x0e,0x00,0x00,0x08,0xff,0xf8,0x7f,0xff,0xff,0xfe,0x30,0x1f, +0xfa,0xff,0x79,0xb0,0xfe,0xff,0x01,0x00,0x00,0x13,0x00,0x00,0x77,0x00,0x57, +0x00,0x02,0x47,0x93,0x64,0x49,0x4a,0x11,0xea,0xb5,0x48,0x0f,0xc9,0x80,0x00, +0x13,0x00,0x00,0x37,0x1f,0x87,0x7f,0xfc,0x00,0x6d,0x9b,0xaa,0x20,0xf8,0xc8, +0xa6,0x77,0xff,0xff,0xc0,0x00,0x04,0x00,0x00,0x08,0xff,0xf8,0xfe,0xff,0x0b, +0xfe,0x00,0x17,0xff,0xff,0x37,0x5b,0xbf,0xff,0xff,0xc0,0x00,0x13,0x00,0x00, +0x2f,0xe0,0xcf,0x00,0x01,0x7f,0xa3,0xf2,0x86,0x05,0x90,0x96,0x1d,0xce,0xa0, +0x72,0x40,0x00,0x13,0x00,0x00,0xef,0xdf,0x0f,0xff,0xfe,0x00,0x1d,0xdd,0x99, +0xf1,0x60,0x99,0x1d,0x97,0xff,0xff,0xe0,0x00,0x04,0x00,0x00,0x10,0x3f,0xf0, +0xfe,0xff,0x0b,0xfe,0x00,0x60,0x0e,0xff,0x60,0xe2,0x6f,0xff,0xff,0xe0,0x00, +0x13,0x00,0x00,0xd7,0x82,0xf7,0x05,0x23,0xf6,0x8b,0x81,0x21,0x07,0xc5,0x61, +0xef,0xf9,0x9f,0x9a,0xa0,0x00,0x13,0x00,0x00,0x57,0xdd,0x1e,0xff,0xfc,0x00, +0x05,0xff,0x3e,0xf5,0xc5,0xa1,0xdf,0x7f,0xff,0xff,0xf8,0x00,0x04,0x00,0x00, +0x28,0x3f,0xe1,0xfe,0xff,0x0b,0xfe,0x00,0xc0,0x0e,0x3a,0xde,0x00,0x07,0xff, +0xff,0xf8,0x00,0x13,0x00,0x00,0x0f,0x02,0xed,0x08,0x81,0xfd,0x0a,0xc7,0x6b, +0xfd,0xb2,0x24,0x8a,0x5c,0x00,0xce,0x68,0x00,0x13,0x00,0x01,0x8f,0x5d,0x3c, +0xff,0xfe,0x00,0x06,0xbf,0x74,0x13,0xbf,0xea,0xfc,0xa3,0xff,0xff,0xf8,0x00, +0x04,0x00,0x00,0x70,0xbf,0xc3,0xfd,0xff,0x0a,0x00,0x80,0x0e,0x41,0xdf,0x03, +0x7f,0xff,0xff,0xfc,0x00,0x13,0x00,0x01,0x9b,0x60,0x6f,0x04,0x23,0xff,0x05, +0xc1,0xd4,0x2e,0xff,0xf4,0x7f,0xc1,0x00,0x73,0x94,0x00,0x13,0x00,0x00,0x9b, +0x5f,0xbc,0xff,0xfc,0x00,0x03,0xff,0xef,0xd0,0x01,0x70,0x93,0xb6,0xff,0xff, +0xfc,0x00,0x04,0x00,0x00,0x64,0xbf,0xc3,0xfd,0xff,0x0a,0x00,0x00,0x3f,0x00, +0x8f,0x00,0x7f,0xff,0xff,0xfe,0x00,0x13,0x00,0x00,0xbd,0xe0,0x7e,0x01,0x21, +0x3e,0x84,0xc9,0x38,0x21,0x26,0xe5,0xa3,0x9f,0x00,0x0c,0x26,0x00,0x13,0x00, +0x03,0xbd,0xdf,0xbd,0xff,0xfe,0x00,0x03,0xf6,0x87,0xf1,0xd9,0x3f,0x5f,0xa0, +0xff,0xff,0xfe,0x00,0x04,0x00,0x00,0x42,0x3f,0xc3,0xfd,0xff,0x02,0x80,0x40, +0x1e,0xfe,0x00,0x00,0x7f,0xfe,0xff,0x00,0x00,0x13,0x00,0x00,0xb8,0x80,0xfa, +0x14,0x83,0x76,0x44,0xf6,0x01,0xf7,0x12,0x33,0x2d,0xef,0x19,0x0f,0x59,0x00, +0x0f,0x00,0x03,0xb8,0xbf,0x39,0xff,0xfc,0x00,0x03,0x69,0xfd,0x3f,0xed,0x0d, +0xd3,0x80,0xfe,0xff,0x00,0x00,0x04,0x00,0x00,0x47,0x7f,0xc7,0xfd,0xff,0x06, +0xc0,0x02,0x00,0x00,0xc0,0x00,0x7f,0xfe,0xff,0x00,0x00,0x13,0x00,0x01,0x7f, +0xa0,0xb8,0x00,0x84,0x56,0x26,0x8d,0x94,0x40,0xc7,0x5f,0xa0,0x38,0x00,0x0d, +0x49,0x80,0x13,0x00,0x03,0x7f,0x9f,0x3b,0xff,0xf8,0x00,0x00,0x52,0x6a,0xbf, +0xf5,0x40,0x5f,0xc7,0xff,0xf3,0xff,0x00,0x04,0x00,0x00,0x80,0x7f,0xc7,0xfd, +0xff,0x06,0xe0,0x01,0x00,0x08,0xa0,0x00,0x7f,0xfe,0xff,0x00,0x80,0x13,0x00, +0x01,0xf5,0xa0,0xb8,0x26,0x04,0x37,0x01,0xeb,0xa0,0xc1,0xee,0xf1,0x90,0x88, +0xe6,0x66,0x26,0xc0,0x13,0x00,0x03,0xf5,0x9f,0x3b,0xff,0xf8,0x00,0x00,0x14, +0x5f,0x3e,0xe9,0xee,0x6f,0xf7,0xff,0xd9,0xff,0x80,0x04,0x00,0x00,0x0a,0x7f, +0xc7,0xfd,0xff,0x06,0xe0,0x00,0x00,0x10,0x00,0x00,0x7f,0xfe,0xff,0x00,0xc0, +0x13,0x00,0x01,0xfa,0x80,0xa8,0x00,0x00,0x08,0x11,0x43,0xb3,0x0b,0x2f,0x65, +0x17,0x45,0x20,0x03,0x9a,0x40,0x13,0x00,0x03,0xfa,0xbf,0x2b,0xff,0xf8,0x00, +0x10,0x3c,0x4c,0xf4,0xf0,0xba,0xef,0x7f,0xff,0xfc,0xff,0xc0,0x04,0x00,0x00, +0x05,0x7f,0xd7,0xfe,0xff,0x01,0xef,0xe0,0xfc,0x00,0xfd,0xff,0x00,0xe0,0x13, +0x00,0x01,0xf6,0x81,0xb8,0x25,0x0c,0x82,0x00,0x24,0xd4,0xda,0x00,0xb4,0x01, +0x12,0x14,0x0d,0x01,0x80,0x0d,0x00,0x03,0xf6,0xbe,0x3b,0xff,0xf0,0x80,0x00, +0x1b,0x3b,0x25,0xff,0x4b,0xfe,0xff,0x02,0xf2,0xff,0xe0,0x09,0x00,0x00,0x09, +0x7f,0xc7,0xff,0xff,0x7f,0xff,0xe0,0xfc,0x00,0xfd,0xff,0x00,0xe0,0x13,0x00, +0x01,0xf5,0xc1,0xbd,0x00,0x16,0xc8,0x60,0x65,0x2f,0xb7,0xf6,0x42,0x0a,0x9c, +0x88,0x47,0xcd,0x20,0x13,0x00,0x03,0xf5,0xbe,0x3f,0xff,0xe8,0xc8,0x60,0x1a, +0xd0,0x48,0x09,0xbd,0xfe,0xff,0xff,0xb8,0x7f,0xd0,0x09,0x00,0x00,0x0a,0x7f, +0xc3,0xff,0xff,0x37,0x9f,0xe0,0xfd,0x00,0x00,0x01,0xfd,0xff,0x00,0xf0,0x13, +0x00,0x01,0xcd,0xc1,0x3c,0x03,0x3b,0x75,0x68,0x22,0xcf,0xef,0x7f,0x94,0x06, +0x85,0x4d,0x26,0x08,0xf0,0x13,0x00,0x03,0xcd,0xbe,0x3f,0xfc,0xc0,0x75,0x60, +0x1d,0x30,0x10,0x80,0x6b,0xff,0x7f,0xff,0xd9,0x7f,0xd0,0x09,0x00,0x00,0x32, +0x7f,0xc3,0xff,0xff,0x8a,0x9f,0xe0,0xfd,0x00,0x00,0x01,0xfd,0xff,0x00,0xf0, +0x13,0x00,0x01,0xfa,0xd1,0xfe,0x0f,0x40,0xde,0x6d,0x65,0x4f,0xfe,0xed,0x78, +0x19,0xac,0xa2,0x0b,0xa1,0x30,0x13,0x00,0x03,0xfa,0xae,0x7d,0xf0,0x80,0x1e, +0x60,0x0a,0xb0,0x01,0x12,0x87,0xf8,0x7f,0xff,0xf0,0x3f,0xd8,0x09,0x00,0x00, +0x05,0x7f,0x83,0xff,0xff,0xe1,0x9f,0xf0,0xfd,0x00,0x00,0x07,0xfd,0xff,0x00, +0xf8,0x13,0x00,0x00,0x6f,0x00,0xfe,0x0e,0xe1,0x33,0xec,0x38,0x94,0xb7,0xfe, +0xe0,0x08,0x83,0x5b,0x1a,0xc4,0xd8,0x13,0x00,0x03,0xef,0x7f,0x7d,0xf1,0x01, +0x3f,0xe0,0x07,0x6b,0x48,0x01,0x1f,0xf8,0x7f,0xff,0xe0,0x3f,0xb8,0x09,0x00, +0x00,0x10,0xff,0x83,0xff,0xfe,0xc0,0x1f,0xf0,0xfd,0x00,0x00,0x07,0xfd,0xff, +0x00,0xf8,0x13,0x00,0x01,0x74,0x00,0x38,0x0f,0x8b,0x78,0xc7,0xe0,0x5a,0xbe, +0xb7,0x77,0xac,0x80,0xa1,0x53,0xcb,0x78,0x13,0x00,0x01,0xf4,0xff,0xbb,0xf0, +0x0b,0x77,0xc0,0x1f,0xa5,0x41,0x48,0x88,0xf8,0x7f,0xff,0xa0,0x37,0x98,0x09, +0x00,0x00,0x0b,0xff,0xc7,0xff,0xf4,0x80,0x3f,0xf0,0xfd,0x00,0x00,0x07,0xfd, +0xff,0x00,0xf8,0x13,0x00,0x01,0x6d,0x81,0x39,0x3e,0x1b,0xf5,0xc8,0x61,0x21, +0x6d,0xed,0xa6,0x7e,0xc0,0x5c,0x50,0x18,0x78,0x13,0x00,0x01,0xec,0x7e,0xba, +0xc0,0x1b,0xfa,0xc0,0x16,0xde,0x92,0x12,0x59,0xf8,0x3f,0xff,0xa0,0xb7,0x98, +0x09,0x00,0x00,0x13,0xff,0xc7,0xff,0xe4,0x00,0x3f,0xf8,0xfd,0x00,0x00,0x07, +0xfd,0xff,0x00,0xf8,0x13,0x00,0x00,0xf9,0xc5,0x99,0xfc,0x12,0xf8,0x80,0x34, +0x46,0xb4,0xb6,0xe0,0x07,0x71,0x00,0x30,0x6a,0x18,0x13,0x00,0x00,0xf8,0x3a, +0x1a,0x00,0x12,0xf7,0x80,0x0f,0xb9,0x4b,0x49,0x1f,0xc0,0x0e,0xff,0xc0,0x97, +0xf8,0x09,0x00,0x00,0x07,0xff,0xe7,0xff,0xed,0x00,0x7f,0xf8,0xfd,0x00,0x00, +0x3f,0xfd,0xff,0x00,0xf8,0x13,0x00,0x00,0xff,0x03,0x17,0xf0,0xab,0xc1,0x00, +0x30,0x00,0x4b,0x53,0x76,0xe3,0xf1,0xe0,0x70,0xab,0xd8,0x13,0x00,0x00,0xfc, +0xfc,0x18,0x00,0xab,0xe3,0x00,0x0b,0xff,0xb4,0xac,0x89,0x40,0x00,0x1f,0x80, +0x57,0x38,0x09,0x00,0x00,0x03,0xff,0xe7,0xff,0x54,0x00,0xff,0xfc,0xfd,0x00, +0x00,0x3f,0xfd,0xff,0x00,0xf8,0x13,0x00,0x01,0x85,0x03,0x5b,0x00,0x9d,0x00, +0x80,0x05,0x08,0x91,0x28,0x00,0x43,0x80,0x0d,0x00,0xa5,0x68,0x13,0x00,0x01, +0xfc,0xfc,0x1c,0x00,0x9d,0x02,0x80,0x19,0xf7,0x6e,0xd7,0xff,0xc0,0x60,0x00, +0x00,0x5b,0x38,0x09,0x00,0x0e,0x03,0xff,0xe7,0xff,0x62,0x01,0x7f,0xfe,0xfd, +0x00,0x00,0x3f,0xfd,0xff,0x00,0xf8,0x13,0x00,0x00,0x92,0x11,0x0e,0x02,0xcc, +0x03,0x10,0x1d,0x00,0x12,0x50,0x10,0xc1,0xa7,0xc0,0x28,0x02,0x28,0x13,0x00, +0x0f,0x11,0xec,0x18,0x02,0xcc,0x03,0x10,0x02,0xff,0xed,0xaf,0xef,0x80,0x47, +0xc0,0x28,0xdf,0x78,0x09,0x00,0x1f,0xef,0xff,0xe7,0xfd,0x32,0x00,0xef,0xff, +0xfd,0x00,0x05,0x7f,0xf8,0x3f,0xd7,0xff,0xf8,0x13,0x00,0x11,0xe0,0x2f,0x28, +0x3a,0x7e,0x00,0x94,0x15,0x80,0x00,0x80,0x01,0x83,0xf0,0x8c,0xc8,0x2c,0xb8, +0x13,0x00,0x0e,0x1f,0xd0,0x38,0x3a,0x7e,0x03,0x94,0x0a,0xff,0xff,0x7f,0xff, +0x80,0x00,0x8c,0xc8,0xd2,0x78,0x09,0x00,0x1f,0xff,0xff,0xc7,0xc5,0x80,0x00, +0x6b,0xff,0xfd,0x00,0x05,0x7f,0xff,0x73,0x37,0xff,0xf8,0x13,0x00,0x08,0x46, +0x65,0xc9,0xcf,0x7c,0x00,0xd0,0x1c,0x20,0x00,0x10,0x14,0x00,0x39,0x13,0x70, +0x32,0x88,0x13,0x00,0x1f,0xb9,0x9a,0x79,0xcf,0x7c,0x01,0xd0,0x03,0x7f,0xff, +0xef,0xfc,0x00,0x01,0x13,0x70,0xcc,0xf8,0x13,0x00,0x3f,0xff,0xff,0x86,0x30, +0x80,0x00,0x2f,0xff,0x80,0x00,0x00,0x03,0xff,0xfe,0xec,0x8f,0xff,0xf8,0xfe, +0x00,0x10,0x9b,0xd9,0xf7,0xf8,0x00,0x6c,0x1f,0x40,0x01,0x80,0xdc,0x00,0x0d, +0xdd,0xe8,0x28,0x58,0x13,0x00,0x1f,0xff,0x64,0x79,0xf7,0xf8,0x00,0xec,0x00, +0x7f,0xfe,0x7f,0xfc,0x00,0x01,0xdd,0xe8,0xd4,0xf8,0x13,0x00,0x3f,0xff,0xff, +0x86,0x08,0x00,0x00,0x13,0xff,0x80,0x00,0x00,0x03,0xff,0xfe,0x22,0x17,0xff, +0xf8,0x13,0x00,0x00,0xf9,0xcd,0x09,0xfd,0x00,0x00,0x40,0x37,0x78,0x00,0x01, +0x36,0x01,0x06,0x2f,0xd8,0x98,0xb0,0x09,0x00,0x1f,0x06,0x32,0xf9,0xff,0xf0, +0x00,0xc0,0x08,0xfe,0xff,0x06,0xf0,0x01,0x00,0x2f,0xd8,0x75,0xf0,0x04,0x00, +0x3f,0xff,0xff,0x86,0xfe,0x00,0x0b,0x3f,0xff,0x80,0x00,0x00,0x0f,0xfe,0xff, +0xd0,0x27,0xff,0xf8,0x13,0x00,0x00,0x25,0x87,0x0d,0xe0,0x00,0x00,0x75,0x10, +0x20,0x00,0x03,0x64,0x10,0xc5,0x7f,0xfc,0x01,0xb0,0x09,0x00,0x3f,0xda,0x78, +0xbd,0xfe,0x00,0x00,0xf5,0x0f,0xfe,0xff,0x06,0xf0,0x10,0xc2,0x7f,0xfc,0xfb, +0xf0,0x04,0x00,0x3f,0xff,0xff,0xc2,0xfe,0x00,0x0b,0x0a,0xff,0xc0,0x00,0x00, +0x0f,0xef,0x3f,0x80,0x03,0xff,0xf0,0x04,0x00,0x00,0x51,0x87,0x9f,0xfe,0x00, +0x0b,0x48,0x3c,0x88,0x00,0x12,0x58,0x00,0x00,0x0f,0x28,0x84,0x60,0x04,0x00, +0x3f,0x8e,0x78,0x6f,0xfe,0x00,0x0b,0xc8,0x03,0x6f,0xff,0xff,0xf0,0x00,0x00, +0x0f,0xf8,0xfb,0xf0,0x04,0x00,0x3f,0xff,0xff,0xc0,0xfe,0x00,0x0b,0x37,0xff, +0xf0,0x00,0x00,0x0f,0xff,0xff,0xf0,0x07,0xff,0xf0,0x04,0x00,0x00,0x08,0x0e, +0xec,0xfe,0x00,0x0b,0x40,0x3b,0xf6,0x8c,0x13,0xae,0x40,0x09,0xaf,0x1d,0x0b, +0x60,0x04,0x00,0x3f,0x87,0xf1,0x1c,0xfe,0x00,0x0b,0xc0,0x04,0x0b,0xff,0xff, +0xe0,0x00,0x08,0x2e,0xfc,0xf7,0xe0,0x04,0x00,0x3f,0x9f,0xff,0xe0,0xfe,0x00, +0x0b,0x3f,0xff,0xfc,0x00,0x00,0x1f,0xff,0xf7,0xd0,0x03,0xff,0xf0,0x04,0x00, +0x00,0x81,0x7e,0x48,0xfe,0x00,0x0b,0x70,0x33,0x19,0xe4,0x95,0xb0,0x40,0x40, +0x06,0x1d,0x3a,0xa0,0x04,0x00,0x3f,0x00,0x81,0xa8,0xfe,0x00,0x0b,0xf0,0x0c, +0xa5,0xff,0xfc,0x80,0x00,0x00,0x07,0xfd,0xe7,0xe0,0x04,0x00,0x3f,0x87,0xff, +0xf0,0xfe,0x00,0x0b,0x0f,0xff,0xfe,0x00,0x03,0x7f,0xff,0xff,0xf8,0x03,0xff, +0xe0,0x04,0x00,0x00,0x01,0x12,0x50,0xfe,0x00,0x0b,0x68,0x63,0xff,0xbc,0x11, +0x80,0x00,0xe0,0x5b,0x3d,0x35,0xe0,0x04,0x00,0x3f,0x00,0xed,0xa0,0xfe,0x00, +0x04,0xe8,0x1c,0x00,0xff,0xfc,0xfe,0x00,0x03,0x1b,0xfd,0xcf,0xc0,0x04,0x00, +0x3f,0x83,0xff,0xf0,0xfe,0x00,0x04,0x17,0xff,0xff,0x00,0x03,0xfe,0xff,0x03, +0xe4,0x03,0xff,0xe0,0x02,0x00,0x00,0x01,0xfc,0x00,0x0b,0x40,0xf3,0xc1,0x8a, +0x05,0x00,0x00,0x70,0x07,0xbd,0x0a,0x60,0x04,0x00,0x3f,0x00,0xff,0xf0,0xfe, +0x00,0x04,0xc0,0x0c,0x00,0x0f,0xfc,0xfe,0x00,0x03,0x07,0xfe,0xff,0xe0,0x04, +0x00,0x7f,0x83,0xff,0xf8,0xfe,0x00,0x04,0x3f,0xff,0xff,0xf0,0x03,0xfe,0xff, +0x03,0xf8,0x03,0xff,0xc0,0x01,0x00,0x40,0xfb,0x00,0x0b,0x73,0xf9,0xf8,0x01, +0x80,0x01,0x60,0x78,0x2f,0x3d,0x05,0xa0,0x04,0x00,0x3f,0x01,0xff,0xf8,0xfe, +0x00,0x0b,0xf0,0x06,0x00,0x03,0xb8,0x01,0x60,0x00,0x2f,0xfa,0xff,0xa0,0x04, +0x00,0x7f,0x83,0xff,0xf8,0xfe,0x00,0x0b,0x0f,0xff,0xff,0xfc,0x47,0xfe,0x9f, +0xff,0xd0,0x07,0xff,0xc0,0x03,0x00,0x01,0x81,0x04,0xfd,0x00,0x0b,0xe0,0x77, +0xe0,0x03,0x58,0x0a,0x80,0x21,0x2f,0x79,0x93,0xc0,0x04,0x00,0x7e,0x00,0xfb, +0xfc,0xfe,0x00,0x0b,0x60,0x08,0x00,0x03,0x58,0x0a,0x80,0x01,0x2f,0xfc,0x7f, +0x40,0x04,0x00,0x7f,0x81,0xff,0xfc,0xfe,0x00,0x0b,0x1f,0xff,0xff,0xfc,0xa7, +0xf5,0x7f,0xfe,0xd0,0x07,0xff,0xa0,0xfe,0x00,0x01,0x01,0x02,0xfe,0x00,0x0b, +0x68,0x35,0xfc,0x16,0xc1,0x54,0x00,0x01,0xf8,0x9a,0x0c,0xc0,0x13,0x00,0x7f, +0x01,0xfe,0xfc,0x00,0x00,0x01,0xe8,0x0a,0x00,0x16,0xc1,0x54,0x00,0x01,0xff, +0xf5,0xff,0xc0,0x04,0x00,0x7f,0x01,0xff,0xfe,0xfe,0x00,0x0b,0x17,0xff,0xff, +0xe9,0x3e,0xab,0xff,0xfe,0x00,0x0f,0xff,0x20,0x04,0x00,0x02,0x00,0x04,0x40, +0xfe,0x00,0x0b,0x94,0x73,0xe0,0x11,0x18,0xe4,0x00,0x05,0x38,0x02,0x10,0x00, +0x13,0x00,0xfd,0x01,0xf8,0x3f,0x80,0x00,0x03,0x54,0x0c,0x00,0x11,0x08,0xe4, +0x00,0x05,0xc7,0xe0,0x3d,0x00,0x13,0x00,0xff,0x01,0xff,0xff,0x80,0x00,0x00, +0x2b,0xff,0xff,0xee,0xf7,0x1b,0xff,0xfa,0x00,0x1f,0xfe,0xc0,0x13,0x00,0x80, +0x00,0x0c,0x50,0x00,0x00,0x05,0x30,0x26,0x79,0x04,0x08,0x00,0x00,0x0a,0x4f, +0x01,0x84,0x00,0x0b,0x00,0x7e,0x01,0xf0,0x2f,0x80,0x00,0x05,0xf0,0x19,0x80, +0x04,0xfe,0x00,0x04,0x0b,0xb0,0xe1,0xfb,0x80,0x0b,0x00,0xfe,0x01,0xfe,0x7f, +0x80,0x00,0x02,0x0f,0xff,0xff,0xfb,0xfe,0xff,0x04,0xf4,0x00,0x1e,0x7c,0xc0, +0x03,0x00,0x80,0x00,0x8c,0xfe,0x00,0x0c,0x08,0xbc,0x1b,0xff,0x00,0x0c,0x00, +0x00,0x93,0x42,0x64,0x84,0x00,0x09,0x00,0x7e,0x01,0xf0,0x1f,0xc0,0x00,0x08, +0x7c,0x04,0xfc,0x00,0x04,0x92,0xbd,0xa5,0xff,0x00,0x08,0x00,0xfe,0x01,0xfc, +0x3f,0xc0,0x00,0x07,0x03,0xfb,0xff,0x04,0x6c,0x00,0x1b,0xf9,0xc0,0x13,0x00, +0x88,0x00,0x04,0x01,0x00,0x00,0x76,0x93,0x1d,0xe9,0x10,0x1e,0x00,0x04,0x49, +0x21,0x84,0xdf,0x40,0x08,0x00,0x76,0x01,0xf8,0x0f,0xc0,0x00,0x66,0xf3,0xfc, +0x00,0x05,0x04,0x4a,0xde,0x43,0x2c,0x40,0x08,0x00,0xfe,0x01,0xfc,0x1f,0xc0, +0x00,0x19,0x0c,0xfc,0xff,0x05,0xfb,0xb4,0x00,0x3f,0xf3,0x80,0x13,0x00,0x0c, +0x00,0x0c,0x18,0x00,0x00,0x8d,0xbc,0x05,0xc8,0xb4,0x19,0x80,0x08,0x05,0x82, +0xc0,0xd8,0x00,0x08,0x01,0xf2,0x01,0xf0,0x17,0xc0,0x00,0x8d,0xfc,0xfe,0x00, +0x07,0x06,0x00,0x08,0x06,0x7d,0x46,0x1a,0x00,0x08,0x01,0xfe,0x01,0xfc,0x0f, +0xc0,0x00,0x72,0x03,0xfc,0xff,0x05,0xf7,0xf8,0x00,0x3f,0xe7,0x80,0xfe,0x00, +0x10,0x08,0x01,0x00,0x00,0x86,0xde,0x80,0x00,0x08,0x4f,0x08,0x54,0x8f,0x85, +0x07,0xf8,0x00,0x13,0x01,0xfc,0x01,0xf0,0x07,0xc0,0x00,0x86,0xfe,0x80,0x00, +0x00,0x40,0x00,0x54,0x8c,0x7a,0x88,0x3e,0x00,0x13,0x01,0xfc,0x01,0xfc,0x0f, +0xc0,0x00,0x79,0x01,0x7f,0xff,0xff,0xbf,0xff,0xab,0x70,0x00,0x7f,0xc7,0x80, +0x03,0x00,0x5c,0x00,0x08,0xfe,0x00,0x0c,0x57,0xfd,0x00,0x00,0x01,0x80,0x01, +0x08,0x9b,0x0a,0x3f,0x60,0x00,0x13,0x01,0xa0,0x01,0xf0,0x07,0xc0,0x01,0x47, +0xfd,0x00,0x00,0x01,0x80,0x01,0x08,0x9c,0xf5,0x00,0x6c,0x00,0x13,0x01,0xfc, +0x01,0xf8,0x0f,0xc0,0x00,0xb8,0x02,0xff,0xff,0xfe,0x7f,0xfe,0xf7,0x60,0x00, +0xff,0x9f,0x80,0x13,0x00,0x98,0x00,0x08,0x08,0x00,0x01,0x85,0xf7,0x40,0x02, +0xbf,0xc9,0x48,0xa0,0x57,0x95,0x01,0xf0,0x80,0x13,0x01,0xe4,0x01,0xf0,0x07, +0xc0,0x01,0x87,0xf7,0x40,0x02,0xbf,0xc9,0x48,0xa0,0x50,0x6b,0x01,0xe8,0x80, +0x13,0x01,0xfc,0x01,0xf8,0x0f,0xc0,0x00,0x78,0x08,0xbf,0xfd,0x40,0x36,0xb7, +0x5f,0xa8,0x00,0xfe,0x1f,0x00,0x13,0x00,0x18,0x00,0x08,0x08,0x00,0x01,0xe3, +0xf0,0x00,0x12,0x4b,0x1f,0x54,0x40,0xc7,0x78,0x0f,0xef,0x00,0x13,0x01,0xe0, +0x01,0xf0,0x07,0xc0,0x01,0xe3,0xf0,0x00,0x12,0x4b,0x1f,0x54,0x40,0xc8,0x84, +0x0f,0xf7,0x80,0x13,0x01,0xf8,0x01,0xf8,0x0f,0xc0,0x00,0x1c,0x0f,0xff,0xed, +0xb4,0xe0,0xab,0xbf,0x30,0x03,0xf0,0x38,0x00,0x13,0x03,0x08,0x00,0x00,0x01, +0x00,0x00,0x23,0x92,0x00,0x04,0xb5,0x80,0x2a,0x00,0x7b,0xc3,0xa1,0xe8,0x00, +0x13,0x01,0xf0,0x03,0xf0,0x0f,0xc0,0x02,0x63,0xf2,0x00,0x04,0xb5,0x80,0x2a, +0x00,0x74,0x38,0x3f,0x4f,0x00,0x13,0x03,0xf8,0x03,0xf8,0x0f,0xc0,0x01,0x9c, +0x0d,0xff,0xfb,0x4a,0x7f,0xd5,0xff,0x80,0x07,0xc0,0xf0,0x00,0x03,0x00,0x00, +0x02,0x10,0xfe,0x00,0x0c,0xf1,0xd8,0x20,0x28,0x92,0x80,0x11,0x25,0x5e,0xfd, +0xe6,0x0b,0x00,0x13,0x03,0xf0,0x01,0xe0,0x0f,0xc0,0x02,0xf1,0xf8,0x20,0x28, +0x92,0x80,0x11,0x25,0x51,0x09,0xfd,0xb7,0x00,0x13,0x03,0xf8,0x03,0xf8,0x0f, +0xc0,0x01,0x0e,0x07,0xdf,0xd7,0x6d,0x7f,0xee,0xda,0xa0,0x06,0x03,0xc0,0x00, +0x00,0x02,0xfb,0x00,0x0c,0x71,0xd9,0x00,0x00,0xae,0x91,0x00,0x08,0xaf,0xc1, +0xd0,0x86,0x00,0x13,0x03,0xf8,0x03,0xf0,0x0f,0xc0,0x00,0x71,0xf9,0x00,0x00, +0xae,0x91,0x00,0x08,0xb0,0x3f,0xce,0xff,0x00,0x13,0x03,0xf8,0x03,0xf0,0x0f, +0xc0,0x03,0x8e,0x06,0xff,0xff,0x51,0x6e,0xff,0xf7,0x40,0x00,0x3f,0x00,0x00, +0xfe,0x00,0x10,0x10,0x00,0x00,0x02,0x7c,0x5c,0x00,0x04,0xc3,0x80,0x91,0x41, +0xee,0xd8,0x62,0x1a,0x00,0x13,0x03,0xfe,0x03,0xe0,0x0f,0xc0,0x02,0x7c,0x7c, +0x00,0x04,0xc3,0x80,0x91,0x41,0xf1,0x39,0xdb,0xea,0x00,0x13,0x03,0xfe,0x03, +0xf0,0x0f,0xc0,0x01,0x83,0x83,0xff,0xfb,0x3c,0x7f,0x6e,0xbe,0x00,0x07,0xfc, +0x04,0x00,0x13,0x05,0x10,0x00,0x10,0x00,0x00,0x06,0x3d,0x4c,0x00,0x12,0x7b, +0x08,0x00,0x2a,0xff,0x54,0xa8,0x54,0x00,0x13,0x03,0xe0,0x03,0xe0,0x0f,0xc0, +0x06,0x3d,0x7c,0x00,0x12,0x7b,0x08,0x00,0x2a,0xe0,0xc8,0x0f,0xb4,0x00,0x13, +0x07,0xfc,0x03,0xf0,0x0f,0xc0,0x01,0xc2,0x83,0xff,0xed,0x84,0xf7,0xff,0xd5, +0x00,0x3f,0xf0,0x0a,0x00,0x02,0x00,0x40,0x02,0xfe,0x00,0x0d,0x06,0x3c,0x4e, +0x02,0x09,0x13,0x24,0x2a,0x45,0x4b,0x82,0xa0,0x3c,0x00,0x13,0x07,0x80,0x03, +0xf0,0x0f,0xc0,0x06,0x3c,0x7e,0x00,0x09,0x13,0x24,0x2a,0x45,0x74,0x00,0xbf, +0xec,0x00,0x13,0x07,0xe0,0x03,0xf0,0x0f,0xc0,0x01,0xc3,0x81,0xff,0xf6,0xec, +0xdb,0xd5,0xba,0x80,0x7f,0x40,0x10,0x00,0x13,0x02,0x00,0x02,0x30,0x08,0x80, +0x05,0x9f,0xb7,0x6e,0x62,0xfb,0x29,0x10,0x9b,0xce,0x81,0x80,0x70,0x00,0x13, +0x07,0x00,0x03,0xc0,0x07,0x40,0x07,0x9f,0xaf,0x08,0x62,0xfb,0x29,0x10,0x9b, +0xf1,0x81,0xff,0xd8,0x00,0x13,0x07,0x80,0x03,0xf0,0x0f,0xc0,0x00,0x60,0x40, +0xf7,0x9d,0x04,0xd6,0xef,0x64,0x00,0x7e,0x00,0x20,0x00,0xfe,0x00,0x10,0x30, +0x08,0x00,0x05,0x4f,0x63,0x45,0x88,0x9f,0x4a,0x45,0x54,0xff,0xf8,0x20,0x30, +0x00,0x13,0x06,0x00,0x03,0xc0,0x07,0xc0,0x0f,0x4f,0x7f,0x32,0x08,0x9f,0x4a, +0x45,0x54,0xc0,0xff,0xdf,0x30,0x00,0x0e,0x0f,0x00,0x03,0xf0,0x0f,0xc0,0x00, +0xb0,0x80,0xff,0xf7,0x60,0xb5,0xba,0xab,0xfe,0x00,0x01,0xc8,0x00,0x13,0x02, +0x00,0x04,0x00,0x08,0x40,0x0a,0xe6,0xa0,0xa4,0x6e,0xdb,0x2a,0xb2,0xaf,0xbf, +0xe0,0x03,0x20,0x00,0x13,0x02,0x00,0x03,0xe0,0x07,0x80,0x0b,0xe6,0xbe,0x1b, +0xae,0xdb,0x2a,0xb2,0xaf,0xc0,0x1f,0xfe,0x30,0x00,0x13,0x04,0x00,0x07,0xf0, +0x0f,0xc0,0x04,0x19,0x41,0xff,0xd1,0x24,0xd5,0x4d,0x50,0x00,0x00,0x01,0xc0, +0x00,0x13,0x00,0x00,0x04,0x00,0x08,0x00,0x0a,0xd8,0x40,0x08,0x37,0xff,0x77, +0x5f,0x71,0xf5,0x42,0x39,0x60,0x00,0x13,0x00,0x00,0x03,0xe0,0x07,0xc0,0x0b, +0xd8,0x5e,0x37,0xf7,0xff,0x77,0x5f,0x71,0x8a,0xbd,0xda,0x60,0x00,0x13,0x00, +0x00,0x07,0xe0,0x0f,0xc0,0x04,0x27,0xa1,0xff,0xc8,0x00,0x88,0xa0,0x8e,0x00, +0x00,0x07,0x80,0x00,0x13,0x00,0x00,0x84,0x00,0x08,0x00,0x08,0xf4,0x38,0x08, +0xff,0xfe,0x7e,0xed,0x98,0x7f,0xb0,0x2d,0x40,0x00,0x13,0x00,0x00,0x47,0xe0, +0x07,0xc0,0x09,0xf4,0x36,0x77,0x3f,0xfe,0x7e,0xed,0x98,0x80,0x4f,0xe0,0x40, +0x00,0x13,0x00,0x01,0xe7,0xe0,0x0f,0xc0,0x06,0x0b,0xc1,0xff,0xc0,0x01,0x81, +0x12,0x67,0x00,0x00,0x1f,0x80,0x00,0x13,0x00,0x01,0x44,0x00,0x08,0x80,0x09, +0x6e,0x04,0x1f,0x8f,0x44,0x3f,0xfe,0xf1,0x7b,0x4e,0x03,0x80,0x00,0x13,0x00, +0x00,0xb3,0xe0,0x07,0x40,0x09,0xee,0x0a,0x60,0x2f,0xfc,0x3f,0xfe,0xf1,0x84, +0xb1,0x01,0x80,0x00,0x13,0x00,0x01,0xf7,0xe0,0x0f,0xc0,0x06,0x11,0xf1,0xff, +0xf0,0x03,0xc0,0x01,0x0e,0x00,0x00,0xfe,0x00,0x00,0x13,0x00,0x00,0x48,0x20, +0x08,0x00,0x0d,0xff,0x08,0xfe,0xd8,0x98,0x1f,0xff,0xfc,0xff,0xe4,0x43,0x00, +0x00,0x13,0x00,0x00,0x37,0xc0,0x07,0xc0,0x0d,0xff,0x0e,0x00,0x2f,0xf8,0x1f, +0xff,0xff,0x00,0x1b,0xc3,0x00,0x00,0x0c,0x00,0x00,0xff,0xe0,0x0f,0xc0,0x02, +0x00,0xf1,0xff,0xf0,0x07,0xe0,0xfd,0x00,0x02,0x3c,0x00,0x00,0xfd,0x00,0x0f, +0x01,0x00,0x0c,0x7f,0x86,0xff,0xb4,0x10,0x2e,0xfb,0xd0,0xed,0x5b,0x0e,0x00, +0x00,0x13,0x00,0x00,0x7f,0xc0,0x06,0xc0,0x0c,0x7f,0x87,0x00,0x43,0xf0,0x2f, +0xff,0xff,0x12,0xa7,0x0e,0x00,0x00,0x0c,0x00,0x00,0xff,0xe0,0x0f,0xc0,0x03, +0x80,0x79,0xff,0xf8,0x0f,0xd0,0xfd,0x00,0x02,0xf0,0x00,0x00,0x13,0x00,0x00, +0x43,0x80,0x00,0x00,0x03,0x7f,0x41,0x11,0x5c,0xf7,0x16,0x00,0x08,0x7f,0xb6, +0x30,0x00,0x00,0x13,0x00,0x00,0x3c,0x40,0x07,0xc0,0x1f,0x7f,0x40,0xae,0x27, +0xf7,0x17,0xff,0xf7,0x80,0x4e,0x3c,0x00,0x00,0x0c,0x00,0x00,0x7f,0xe0,0x0f, +0xc0,0x00,0x80,0xbf,0xff,0xf8,0x08,0xe8,0xfe,0x00,0x03,0x01,0xc0,0x00,0x00, +0x13,0x00,0x00,0x2a,0x40,0x01,0x80,0x02,0x2f,0xc0,0x10,0x02,0x9f,0xa2,0xa0, +0x80,0xfd,0xc6,0x60,0x00,0x00,0x13,0x00,0x00,0x1d,0x80,0x06,0x40,0x1e,0x2f, +0xc0,0xaf,0x72,0x9f,0xa2,0xdf,0x7f,0x02,0x3f,0xd0,0x00,0x00,0x0c,0x00,0x00, +0x7f,0xe0,0x0f,0xc0,0x01,0xd0,0x3f,0xff,0xfd,0x60,0x5d,0xfa,0x00,0x13,0x00, +0x00,0x20,0xc0,0x0c,0x00,0x02,0xcb,0xf0,0x30,0x59,0x6f,0x49,0x76,0x24,0xff, +0x73,0xc0,0x00,0x00,0x13,0x00,0x00,0x1f,0x20,0x0b,0xc0,0x1e,0xcb,0xf0,0x8e, +0x21,0x6f,0x49,0x79,0xdb,0x00,0x8c,0x30,0x00,0x00,0x0d,0x00,0x00,0x3f,0xf8, +0x07,0xc0,0x01,0x34,0x0f,0xff,0xfe,0x90,0xb6,0x80,0xfb,0x00,0x10,0x00,0x00, +0x24,0x70,0x48,0x00,0x1b,0xb7,0xec,0x84,0x10,0x1a,0x84,0x04,0x10,0xeb,0x6c, +0xfe,0x00,0x13,0x00,0x00,0x1f,0x80,0x37,0xc0,0x1f,0xb7,0xe4,0x00,0x60,0x1a, +0x84,0x07,0xef,0x14,0x93,0xe0,0x00,0x00,0x0d,0x00,0x00,0x3f,0xfc,0x7f,0xc0, +0x00,0x48,0x1b,0xff,0xff,0xe5,0x7b,0xf8,0xfb,0x00,0xfe,0x00,0x0d,0xbc,0x00, +0x80,0x0d,0x61,0xe3,0x20,0x22,0x08,0x21,0xdf,0x80,0xf6,0x6a,0xfe,0x00,0x13, +0x00,0x00,0x1f,0x40,0x1f,0x40,0x1f,0x61,0xe7,0x20,0x42,0x08,0x01,0xdf,0xff, +0x09,0x95,0xe0,0x00,0x00,0x0d,0x00,0x00,0x1f,0xff,0x3f,0xc0,0x00,0x9e,0x18, +0xdf,0xfd,0xf7,0xfe,0x20,0xfb,0x00,0x13,0x00,0x00,0x04,0x3f,0x31,0x00,0x01, +0xe4,0xd7,0xbc,0xa6,0x36,0x00,0x1b,0x38,0xb5,0xd8,0x60,0x00,0x00,0x13,0x00, +0x00,0x0f,0xc0,0x0e,0xc0,0x13,0xe4,0xf7,0xbc,0x46,0x36,0x00,0x1b,0x37,0x4e, +0x5f,0xe0,0x00,0x00,0x10,0x00,0x00,0x1f,0xff,0x3f,0xc0,0x0c,0x1b,0x08,0x43, +0xf9,0xc9,0xff,0xe4,0xc0,0x00,0x20,0xfe,0x00,0xfe,0x00,0x10,0x60,0x31,0x00, +0x03,0xf9,0xff,0xca,0xf2,0x5c,0x80,0x06,0xf3,0xe5,0x84,0x20,0x00,0x00,0x13, +0x00,0x00,0x0f,0x80,0x2e,0xc0,0x3b,0xf9,0xff,0x85,0x0a,0x5c,0x80,0x06,0xfe, +0x10,0x07,0xc0,0x00,0x00,0x10,0x00,0x00,0x1f,0xfc,0x1f,0xc0,0x04,0x06,0x00, +0x7f,0xfd,0xa3,0x7f,0xf9,0x00,0x0f,0xf8,0xfe,0x00,0xfe,0x00,0x0d,0x60,0x08, +0x80,0x07,0xf9,0x3c,0x08,0x00,0xfe,0x90,0x9c,0xc1,0xe1,0xf6,0xfe,0x00,0x13, +0x00,0x00,0x0f,0x80,0x07,0x40,0x3f,0xf9,0x3c,0xf7,0xf8,0xfe,0x90,0x9c,0xfe, +0x1f,0xf9,0xe0,0x00,0x00,0x0d,0x00,0x00,0x1f,0xe0,0x1f,0xc0,0x00,0x06,0xc3, +0xff,0xff,0x01,0x6f,0x63,0xfb,0x00,0xfd,0x00,0x0c,0x04,0x00,0x06,0x7b,0x9a, +0x4c,0xbe,0xcf,0xe1,0x70,0xe3,0xbb,0xb0,0xfe,0x00,0x13,0x00,0x00,0x0f,0x80, +0x03,0xc0,0x3e,0x7b,0x99,0xb3,0x40,0xff,0xe1,0x70,0xfc,0x44,0x4f,0xc0,0x00, +0x00,0x0d,0x00,0x00,0x1f,0xc0,0x0f,0xc0,0x01,0x84,0x67,0xff,0xff,0x00,0x1e, +0x8f,0xfb,0x00,0x13,0x00,0x00,0x01,0x80,0x04,0x00,0x27,0x87,0x6f,0xd9,0x97, +0xce,0xc3,0xfd,0xe3,0xdd,0x60,0x80,0x00,0x00,0x13,0x00,0x00,0x0f,0x00,0x03, +0xc0,0x7f,0x9e,0x60,0x26,0x68,0x7e,0xc1,0xfd,0xfc,0x22,0x9f,0x40,0x00,0x00, +0x0d,0x00,0x00,0x0f,0x80,0x07,0xc0,0x00,0x61,0x9f,0xff,0xff,0x81,0x3e,0x02, +0xfb,0x00,0xfd,0x00,0x0f,0x02,0x00,0x53,0xd5,0x8d,0x7e,0x2d,0xbf,0x27,0x7a, +0xc7,0xbb,0x89,0x40,0x00,0x00,0x13,0x00,0x00,0x0f,0x00,0x01,0xc0,0x5f,0xdf, +0x80,0x81,0xd2,0x3f,0x19,0xfa,0xf8,0x44,0x76,0xc0,0x00,0x00,0x0d,0x00,0x00, +0x0f,0x00,0x07,0xc0,0x20,0x20,0x7f,0xff,0xff,0xc0,0xfe,0x05,0xfb,0x00,0xfd, +0x00,0x0c,0x02,0x40,0x3b,0xee,0xd3,0x7f,0xa2,0xcf,0xfc,0x1c,0x07,0xf4,0xa4, +0xfe,0x00,0x13,0x00,0x00,0x0f,0x00,0x01,0x80,0x3f,0xea,0xc0,0x80,0x5d,0x00, +0x02,0xff,0xf8,0x0b,0x5b,0xc0,0x00,0x00,0x08,0x00,0x00,0x0f,0x00,0x03,0xc0, +0x40,0x11,0x3f,0xfd,0xff,0xfa,0x00,0xfd,0x00,0x0f,0x01,0x00,0x9f,0xfe,0x85, +0xe5,0x30,0xdd,0x7e,0x38,0x45,0xb7,0x11,0x80,0x00,0x00,0x13,0x00,0x00,0x06, +0x00,0x00,0xc0,0x9f,0xf8,0x02,0x1a,0xcf,0x00,0x00,0xff,0xfa,0x48,0xee,0x80, +0x00,0x00,0x07,0x00,0x00,0x06,0x00,0x01,0xc0,0x60,0x07,0xfc,0xff,0xfa,0x00, +0xfd,0x00,0x0f,0x01,0x00,0xed,0x76,0x0f,0xda,0xfc,0x6e,0xf4,0xe0,0x47,0x9a, +0xc5,0x80,0x00,0x00,0xfc,0x00,0x0e,0xc0,0x8f,0xf0,0x00,0x25,0x03,0x90,0x0d, +0xff,0xf8,0x65,0x3a,0x80,0x00,0x00,0xfd,0x00,0x03,0x01,0xc0,0x70,0x0f,0xfd, +0xff,0x00,0xfb,0xfa,0x00,0xfd,0x00,0x0c,0x01,0x40,0x05,0x3c,0x0f,0x44,0x46, +0xde,0x43,0xf0,0x87,0xb7,0x40,0xfe,0x00,0xfc,0x00,0x0e,0x80,0x07,0xf0,0x00, +0xbb,0xb9,0x20,0x34,0xff,0xf8,0x48,0xbf,0x80,0x00,0x00,0xfd,0x00,0x03,0x01, +0xc0,0xf8,0x0f,0xfd,0xff,0x00,0xfb,0xfa,0x00,0xfd,0x00,0x0c,0x01,0x00,0x05, +0x0c,0x2f,0xeb,0x4e,0x9a,0x0d,0x67,0xed,0xfb,0x04,0xfe,0x00,0xfc,0x00,0x0b, +0x80,0x07,0xe0,0x00,0x14,0xb1,0x64,0x3c,0x7f,0xf2,0x04,0xfb,0xfe,0x00,0xfd, +0x00,0x03,0x01,0x80,0xf8,0x1f,0xfd,0xff,0x01,0xf3,0x80,0xfb,0x00,0xfb,0x00, +0x0a,0x09,0x0e,0x7f,0xf5,0xa1,0x12,0x16,0x40,0x5f,0xd4,0x12,0xfe,0x00,0xfb, +0x00,0x0a,0x01,0xe0,0x00,0x0a,0x5e,0xec,0x2c,0xff,0xe0,0x2b,0xed,0xfe,0x00, +0xfb,0x00,0x01,0xfe,0x1f,0xfd,0xff,0x00,0xf3,0xfa,0x00,0xfc,0x00,0x0b,0x01, +0x03,0xef,0xfd,0xfd,0x43,0x1c,0x92,0x00,0x5f,0xea,0x40,0xfe,0x00,0xfc,0x00, +0x0b,0x01,0x03,0xe0,0x00,0x02,0xbc,0xe8,0xa8,0xff,0xe0,0x15,0xbf,0xfe,0x00, +0xfb,0x00,0x01,0xfc,0x1f,0xfd,0xff,0x00,0x77,0xfa,0x00,0xfc,0x00,0x0b,0x01, +0x05,0x13,0xfd,0xfa,0x6f,0x10,0xbd,0x0c,0x9f,0x64,0x08,0xfe,0x00,0xfc,0x00, +0x0b,0x01,0x05,0x00,0x00,0x05,0x90,0xeb,0x19,0xff,0xe0,0x9b,0xf6,0xfe,0x00, +0xfb,0x00,0x00,0xfa,0xfc,0xff,0x00,0xe6,0xfa,0x00,0xfb,0x00,0x0a,0x21,0x0f, +0xfc,0xf2,0x50,0x9d,0x36,0x20,0xfb,0xd0,0xa0,0xfe,0x00,0xfc,0x00,0x0b,0x02, +0x21,0x00,0x00,0x0d,0xaf,0x62,0x33,0xff,0xe4,0x2f,0x5e,0xfe,0x00,0xfc,0x00, +0x01,0x01,0xde,0xfc,0xff,0x00,0xcc,0xfa,0x00,0xfc,0x00,0x0a,0x03,0x01,0xbf, +0xff,0xf5,0x7b,0x29,0x18,0x01,0xff,0xb4,0xfd,0x00,0xfc,0x00,0x0b,0x03,0x01, +0x80,0x00,0x0a,0x84,0xc6,0x33,0xff,0xe0,0x4b,0xfe,0xfe,0x00,0xfb,0x00,0x01, +0xfe,0x7f,0xfd,0xff,0x00,0xcc,0xfa,0x00,0xfb,0x00,0x09,0x81,0x57,0x3f,0xf3, +0xf8,0x0c,0x59,0x41,0xef,0xc0,0xfd,0x00,0xfb,0x00,0x0a,0x81,0x00,0x00,0x0c, +0x07,0xc0,0x7f,0xff,0xf0,0xff,0xfc,0xfe,0x00,0xfc,0x00,0x01,0x03,0x7e,0xfc, +0xff,0x00,0x80,0xfa,0x00,0xfc,0x00,0x0b,0x01,0x11,0x1f,0x1f,0xec,0xf8,0x64, +0xd6,0x03,0x4e,0x8c,0x40,0xfe,0x00,0xfc,0x00,0x0b,0x01,0x01,0x00,0x00,0x13, +0x07,0xa8,0xff,0xff,0xd1,0x8f,0xbc,0xfe,0x00,0xfc,0x00,0x01,0x02,0xfe,0xfd, +0xff,0x04,0xdf,0x00,0x00,0x20,0x70,0xfd,0x00,0xfa,0x00,0x09,0xb6,0x59,0x4f, +0xfc,0x14,0xe0,0x03,0x8c,0xc1,0x10,0xfe,0x00,0xfa,0x00,0x09,0x88,0x06,0xb0, +0x03,0x88,0xff,0xff,0x93,0xc1,0xfc,0xfe,0x00,0xfc,0x00,0x02,0x03,0xff,0x7f, +0xfd,0xff,0x03,0x00,0x00,0x60,0x3e,0xfd,0x00,0xfc,0x00,0x0b,0x01,0x40,0x7c, +0x9e,0x7f,0x78,0x04,0x44,0x06,0x5f,0x80,0x40,0xfe,0x00,0xfc,0x00,0x0b,0x03, +0x40,0x40,0x01,0x80,0x83,0x18,0x7f,0xff,0x41,0x80,0x7c,0xfe,0x00,0xfb,0x00, +0x01,0xbf,0xbf,0xfd,0xff,0x04,0x80,0x00,0xa0,0x7f,0x80,0xfe,0x00,0xfc,0x00, +0x0b,0x01,0x06,0x1e,0x2e,0x2f,0x79,0x1c,0x00,0x08,0x1d,0x84,0xa0,0xfe,0x00, +0xfc,0x00,0x0b,0x03,0x06,0xc0,0x01,0xd0,0x82,0x20,0x7f,0xfe,0x03,0x80,0x38, +0xfe,0x00,0xfb,0x00,0x01,0xf9,0xbf,0xfd,0xff,0x04,0x80,0x01,0xe0,0x7f,0xc0, +0xfe,0x00,0xfc,0x00,0x0b,0x04,0x82,0xac,0x5e,0xff,0xf1,0x56,0x00,0x04,0x5f, +0x06,0x18,0xfe,0x00,0xfc,0x00,0x0b,0x07,0x82,0x60,0x01,0x00,0x02,0x20,0x7f, +0xfc,0x41,0x00,0x10,0xfe,0x00,0xfb,0x00,0x01,0x7d,0x9f,0xfd,0xff,0x04,0x80, +0x03,0xa0,0xff,0xe0,0xfe,0x00,0xfc,0x00,0x0b,0x09,0x43,0x44,0x2f,0x5a,0xe3, +0xf1,0x40,0x12,0x5f,0x84,0xa0,0xfe,0x00,0xfc,0x00,0x0b,0x09,0xc3,0x60,0x00, +0xa5,0x00,0x01,0x7f,0xf4,0x41,0x80,0x08,0xfe,0x00,0xfc,0x00,0x02,0x06,0x3c, +0x9f,0xfe,0xff,0x05,0xfe,0x80,0x0f,0xa0,0x7f,0xf0,0xfe,0x00,0xfc,0x00,0x0b, +0x04,0x70,0x04,0x3f,0x7e,0xfd,0xc3,0x01,0xdc,0x9d,0xd0,0x80,0xfe,0x00,0xfc, +0x00,0x0a,0x04,0x71,0x30,0x00,0x81,0x0a,0x23,0x3f,0xc0,0x83,0xc0,0xfd,0x00, +0xfc,0x00,0x0b,0x0b,0x8e,0xcf,0xff,0xff,0xf7,0xfc,0xc0,0x3f,0x60,0x3f,0xf8, +0xfe,0x00,0xfb,0x00,0x0a,0x33,0x85,0x07,0x7b,0x67,0xe8,0xc1,0xbc,0xdf,0x8c, +0xe8,0xfe,0x00,0xfb,0x00,0x0a,0x33,0x81,0x00,0x84,0x80,0x00,0x7f,0x40,0xc1, +0x80,0x08,0xfe,0x00,0xfc,0x00,0x02,0x0f,0xcc,0x7e,0xfd,0xff,0x04,0x80,0xff, +0x20,0x7f,0xf0,0xfe,0x00,0xfc,0x00,0x0b,0x04,0x3d,0x04,0x1d,0xf3,0xc7,0xe0, +0x70,0x0b,0x5a,0xff,0x50,0xfe,0x00,0xfc,0x00,0x0b,0x04,0x1d,0x00,0x02,0x0c, +0x00,0x00,0x41,0xf3,0x45,0xc0,0x90,0xfe,0x00,0xfc,0x00,0x01,0x0b,0xe2,0xfc, +0xff,0x04,0xbf,0xfc,0xa0,0x3f,0xe8,0xfe,0x00,0xfb,0x00,0x0a,0x27,0xe0,0x87, +0x7f,0xc6,0xe1,0x00,0x61,0xcd,0xbc,0xc0,0xfe,0x00,0xfb,0x00,0x09,0x17,0xe0, +0x80,0x80,0x01,0x00,0x00,0x81,0xd3,0x83,0xfd,0x00,0xfc,0x00,0x03,0x1f,0xf8, +0x1f,0x7f,0xfd,0xff,0x03,0xfe,0x20,0x7f,0xf8,0xfe,0x00,0xfb,0x00,0x0a,0x8b, +0x82,0x8a,0xfe,0x85,0xe7,0x41,0x47,0xfd,0xb8,0x98,0xfe,0x00,0xfb,0x00,0x0a, +0x03,0x80,0x81,0x01,0x02,0x00,0x40,0x87,0xe3,0x87,0x18,0xfe,0x00,0xfc,0x00, +0x03,0x1f,0xfc,0x7f,0x7f,0xfe,0xff,0x04,0xbf,0xf8,0x00,0x7f,0xe0,0xfe,0x00, +0xfb,0x00,0x0a,0x82,0xaa,0xce,0xff,0x0f,0xef,0x84,0x1f,0xb7,0xe0,0x90,0xfe, +0x00,0xfb,0x00,0x02,0x44,0xe8,0xc1,0xfe,0x00,0x04,0x84,0x1f,0xa9,0xdf,0x10, +0xfe,0x00,0xfc,0x00,0x03,0x1f,0xff,0x17,0x3f,0xfe,0xff,0x04,0x7b,0xe0,0x40, +0x3f,0xe8,0xfe,0x00,0xfc,0x00,0x0b,0x11,0xf2,0x68,0x4f,0xfe,0x13,0xcf,0x88, +0x29,0x1f,0x21,0x08,0xfe,0x00,0xfc,0x00,0x0b,0x10,0x01,0x68,0x40,0x00,0x0c, +0x00,0x88,0x28,0xc1,0x1e,0x08,0xfe,0x00,0xfc,0x00,0x03,0x2f,0xff,0x97,0xbf, +0xfe,0xff,0x04,0x77,0xd7,0xe0,0xff,0xf0,0xfe,0x00,0xfc,0x00,0x0b,0x20,0x91, +0xf0,0x64,0x9c,0x16,0x92,0x4c,0x84,0x1a,0xe1,0x28,0xfe,0x00,0xfc,0x00,0x0b, +0x20,0x60,0x30,0x63,0x60,0x09,0x0c,0x4c,0x83,0x05,0xde,0x28,0xfe,0x00,0xfc, +0x00,0x03,0x1f,0xff,0xcf,0x9f,0xfe,0xff,0x04,0xb3,0x7f,0xe0,0x3f,0xd0,0xfe, +0x00,0xfc,0x00,0x0b,0x01,0xc8,0x31,0xaf,0x78,0x6d,0x9e,0x84,0x87,0x6c,0x83, +0x98,0xfe,0x00,0xfb,0x00,0x0a,0x30,0x71,0x60,0x80,0x12,0x00,0x84,0x08,0x13, +0x9c,0x08,0xfe,0x00,0xfc,0x00,0x03,0x3f,0xff,0xce,0xdf,0xfe,0xff,0x04,0x7b, +0xff,0xe0,0x7f,0xf0,0xfe,0x00,0xfc,0x00,0x0b,0x41,0xc4,0x6c,0xc7,0x3c,0xef, +0x11,0x8b,0x2c,0x8e,0x62,0x98,0xfe,0x00,0xfc,0x00,0x0b,0x40,0x38,0x2c,0x00, +0xc0,0x10,0x09,0x88,0x10,0x11,0x5d,0x08,0xfe,0x00,0xfc,0x00,0x02,0x3f,0xff, +0xd3,0xfe,0xff,0x05,0xfe,0x77,0xff,0xe0,0xbf,0xf0,0xfe,0x00,0xfc,0x00,0x0b, +0x43,0x82,0x50,0x16,0xec,0x7f,0x2c,0x82,0x4c,0xd7,0x80,0x98,0xfe,0x00,0xfc, +0x00,0x0b,0x40,0x7c,0x50,0x11,0x11,0x80,0x10,0x81,0x30,0x19,0x9f,0x08,0xfe, +0x00,0xfc,0x00,0x03,0x3f,0xff,0xaf,0xef,0xfe,0xff,0x04,0x7f,0xff,0xe0,0x7f, +0xf0,0xfe,0x00,0xfc,0x00,0x0a,0x03,0x0f,0x24,0x1e,0xe9,0x98,0x19,0x05,0x9f, +0xea,0xa0,0xfd,0x00,0xfb,0x00,0x0a,0xf0,0x24,0x11,0x10,0x00,0x21,0x00,0x60, +0x05,0x9f,0x90,0xfe,0x00,0xfc,0x00,0x0b,0x7f,0xff,0xdb,0xef,0xff,0xff,0xfe, +0xff,0xff,0xf0,0x7f,0xf8,0xfe,0x00,0xfc,0x00,0x0b,0x02,0x07,0x20,0x9f,0xa3, +0xba,0x9a,0xa7,0x03,0xcc,0xa0,0xd0,0xfe,0x00,0xfc,0x00,0x0a,0x01,0xf8,0x20, +0x90,0x50,0x00,0x22,0xa0,0xfc,0x03,0x9f,0xfd,0x00,0xfc,0x00,0x0b,0x7f,0xff, +0xdf,0x6f,0xff,0xff,0xfd,0x5f,0xff,0xf0,0x7f,0xf8,0xfe,0x00,0xfc,0x00,0x0b, +0x83,0x61,0x9a,0x45,0xd9,0x73,0x46,0x46,0x1f,0xdc,0xe0,0xc0,0xfe,0x00,0xfc, +0x00,0x0a,0x80,0x9e,0x12,0x02,0x26,0x00,0x26,0x41,0xe0,0x0b,0xdf,0xfd,0x00, +0xfc,0x00,0x02,0x7f,0xff,0xed,0xfe,0xff,0x05,0xf9,0xbf,0xff,0xf0,0x3f,0xf8, +0xfe,0x00,0xfc,0x00,0x0b,0x07,0x21,0xc0,0x01,0xf9,0x45,0x59,0x05,0x07,0xd6, +0x10,0x48,0xfe,0x00,0xfb,0x00,0x0a,0xde,0x00,0x02,0x06,0x02,0x19,0x02,0xf8, +0x01,0x0f,0x88,0xfe,0x00,0xfc,0x00,0xfb,0xff,0x05,0xe6,0xff,0xff,0xf8,0xff, +0xf0,0xfe,0x00,0xfc,0x00,0x0b,0x06,0x61,0xd2,0x47,0xe1,0x79,0x54,0xc4,0x07, +0xc0,0x20,0x60,0xfe,0x00,0xfc,0x00,0x0b,0x01,0x9e,0x12,0x40,0x0e,0x06,0x14, +0xc3,0xf8,0x07,0x0f,0x84,0xfe,0x00,0xfc,0x00,0x0b,0xff,0xff,0xed,0xbf,0xff, +0xff,0xeb,0x3f,0xff,0xf8,0xff,0xfc,0xfe,0x00,0xfd,0x00,0x0c,0x01,0xae,0x77, +0xf2,0x07,0x45,0xe2,0x00,0x40,0x67,0xe6,0xfc,0xe8,0xfe,0x00,0xfd,0x00,0x0c, +0x01,0x01,0x88,0x12,0x00,0x8a,0x1c,0x00,0x43,0x98,0x05,0x03,0x04,0xfe,0x00, +0xfc,0x00,0x02,0xff,0xff,0xed,0xfd,0xff,0x04,0xbf,0xff,0xf8,0xff,0xfc,0xfe, +0x00,0xfc,0x00,0x0b,0x0e,0xac,0xee,0x0f,0xfc,0x07,0x02,0xc2,0x27,0x79,0xfd, +0x78,0xfe,0x00,0xfc,0x00,0x0b,0x01,0x53,0x0e,0x00,0x03,0xb8,0x02,0xc1,0xd8, +0x83,0x02,0x84,0xfe,0x00,0xfd,0x00,0x03,0x01,0xff,0xff,0xf1,0xfe,0xff,0x05, +0xfd,0x3f,0xff,0xfc,0xff,0xfc,0xfe,0x00,0xfd,0x00,0x0c,0x03,0x7c,0xfc,0xfb, +0x0f,0xf8,0xc6,0xe2,0x00,0x94,0xd6,0xeb,0xf8,0xfe,0x00,0xfd,0x00,0x0c,0x02, +0x03,0x03,0x0f,0x00,0x07,0x39,0x02,0x03,0x6b,0x22,0x14,0x07,0xfe,0x00,0xfd, +0x00,0x03,0x01,0xff,0xff,0xf0,0xfe,0xff,0x05,0xfd,0xff,0xff,0xfd,0xff,0xff, +0xfe,0x00,0xfd,0x00,0x0c,0x01,0x05,0x6f,0xa6,0xfc,0x70,0x20,0x91,0x40,0xac, +0x55,0xe7,0xf5,0xfe,0x00,0xfb,0x00,0x0d,0x90,0x53,0x03,0x8f,0xdf,0x61,0x43, +0x53,0xa0,0x18,0x02,0x80,0x00,0x00,0xfd,0x00,0x03,0x03,0xff,0xff,0xf9,0xfe, +0xff,0x01,0xfe,0xbf,0xfd,0xff,0x02,0x80,0x00,0x00,0xfd,0x00,0x0f,0x02,0x5f, +0xdf,0x75,0x68,0x80,0x50,0x10,0x43,0x1b,0xfa,0x84,0x4f,0x80,0x00,0x00,0xfb, +0x00,0x0d,0x20,0x8b,0x97,0x7e,0x4f,0xe0,0x40,0xe4,0x01,0x7b,0xb0,0x40,0x00, +0x00,0xfd,0x00,0x00,0x03,0xfc,0xff,0x02,0xbf,0xff,0xbf,0xfd,0xff,0x02,0xc0, +0x00,0x00,0xfd,0x00,0x0f,0x06,0x31,0xff,0xfb,0x18,0x83,0x3c,0x00,0x83,0xde, +0x7d,0x04,0x46,0x48,0x00,0x00,0xfd,0x00,0x0f,0x04,0x0e,0x00,0x01,0xe7,0x7f, +0x3b,0xf0,0x80,0x21,0x80,0xfb,0xb9,0xb0,0x00,0x00,0xfd,0x00,0x08,0x03,0xff, +0xff,0xfe,0xff,0xfc,0xc7,0xff,0x7f,0xfd,0xff,0x02,0xf8,0x00,0x00,0xfd,0x00, +0x0f,0x0d,0x87,0x77,0x6d,0x40,0x03,0xfe,0x00,0x83,0xff,0xf8,0x06,0x36,0x60, +0x00,0x00,0xfd,0x00,0x0f,0x08,0x78,0x88,0x0d,0xff,0xff,0xb9,0xf0,0x80,0x00, +0x01,0xf9,0xc9,0x9e,0x00,0x00,0xfd,0x00,0x08,0x07,0xff,0xff,0xf2,0xff,0xfc, +0x47,0xff,0x7f,0xfd,0xff,0x02,0xfe,0x00,0x00,0xfd,0x00,0x0f,0x03,0x60,0xff, +0x7b,0x00,0x09,0x84,0x06,0x81,0x57,0x3f,0x2f,0x9d,0x10,0x00,0x00,0xfc,0x00, +0x0e,0x9f,0x00,0x9f,0x7f,0xfc,0x93,0xf0,0x80,0x00,0xc0,0xd0,0x62,0xef,0x00, +0x00,0xfd,0x00,0x08,0x3f,0xff,0xff,0xe0,0xff,0xff,0x6f,0xff,0x7f,0xfc,0xff, +0x01,0x00,0x00,0xfd,0x00,0x0f,0x27,0x90,0x0f,0xff,0x00,0x0f,0x7c,0x04,0x41, +0x3f,0xec,0x98,0x61,0x18,0x00,0x00,0xfc,0x00,0x0e,0x6f,0xf0,0x1f,0x7f,0xf3, +0x71,0xf0,0x40,0x00,0x10,0x60,0x1e,0xf7,0xc0,0x00,0xfd,0x00,0x08,0x3f,0xff, +0xff,0xe0,0xff,0xfc,0x8f,0xff,0xbf,0xfc,0xff,0x01,0xc0,0x00,0xfd,0x00,0x0f, +0x67,0x00,0xf9,0xee,0x00,0x00,0x79,0x05,0x41,0xbf,0xfc,0x83,0x30,0x42,0x00, +0x00,0xfc,0x00,0x0e,0xff,0x00,0x0f,0x7f,0xf9,0x00,0xf1,0x40,0x00,0x00,0x6b, +0x0f,0xff,0xe0,0x00,0xfd,0x00,0x0f,0x7f,0xff,0xff,0xf0,0xff,0xfe,0xff,0xfe, +0xbf,0xff,0xff,0xfc,0xff,0xff,0xe0,0x00,0xfd,0x00,0x0f,0x87,0xe2,0x4e,0xe0, +0x80,0x42,0x60,0x02,0x60,0xff,0xfc,0x30,0x10,0x88,0x10,0x00,0xfd,0x00,0x0f, +0x80,0x1d,0xb0,0x1b,0xff,0xfd,0x1f,0xf0,0x40,0x00,0x00,0x4e,0x0f,0x7f,0xf0, +0x00,0xfd,0x00,0x04,0x7f,0xff,0xff,0xfc,0x7f,0xfe,0xff,0x00,0xbf,0xfc,0xff, +0x01,0xf0,0x00,0xfe,0x00,0x0d,0x01,0x85,0xfc,0xfd,0xc6,0x50,0x06,0xe2,0x10, +0xa0,0xbf,0xbe,0x11,0xc8,0xfe,0x00,0xfe,0x00,0x00,0x01,0xfe,0x00,0x0c,0x1a, +0x3f,0xf9,0x1d,0xe0,0x80,0x00,0x40,0x61,0xc7,0xff,0xf8,0x00,0xfd,0x00,0xfe, +0xff,0x00,0xfd,0xfd,0xff,0x07,0x7f,0xff,0xff,0xfe,0x3f,0xff,0xf8,0x00,0xfe, +0x00,0x10,0x02,0x0e,0x80,0xd1,0x50,0x80,0x15,0x8f,0x18,0xa0,0xbf,0xf3,0x4c, +0xa9,0xc0,0x08,0x00,0xfe,0x00,0x10,0x02,0x01,0x7f,0x20,0x8f,0x7f,0xfa,0x00, +0xe8,0x80,0x00,0x00,0x2f,0xe7,0x1f,0xfc,0x00,0xfe,0x00,0x00,0x01,0xfa,0xff, +0x08,0xf7,0x7f,0xff,0xff,0xf0,0x1f,0xff,0xfc,0x00,0xfe,0x00,0x10,0x04,0x3d, +0x3f,0xf0,0x3e,0x04,0x42,0x5e,0x81,0xa0,0x1f,0xf8,0x17,0xc8,0x52,0x04,0x00, +0xfe,0x00,0x10,0x04,0x02,0xc0,0x0c,0x06,0xff,0xfc,0x1d,0x61,0x80,0x00,0x00, +0x68,0x3f,0x8f,0xfc,0x00,0xfe,0x00,0x00,0x03,0xfe,0xff,0x0c,0xf9,0xff,0xff, +0xe3,0xfe,0x7f,0xff,0xff,0xf0,0x07,0xff,0xfc,0x00,0xfe,0x00,0x10,0x0c,0x23, +0xfb,0x53,0x97,0x00,0x00,0xda,0xb1,0x20,0x3f,0x9c,0x4a,0xfc,0x60,0x12,0x00, +0xfe,0x00,0x08,0x0c,0x1c,0x04,0xa0,0x06,0x7f,0xfc,0x18,0x51,0xfe,0x00,0x04, +0x3d,0x0b,0xaf,0xec,0x00,0xfe,0x00,0x00,0x03,0xfe,0xff,0x04,0xf9,0xff,0xff, +0xe7,0xee,0xfe,0xff,0x04,0xf0,0x07,0xdf,0xfe,0x00,0xfe,0x00,0x10,0x10,0x4d, +0xe4,0xff,0xc8,0xc4,0x04,0x6a,0xf2,0xe0,0x3f,0xe4,0x0f,0x3e,0xe0,0x24,0x00, +0xfe,0x00,0x10,0x10,0x32,0x1b,0x00,0x00,0x3f,0xf8,0x08,0x32,0x80,0x00,0x00, +0x30,0xc9,0xaf,0xfe,0x00,0xfe,0x00,0x00,0x0f,0xfb,0xff,0x09,0xf7,0xcd,0x7f, +0xff,0xff,0xf8,0x07,0xdf,0xfe,0x00,0xfe,0x00,0x10,0x21,0xe0,0x79,0x3b,0xf0, +0xe0,0x04,0xec,0xe9,0xd0,0xdf,0xe8,0x86,0x9c,0x2e,0x9c,0x00,0xfe,0x00,0x10, +0x20,0x00,0x06,0xc0,0x00,0x1f,0xf8,0x1f,0x69,0x80,0x00,0x00,0x1d,0x67,0xe0, +0x66,0x00,0xfe,0x00,0x00,0x1f,0xfb,0xff,0x09,0xf3,0x96,0x7f,0xff,0xff,0xf8, +0x03,0xdf,0xfe,0x00,0xfe,0x00,0x10,0x17,0x29,0xfe,0x00,0x9c,0x7b,0x1a,0x82, +0x0d,0x90,0xbf,0xf8,0x12,0xdd,0xe7,0x90,0x00,0xfe,0x00,0x01,0x10,0x28,0xfe, +0x00,0x0b,0x04,0xe2,0x00,0x8d,0xc0,0x00,0x00,0x09,0x26,0x20,0x6e,0x00,0xfe, +0x00,0x01,0x6f,0xd7,0xfd,0xff,0x0a,0xfd,0xff,0xf2,0x7f,0xff,0xff,0xfc,0x03, +0xdf,0xfe,0x00,0xfe,0x00,0x10,0x41,0x8f,0x8f,0xf1,0x0d,0x3d,0x2c,0x01,0x31, +0x50,0xaf,0xf4,0x81,0x2a,0x20,0x04,0x00,0xfe,0x00,0x08,0x41,0x80,0x70,0x01, +0x01,0x42,0xc0,0x01,0xb1,0xfe,0x00,0x04,0x0e,0xd4,0x20,0xee,0x00,0xfe,0x00, +0x08,0x3e,0x7f,0xff,0xfe,0xfe,0xff,0xff,0xfe,0xce,0xfe,0xff,0x04,0xf0,0x03, +0xdf,0xfe,0x00,0xfe,0x00,0x10,0x83,0x3f,0x47,0x9d,0x03,0x08,0x2f,0x8c,0xb7, +0xd0,0x7f,0xf8,0x14,0xd4,0x08,0x02,0x00,0xfe,0x00,0x08,0x83,0x00,0xb8,0x00, +0x03,0x77,0xc2,0x00,0x37,0xfe,0x00,0x04,0x1b,0x2c,0x20,0xec,0x00,0xfe,0x00, +0x00,0x7c,0xfe,0xff,0x04,0xfc,0xff,0xfd,0xff,0xc8,0xfe,0xff,0x04,0xe0,0x03, +0xdf,0xfe,0x00,0xfe,0x00,0x10,0x5c,0x57,0x47,0x4f,0xc2,0x40,0x48,0x94,0xf6, +0xd8,0xef,0xfc,0x12,0x3c,0x48,0x4a,0x00,0xfe,0x00,0x08,0x5c,0x00,0xb8,0x80, +0x02,0x3f,0x80,0x08,0x76,0xfe,0x00,0x04,0x1d,0xc4,0x61,0x84,0x00,0xfe,0x00, +0x00,0xa3,0xfe,0xff,0x00,0xfd,0xfe,0xff,0x00,0x89,0xfe,0xff,0x04,0xe0,0x03, +0x9f,0xfe,0x00,0xfe,0x00,0x10,0x5c,0x36,0xcf,0xf8,0x93,0x60,0x28,0x68,0x5a, +0xb8,0x7c,0x70,0x0c,0x8c,0x68,0x74,0x00,0xfe,0x00,0x08,0x5c,0x01,0x30,0x00, +0x03,0x1f,0xc0,0x10,0x5a,0xfe,0x00,0x04,0x07,0x74,0x61,0xbe,0x00,0xfe,0x00, +0x00,0xa3,0xfe,0xff,0x00,0xfc,0xfe,0xff,0x00,0xa5,0xfe,0xff,0x04,0xf8,0x03, +0x9f,0xce,0x00,0xfe,0x00,0x10,0x08,0x2f,0xff,0xff,0x3c,0xc0,0x1c,0xad,0xde, +0xb8,0xf7,0x38,0x22,0x0e,0x62,0x16,0x00,0xfe,0x00,0x00,0x78,0xfd,0x00,0x03, +0x3f,0xe0,0x4b,0xde,0xfe,0x00,0x04,0x2d,0xf4,0x61,0x80,0x00,0xfe,0x00,0x00, +0x87,0xfb,0xff,0x01,0xf0,0x21,0xfe,0xff,0x04,0xde,0x03,0x9f,0xee,0x00,0xfe, +0x00,0x10,0x90,0x76,0x92,0xed,0xf8,0x44,0x86,0x52,0xde,0xa1,0xb9,0x3c,0x31, +0x04,0xa4,0x60,0x00,0xfe,0x00,0x10,0x70,0x01,0x6d,0x00,0x04,0x3f,0xf9,0x9e, +0xff,0x18,0x00,0x00,0x2e,0xfc,0xe7,0x40,0x00,0xfe,0x00,0x00,0x8f,0xfb,0xff, +0x01,0xe1,0x01,0xfe,0xff,0x04,0xdf,0x03,0x1b,0xa0,0x00,0xfe,0x00,0x10,0x10, +0x07,0xe5,0xde,0x4c,0x73,0x60,0xc8,0x3e,0x29,0xa2,0x5c,0x60,0x05,0x03,0x60, +0x00,0xfe,0x00,0x10,0x70,0x00,0x1a,0x20,0x00,0x43,0x60,0xf4,0xfd,0x10,0x00, +0x00,0x7f,0x7d,0xc1,0xc0,0x00,0xfe,0x00,0x00,0x8f,0xfd,0xff,0x03,0xbc,0x9f, +0x03,0x03,0xfe,0xff,0x04,0x9f,0x82,0x3f,0xa0,0x00,0xfe,0x00,0x10,0x40,0x4e, +0x7c,0xa9,0xd1,0x44,0x40,0x87,0x7c,0xa9,0x9b,0x2c,0x80,0x45,0xc2,0x60,0x00, +0xfe,0x00,0x10,0x60,0x01,0x83,0x50,0x00,0x7f,0xff,0xff,0xfe,0x50,0x00,0x00, +0x8f,0xfd,0x06,0x40,0x00,0xfe,0x00,0x00,0x9f,0xfd,0xff,0x03,0x80,0x00,0x02, +0x03,0xfe,0xff,0x04,0x7f,0x82,0xb9,0xa0,0x00,0xfe,0x00,0x10,0x40,0x0e,0x7f, +0x3a,0x63,0xbf,0x3f,0x95,0x01,0x89,0x84,0xc8,0x40,0x11,0x65,0x00,0x00,0xfe, +0x00,0x10,0x60,0x00,0x00,0x44,0x00,0x3f,0x3f,0xff,0xfa,0x30,0x00,0x00,0x4f, +0xb9,0xbf,0x80,0x00,0xfe,0x00,0x00,0x9f,0xfd,0xff,0x03,0xc0,0xc0,0x02,0x07, +0xfe,0xff,0x04,0xbf,0xc6,0x98,0x40,0x00,0xfe,0x00,0x10,0x04,0x8a,0xff,0xa6, +0x9c,0x3f,0xe0,0x29,0xd0,0xfd,0xb4,0xc0,0xb5,0x24,0x98,0x80,0x00,0xfe,0x00, +0x08,0x84,0x80,0x00,0x07,0x02,0x3f,0xff,0xfd,0xc4,0xfe,0x00,0x04,0xaa,0xfc, +0x7f,0x80,0x00,0xfe,0x00,0x08,0xfb,0x7f,0xff,0xf9,0xff,0xc0,0x00,0x06,0x3f, +0xfe,0xff,0x04,0x5f,0xc3,0x80,0x00,0x00,0xfe,0x00,0x10,0xc8,0x2f,0x6b,0xda, +0xa4,0x15,0x00,0x39,0xa8,0x94,0xfe,0xc1,0xb4,0x00,0x86,0x00,0x00,0xfe,0x00, +0x10,0x48,0x00,0x00,0x1e,0x58,0x1f,0xff,0xf5,0x81,0x20,0x00,0x01,0xab,0xde, +0xfb,0x00,0x00,0xfe,0x00,0x0d,0xb7,0xff,0xff,0xe1,0xff,0xe0,0x00,0x0e,0x7f, +0xff,0xff,0xfe,0x5f,0xe1,0xfe,0x00,0xfe,0x00,0x10,0x45,0x0d,0x3f,0xbf,0x71, +0x85,0x00,0x5a,0x36,0xfb,0xcf,0x62,0x90,0x01,0x01,0x00,0x00,0xfe,0x00,0x10, +0x45,0x00,0x00,0x3f,0x01,0x9f,0xff,0xc7,0x88,0x00,0x30,0x02,0x8f,0xfe,0xff, +0x00,0x00,0xfe,0x00,0x0d,0xba,0xff,0xff,0xc0,0xfe,0x60,0x00,0x3c,0x7f,0xff, +0xff,0xfd,0x7f,0xe1,0xfe,0x00,0xfe,0x00,0x0d,0x28,0x13,0xa7,0xbe,0x00,0x0c, +0x01,0x13,0x58,0x9d,0x87,0xc1,0x8b,0x06,0xfe,0x00,0xfe,0x00,0x10,0x28,0x00, +0x00,0x3e,0x00,0x1f,0xff,0xef,0x27,0x00,0x78,0x01,0x94,0xff,0xfe,0x00,0x00, +0xfe,0x00,0x07,0xd7,0xff,0xff,0xc1,0xff,0xe0,0x00,0x3c,0xfe,0xff,0x05,0xfe, +0x7f,0xe1,0x01,0x00,0x00,0x13,0x00,0x00,0x01,0xd2,0x1d,0x7f,0x3f,0x70,0x16, +0xce,0x43,0x26,0x00,0x06,0xc2,0x00,0x2a,0xda,0x00,0x00,0x13,0x00,0x00,0x01, +0xd2,0x00,0x00,0xbe,0x70,0x1f,0xff,0xbf,0xd8,0x79,0xf9,0x02,0x3f,0xdf,0xfe, +0x00,0x00,0xfe,0x00,0x07,0x2d,0xff,0xff,0xc1,0x8f,0xe0,0x00,0x7c,0xfe,0xff, +0x02,0xfd,0xff,0xe1,0xfe,0x00,0x13,0x00,0x00,0x01,0x2f,0x3e,0x3f,0x7e,0x2e, +0x06,0xa1,0x03,0x16,0x39,0x04,0xe3,0x48,0x4c,0xb2,0x00,0x00,0x13,0x00,0x00, +0x01,0x2f,0x00,0x00,0xfe,0x6e,0x1f,0xff,0x7e,0xe9,0xc0,0xfb,0x03,0x37,0xbd, +0xfe,0x00,0x00,0xfe,0x00,0x07,0xd0,0xff,0xff,0x81,0x91,0xe0,0x00,0xfd,0xfe, +0xff,0x02,0xfc,0xff,0xe3,0xfe,0x00,0x13,0x00,0x00,0x03,0xe2,0x19,0xdf,0xff, +0x47,0x9f,0x1f,0x66,0x00,0xfd,0x00,0x42,0xc0,0x29,0x06,0x00,0x00,0x13,0x00, +0x00,0x03,0xe2,0x00,0x00,0x7f,0x87,0x9f,0xfe,0x9b,0xff,0x00,0xff,0x82,0x3f, +0xfd,0x74,0x00,0x00,0xfe,0x00,0x07,0x1d,0xff,0xff,0x80,0xf8,0x60,0x01,0xfd, +0xfe,0xff,0x05,0xfd,0xff,0xe3,0x9a,0x00,0x00,0xfe,0x00,0x10,0xee,0x3f,0x7e, +0x7e,0x57,0x2f,0xfd,0xc0,0xbf,0x7e,0xff,0x03,0xa0,0x1f,0x1e,0x00,0x00,0x13, +0x00,0x00,0x03,0xee,0x00,0x01,0x7e,0x10,0x0f,0xfc,0x39,0x40,0x80,0x00,0xc2, +0x1f,0xee,0xb0,0x00,0x00,0xfe,0x00,0x06,0x11,0xff,0xff,0x81,0xef,0xf0,0x03, +0xfd,0xff,0x05,0xfd,0xff,0xf3,0xfe,0x00,0x00,0x10,0x00,0x00,0x0c,0xc4,0x14, +0xfe,0xf7,0xf7,0xe6,0xf9,0xc0,0x00,0x7e,0x9a,0x09,0xf0,0x08,0xfe,0x00,0x13, +0x00,0x00,0x0b,0xc4,0x00,0x01,0xf7,0xfc,0x0f,0xf8,0x3b,0xff,0x80,0x65,0xc0, +0x0f,0xf7,0xfc,0x00,0x00,0x09,0x00,0x00,0x04,0x3b,0xff,0xff,0x08,0x03,0xf0, +0x07,0xfa,0xff,0x02,0xfe,0x00,0x00,0x10,0x00,0x00,0x0f,0x7c,0x1f,0x7c,0xff, +0xd3,0xef,0xf1,0x04,0x79,0xda,0x1e,0xe0,0x70,0x48,0xfe,0x00,0x13,0x00,0x00, +0x0f,0xfc,0x00,0x03,0xff,0xfe,0x0f,0xf0,0xfb,0x80,0x24,0xe1,0x01,0x8f,0xff, +0xfc,0x00,0x00,0xfe,0x00,0x06,0x03,0xff,0xff,0x00,0x01,0xf0,0x0f,0xfa,0xff, +0x02,0xfe,0x00,0x00,0xfe,0x00,0x10,0xe6,0x18,0xf0,0x77,0xe9,0x9b,0xd0,0x11, +0xc2,0x06,0xff,0x62,0xf0,0x00,0x12,0x00,0x00,0x13,0x00,0x00,0x07,0xee,0x00, +0x0f,0x77,0xff,0x1b,0xcf,0xe6,0x3d,0xf8,0x00,0x81,0x0f,0xff,0xfc,0x00,0x00, +0x09,0x00,0x00,0x08,0x11,0xff,0xff,0x88,0x00,0xe4,0x3f,0xfa,0xff,0x02,0xfe, +0x00,0x00,0xfe,0x00,0x10,0x76,0x3f,0x8f,0x7f,0xb5,0x5d,0x05,0x68,0x1e,0x4a, +0x7d,0x41,0x30,0x41,0x02,0x00,0x00,0x13,0x00,0x00,0x07,0xf6,0x00,0x70,0x7f, +0xfe,0xe4,0xfa,0x87,0xe1,0xb4,0x02,0x80,0xcf,0xff,0xfd,0x00,0x00,0xfe,0x00, +0x05,0x01,0xff,0xff,0x80,0x00,0x1b,0xf8,0xff,0x01,0x00,0x00,0x13,0x00,0x00, +0x03,0x06,0x6f,0x36,0x7b,0xdb,0xdd,0xbe,0x31,0x83,0x04,0x5b,0x85,0x38,0x00, +0x49,0x00,0x00,0x13,0x00,0x00,0x03,0x06,0x00,0xc9,0xfb,0xff,0x3c,0x40,0x3e, +0x7c,0xf8,0x20,0x40,0xc7,0xff,0xfe,0x00,0x00,0xfe,0x00,0x07,0xc1,0xff,0xff, +0x84,0x00,0x03,0xff,0xcf,0xfa,0xff,0x01,0x00,0x00,0xfe,0x00,0x10,0x02,0x3e, +0x8a,0xdf,0xd0,0x1d,0xed,0x23,0x01,0x02,0x66,0xc5,0xb0,0x0a,0x03,0x00,0x00, +0xfe,0x00,0x10,0x06,0x01,0x75,0x1f,0xfe,0xed,0xed,0x2c,0xfe,0xfc,0x11,0x00, +0x4f,0xff,0xfe,0x00,0x00,0xfe,0x00,0x07,0x01,0xff,0xff,0xe0,0x01,0x02,0x12, +0xdf,0xfa,0xff,0x01,0x00,0x00,0xfe,0x00,0x10,0x06,0x3e,0x1e,0xdf,0xed,0xef, +0xdf,0xe0,0x48,0x06,0x7f,0xc5,0xb4,0x00,0xa9,0x00,0x00,0xfe,0x00,0x10,0x06, +0x01,0xe0,0x1f,0xff,0x9f,0xdf,0xef,0xb7,0xf8,0x00,0x00,0x4b,0xff,0xfe,0x00, +0x00,0xfe,0x00,0x07,0x01,0xff,0xff,0xe0,0x00,0x00,0x20,0x1f,0xfa,0xff,0x01, +0x00,0x00,0xfe,0x00,0x10,0x06,0x1e,0x3f,0xbf,0xd0,0x4a,0xbf,0xe4,0x00,0x03, +0x36,0xd0,0x58,0x24,0x05,0x00,0x00,0xfe,0x00,0x10,0x06,0x01,0xc0,0x7f,0xff, +0xba,0xbf,0xeb,0xff,0xfc,0x00,0x01,0x27,0xff,0xfe,0x00,0x00,0xfe,0x00,0x07, +0x01,0xff,0xff,0xc0,0x00,0x05,0x40,0x1f,0xfa,0xff,0x01,0x00,0x00,0xfe,0x00, +0x10,0x06,0x1d,0xff,0xbe,0xd9,0xef,0xff,0xe2,0x08,0x06,0x0f,0x03,0xfc,0x00, +0x92,0x80,0x00,0xfe,0x00,0x10,0x06,0x02,0x00,0x3e,0xff,0x1f,0xff,0xfd,0xf7, +0xf8,0x00,0x80,0x03,0xff,0xff,0x00,0x00,0xfe,0x00,0x03,0x01,0xff,0xff,0xc1, +0xfe,0x00,0x00,0x1f,0xfa,0xff,0x01,0x80,0x00,0xfe,0x00,0x10,0x06,0x15,0xff, +0x77,0xed,0xa2,0x5f,0xe9,0x00,0x01,0x03,0x80,0x98,0x54,0x44,0x80,0x00,0xfe, +0x00,0x10,0x06,0x0a,0x00,0x77,0xfe,0x52,0x5f,0xf6,0xff,0xfe,0x00,0x00,0x07, +0xff,0xff,0x00,0x00,0xfe,0x00,0x07,0x01,0xff,0xff,0x88,0x00,0x0d,0xa0,0x1f, +0xfa,0xff,0x01,0x80,0x00,0xfe,0x00,0x10,0x05,0xa7,0xbd,0xff,0xd9,0x77,0xff, +0xa0,0x00,0x03,0x03,0x80,0xb4,0x01,0x20,0x80,0x00,0xfe,0x00,0x05,0x05,0x58, +0x02,0xff,0xfe,0x97,0xfe,0xff,0x07,0xfc,0x00,0x00,0x03,0xff,0xff,0x00,0x00, +0xfe,0x00,0x07,0x02,0xff,0xff,0x00,0x00,0x08,0x00,0x1f,0xfa,0xff,0x01,0x80, +0x00,0xfe,0x00,0x10,0x07,0xc6,0xf9,0xef,0xdb,0xba,0xff,0xa4,0x00,0x04,0x13, +0x80,0x4e,0x08,0x4d,0x00,0x00,0xfe,0x00,0x10,0x07,0x38,0x01,0xef,0xfc,0x7a, +0xff,0xfb,0xff,0xfb,0x10,0x00,0x01,0xff,0xff,0xc0,0x00,0xfd,0x00,0x09,0xff, +0xfe,0x10,0x00,0x05,0x00,0x1f,0xff,0xff,0xef,0xfd,0xff,0x01,0xc0,0x00,0xfe, +0x00,0x10,0x06,0x7c,0xef,0xff,0xe7,0xf7,0x7f,0xc8,0x24,0x06,0x10,0x0c,0x84, +0x44,0x90,0x40,0x00,0xfe,0x00,0x10,0x06,0x00,0x0f,0xff,0xf8,0x57,0x7f,0xd7, +0xdb,0xf9,0x10,0x00,0x01,0xff,0xff,0x80,0x00,0xfe,0x00,0x0a,0x01,0xff,0xf0, +0x00,0x00,0x28,0x80,0x3f,0xff,0xff,0xef,0xfd,0xff,0x01,0xc0,0x00,0xfe,0x00, +0x10,0x07,0x3d,0x6e,0xfe,0xbb,0xea,0xbe,0xc9,0x36,0x82,0xd8,0x18,0x06,0x90, +0x04,0xc0,0x00,0xfe,0x00,0x10,0x07,0x00,0x0e,0xff,0xf4,0x8a,0xbe,0xd6,0xc9, +0x7d,0x18,0x00,0x00,0x7f,0xff,0x80,0x00,0xfd,0x00,0x09,0xff,0xf1,0x00,0x00, +0x75,0x41,0x3f,0xff,0xff,0xe7,0xfd,0xff,0x01,0xc0,0x00,0xfe,0x00,0x10,0x01, +0x3f,0xff,0xff,0x4f,0xf6,0xfd,0xc8,0xa7,0x02,0xe9,0x08,0x43,0x89,0x64,0x80, +0x00,0xfe,0x00,0x10,0x01,0x00,0x1f,0xff,0xf1,0x36,0xfd,0xf7,0x58,0xfd,0x09, +0x00,0x00,0x7f,0xff,0xe0,0x00,0xfe,0x00,0x0a,0x02,0xff,0xe0,0x00,0x00,0xc9, +0x02,0x3f,0xff,0xff,0xf6,0xfd,0xff,0x01,0xe0,0x00,0xfe,0x00,0x10,0x01,0x8f, +0x3b,0xfd,0xde,0x16,0x7f,0xc0,0xbf,0xc0,0xcd,0x89,0xa1,0x08,0x09,0x00,0x00, +0xfe,0x00,0x10,0x01,0x80,0xdb,0xff,0xe2,0x16,0x7f,0xff,0x40,0x3f,0x2d,0x80, +0x00,0x7f,0xff,0xe0,0x00,0xfe,0x00,0x0b,0x02,0x7f,0xe4,0x00,0x01,0xe9,0x80, +0x3f,0xff,0xff,0xf2,0x7f,0xfe,0xff,0x01,0xe0,0x00,0xfe,0x00,0x10,0x02,0x0f, +0x8f,0xfc,0x1f,0x33,0x7f,0xc1,0x77,0xb0,0x4c,0x91,0x13,0x80,0x91,0x40,0x00, +0xfe,0x00,0x10,0x02,0x00,0x6f,0xff,0xe2,0x33,0x7f,0xfe,0x88,0x4f,0xac,0x80, +0x00,0x3f,0xff,0xe0,0x00,0xfe,0x00,0x0b,0x01,0xff,0xf0,0x00,0x01,0xcc,0x80, +0x3f,0xff,0xff,0xf3,0x7f,0xfe,0xff,0x01,0xe0,0x00,0xfd,0x00,0x0f,0x03,0xaf, +0xfd,0xba,0xb6,0x36,0x80,0xb7,0x80,0x4d,0x00,0x12,0x04,0x24,0x00,0x00,0xfc, +0x00,0x0e,0x4f,0xff,0xc6,0x36,0x36,0xbf,0x48,0x7f,0xad,0x00,0x00,0x3f,0xff, +0xe0,0x00,0xfe,0x00,0x0a,0x01,0xff,0xf0,0x00,0x01,0xc9,0xc9,0x7f,0xff,0xff, +0xf2,0xfd,0xff,0x01,0xe0,0x00,0xfe,0x00,0x10,0x01,0x0b,0x27,0xc8,0xee,0x66, +0xff,0x03,0x77,0xb0,0x14,0xac,0x0e,0x09,0x09,0x80,0x00,0xfe,0x00,0x10,0x01, +0x00,0xd7,0xff,0x92,0x66,0xff,0x7c,0x88,0x4f,0xe4,0xac,0x00,0x1f,0xff,0xf8, +0x00,0xfd,0x00,0x05,0xff,0xf8,0x00,0x01,0x99,0x00,0xfe,0xff,0x01,0xfb,0x53, +0xfe,0xff,0x01,0xf8,0x00,0xfe,0x00,0x10,0x01,0x0b,0x0f,0x90,0x7e,0xd2,0x28, +0x80,0xbe,0xfc,0x75,0xb0,0x0c,0x00,0x44,0x40,0x00,0xfe,0x00,0x10,0x01,0x00, +0xf7,0xff,0x82,0xd2,0x28,0x7f,0x40,0x03,0x85,0xb0,0x00,0x1f,0xff,0xf8,0x00, +0xfd,0x00,0x05,0xff,0xf8,0x00,0x01,0x2d,0xd7,0xfe,0xff,0x01,0xfa,0x4f,0xfe, +0xff,0x01,0xf8,0x00,0xed,0x00,0xed,0x00,0xed,0x00,0x00, }; +#endif -- 2.11.4.GIT