// // rpitouchscreen.cpp // // This is based on the the Raspbian Linux driver: // // drivers/input/touchscreen/rpi-ft5406.c // // Driver for memory based ft5406 touchscreen // // Copyright (C) 2015 Raspberry Pi // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License version 2 as // published by the Free Software Foundation. // #include #include #include #include #include #include #include struct TFT5406Buffer { u8 DeviceMode; u8 GestureID; u8 NumPoints; struct { u8 xh; u8 xl; u8 yh; u8 yl; u8 Reserved[2]; } Point[RPITOUCH_SCREEN_MAX_POINTS]; }; #define FTS_TOUCH_DOWN 0 #define FTS_TOUCH_UP 1 #define FTS_TOUCH_CONTACT 2 static const char FromFT5406[] = "ft5406"; CRPiTouchScreen::CRPiTouchScreen (void) : m_pFT5406Buffer (0), m_nKnownIDs (0), m_pDevice (0) { } CRPiTouchScreen::~CRPiTouchScreen (void) { delete m_pDevice; m_pDevice = 0; m_pFT5406Buffer = 0; } boolean CRPiTouchScreen::Initialize (void) { assert (m_pFT5406Buffer == 0); uintptr nTouchBuffer = CMemorySystem::GetCoherentPage (COHERENT_SLOT_TOUCHBUF); CBcmPropertyTags Tags; TPropertyTagSimple TagSimple; TagSimple.nValue = BUS_ADDRESS (nTouchBuffer); if (!Tags.GetTag (PROPTAG_SET_TOUCHBUF, &TagSimple, sizeof TagSimple)) { if (!Tags.GetTag (PROPTAG_GET_TOUCHBUF, &TagSimple, sizeof TagSimple)) { CLogger::Get ()->Write (FromFT5406, LogError, "Cannot get touch buffer"); return FALSE; } if (TagSimple.nValue == 0) { CLogger::Get ()->Write (FromFT5406, LogError, "Touchscreen not detected"); return FALSE; } nTouchBuffer = TagSimple.nValue & ~0xC0000000; } m_pFT5406Buffer = (TFT5406Buffer *) nTouchBuffer; assert (m_pFT5406Buffer != 0); *(volatile u8 *) &m_pFT5406Buffer->NumPoints = 99; assert (m_pDevice == 0); m_pDevice = new CTouchScreenDevice (UpdateStub, this); assert (m_pDevice != 0); return TRUE; } void CRPiTouchScreen::Update (void) { TFT5406Buffer Regs; assert (m_pFT5406Buffer != 0); // Cannot use memcpy() here, because the optimizer may optimize this out, // and may generate unaligned memory accesses to uncached memory regions. volatile u8 *pDst = reinterpret_cast (&Regs); volatile u8 *pSrc = reinterpret_cast (m_pFT5406Buffer); size_t nLen = sizeof *m_pFT5406Buffer; while (nLen--) { *pDst++ = *pSrc++; } *(volatile u8 *) &m_pFT5406Buffer->NumPoints = 99; // Do not output if theres no new information (NumPoints is 99) // or we have no touch points and don't need to release any if ( Regs.NumPoints == 99 || ( Regs.NumPoints == 0 && m_nKnownIDs == 0)) { return; } assert (m_pDevice != 0); unsigned nModifiedIDs = 0; assert (Regs.NumPoints <= RPITOUCH_SCREEN_MAX_POINTS); for (unsigned i = 0; i < Regs.NumPoints; i++) { unsigned x = (((unsigned) Regs.Point[i].xh & 0xF) << 8) | Regs.Point[i].xl; unsigned y = (((unsigned) Regs.Point[i].yh & 0xF) << 8) | Regs.Point[i].yl; unsigned nTouchID = (Regs.Point[i].yh >> 4) & 0xF; unsigned nEventID = (Regs.Point[i].xh >> 6) & 0x3; assert (nTouchID < RPITOUCH_SCREEN_MAX_POINTS); nModifiedIDs |= 1 << nTouchID; if (nEventID == FTS_TOUCH_CONTACT || nEventID == FTS_TOUCH_DOWN) { if (!((1 << nTouchID) & m_nKnownIDs)) { m_nPosX[nTouchID] = x; m_nPosY[nTouchID] = y; m_pDevice->ReportHandler (TouchScreenEventFingerDown, nTouchID, x, y); } else { if ( x != m_nPosX[nTouchID] || y != m_nPosY[nTouchID]) { m_nPosX[nTouchID] = x; m_nPosY[nTouchID] = y; m_pDevice->ReportHandler (TouchScreenEventFingerMove, nTouchID, x, y); } } } } unsigned nReleasedIDs = m_nKnownIDs & ~nModifiedIDs; for (unsigned i = 0; nReleasedIDs != 0 && i < RPITOUCH_SCREEN_MAX_POINTS; i++) { if (nReleasedIDs & (1 << i)) { m_pDevice->ReportHandler (TouchScreenEventFingerUp, i, 0, 0); nModifiedIDs &= ~(1 << i); } } m_nKnownIDs = nModifiedIDs; } void CRPiTouchScreen::UpdateStub (void *pParam) { CRPiTouchScreen *pThis = static_cast (pParam); assert (pThis != 0); pThis->Update (); }