1

I am studying the IOUserSerial driverKit driver. My driver is able to detect a specify USB device. (The story that I don't use IOUserUSBSerial was depicted in this thread.)

This post inspired me to create a practice project with a loopback serial port that receive the data that serial program just send out. Therefore, I ignored the UART settings and underlying USB configuration at this moment.

Tty and cu devices in the /dev are created. I can also use following terminal command to open the serial port.

screen /dev/cu.serial-xxx

The system console printed following tracks indicating the serial startup procedure should be ok.

17:27:09.635215+0800    kernel  IOUserSerial::allocResources: 904 <==
17:27:09.635230+0800    kernel  IOUserSerial::allocResources: 904 locklevel = 1
17:27:09.635389+0800    kernel  IOUserSerial::ConnectQueues_Impl: 59 0x600001560058
17:27:09.635519+0800    kernel  IOUserSerial::allocResources: 904 ==>0
17:27:09.635524+0800    kernel  IOUserSerial::hwProgramMCR: 1115 <==
17:27:09.635525+0800    kernel  IOUserSerial::hwProgramMCR: 1115 locklevel = 1
17:27:09.635571+0800    kernel  IOUserSerial::hwProgramMCR: 1115 ==>0
17:27:09.635605+0800    kernel  IOUserSerial::HwActivate_Impl: 130 0x600001560058
17:27:09.635683+0800    kernel  IOUserSerial::hwResetFIFO: 1076 ==>0
17:27:09.635727+0800    kernel  IOUserSerial::hwResetFIFO: 1076 ==>0
                           : 
                       (Ignored)
                           : 
17:27:09.647165+0800    kernel  IOUserSerial::hwGetModemStatus: 1122 <==
17:27:09.647177+0800    kernel  IOUserSerial::hwGetModemStatus: 1122 locklevel = 1
17:27:09.647277+0800    kernel  IOUserSerial::hwGetModemStatus: 1122 ==>0

Then, I follow the ConnectQueue document to configure the interrupt, TX, and RX buffer in the Start().

When I strike a key in the screen program trying to send a byte to our driver. My overloaded TxDataAvailable method was called. However, if I try to print the content of the buffer mapping to the TX data, they are all zero.

void
IMPL(MyDriver, TxDataAvailable)
{
    kern_return_t ret = kIOReturnSuccess;
    
    Log("Entered %s", __FUNCTION__);

    // Some code is ignored to focus on TX buffer

    unsigned char * ptr = reinterpret_cast<unsigned char *>(ivars->tx_buf);
    static uint32_t idx;
    
    for( idx=0; idx<16; idx++ ){
        Log("[%02X]", ptr[idx]);
    }
}

I have tried both following way that ConnectQueue offered. They both don't work.

    // 1. Use system created buffer
    IOMemoryMap * pMap;
    
    ConnectQueues(&ivars->ifmd, &ivars->rxqmd, &ivars->txqmd, NULL, NULL, 0, 0, 0, 0, SUPERDISPATCH);
    
    // I have tried different options
    ivars->txqmd->CreateMapping(kIOMemoryMapCacheModeDefault, 0, 0, 0, 0, &pMap);
    ivars->tx_buf = pMap->GetAddress();
    // 2. Use manually created buffer
    // I have tried different buffer size, change the alignment to 0, 8, 4096 to fit the page alignment.
    IOBufferMemoryDescriptor::Create(kIOMemoryDirectionInOut, 8192, 4096, &ivars->in_txqmd);
    ivars->in_txqmd->GetAddressRange(&ioaddrseg);
    ivars->tx_buf = ioaddrseg.address;

    IOBufferMemoryDescriptor::Create(kIOMemoryDirectionInOut, 8192, 4096, &ivars->in_rxqmd);
    ivars->in_rxqmd->GetAddressRange(&ioaddrseg);
    ivars->rx_buf = ioaddrseg.address;
    
    ret = ConnectQueues(&ivars->ifmd, &ivars->rxqmd, &ivars->txqmd, ivars->in_rxqmd, ivars->in_txqmd, 0, 0, 13, 13, SUPERDISPATCH);
    if (ret != kIOReturnSuccess) {
        Log("ERR: @ %d, %s", __LINE__, __FUNCTION__);
        return ret;
    }

This article gave me some direction that I have tried to change different buffer size. I have also reviewed the IOKit memory management that I know there should be a kernel-user space memory mapping in somewhere of IOUserSerial::ConnectQueue(), but I can't dig more because they are warpped and all function calls return success.

The issue is so obviously, and moreover I found all Apple inbox driver are all subclass of IOUserUSBSerisl instead of IOUserSerial. I post this question to inquire if anybody subclassing IOUserSerial successfully? Any suggestion or prompt is appreciated.

Jason
  • 33
  • 3
  • I haven't experimented with SerialDriverKit, so I don't know about buffer sizes there, but I don't follow how [my answer to another question you linked to](https://stackoverflow.com/a/62214463/48660) implies a buffer size issue? In any case, surely the default buffers created by `ConnectQueues` will be of appropriate size. – pmdj Apr 20 '23 at 08:37
  • One thing I notice is that you're using `SUPERDISPATCH` in places where I wouldn't expect it to be necessary. Normally you use it to call the original implementation from an overridden method. Is there a particular reason for it here? Have you tried without `SUPERDISPATCH`? Are you checking return codes from `ConnectQueues` and `CreateMapping` in variant 1? I mean I'd expect it to crash with a `NULL` pointer dereference if it was failing outright or no-op'ing, but checking return codes and properties of returned objects is always a good idea when code isn't working as expected. – pmdj Apr 20 '23 at 08:42
  • Thank for your advise. I called ConnectQueues originally without SUPERDISPATCH. Using SUPERDISPATCH in snippet because I want to highlight that I don't override it. Also, all methods return kIOReturnSuccess in this snippet. I removed some return checking for a clear code. – Jason Apr 25 '23 at 15:14

0 Answers0