Device Register Access

This is a discussion on Device Register Access within the C Programming forums, part of the General Programming Boards category; Not sure what your background is, but if you have never written a device driver before I can tell you ...

  1. #16
    Registered User
    Join Date
    Sep 2008
    Posts
    22
    Not sure what your background is, but if you have never written a device driver before I can tell you from first hand experience that you definitely could. Have you ever written drivers or kernels before? Anyway, thanks a lot for helping me out here. I feel a lot less confused now, so I will go ahead and try this out and post back if I hit a snag. Much appreciated.

  2. #17
    Registered User
    Join Date
    Sep 2008
    Posts
    22
    At any rate, I am still having issues, perhaps I am still doing it wrong:

    Code:
    #define secPerTrk 0x3F //= 63
    #define maxHeadNm 0xFE //= 254
    #define intATACmd 0x91 //= initialize ata command
    
    unsigned long val;
    unsigned long res;
    
    // read, then write
    pci_read_config_dword(&pci,BAR5+0x90,&i);
    val=(i&0xFF00FFFF) + (secPerTrk<<16);
    pci_write_config_dword(&pci, BAR5+0x90, val);
    res=(i>>16) & 0xff;
    
    //print
    printf(0x0F,3,10,"res: 0x&#37;x, val: 0x%x", res, val);
    Output:
    res: 0x0, val: 0x3F0000
    Shouldn't *res* be the same as *val*, and shouldn't val = 0x003F0000?

  3. #18
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,185
    The value of res depends on the value of i, which depends on what came in from your read_config. Apparently the original value of your bit_field was 0. (If you had done
    Code:
    res=(val>>16) & 0xff;
    I would expect res to be the same secPerTrk, i.e., 0x3F.

    And val is 0x003F0000. (Leading zeroes don't print unless you do something fancy. Granted you're using an outre version of printf, but %x by default doesn't pad zeroes.)

  4. #19
    Registered User
    Join Date
    Sep 2008
    Posts
    22
    still having trouble understanding this. I tried mapping the memory to a pointer, but I am sure I am using it wrong as it keeps causing a double-fault:

    Code:
    unsigned char* pBar5;
    unsigned int* pTFR0;
    
    pBar5 = (unsigned char*)mapreg(BAR5, BAR5Sze); //map bar5
    				    
    pTFR0 = (unsigned int*)(pBar5+0x90); //map offset to pointer
    
    //initialize ata
    *pTFR0 = (pTFR0&0xFF00FFFF) + (secPerTrk<<16); //write to memory
    pci_read_config_dword(&pci,pBar5[0x90],&i); //read offset to i
    res=(i>>16) & 0xff; //shift and mask
    printf("res: 0x%x", res);
    thanks in advance

  5. #20
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,185
    If you plan to mask off what is pointed to by pTFR0, you would use (*pTFR0&0xFF00FFFF).
    Also pBar5[0x90] corresponds to *(pBar5+0x90), in other words the contents of your 0x90, not the pointer itself, which I'm pretty sure you were using before. (In other words: pBar5[0x90] is a character while pBar5+0x90 is a pointer.)

  6. #21
    Registered User
    Join Date
    Sep 2008
    Posts
    22
    I am not able to test this now, but if I:

    Code:
    unsigned char* pBar5;
    unsigned int* pTFR0;
    
    pBar5 = (unsigned char*)mapreg(BAR5, BAR5Sze); //map bar5
    				    
    pTFR0 = (unsigned int*)(pBar5+0x90); //map offset to pointer
    
    //initialize ata
    *pTFR0 = (*pTFR0&0xFF00FFFF) + (secPerTrk<<16); //write to memory
    pci_read_config_dword(&pci,pBar5+0x90,&i); //read offset to i
    res=(i>>16) & 0xff; //shift and mask
    printf("res: 0x%x", res);
    that should work and if not then it is a problem with my mapping?

  7. #22
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,185
    The read_config thing is at least consistent with what you had before that appeared to give you an answer, so that's probably right. And the *pTFR0 is what you wanted.

  8. #23
    Registered User
    Join Date
    Sep 2008
    Posts
    22
    I tried this:

    Code:
    unsigned char* pBar5;
    unsigned int* pTFR0;
    
    // Map the memory
    pBar5 = (unsigned char*)mapReg(BAR5, BAR5Sze);
                                                                               
    pTFR0 = (unsigned int*)(pBar5+0x90); //map offset to pointer
    
    //initialize ata
    *pTFR0 = (*pTFR0&0xFF00FFFF) + (secPerTrk<<16); //write to memory
    pci_read_config_dword(&pci,(unsigned)(pBar5+0x90),&i); //read offset to i
    res=(i>>16) & 0xff; //shift and mask
    printf(0x0f,3,10,"res: 0x&#37;x", res);
    And it double-faults the CPU. I think what is happening is that I am trying to map an address to a part of memory that I am not allowed to access as it is not apart of my kernels address space. So is there a way to access a memory address without mapping it? If so, how?

  9. #24
    Registered User
    Join Date
    Sep 2008
    Posts
    22
    to pick back up on our discussion about bitfields, suppose I have this dilema:

    I must use outb and inb to read from an IO address at 0x9804, this address contains four 8bit registers totaling 32bits wide. How would I access bitfield 23:16 for both read and write; knowing I can only read and write 8 bits at a time?

  10. #25
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,185
    That depends on the specifics of how you can read and write 8 bits at a time.
    Is your IO address byte-based? If so, then with your address at 0x9804 the bitfield you want is 0x9805, and we're done. However, if you can only access aligned addresses, then you'll have to think. OTOH, if you can only read and write 8 bits at a time, I would be somewhat surprised to be restricted to an alignment.

    So the question is: can you read/write to address 0x9805?

  11. #26
    Registered User
    Join Date
    Sep 2008
    Posts
    22
    oh, your right, I am sure it must be aligned by doing ~3, just as I was doing with the pci config registers. I'll try though, brb.

    EDIT:

    I tried it and it returned the right value, but how would I align as I think I must.
    Last edited by jacob12; 10-12-2008 at 12:27 AM.

  12. #27
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,185
    Well, but wait. 0x9805 & ~3 is 0x9804. Can you do inb (or whatever your "read eight bits at a time" function is) on address 0x9805 (no ~3 stuff), or does it have to be aligned to a 32-bit boundary (which is what the ~3 is doing for you)?

  13. #28
    Registered User
    Join Date
    Sep 2008
    Posts
    22
    I think it must be aligned to a 32 bit boundary because each new base address starts with 0x00 as an offset and this one has two 32 bit boundaries one at offset 0x00 and the other at 0x04, then like I said the next base address starts with an offset of 0x00. I could show you the data sheet if you want.

    There are a total of 6 base addresses 5 of which are I/O addresses. The address I am after is the first base address (I/O) and it starts at 9800 with two offsets (0x00 and 0x04) each containing 32 bits, then the next base address (I/O) starts at 9C00 with one offset (0x00) containing 32 bits.

    EDIT: found out they are standard byte-aligned.
    Last edited by jacob12; 10-12-2008 at 12:54 AM.

  14. #29
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,185
    By "returned the right value", you mean you have a BYTE with the correct eight bits in it? If so, then that part's done. Or do you have an int, with the proper bits in 23..16? And then outb is probably the same way.

    As I said, if you can access just the eight bits at address 0x9805, then do so. Somewhere on your data sheet it should say whether those base addresses are the only places you can start or if you can get single bytes (or maybe the function that you're using has documentation). I don't know enough about PCI to be able to tell you. If you must start at 0x9804, then you'll need to read eight bits, throw them away, and then read the next eight bits.

    Edit: If they are byte-aligned, then address 0x9805 should be a perfectly cromulent address to read from/write to.
    Last edited by tabstop; 10-12-2008 at 12:57 AM.

  15. #30
    Registered User
    Join Date
    Sep 2008
    Posts
    22
    here is the data sheet: http://gkernel.sourceforge.net/specs...095-B2.pdf.bz2

    here is what I tried that returned what was written:

    Code:
    //let base = 9800
    unsigned char i;
    outb(base+0x05, 0x3F);
    i=inb(base+0x05);
    return: 0x3F

    my inb and outb are just inline asm to work with asm instructions inb and outb as normal. If I am to start at 9804 and throw away bytes how would I do that, in a loop counting down from 8? /me confused

Page 2 of 3 FirstFirst 123 LastLast
Popular pages Recent additions subscribe to a feed

Similar Threads

  1. DirectInput Device Access (DirectX 10)
    By DarkMasterBosel in forum Game Programming
    Replies: 0
    Last Post: 12-27-2008, 11:41 PM
  2. logical and physical device access
    By pastitprogram in forum Windows Programming
    Replies: 9
    Last Post: 08-05-2008, 04:46 PM
  3. brace-enclosed error
    By jdc18 in forum C++ Programming
    Replies: 53
    Last Post: 05-03-2007, 06:49 PM
  4. Device Driver: sysfs confusion
    By filker0 in forum Linux Programming
    Replies: 0
    Last Post: 12-02-2005, 11:36 AM
  5. Replies: 4
    Last Post: 06-30-2004, 04:11 PM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21