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.