Dinosaur wrote:Where I am getting confused (it's easy) is the purpose of the linear address.
I misunderstood it to be a linear address of where the "device" is hiding.
Dimosaur wrote:So, if usbuhcil translates the Seg:offs address that my app provides to issue a physical address to the host controller, (which is only a place to exchange commands & Data) then my only problem is to locate such a free address in Real Mode memory area.
This is where I thought that making a buffer for the Struct larger (1024 bytes) to allow room for this would solve that problem.
Equally, I can create another buffer specifically for this.
Am I still missing something ?
Dimosaur wrote:I was referring to this call, where bit 0 in BH was set.
But no error code in DX
Get Device Status Information
...
) Conventional Memory
Conventional memory (address space 0-10FFFFh) is under control of DOS.
In XMS and raw mode HDPMI will initialize the page table for this region
so that physical memory addresses and linear memory addresses are identical.
For its API translation HDPMI will use a DOS memory block of 8 kB.
Additionally some host code has to be run in real/v86-mode, and a 2 kB
host stack also is located in conventional memory to make it accessible
for both modes. All in all HDPMI will use about 13 kB of DOS memory.
This means that the buffer I create is in fact both Linear & Physical.You have several alternatives to get the physical address of your buffer:
* Allocate the buffer in conventional memory, below the 1MB mark. This memory is mapped 1:1 by all DPMI servers, so the linear address is equal to the physical one. You can allocate a buffer in conventional memory using the library function __dpmi_allocate_dos_memory.
Dinosaur wrote:*Allocate the buffer in conventional memory, below the 1MB mark. This memory is mapped 1:1 by all DPMI servers, so the linear address is equal to the physical one. You can allocate a buffer in conventional memory using the library function __dpmi_allocate_dos_memory
c.m wrote:I think this depends on the CPU mode the DPMI host found when it installed. When no VCPI host/EMM was found and the CPU was in real mode, the DPMI host probably switches to real mode (instead of V86) to handle interrupts.
Bret wrote:Christian's idea of using HDPMI and creating a DMA buffer seems like it could also work. The best solution, though, if it's possible, is to go directly from physical to linear, without even needing to mess with segment:offset in the middle.
Format of Extended DMA descriptor structure (EDDS):
Offset Size Description (Table 03222)
00h DWORD region size
04h DWORD offset
08h WORD segment/selector
0Ah WORD reserved
0Ch WORD number available
0Eh WORD number used
10h DWORD region 0 physical address
14h DWORD region 0 size in bytes
18h DWORD region 1 physical address
1Ch DWORD region 1 size in bytes
...
Dinosaur wrote:*Allocate the buffer in conventional memory, below the 1MB mark. This memory is mapped 1:1 by all DPMI servers, so the linear address is equal to the physical one. You can allocate a buffer in conventional memory using the library function __dpmi_allocate_dos_memory
If this is in fact true (if ALL DPMI servers map the memory 1:1), the problem appears to be solved. We can try testing it and see - maybe we've all spent a lot of effort worrying about something that's not even a problem.
I do know that under VCPI the statement is NOT true. Under VCPI, the memory between 0 and 640k is usually mapped 1:1, but the memory between 640k and 1MB is usually not.
It also doesn't seem likely, because of the multi-tasking nature of DPMI. Under DPMI (at least DOS-based Windows like 9x and Me), you can have several independent DOS boxes (command shells) at the same time. They all "share" the same DOS memory (including TSR's in Upper memory)) that was installed before Windows started, but the "extra" memory under 1MB that was not in use before Windows started is completely independent for each DOS box. This implies that the allocated memory is not mapped 1:1, at least under Windows DPMI.
mov ax, 0303h
push ds
mov bx, cs
mov ds, bx
mov esi, OFFSET My_CallBack
pop es
mov edi, OFFSET PM_Struc
int 0x31
mov ax, 0x0303
mov esi, OFFSET My_CallBack
push ds
pop es
mov edi, OFFSET PM_Struc
Int 0x31
mov ax, 0303h
push ds
mov bx, cs
mov ds, bx
mov esi, OFFSET My_CallBack
pop es
mov edi, OFFSET PM_Struc
int 0x31
Dinosaur wrote:Currently my stumbling block is the CallBackAddr, and I took your advice and emailed japheth, and according to his response
the following code should work. However remember that this is in-line asm within FreeBasic.This causes gpf's.
- Code: Select all
mov ax, 0303h
push ds
mov bx, cs
mov ds, bx
mov esi, OFFSET My_CallBack
pop es
mov edi, OFFSET PM_Struc
int 0x31
push ds ; save ds
mov ax, 0303h
push ds
pop es ; (set es = ds)
mov edi, OFFSET PM_Struc ; set es:edi-> PM_Struc
push cs
pop ds ; (set ds = cs)
mov esi, OFFSET My_CallBack ; set ds:esi-> My_CallBack
int 31h ; (call DPMI host)
pop ds ; restore ds
However changing it to the following, doesnt.But the Seg:Off created with this is wrong, as unplugging the usb lead causes
- Code: Select all
mov ax, 0x0303
mov esi, OFFSET My_CallBack
push ds
pop es
mov edi, OFFSET PM_Struc
Int 0x31
Exception 0D in ring 0
{General Protection Violation}
called in protected mode on protection violations not covered by INT 06
through INT 0C, including
segment limit violations
write to read-only segments
accesses using null DS or ES selectors
accesses to segments with privilege greater than CPL
wrong descriptor type
; This is a RM callback. Called from RM, executed in PM.
;
; INP: es:edi-> RM call structure
; ds:esi-> RM stack
; ss:esp-> DPMI host internal stack
; CHG: all (?) except es:edi
; read/write RM call structure to communicate with RM code
callback:
push dword [esi]
pop dword [es:edi+2Ah] ; set RM cs:ip
add word [es:edi+2Eh], byte 4 ; pop 4 byte from the stack
iret
Dinosaur wrote:However by moving the in-line asm to a totally different area of my program, it still comes back
with the same Seg:off. (0FF5:0CD4)
Bret wrote:I also noticed in RBIL that DPMI function 0303h refers to an IRET needed at the end of the PM call, which makes me wonder if it expects the real mode call to need an IRET (instead of a RETF) as well.
Maybe you've already seen this, and maybe this is where everybody is getting their information from
push ds
mov bx, cs
mov ds, bx
Asm
push ds
push es
'---------
mov ax, 0x0303
mov dssave,ds
mov esi, OFFSET My_CallBack
mov es,dssave
mov edi, OFFSET PM_Struc
Int 0x31
jc 1f
mov WORD PTR DataAddr[2],CX
mov WORD PTR DataAddr[0],DX
mov dword Ptr [Function], 0
'---------
pop es
pop ds
jmp 1f
0:
mov dword Ptr [Function],0x14
jmp 1f
My_CallBack:
iret
1:
End Asm
or the values in your PM_STRUC (particularly the selectors) may not be correct.
Type PMdpmiStruc Field = 1
edi As UInteger
esi As UInteger
ebp As UInteger
Res As UInteger
Ebx As UInteger
Edx As UInteger
Ecx As UInteger
Eax As UInteger
Flags As UShort
ES As UShort
DS As UShort
FS As UShort
GS As UShort
IP As UShort
CS As UShort
SP As UShort
SS As UShort
End Type
Common Shared PM_Struc As PMdpmiStruc
My_CallBack:
lodsd
mov es:[di+2Ah],eax ;Copy return CS:IP
add WORD PTR es:[di+2Eh],4 ;Adjust Stack
iret
Dinosaur wrote:Reading through your response, it appears that in the callback the caller uses Real Mode registers ?
You cant use any PM instructions or registers or variables?
But that is what causes the gpf.This is the complete asm part of the routine
- Code: Select all
push ds
mov bx, cs
mov ds, bx
- Code: Select all
Asm
push ds
push es
'---------
mov ax, 0x0303
mov dssave,ds
mov esi, OFFSET My_CallBack
mov es,dssave
mov edi, OFFSET PM_Struc
Int 0x31
jc 1f
mov WORD PTR DataAddr[2],CX
mov WORD PTR DataAddr[0],DX
mov dword Ptr [Function], 0
'---------
pop es
pop ds
jmp 1f
0:
mov dword Ptr [Function],0x14
jmp 1f
My_CallBack:
iret
1:
End Asm
I tried your suggestion in the callback, but some cause compiler problems. I dont think it even gets there, so it doesnt matter what is there.
; This is a RM callback. Called from RM, executed in PM.
;
; INP: es:edi-> RM call structure
; ds:esi-> RM stack
; ss:esp-> DPMI host internal stack
; CHG: all (?) except es:edi
; read/write RM call structure to communicate with RM code
callback:
push dword PTR [esi]
pop dword PTR es:[edi][2Ah] ; set RM cs:ip
add word PTR es:[edi][2Eh], byte 4 ; pop 4 byte from the stack
iret
Either the address is wrong or the way it is being called.
Bret wrote:or the values in your PM_STRUC (particularly the selectors) may not be correct.
32h or 50 bytes long
- Code: Select all
Type PMdpmiStruc Field = 1
edi As UInteger
esi As UInteger
ebp As UInteger
Res As UInteger
Ebx As UInteger
Edx As UInteger
Ecx As UInteger
Eax As UInteger
Flags As UShort
ES As UShort
DS As UShort
FS As UShort
GS As UShort
IP As UShort
CS As UShort
SP As UShort
SS As UShort
End Type
Common Shared PM_Struc As PMdpmiStruc
Afther that, I didnt get any more gpf's. So the complete code.you copy CS to DS, that's good, but you don't save/restore the value of DS.
With a code selector in DS you cannot write to global variables anymore! This code looks better:
mov ax, 0x0303
push ds ;<-added
push ds
mov bx, cs
mov ds, bx
mov esi, OFFSET My_CallBack
pop es
mov edi, OFFSET _RM_STRUC
int 0x31
pop ds ;<-added
jc 1f
mov WORD PTR _DATAADDR[2],CX
Asm
mov ax, 0x0303
push ds
push ds
mov bx, cs
mov ds, bx
mov esi, OFFSET My_CallBack
pop es
mov edi, OFFSET _RM_STRUC
int 0x31
pop ds
jc 1f
mov WORD PTR DataAddr[2],CX
mov WORD PTR DataAddr[0],DX
mov dword Ptr [Function], 0
'---------
jmp 1f
0:
mov dword Ptr [Function],0x14
jmp 1f
My_CallBack:
mov eax,&Hffff
Mov FdBack,eax
push dword PTR [esi]
pop dword PTR es:[edi][0x2A]
add word Ptr es:[edi][0x2E], 4
Sti
iret
1:
End Asm
But it doesnt, although there is no gpf when I pull the plug.So I suspect that I have set registers up to allow access to that variable.Execution is then passed to protected mode.
Dinosaur wrote:Afther that, I didnt get any more gpf's. So the complete code.
- Code: Select all
Asm
mov ax, 0x0303
push ds
push ds
mov bx, cs
mov ds, bx
mov esi, OFFSET My_CallBack
pop es
mov edi, OFFSET _RM_STRUC
int 0x31
pop ds
jc 1f
mov WORD PTR DataAddr[2],CX
mov WORD PTR DataAddr[0],DX
mov dword Ptr [Function], 0
'---------
jmp 1f
0:
mov dword Ptr [Function],0x14
jmp 1f
My_CallBack:
mov eax,&Hffff
Mov FdBack,eax
push dword PTR [esi]
pop dword PTR es:[edi][0x2A]
add word Ptr es:[edi][0x2E], 4
Sti
iret
1:
End Asm
After creating this CallBack, I claim ownership of an interface. Then I wait in a loop to see if
either Q is pressed or value of FdBack changes. By pulling the plug it should modify the variable if as you stated
"Execution is then passed to protected mode." But it doesnt, although there is no gpf when I pull the plug. So I suspect that I have set registers up to allow access to that variable.
or word PTR es:[edi][0x32], -1
c.m wrote:BTW, you've a "sti" instruction up there in your code. I would remove it, is there a reason you added it?
c.m wrote:Another thing I noticed (and can't answer myself, since I didn't read much of Bret's documentation yet): Is the call back used only to notify you when the interface disconnected? Because, if it would be used for other things too, you probably want to add a conditional to My_CallBack so to set FdBack only if the interface really got disconnected.
c.m wrote:The problem is that inside the call-back, ds will be set up to another selector (as stated in the commentary and RBIL, ds:esi points to the RM stack) with which you can't access your code segment. You may work around this easily: Change the specification of your _RM_STRUC so that it contains another UShort field "FdBack" behind the ss field. Then you can access that field inside the callback as "word PTR es:[edi][0x32]".
Bret wrote:You can also use a single call-back routine for everything, and distinguish between them somehow with the User Packet ID (see below).
Rather than adding a UShort field for FdBack to the _RM_STRUC, could he add a UInteger field and store his "real" DS there so he can use it in the call-back code? I assume that DPMI will only change the first 50 bytes of the structure, and leave the rest of it completely alone at all times?
BTW, you've a "sti" instruction up there in your code. I would remove it, is there a reason you added it?
then either interrupts should remain disabled (CLI, not STI) or you should temporarily move things
Dinosaur wrote:My reading of the dpmi spec show that the caller enters the CallBack with Interupts disabled. It is the client's (dpmi) responsibility to enable them when done.That is why I have STI. I dont recall if iret does this as well.
Dinosaur wrote:I think the Struc addition is a good solution, will work on that and see if I can knock this over. The caller has definitely come to the right address after the "unplug" , as when I changed my code to mov [FdBack],ax 'write to location pointed to by FdBack there was a gpf. Was the wrong thing to do anyway, but it proved it.
Dinosaur wrote:Bret, with your familiarity of usb devices, is it normal to set led's using a control instruction.? If I purchase another brand board is it likely that this changes.?
That is why, when I was finished with the Callback I issued a STISTI enables them.
Dinosaur wrote:Bret, what is in AX if I pull the plug ?
I am getting:
Ax =2 Unknown Hardware Problem with Host
Dinosaur wrote:What is annoying, is that I have read and re-read the desription on int31.0303 dozens of times, and I couldnt extract the fact that the Struc is left intact for PM to use.
Dinosaur wrote:Also, I would use different callbacks for different usb devices, as the function assigned to them
would need to be identified at the time of callback.
Bret wrote:CLI disables interrupts, STI enables them. Maybe backwards from what seems logical, but the way it is nonetheless.
Dinosaur wrote:Bret wrote:STI enables them.
That is why, when I was finished with the Callback I issued a STI
I decided that the using a seperate global variable as a flag may be the best way.
In other words, extend the RM_Struc and put the PM ds in it.
Then in the callback, restore the PM ds, and set the Flag.
Restore the RM ds, and quit.
Users browsing this forum: No registered users and 2 guests