Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

6360 lines
207 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. hidphone.c
  5. Abstract:
  6. This module contains implements the phone tsp functions is called by
  7. tapi in order to access the HID compliant USB phone device.
  8. This module communicates with the phone device using the HID interface.
  9. Author: Shivani Aggarwal
  10. Comments:
  11. Locking Mechanism:
  12. There are two critical section objects being used inorder to protect
  13. the phone structure from simultaneous access - csAllPhones and
  14. csThisPhone. Every phone has one csThisPhone, the critical section
  15. object, associated with it. csThisPhone ensures that the Phone Info
  16. is accessed in a thread-safe manner. csAllPhones is a global Critical
  17. Section Object that ensures that a thread acquires the csThisPhone
  18. Critical Section Object in a thread safe manner. In other words, it
  19. ensures that, the thread waits on csThisPhone while the Critical
  20. Section Object is still valid.
  21. The csAllPhones should always be acquired before csThisPhone.
  22. A phone can be closed only after the thread has acquired both
  23. csAllPhones and csThisPhone for the specific phone to be closed. Both
  24. these objects are released only after the function is completed. For
  25. all other functions, the csAllPhones critical section is released as
  26. soon as the thread acquires csThisPhone object.
  27. ------------------------------------------------------------------------------*/
  28. #include "hidphone.h" //** NOTE - hidphone.h must be defined before mylog.h
  29. #include "mylog.h"
  30. BOOL
  31. WINAPI
  32. DllMain(
  33. HANDLE hDLL,
  34. DWORD dwReason,
  35. LPVOID lpReserved
  36. )
  37. {
  38. switch (dwReason)
  39. {
  40. case DLL_PROCESS_ATTACH:
  41. {
  42. // inorder to enable logging for this tsp
  43. LOGREGISTERDEBUGGER(_T("hidphone"));
  44. LOG((PHONESP_TRACE, "DllMain - DLL_PROCESS_ATTACH"));
  45. ghInst = hDLL;
  46. // if the heap cannot be created, use the heap from the process
  47. if (!(ghHeap = HeapCreate(
  48. 0, // NULL on failure,serialize access
  49. 0x1000, // initial heap size
  50. 0 // max heap size (0 == growable)
  51. )))
  52. {
  53. LOG((PHONESP_ERROR, "DllMain - HeapCreate failed %d", GetLastError()));
  54. ghHeap = GetProcessHeap();
  55. if (ghHeap == NULL)
  56. {
  57. LOG((PHONESP_ERROR, "DllMain - GetProcessHeap failed %d", GetLastError()));
  58. return GetLastError();
  59. }
  60. }
  61. // Inorder to diasble notifications of thread attach and detach in
  62. // multi-threaded apps it can be a very useful optimization
  63. DisableThreadLibraryCalls( hDLL );
  64. break;
  65. }
  66. case DLL_PROCESS_DETACH:
  67. {
  68. LOG((PHONESP_TRACE, "DllMain - DLL_PROCESS_DETACH"));
  69. LOGDEREGISTERDEBUGGER();
  70. // if ghHeap is NULL, then there is no heap to destroy
  71. if ( ( ghHeap != NULL) && ( ghHeap != GetProcessHeap() ) )
  72. {
  73. HeapDestroy (ghHeap);
  74. }
  75. break;
  76. }
  77. case DLL_THREAD_ATTACH:
  78. break;
  79. case DLL_THREAD_DETACH:
  80. break;
  81. } // switch
  82. return TRUE;
  83. }
  84. /*************************DLLMAIN - END***************************************/
  85. /******************************************************************************
  86. IsTSPAlreadyInstalled:
  87. Searchs registry for previous instance of HidPhone TSP.
  88. Arguments:
  89. none
  90. Returns BOOL:
  91. Returns true if TSP already installed
  92. Comments:
  93. ******************************************************************************/
  94. BOOL
  95. IsTSPAlreadyInstalled()
  96. {
  97. DWORD i;
  98. HKEY hKey;
  99. LONG lStatus;
  100. DWORD dwNumProviders = 0;
  101. DWORD dwDataSize = sizeof(DWORD);
  102. DWORD dwDataType = REG_DWORD;
  103. LPTSTR pszProvidersKey = TAPI_REGKEY_PROVIDERS;
  104. LPTSTR pszNumProvidersValue = TAPI_REGVAL_NUMPROVIDERS;
  105. TCHAR szName[MAX_PATH];
  106. TCHAR szPath[MAX_PATH];
  107. // attempt to open key
  108. lStatus = RegOpenKeyEx(
  109. HKEY_LOCAL_MACHINE,
  110. pszProvidersKey,
  111. 0,
  112. KEY_READ,
  113. &hKey
  114. );
  115. // validate status
  116. if (lStatus != ERROR_SUCCESS)
  117. {
  118. LOG((PHONESP_ERROR, "IsTSPAlreadyInstalled - "
  119. "error opening tapi providers key - %lx", lStatus));
  120. // done
  121. return FALSE;
  122. }
  123. // see if installed bit set
  124. lStatus = RegQueryValueEx(
  125. hKey,
  126. pszNumProvidersValue,
  127. 0,
  128. &dwDataType,
  129. (LPBYTE) &dwNumProviders,
  130. &dwDataSize
  131. );
  132. // validate status
  133. if( lStatus != ERROR_SUCCESS )
  134. {
  135. LOG((PHONESP_ERROR, "IsTSPAlreadyInstalled - "
  136. "error determining number of providers - %lx", lStatus));
  137. // release handle
  138. RegCloseKey(hKey);
  139. // done
  140. return FALSE;
  141. }
  142. // loop through each provider
  143. for (i = 0; i < dwNumProviders; i++)
  144. {
  145. // construct path to provider name
  146. wsprintf(szName, _T("ProviderFileName%d"), i);
  147. // reinitialize size
  148. dwDataSize = sizeof(szPath);
  149. // query the next name
  150. lStatus = RegQueryValueEx(
  151. hKey,
  152. szName,
  153. 0,
  154. &dwDataType,
  155. (unsigned char*)szPath,
  156. &dwDataSize
  157. );
  158. // validate status
  159. if (lStatus == ERROR_SUCCESS)
  160. {
  161. // upper case
  162. _tcsupr(szPath);
  163. // compare path string to hidphone provider
  164. if (_tcsstr(szPath, HIDPHONE_TSPDLL) != NULL)
  165. {
  166. // release handle
  167. RegCloseKey(hKey);
  168. // done
  169. return TRUE;
  170. }
  171. }
  172. else
  173. {
  174. LOG((PHONESP_ERROR, "IsTSPAlreadyInstalled - "
  175. "error querying %s - %lx", szName, lStatus));
  176. }
  177. }
  178. // release handle
  179. RegCloseKey(hKey);
  180. // done
  181. return FALSE;
  182. }
  183. /******************************************************************************
  184. ReenumDevices:
  185. This function reenumerated hid devices after a pnp event. It will
  186. create phone devices for new hid arrivals and remove phone devices
  187. (provided they are closed) for hid removals. It will also notify
  188. TAPI of these events.
  189. Arguments:
  190. none
  191. Returns VOID:
  192. Comments:
  193. ******************************************************************************/
  194. VOID
  195. ReenumDevices ()
  196. {
  197. PHID_DEVICE pHidDevices;
  198. PHID_DEVICE pHidDevice;
  199. PHID_DEVICE pNextHidDevice;
  200. ULONG NumHidDevices;
  201. DWORD dwNewCount;
  202. DWORD dwRemovedCount;
  203. DWORD dwPhone;
  204. LONG lResult;
  205. PPHONESP_PHONE_INFO pPhone;
  206. LOG((PHONESP_TRACE, "ReenumDevices - enter"));
  207. EnterCriticalSection(&csHidList);
  208. // Find Telephony hid Devices
  209. lResult = FindKnownHidDevices (&pHidDevices,
  210. &NumHidDevices);
  211. LOG((PHONESP_TRACE, "ReenumDevices - number of Hid Devices : %d ", NumHidDevices));
  212. dwNewCount = 0;
  213. dwRemovedCount = 0;
  214. EnterCriticalSection(&csAllPhones);
  215. for (pHidDevice = pHidDevices; pHidDevice != NULL; pHidDevice = pNextHidDevice)
  216. {
  217. //
  218. // Get pointer to the next Hid device now, so we can remove the current
  219. // device if necessary without messing up our search
  220. //
  221. pNextHidDevice = pHidDevice->Next;
  222. if (pHidDevice->bRemoved)
  223. {
  224. //
  225. // This device has been removed
  226. //
  227. dwRemovedCount++;
  228. pPhone = GetPhoneFromHid(pHidDevice);
  229. // Check whether the phone handle is still valid
  230. if ( !IsBadReadPtr(pPhone,sizeof(PHONESP_PHONE_INFO) ))
  231. {
  232. EnterCriticalSection(&pPhone->csThisPhone);
  233. //
  234. // First lets get rid of the Hid device since it has already
  235. // physically left the system
  236. //
  237. pPhone->pHidDevice = NULL;
  238. CloseHidDevice(pHidDevice);
  239. //
  240. // Send a phone remove to TAPI
  241. //
  242. SendPhoneEvent(
  243. pPhone,
  244. PHONE_REMOVE,
  245. pPhone->dwDeviceID,
  246. 0,
  247. 0
  248. );
  249. if (pPhone->bPhoneOpen)
  250. {
  251. //
  252. // The phone is open, we can't remove it right away so
  253. // mark it remove pending
  254. //
  255. pPhone->bRemovePending = TRUE;
  256. LOG((PHONESP_TRACE, "ReenumDevices - phone remove pending [dwDeviceID %d] ", pPhone->dwDeviceID));
  257. }
  258. else
  259. {
  260. //
  261. // The phone is closed, we can remove it now
  262. //
  263. FreePhone(pPhone);
  264. LOG((PHONESP_TRACE, "ReenumDevices - phone remove complete [dwDeviceID %d] ", pPhone->dwDeviceID));
  265. }
  266. LeaveCriticalSection(&pPhone->csThisPhone);
  267. }
  268. else
  269. {
  270. LOG((PHONESP_ERROR, "ReenumDevices - GetPhoneFromHid returned an invalid phone pointer"));
  271. }
  272. }
  273. else if (pHidDevice->bNew)
  274. {
  275. BOOL bFound = FALSE;
  276. //
  277. // This device is new
  278. //
  279. dwNewCount++;
  280. pHidDevice->bNew = FALSE;
  281. //
  282. // We need to create a new phone device, find a spot
  283. //
  284. for (dwPhone = 0; dwPhone < gdwNumPhones; dwPhone++)
  285. {
  286. pPhone = (PPHONESP_PHONE_INFO) gpPhone[ dwPhone ];
  287. EnterCriticalSection(&pPhone->csThisPhone);
  288. if ( !pPhone->bAllocated && !pPhone->bCreatePending )
  289. {
  290. //
  291. // We have an open slot for this phone
  292. //
  293. LOG((PHONESP_TRACE, "ReenumDevices - slot %d open", dwPhone));
  294. bFound = TRUE;
  295. LeaveCriticalSection(&pPhone->csThisPhone);
  296. break;
  297. }
  298. LeaveCriticalSection(&pPhone->csThisPhone);
  299. }
  300. if (!bFound)
  301. {
  302. //
  303. // We don't have a slot open, so we will have to realloc the
  304. // array to create a new one
  305. //
  306. PPHONESP_PHONE_INFO *pNewPhones;
  307. LOG((PHONESP_TRACE, "ReenumDevices - creating a new slot"));
  308. if ( ! ( pNewPhones = MemAlloc((gdwNumPhones + 1) * sizeof(PPHONESP_PHONE_INFO)) ) )
  309. {
  310. LOG((PHONESP_ERROR,"ReenumDevices - out of memory "));
  311. }
  312. else
  313. {
  314. CopyMemory(
  315. pNewPhones,
  316. gpPhone,
  317. sizeof(PPHONESP_PHONE_INFO) * gdwNumPhones
  318. );
  319. // Allocate memory for this phone
  320. if ( pNewPhones[gdwNumPhones] = (PPHONESP_PHONE_INFO)MemAlloc(sizeof(PHONESP_PHONE_INFO)) )
  321. {
  322. LOG((PHONESP_TRACE, "ReenumDevices - initializing device: %d",gdwNumPhones+1));
  323. ZeroMemory( pNewPhones[gdwNumPhones], sizeof(PHONESP_PHONE_INFO));
  324. //
  325. // Initialize the critical section object for this phone. only the
  326. // thread that owns this object can access the structure for this phone
  327. //
  328. __try
  329. {
  330. InitializeCriticalSection( &pNewPhones[gdwNumPhones]->csThisPhone );
  331. }
  332. __except(1)
  333. {
  334. MemFree(pNewPhones[gdwNumPhones]);
  335. MemFree(pNewPhones);
  336. pNewPhones = NULL;
  337. LOG((PHONESP_ERROR,"ReenumDevices - Initialize Critical Section"
  338. " Failed for Phone %d", gdwNumPhones+1));
  339. }
  340. if ( pNewPhones != NULL )
  341. {
  342. //
  343. // Success
  344. //
  345. LOG((PHONESP_TRACE, "ReenumDevices - slot %d created", gdwNumPhones));
  346. dwPhone = gdwNumPhones;
  347. pPhone = pNewPhones[dwPhone];
  348. bFound = TRUE;
  349. MemFree(gpPhone);
  350. gpPhone = pNewPhones;
  351. gdwNumPhones++;
  352. }
  353. }
  354. else
  355. {
  356. MemFree(pNewPhones);
  357. LOG((PHONESP_ERROR,"ReenumDevices - out of memory "));
  358. }
  359. }
  360. }
  361. if (bFound)
  362. {
  363. //
  364. // Now actually create the phone
  365. //
  366. EnterCriticalSection(&pPhone->csThisPhone);
  367. lResult = CreatePhone( pPhone, pHidDevice, dwPhone );
  368. if ( lResult != ERROR_SUCCESS )
  369. {
  370. LOG((PHONESP_ERROR,"ReenumDevices - CreatePhone"
  371. " Failed for Phone %d: error: %d", dwPhone, lResult));
  372. }
  373. else
  374. {
  375. // Phone created successfully, send a PHONE_CREATE message
  376. pPhone->bCreatePending = TRUE;
  377. SendPhoneEvent(
  378. pPhone,
  379. PHONE_CREATE,
  380. (DWORD_PTR)ghProvider,
  381. dwPhone,
  382. 0
  383. );
  384. LOG((PHONESP_TRACE, "ReenumDevices - phone create pending [dwTempID %d] ", dwPhone));
  385. }
  386. LeaveCriticalSection(&pPhone->csThisPhone);
  387. }
  388. else
  389. {
  390. LOG((PHONESP_ERROR, "ReenunDevices - unable to create new phone"));
  391. }
  392. }
  393. }
  394. LeaveCriticalSection(&csAllPhones);
  395. LeaveCriticalSection(&csHidList);
  396. LOG((PHONESP_TRACE, "ReenumDevices - new : %d ", dwNewCount));
  397. LOG((PHONESP_TRACE, "ReenumDevices - removed : %d ", dwRemovedCount));
  398. LOG((PHONESP_TRACE, "ReenumDevices - exit"));
  399. }
  400. /******************************************************************************
  401. FreePhone:
  402. This function frees all of a phones data structures
  403. Arguments:
  404. PPHONESP_PHONE_INFO pPhone
  405. Returns VOID:
  406. Comments:
  407. ******************************************************************************/
  408. VOID
  409. FreePhone (
  410. PPHONESP_PHONE_INFO pPhone
  411. )
  412. {
  413. DWORD dwButtonCnt;
  414. LOG((PHONESP_TRACE, "FreePhone - enter"));
  415. // Check whether the phone handle is still valid
  416. if ( IsBadReadPtr(pPhone,sizeof(PHONESP_PHONE_INFO) ))
  417. {
  418. LOG((PHONESP_ERROR, "FreePhone - phone handle invalid"));
  419. return;
  420. }
  421. if ( !pPhone->bAllocated )
  422. {
  423. LOG((PHONESP_ERROR, "FreePhone - phone not allocated"));
  424. return;
  425. }
  426. for (dwButtonCnt = 0;
  427. dwButtonCnt < pPhone->dwNumButtons; dwButtonCnt++)
  428. {
  429. if (pPhone->pButtonInfo[dwButtonCnt].szButtonText != NULL)
  430. {
  431. MemFree(pPhone->pButtonInfo[dwButtonCnt].szButtonText);
  432. pPhone->pButtonInfo[dwButtonCnt].szButtonText = NULL;
  433. }
  434. }
  435. if (pPhone->pButtonInfo != NULL)
  436. {
  437. MemFree(pPhone->pButtonInfo);
  438. pPhone->pButtonInfo = NULL;
  439. }
  440. if (pPhone->wszPhoneInfo != NULL)
  441. {
  442. MemFree((LPVOID) pPhone->wszPhoneInfo);
  443. pPhone->wszPhoneInfo = NULL;
  444. }
  445. if (pPhone->wszPhoneName != NULL)
  446. {
  447. MemFree((LPVOID) pPhone->wszPhoneName);
  448. pPhone->wszPhoneName = NULL;
  449. }
  450. pPhone->bAllocated = FALSE;
  451. LOG((PHONESP_TRACE, "FreePhone - exit"));
  452. }
  453. /******************************************************************************
  454. UpdatePhoneFeatures:
  455. This function reads feature values from the phone.
  456. Arguments:
  457. PPHONESP_PHONE_INFO pPhone
  458. Returns VOID:
  459. Comments:
  460. ******************************************************************************/
  461. VOID UpdatePhoneFeatures(
  462. PPHONESP_PHONE_INFO pPhone
  463. )
  464. {
  465. LOG((PHONESP_TRACE, "UpdatePhoneFeatures - enter"));
  466. if( pPhone->pHidDevice->Caps.NumberFeatureValueCaps ||
  467. pPhone->pHidDevice->Caps.NumberFeatureButtonCaps )
  468. {
  469. USAGE UsagePage;
  470. USAGE Usage;
  471. if (GetFeature(pPhone->pHidDevice))
  472. {
  473. DWORD dwDataCnt;
  474. PHID_DATA pHidData;
  475. pHidData = pPhone->pHidDevice->FeatureData;
  476. for ( dwDataCnt = 0, pHidData = pPhone->pHidDevice->FeatureData;
  477. dwDataCnt < pPhone->pHidDevice->FeatureDataLength;
  478. dwDataCnt++, pHidData++ )
  479. {
  480. UsagePage = pHidData->UsagePage;
  481. if (UsagePage == HID_USAGE_PAGE_TELEPHONY)
  482. {
  483. if(pHidData->IsButtonData)
  484. {
  485. for ( Usage = (USAGE)pHidData->ButtonData.UsageMin;
  486. Usage <= (USAGE)pHidData->ButtonData.UsageMax;
  487. Usage++ )
  488. {
  489. DWORD i;
  490. for (i = 0;
  491. i < pHidData->ButtonData.MaxUsageLength;
  492. i++)
  493. {
  494. if(Usage == pHidData->ButtonData.Usages[i])
  495. {
  496. LOG((PHONESP_TRACE,"Button for Usage "
  497. "0x%04x ON",Usage));
  498. InitUsage(pPhone, Usage, TRUE);
  499. break;
  500. }
  501. }
  502. if ( i == pHidData->ButtonData.MaxUsageLength)
  503. {
  504. InitUsage(pPhone, Usage, FALSE);
  505. }
  506. }
  507. }
  508. else
  509. {
  510. InitUsage(pPhone, pHidData->ValueData.Usage,
  511. pHidData->ValueData.Value);
  512. }
  513. }
  514. }
  515. }
  516. else
  517. {
  518. LOG((PHONESP_ERROR, "UpdatePhoneFeatures - GetFeature failed"));
  519. }
  520. }
  521. else
  522. {
  523. LOG((PHONESP_TRACE, "UpdatePhoneFeatures - NO FEATURE"));
  524. }
  525. LOG((PHONESP_TRACE, "UpdatePhoneFeatures - exit"));
  526. }
  527. /******************************************************************************
  528. CreatePhone:
  529. This function creates all of a phones data structures
  530. Arguments:
  531. PPHONESP_PHONE_INFO pPhone
  532. PHID_DEVICE pHidDevice
  533. Returns LONG:
  534. Comments:
  535. ******************************************************************************/
  536. LONG
  537. CreatePhone (
  538. PPHONESP_PHONE_INFO pPhone,
  539. PHID_DEVICE pHidDevice,
  540. DWORD dwPhoneCnt
  541. )
  542. {
  543. LONG lResult;
  544. LPWSTR wszPhoneName, wszPhoneInfo;
  545. WCHAR wszPhoneID[MAX_CHARS];
  546. PHIDP_BUTTON_CAPS pButtonCaps;
  547. PHIDP_VALUE_CAPS pValueCaps;
  548. HRESULT hr;
  549. LOG((PHONESP_TRACE, "CreatePhone - enter"));
  550. // Check whether the phone handle is still valid
  551. if ( IsBadReadPtr(pPhone,sizeof(PHONESP_PHONE_INFO) ))
  552. {
  553. LOG((PHONESP_ERROR, "CreatePhone - phone handle invalid"));
  554. return PHONEERR_INVALPHONEHANDLE;
  555. }
  556. if ( IsBadReadPtr(pHidDevice,sizeof(PHID_DEVICE) ))
  557. {
  558. LOG((PHONESP_ERROR, "CreatePhone - hid device pointer invalid"));
  559. return PHONEERR_OPERATIONFAILED;
  560. }
  561. if ( pPhone->bAllocated )
  562. {
  563. LOG((PHONESP_ERROR, "CreatePhone - phone already allocated"));
  564. return PHONEERR_OPERATIONFAILED;
  565. }
  566. // Load Phone Info From String Table
  567. wszPhoneInfo = PHONESP_LoadString(
  568. IDS_PHONE_INFO,
  569. &lResult
  570. );
  571. if ( lResult != ERROR_SUCCESS )
  572. {
  573. if ( lResult == ERROR_OUTOFMEMORY )
  574. {
  575. LOG((PHONESP_ERROR, "CreatePhone - "
  576. "PHONESP_LoadString out of memory"));
  577. return PHONEERR_NOMEM;
  578. }
  579. else
  580. {
  581. LOG((PHONESP_ERROR, "CreatePhone - "
  582. "PHONESP_LoadString failed %d", lResult));
  583. return lResult;
  584. }
  585. }
  586. // Load Phone Name From String Table
  587. wszPhoneName = PHONESP_LoadString(
  588. IDS_PHONE_NAME,
  589. &lResult
  590. );
  591. if ( lResult != ERROR_SUCCESS )
  592. {
  593. MemFree((LPVOID)wszPhoneInfo);
  594. if ( lResult == ERROR_OUTOFMEMORY )
  595. {
  596. LOG((PHONESP_ERROR, "CreatePhone - "
  597. "PHONESP_LoadString out of memory"));
  598. return PHONEERR_NOMEM;
  599. }
  600. else
  601. {
  602. LOG((PHONESP_ERROR, "CreatePhone - "
  603. "PHONESP_LoadString failed %d", lResult));
  604. return lResult;
  605. }
  606. }
  607. //
  608. // Associate phone with the hid and wave devices
  609. //
  610. pPhone->bAllocated = TRUE;
  611. pPhone->pHidDevice = pHidDevice;
  612. // Discover Render Wave ID
  613. hr = DiscoverAssociatedWaveId(pHidDevice->dwDevInst,
  614. TRUE,
  615. &pPhone->dwRenderWaveId);
  616. if (hr != S_OK)
  617. {
  618. pPhone->bRender = FALSE;
  619. LOG((PHONESP_ERROR, "CreatePhone - DiscoverAssociatedWaveID:"
  620. " Render Failed for Phone %d: %0x", dwPhoneCnt, hr));
  621. }
  622. else
  623. {
  624. pPhone->bRender = TRUE;
  625. LOG((PHONESP_TRACE,"CreatePhone - DiscoverAssociatedWaveId for Render: %d",
  626. pPhone->dwRenderWaveId));
  627. }
  628. // Discover Capture Wave ID
  629. hr = DiscoverAssociatedWaveId(pHidDevice->dwDevInst,
  630. FALSE,
  631. &pPhone->dwCaptureWaveId);
  632. if (hr != S_OK)
  633. {
  634. pPhone->bCapture = FALSE;
  635. LOG((PHONESP_ERROR, "CreatePhone - DiscoverAssociatedWaveID:"
  636. " Capture Failed for Phone %d: %0x", dwPhoneCnt, hr));
  637. }
  638. else
  639. {
  640. pPhone->bCapture = TRUE;
  641. LOG((PHONESP_TRACE,"CreatePhone - DiscoverAssociatedWaveId for Capture: %d",
  642. pPhone->dwCaptureWaveId));
  643. }
  644. pPhone->dwButtonModesMsgs = PHONESP_ALLBUTTONMODES;
  645. pPhone->dwButtonStateMsgs = PHONESP_ALLBUTTONSTATES;
  646. //
  647. // Extract Usages and Initialize the phone structure
  648. //
  649. // Get the usages from the HID structure
  650. // Parse input button caps structure
  651. LOG((PHONESP_TRACE, "CreatePhone - INPUT BUTTON CAPS"));
  652. pButtonCaps = pHidDevice->InputButtonCaps;
  653. GetButtonUsages(
  654. pPhone,
  655. pButtonCaps,
  656. pHidDevice->Caps.NumberInputButtonCaps,
  657. INPUT_REPORT
  658. );
  659. // Parse output button caps structure
  660. LOG((PHONESP_TRACE, "CreatePhone - OUTPUT BUTTON CAPS" ));
  661. pButtonCaps = pHidDevice->OutputButtonCaps;
  662. GetButtonUsages(
  663. pPhone,
  664. pButtonCaps,
  665. pHidDevice->Caps.NumberOutputButtonCaps,
  666. OUTPUT_REPORT
  667. );
  668. // Parse feature button caps structure
  669. LOG((PHONESP_TRACE, "CreatePhone - FEATURE BUTTON CAPS" ));
  670. pButtonCaps = pHidDevice->FeatureButtonCaps;
  671. GetButtonUsages(
  672. pPhone,
  673. pButtonCaps,
  674. pHidDevice->Caps.NumberFeatureButtonCaps,
  675. FEATURE_REPORT
  676. );
  677. // Parse input value caps structure
  678. LOG((PHONESP_TRACE, "CreatePhone - INPUT VALUE CAPS"));
  679. pValueCaps = pHidDevice->InputValueCaps;
  680. GetValueUsages(
  681. pPhone,
  682. pValueCaps,
  683. pHidDevice->Caps.NumberInputValueCaps,
  684. INPUT_REPORT
  685. );
  686. // Parse output value caps structure
  687. LOG((PHONESP_TRACE, "CreatePhone - OUTPUT VALUE CAPS" ));
  688. pValueCaps = pHidDevice->OutputValueCaps;
  689. GetValueUsages(
  690. pPhone,
  691. pValueCaps,
  692. pHidDevice->Caps.NumberOutputValueCaps,
  693. OUTPUT_REPORT
  694. );
  695. // Parse feature value caps structure
  696. LOG((PHONESP_TRACE, "CreatePhone - FEATURE VALUE CAPS" ));
  697. pValueCaps = pHidDevice->FeatureValueCaps;
  698. GetValueUsages(
  699. pPhone,
  700. pValueCaps,
  701. pHidDevice->Caps.NumberFeatureValueCaps,
  702. FEATURE_REPORT
  703. );
  704. //
  705. // The Phone should have a handset with input and feature
  706. // reports supported. If it does not the phone will not be supported
  707. // by this TSP. If this part of the code is uncommented, then the nokia
  708. // box will be the unsupported phone device since it does not contain
  709. // a feature report for the handset
  710. //
  711. if ( !( pPhone->dwHandset & INPUT_REPORT ) )
  712. {
  713. LOG((PHONESP_ERROR,"CreatePhone - This Phone not Supported"));
  714. MemFree((LPVOID) wszPhoneInfo);
  715. MemFree((LPVOID) wszPhoneName);
  716. FreePhone(pPhone);
  717. return PHONEERR_OPERATIONFAILED;
  718. }
  719. //
  720. // Store the Phone ID as a string Value
  721. //
  722. wsprintf(wszPhoneID, TEXT(": %d"), dwPhoneCnt);
  723. //
  724. // Allocate space for storing the Phone Info
  725. //
  726. pPhone->wszPhoneInfo = (LPWSTR) MemAlloc ( (lstrlen(wszPhoneInfo) +
  727. lstrlen(wszPhoneID) + 1 ) *
  728. sizeof(WCHAR) );
  729. if( NULL == pPhone->wszPhoneInfo)
  730. {
  731. LOG((PHONESP_ERROR,"CreatePhone - unable to allocate wszPhoneInfo"));
  732. MemFree((LPVOID) wszPhoneInfo);
  733. MemFree((LPVOID) wszPhoneName);
  734. FreePhone(pPhone);
  735. return PHONEERR_NOMEM;
  736. }
  737. //
  738. // Copy the Phone Info in the phone structure and append it with
  739. // the Phone ID
  740. //
  741. lstrcpy(pPhone->wszPhoneInfo,wszPhoneInfo);
  742. lstrcat(pPhone->wszPhoneInfo,wszPhoneID);
  743. pPhone->wszPhoneName = (LPWSTR)MemAlloc ( ( lstrlen(wszPhoneName) +
  744. lstrlen(wszPhoneID) +
  745. 1 ) * sizeof(WCHAR) );
  746. if( NULL == pPhone->wszPhoneName)
  747. {
  748. LOG((PHONESP_ERROR,"CreatePhone - unable to allocate wszPhoneName"));
  749. MemFree((LPVOID) wszPhoneInfo);
  750. MemFree((LPVOID) wszPhoneName);
  751. FreePhone(pPhone);
  752. return PHONEERR_NOMEM;
  753. }
  754. //
  755. // Copy the Phone Name in the phone structure and append it with
  756. // the Phone ID
  757. //
  758. lstrcpy(pPhone->wszPhoneName,wszPhoneName);
  759. lstrcat(pPhone->wszPhoneName,wszPhoneID);
  760. //
  761. // Create Buttons for the ones discovered by tracking the usages
  762. //
  763. if ( CreateButtonsAndAssignID(pPhone) != ERROR_SUCCESS)
  764. {
  765. LOG((PHONESP_ERROR,"CreatePhone - CreateButtonsAndAssignID failed"));
  766. MemFree((LPVOID) wszPhoneInfo);
  767. MemFree((LPVOID) wszPhoneName);
  768. FreePhone(pPhone);
  769. return PHONEERR_NOMEM;
  770. }
  771. //
  772. // Get initial values for phone features (such as hookswitch state)
  773. //
  774. UpdatePhoneFeatures( pPhone );
  775. //
  776. // Close the file handle
  777. //
  778. if ( !CloseHidFile(pPhone->pHidDevice) )
  779. {
  780. LOG((PHONESP_ERROR, "CreatePhone - CloseHidFile failed"));
  781. }
  782. MemFree((LPVOID) wszPhoneInfo);
  783. MemFree((LPVOID) wszPhoneName);
  784. LOG((PHONESP_TRACE, "CreatePhone - exit"));
  785. return ERROR_SUCCESS;
  786. }
  787. /******************************************************************************
  788. NotifWndProc:
  789. This function handles the pnp events for which this tsp has registered for
  790. Arguments:
  791. HWND hwnd
  792. UINT uMsg
  793. WPARAM wParam
  794. LPARAM lParam
  795. Returns LRESULT:
  796. Comments:
  797. ******************************************************************************/
  798. LRESULT CALLBACK NotifWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  799. {
  800. switch (uMsg)
  801. {
  802. case WM_DEVICECHANGE:
  803. switch(wParam)
  804. {
  805. case DBT_DEVICEARRIVAL:
  806. LOG((PHONESP_TRACE, "NotifWndProc - DBT_DEVICEARRIVAL"));
  807. ReenumDevices();
  808. break;
  809. case DBT_DEVICEREMOVECOMPLETE:
  810. LOG((PHONESP_TRACE, "NotifWndProc - DBT_DEVICEREMOVECOMPLETE"));
  811. ReenumDevices();
  812. break;
  813. }
  814. break;
  815. case WM_CREATE:
  816. LOG((PHONESP_TRACE, "NotifWndProc - WM_CREATE"));
  817. break;
  818. case WM_DESTROY:
  819. LOG((PHONESP_TRACE, "NotifWndProc - WM_DESTROY"));
  820. break;
  821. default:
  822. return DefWindowProc(hwnd, uMsg, wParam, lParam);
  823. }
  824. return 0;
  825. }
  826. /********************************NotifWndProc - end***************************/
  827. /******************************************************************************
  828. AsyncEventQueueServiceThread:
  829. This routine services, in a serialized manner, the requests present in the
  830. Async Queue. If no requests are currently outstanding, it waits for an
  831. Event which happens when the queue has currently no requests and a new
  832. request comes in.
  833. Arguments:
  834. LPVOID pParams: Any Information that needs to be passed to the thread
  835. when startup. Currently no information is being passed.
  836. Return Parameter: Void
  837. ******************************************************************************/
  838. VOID
  839. AsyncEventQueueServiceThread(
  840. LPVOID pParams
  841. )
  842. {
  843. WNDCLASS wc;
  844. ATOM atom;
  845. LOG((PHONESP_TRACE, "AsyncEventQueueServiceThread - enter"));
  846. //
  847. // Create a window to receive PNP device notifications
  848. //
  849. ZeroMemory(&wc, sizeof(wc));
  850. wc.lpfnWndProc = NotifWndProc;
  851. wc.lpszClassName = TEXT("HidPhoneNotifClass");
  852. if (!(atom = RegisterClass(&wc)))
  853. {
  854. LOG((PHONESP_ERROR, "AsyncEventQueueServiceThread - can't register window class %08x", GetLastError()));
  855. }
  856. else
  857. {
  858. ghWndNotify = CreateWindow((LPCTSTR)atom, TEXT(""), 0,
  859. CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, NULL, NULL);
  860. if (ghWndNotify == NULL)
  861. {
  862. LOG((PHONESP_ERROR, "AsyncEventQueueServiceThread - can't create notification window"));
  863. }
  864. else
  865. {
  866. DEV_BROADCAST_DEVICEINTERFACE NotificationFilter;
  867. LOG((PHONESP_TRACE, "AsyncEventQueueServiceThread - created notification window"));
  868. //
  869. // Register to receive PNP device notifications
  870. //
  871. ZeroMemory( &NotificationFilter, sizeof(NotificationFilter) );
  872. NotificationFilter.dbcc_size =
  873. sizeof(DEV_BROADCAST_DEVICEINTERFACE);
  874. NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
  875. NotificationFilter.dbcc_classguid = GUID_CLASS_INPUT;
  876. if ((ghDevNotify = RegisterDeviceNotification( ghWndNotify,
  877. &NotificationFilter,
  878. DEVICE_NOTIFY_WINDOW_HANDLE
  879. )) == NULL)
  880. {
  881. LOG((PHONESP_ERROR, "AsyncEventQueueServiceThread - can't register for input device notification"));
  882. }
  883. else
  884. {
  885. LOG((PHONESP_TRACE, "AsyncEventQueueServiceThread - registered for PNP device notifications"));
  886. }
  887. }
  888. }
  889. while (!gbProviderShutdown)
  890. {
  891. // Waiting for a new request to arrive since the queue is currently
  892. // empty
  893. DWORD dwResult;
  894. MSG msg;
  895. dwResult = MsgWaitForMultipleObjectsEx(
  896. 1, // wait for one event
  897. &gAsyncQueue.hAsyncEventsPendingEvent, // array of events to wait for
  898. INFINITE, // wait forever
  899. QS_ALLINPUT, // get all window messages
  900. 0 // return when an event is signaled
  901. );
  902. if ( ( dwResult == WAIT_OBJECT_0 ) || ( dwResult == WAIT_OBJECT_0 + 1 ) )
  903. {
  904. LOG((PHONESP_TRACE, "AsyncEventQueueServiceThread - thread is signaled"));
  905. while (1)
  906. {
  907. PPHONESP_ASYNC_REQ_INFO pAsyncReqInfo;
  908. PPHONESP_PHONE_INFO pPhone;
  909. EnterCriticalSection (&gAsyncQueue.AsyncEventQueueCritSec);
  910. // No requests in the queue present - wait for a new request
  911. if (gAsyncQueue.dwNumUsedQueueEntries == 0)
  912. {
  913. ResetEvent (gAsyncQueue.hAsyncEventsPendingEvent);
  914. LeaveCriticalSection (&gAsyncQueue.AsyncEventQueueCritSec);
  915. break;
  916. }
  917. pAsyncReqInfo = *gAsyncQueue.pAsyncRequestQueueOut;
  918. // Increment the next-request-to-be-serviced counter
  919. gAsyncQueue.pAsyncRequestQueueOut++;
  920. //
  921. // The queue is maintained a circular queue. If the bottom of the
  922. // circular queue is reached, go back to the top and process the
  923. // requests if any.
  924. //
  925. if (gAsyncQueue.pAsyncRequestQueueOut ==
  926. (gAsyncQueue.pAsyncRequestQueue +
  927. gAsyncQueue.dwNumTotalQueueEntries))
  928. {
  929. gAsyncQueue.pAsyncRequestQueueOut =
  930. gAsyncQueue.pAsyncRequestQueue;
  931. }
  932. // Decrement the number of outstanding requests present in queue
  933. gAsyncQueue.dwNumUsedQueueEntries--;
  934. LeaveCriticalSection (&gAsyncQueue.AsyncEventQueueCritSec);
  935. // If async function for the request exists - call the function
  936. if (pAsyncReqInfo->pfnAsyncProc)
  937. {
  938. (*(pAsyncReqInfo->pfnAsyncProc))(
  939. pAsyncReqInfo->pFuncInfo
  940. );
  941. }
  942. pPhone = (PPHONESP_PHONE_INFO) pAsyncReqInfo->pFuncInfo->dwParam1;
  943. // Decrement the counter of pending requests for this phone
  944. if ( pPhone )
  945. {
  946. EnterCriticalSection(&pPhone->csThisPhone);
  947. pPhone->dwNumPendingReqInQueue--;
  948. // if there are no requests pending for this phone
  949. // Set no requests pending event on this phone
  950. if (pPhone->dwNumPendingReqInQueue == 0 )
  951. {
  952. SetEvent(pPhone->hNoPendingReqInQueueEvent);
  953. }
  954. LeaveCriticalSection(&pPhone->csThisPhone);
  955. }
  956. // The memory allocated for the processed request is freed.
  957. MemFree(pAsyncReqInfo->pFuncInfo);
  958. MemFree(pAsyncReqInfo);
  959. }
  960. //
  961. // We have processed all commands and unblocked everyone
  962. // who is waiting for us. Now check for window messages.
  963. //
  964. while ( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) )
  965. {
  966. TranslateMessage(&msg);
  967. DispatchMessage(&msg);
  968. }
  969. }
  970. }
  971. LOG((PHONESP_TRACE, "AsyncEventQueueServiceThread - shutdown"));
  972. //
  973. // Unregister for PNP device notifications and destroy window
  974. //
  975. if ( NULL != ghDevNotify )
  976. {
  977. if (!UnregisterDeviceNotification(ghDevNotify))
  978. {
  979. LOG((PHONESP_ERROR, "AsyncEventQueueServiceThread - "
  980. "can't unregister device notification %d", GetLastError()));
  981. }
  982. ghDevNotify = NULL;
  983. }
  984. if ( NULL != ghWndNotify )
  985. {
  986. if (!DestroyWindow(ghWndNotify))
  987. {
  988. LOG((PHONESP_ERROR, "AsyncEventQueueServiceThread - "
  989. "can't destroy notification window %d", GetLastError()));
  990. }
  991. ghWndNotify = NULL;
  992. }
  993. if (!UnregisterClass((LPCTSTR)atom, GetModuleHandle(NULL)))
  994. {
  995. LOG((PHONESP_ERROR, "AsyncEventQueueServiceThread - "
  996. "can't unregister window class %d", GetLastError()));
  997. }
  998. LOG((PHONESP_TRACE, "AsyncEventQueueServiceThread - exit"));
  999. // Since the Provider Shutdown is called .. we terminate the thread
  1000. ExitThread (0);
  1001. }
  1002. /*************************AsyncEventQueueServiceThread - end******************/
  1003. /******************************************************************************
  1004. ReadThread:
  1005. Arguments:
  1006. PVOID lpParameter - The parameter passed to the function when this
  1007. function is called. In this case - the parameter is
  1008. the pointer to the phone structure (PMYPHONE) that
  1009. has just been opened
  1010. Returns VOID
  1011. ******************************************************************************/
  1012. VOID
  1013. ReadThread(
  1014. PVOID lpParameter
  1015. )
  1016. {
  1017. PPHONESP_PHONE_INFO pPhone;
  1018. PHID_DEVICE pHidDevice;
  1019. DWORD dwInputDataCnt;
  1020. PHID_DATA pHidData;
  1021. DWORD dwResult;
  1022. HANDLE hWaitHandles[2];
  1023. DWORD dwWaitResult;
  1024. LOG((PHONESP_TRACE, "ReadThread - enter"));
  1025. EnterCriticalSection(&csAllPhones);
  1026. pPhone = (PPHONESP_PHONE_INFO) lpParameter;
  1027. // Check whether the phone handle is still valid
  1028. if ( IsBadReadPtr(pPhone,sizeof(PHONESP_PHONE_INFO) ))
  1029. {
  1030. LOG((PHONESP_ERROR, "ReadThread - phone handle invalid"));
  1031. LeaveCriticalSection(&csAllPhones);
  1032. ExitThread(0);
  1033. }
  1034. EnterCriticalSection(&pPhone->csThisPhone);
  1035. LeaveCriticalSection(&csAllPhones);
  1036. // Check whether the phone handle is still in use
  1037. if ( !pPhone->bAllocated )
  1038. {
  1039. LOG((PHONESP_ERROR, "ReadThread - phone not allocated"));
  1040. LeaveCriticalSection(&pPhone->csThisPhone);
  1041. ExitThread(0);
  1042. }
  1043. // verify whether the phone is open
  1044. if( !pPhone->bPhoneOpen )
  1045. {
  1046. LOG((PHONESP_ERROR, "ReadThread - Phone not open"));
  1047. LeaveCriticalSection(&pPhone->csThisPhone);
  1048. ExitThread(0);
  1049. }
  1050. pHidDevice = pPhone->pHidDevice;
  1051. // Check whether hid device is present
  1052. if ( pHidDevice == NULL )
  1053. {
  1054. LOG((PHONESP_ERROR, "ReadThread - invalid hid device pointer"));
  1055. LeaveCriticalSection(&pPhone->csThisPhone);
  1056. ExitThread(0);
  1057. }
  1058. hWaitHandles[0] = pPhone->hCloseEvent;
  1059. hWaitHandles[1] = pPhone->hInputReportEvent;
  1060. while (TRUE)
  1061. {
  1062. if (! ReadInputReport(pPhone))
  1063. {
  1064. LOG((PHONESP_ERROR, "ReadThread - ReadInputReport failed - exiting"));
  1065. LeaveCriticalSection(&pPhone->csThisPhone);
  1066. ExitThread(0);
  1067. }
  1068. LeaveCriticalSection(&pPhone->csThisPhone);
  1069. //
  1070. // Wait for the read to complete, or the phone to be closed
  1071. //
  1072. dwWaitResult = WaitForMultipleObjects( 2, hWaitHandles, FALSE, INFINITE );
  1073. LOG((PHONESP_TRACE, "ReadThread - activated"));
  1074. if ( dwWaitResult == WAIT_OBJECT_0 )
  1075. {
  1076. LOG((PHONESP_TRACE, "ReadThread - CloseEvent fired - exiting"));
  1077. //
  1078. // Cancel the pending IO operation
  1079. //
  1080. CancelIo( pHidDevice->HidDevice );
  1081. ExitThread(0);
  1082. }
  1083. EnterCriticalSection(&pPhone->csThisPhone);
  1084. // This function is implemented in report.c
  1085. // The report received from the device is unmarshalled here
  1086. if ( UnpackReport(
  1087. pHidDevice->InputReportBuffer,
  1088. pHidDevice->Caps.InputReportByteLength,
  1089. HidP_Input,
  1090. pHidDevice->InputData,
  1091. pHidDevice->InputDataLength,
  1092. pHidDevice->Ppd
  1093. ) )
  1094. {
  1095. for (dwInputDataCnt = 0, pHidData = pHidDevice->InputData;
  1096. dwInputDataCnt < pHidDevice->InputDataLength;
  1097. pHidData++, dwInputDataCnt++)
  1098. {
  1099. // Since pHidData->IsDataSet in all the input HidData structures
  1100. // initialized to false before reading the input report .. if the
  1101. // pHidData->IsDataSet is set for the HidData structure, that
  1102. // HidData structure contains the new input report
  1103. // Also we are interested in only telephony usage page usages only
  1104. if ( pHidData->IsDataSet &&
  1105. ( (pHidData->UsagePage == HID_USAGE_PAGE_TELEPHONY) ||
  1106. (pHidData->UsagePage == HID_USAGE_PAGE_CONSUMER) ) )
  1107. {
  1108. PPHONESP_FUNC_INFO pFuncInfo;
  1109. PPHONESP_ASYNC_REQ_INFO pAsyncReqInfo;
  1110. if( ! (pFuncInfo = (PPHONESP_FUNC_INFO)
  1111. MemAlloc(sizeof (PHONESP_FUNC_INFO)) ) )
  1112. {
  1113. LOG((PHONESP_ERROR, "ReadThread - "
  1114. "MemAlloc pFuncInfo - out of memory"));
  1115. continue;
  1116. }
  1117. ZeroMemory(pFuncInfo, sizeof(PHONESP_FUNC_INFO));
  1118. pFuncInfo->dwParam1 = (ULONG_PTR) pPhone;
  1119. if ( ! ( pAsyncReqInfo = (PPHONESP_ASYNC_REQ_INFO)
  1120. MemAlloc(sizeof(PHONESP_ASYNC_REQ_INFO))))
  1121. {
  1122. LOG((PHONESP_ERROR, "ReadThread - "
  1123. "MemAlloc pAsyncReqInfo - out of memory"));
  1124. MemFree(pFuncInfo);
  1125. continue;
  1126. }
  1127. pAsyncReqInfo->pfnAsyncProc = ShowData;
  1128. pAsyncReqInfo->pFuncInfo = pFuncInfo;
  1129. // if the usage is associated with a Button
  1130. if( pHidData->IsButtonData )
  1131. {
  1132. PUSAGE Usages;
  1133. // fill the structure to be put on the async queue
  1134. if ( ! ( Usages = (PUSAGE)
  1135. MemAlloc(sizeof(USAGE) *
  1136. pHidData->ButtonData.MaxUsageLength) ) )
  1137. {
  1138. LOG((PHONESP_ERROR, "ReadIOCompletionRoutine - "
  1139. "MemAlloc Usages - out of memory"));
  1140. MemFree(pFuncInfo);
  1141. MemFree(pAsyncReqInfo);
  1142. continue;
  1143. }
  1144. pFuncInfo->dwNumParams = 7;
  1145. pFuncInfo->dwParam2 = PHONESP_BUTTON;
  1146. pFuncInfo->dwParam3 = pHidData->UsagePage;
  1147. pFuncInfo->dwParam4 = pHidData->ButtonData.UsageMin;
  1148. pFuncInfo->dwParam5 = pHidData->ButtonData.UsageMax;
  1149. pFuncInfo->dwParam6 = pHidData->ButtonData.MaxUsageLength;
  1150. CopyMemory(Usages,
  1151. pHidData->ButtonData.Usages,
  1152. sizeof(USAGE) *
  1153. pHidData->ButtonData.MaxUsageLength
  1154. );
  1155. pFuncInfo->dwParam7 = (ULONG_PTR) Usages;
  1156. }
  1157. else
  1158. {
  1159. // the usage is associated with a Value
  1160. pFuncInfo->dwNumParams = 5;
  1161. pFuncInfo->dwParam2 = PHONESP_VALUE;
  1162. pFuncInfo->dwParam3 = pHidData->UsagePage;
  1163. pFuncInfo->dwParam4 = pHidData->ValueData.Usage;
  1164. pFuncInfo->dwParam5 = pHidData->ValueData.Value;
  1165. }
  1166. if ( AsyncRequestQueueIn(pAsyncReqInfo) )
  1167. {
  1168. // Reset the event for number of pending requests in
  1169. // queue for this phone and increment the counter
  1170. if (pPhone->dwNumPendingReqInQueue == 0)
  1171. {
  1172. ResetEvent(pPhone->hNoPendingReqInQueueEvent);
  1173. }
  1174. pPhone->dwNumPendingReqInQueue++;
  1175. }
  1176. else
  1177. {
  1178. if ( pFuncInfo->dwParam2 == PHONESP_BUTTON )
  1179. {
  1180. MemFree((LPVOID)pFuncInfo->dwParam7);
  1181. }
  1182. MemFree(pFuncInfo);
  1183. MemFree(pAsyncReqInfo);
  1184. LOG((PHONESP_ERROR,"ReadIOCompletionRoutine - "
  1185. "AsyncRequestQueueIn failed"));
  1186. continue;
  1187. }
  1188. //ShowData(pFuncInfo);
  1189. }
  1190. }
  1191. }
  1192. }
  1193. }
  1194. /******************** ReadThread - end****************************/
  1195. /******************************************************************************
  1196. ReadInputReport
  1197. This function reads the phone device asynchronously. When an input report
  1198. is received from the device, the Event specified in the lpOverlapped
  1199. structure which is part of the PHONESP_PHONE_INFO structure is set. This
  1200. event results in ReadIOcompletionRoutine being called
  1201. Arguments:
  1202. PPHONESP_PHONE_INFO pPhone - the pointer to the phone to be read
  1203. Return BOOL:
  1204. TRUE if the function succeeds
  1205. FALSE if the function fails
  1206. ******************************************************************************/
  1207. BOOL
  1208. ReadInputReport (
  1209. PPHONESP_PHONE_INFO pPhone
  1210. )
  1211. {
  1212. DWORD i, dwResult;
  1213. PHID_DEVICE pHidDevice;
  1214. PHID_DATA pData;
  1215. BOOL bResult;
  1216. LOG((PHONESP_TRACE, "ReadInputReport - enter"));
  1217. pHidDevice = pPhone->pHidDevice;
  1218. // Check whether hid device is present
  1219. if ( pHidDevice == NULL )
  1220. {
  1221. LOG((PHONESP_ERROR, "ReadInputReport - invalid hid device pointer"));
  1222. return FALSE;
  1223. }
  1224. pData = pHidDevice->InputData;
  1225. //
  1226. // Set all the input hid data structures to False so we can identify the
  1227. // new reports from the device
  1228. for ( i = 0; i < pHidDevice->InputDataLength; i++, pData++)
  1229. {
  1230. pData->IsDataSet = FALSE;
  1231. }
  1232. bResult = ReadFile(
  1233. pHidDevice->HidDevice,
  1234. pHidDevice->InputReportBuffer,
  1235. pHidDevice->Caps.InputReportByteLength,
  1236. NULL,
  1237. pPhone->lpOverlapped
  1238. );
  1239. if ( !bResult )
  1240. {
  1241. // if the Readfile succeeds then GetLastError returns ERROR_IO_PENDING since
  1242. // this is an asynchronous read
  1243. dwResult = GetLastError();
  1244. if ( dwResult && ( dwResult != ERROR_IO_PENDING ) )
  1245. {
  1246. LOG((PHONESP_ERROR, "ReadInputReport - ReadFile Failed, error: %d",
  1247. GetLastError()));
  1248. if (dwResult == ERROR_DEVICE_NOT_CONNECTED)
  1249. {
  1250. //
  1251. // The hid device has most likely gone away. Lets close the file
  1252. // handle so we can get proper pnp notifications.
  1253. //
  1254. if ( CloseHidFile(pHidDevice) )
  1255. {
  1256. LOG((PHONESP_TRACE, "ReadInputReport - "
  1257. "closed hid device file handle"));
  1258. }
  1259. else
  1260. {
  1261. LOG((PHONESP_ERROR, "ReadInputReport - "
  1262. "CloseHidFile failed" ));
  1263. }
  1264. }
  1265. return FALSE;
  1266. }
  1267. }
  1268. LOG((PHONESP_TRACE, "ReadInputReport - exit"));
  1269. return TRUE;
  1270. }
  1271. /************************ReadInputReport - end *******************************/
  1272. // --------------------------- TAPI_lineXxx funcs -----------------------------
  1273. //
  1274. // The TSPI_lineNegotiateTSPIVersion function returns the highest SPI version the
  1275. // service provider can operate under for this device, given the range of possible
  1276. // SPI versions.
  1277. LONG
  1278. TSPIAPI
  1279. TSPI_lineNegotiateTSPIVersion(
  1280. DWORD dwDeviceID,
  1281. DWORD dwLowVersion,
  1282. DWORD dwHighVersion,
  1283. LPDWORD lpdwTSPIVersion
  1284. )
  1285. {
  1286. LOG((PHONESP_TRACE, "TSPI_lineNegotiateTSPIVersion - enter"));
  1287. if (dwHighVersion >= HIGH_VERSION)
  1288. {
  1289. // If the high version of the app is greater than the high version
  1290. // supported by this TSP and the low version of the app is less than
  1291. // the High version of the TSP - The TSP high version will be negotiated
  1292. // else the tsp cannot support this app
  1293. if (dwLowVersion <= HIGH_VERSION)
  1294. {
  1295. *lpdwTSPIVersion = (DWORD) HIGH_VERSION;
  1296. }
  1297. else
  1298. { // the app is too new for us
  1299. return LINEERR_INCOMPATIBLEAPIVERSION;
  1300. }
  1301. }
  1302. else
  1303. {
  1304. if(dwHighVersion >= LOW_VERSION)
  1305. {
  1306. *lpdwTSPIVersion = dwHighVersion;
  1307. }
  1308. else
  1309. {
  1310. //we are too new for the app
  1311. return LINEERR_INCOMPATIBLEAPIVERSION;
  1312. }
  1313. }
  1314. LOG((PHONESP_TRACE, "TSPI_lineNegotiateTSPIVersion - exit"));
  1315. return 0;
  1316. }
  1317. //
  1318. // -------------------------- TSPI_phoneXxx funcs -----------------------------
  1319. //
  1320. /******************************************************************************
  1321. TSPI_phoneClose:
  1322. This function closes the specified open phone device after completing all
  1323. the asynchronous operations pending on the device
  1324. Arguments:
  1325. HDRVPHONE hdPhone - the handle to the phone to be closed
  1326. Returns LONG:
  1327. Zero if the function succeeds
  1328. Error code if an error occurs - Possible values are
  1329. PHONEERR_INVALPHONEHANDLE
  1330. ******************************************************************************/
  1331. LONG
  1332. TSPIAPI
  1333. TSPI_phoneClose(
  1334. HDRVPHONE hdPhone
  1335. )
  1336. {
  1337. PPHONESP_PHONE_INFO pPhone;
  1338. LOG((PHONESP_TRACE, "TSPI_phoneClose - enter"));
  1339. // We need a critical section in order to ensure that the critical section
  1340. // of the phone is obtained while the phone handle is still valid.
  1341. EnterCriticalSection(&csAllPhones);
  1342. pPhone = (PPHONESP_PHONE_INFO) gpPhone[ (DWORD_PTR) hdPhone ];
  1343. // Check whether the phone handle is valid
  1344. if ( IsBadReadPtr( pPhone,sizeof(PHONESP_PHONE_INFO) ) )
  1345. {
  1346. LeaveCriticalSection(&csAllPhones);
  1347. LOG((PHONESP_ERROR, "TSPI_phoneClose - Phone handle invalid"));
  1348. return PHONEERR_INVALPHONEHANDLE;
  1349. }
  1350. EnterCriticalSection(&pPhone->csThisPhone);
  1351. LeaveCriticalSection(&csAllPhones);
  1352. // Check whether the phone handle is still in use
  1353. if ( !pPhone->bAllocated )
  1354. {
  1355. LeaveCriticalSection(&pPhone->csThisPhone);
  1356. LOG((PHONESP_ERROR, "TSPI_phoneClose - phone not allocated"));
  1357. return PHONEERR_NODEVICE;
  1358. }
  1359. // Check if the phone to be closed is still open
  1360. if( pPhone->bPhoneOpen )
  1361. {
  1362. // Inorder to ensure that there no other activities happen on the phone
  1363. pPhone->bPhoneOpen = FALSE;
  1364. //
  1365. // wait for the read thread to exit
  1366. //
  1367. SetEvent(pPhone->hCloseEvent);
  1368. LeaveCriticalSection(&pPhone->csThisPhone);
  1369. LOG((PHONESP_TRACE,"TSPI_phoneClose - waiting for read thread"));
  1370. WaitForSingleObject(pPhone->hReadThread, INFINITE);
  1371. LOG((PHONESP_TRACE,"TSPI_phoneClose - read thread complete"));
  1372. EnterCriticalSection(&pPhone->csThisPhone);
  1373. //
  1374. // if there are still pending requests on the phone in the queue, wait
  1375. // till all the pending asynchronous operations are completed
  1376. //
  1377. if (pPhone->dwNumPendingReqInQueue)
  1378. {
  1379. LOG((PHONESP_TRACE,"TSPI_phoneClose - requests pending"));
  1380. LeaveCriticalSection(&pPhone->csThisPhone);
  1381. WaitForSingleObject(&pPhone->hNoPendingReqInQueueEvent, INFINITE);
  1382. EnterCriticalSection(&pPhone->csThisPhone);
  1383. LOG((PHONESP_TRACE,"TSPI_phoneClose - requests completed"));
  1384. }
  1385. CloseHandle(pPhone->hReadThread);
  1386. CloseHandle(pPhone->hCloseEvent);
  1387. CloseHandle(pPhone->hInputReportEvent);
  1388. MemFree(pPhone->lpOverlapped);
  1389. pPhone->htPhone = NULL;
  1390. //
  1391. // Close HID file handle
  1392. //
  1393. if ( !CloseHidFile(pPhone->pHidDevice) )
  1394. {
  1395. LOG((PHONESP_WARN, "TSPI_phoneClose - CloseHidFile failed"));
  1396. }
  1397. if (pPhone->bRemovePending)
  1398. {
  1399. //
  1400. // This phone is gone, lets get rid of it
  1401. //
  1402. pPhone->bRemovePending = FALSE;
  1403. FreePhone(pPhone);
  1404. LOG((PHONESP_TRACE, "TSPI_phoneClose - phone remove complete [dwDeviceID %d] ", pPhone->dwDeviceID));
  1405. }
  1406. LeaveCriticalSection(&pPhone->csThisPhone);
  1407. }
  1408. else
  1409. {
  1410. LOG((PHONESP_ERROR,"TSPI_phoneClose - Phone Not Open"));
  1411. LeaveCriticalSection(&pPhone->csThisPhone);
  1412. return PHONEERR_INVALPHONEHANDLE;
  1413. }
  1414. LOG((PHONESP_TRACE, "TSPI_phoneClose - exit"));
  1415. return 0;
  1416. }
  1417. /******************************************************************************
  1418. The TSPI_phoneDevSpecific:
  1419. This function is used as a general extension mechanism to enable a Telephony
  1420. API implementation to provide features not described in the other operations.
  1421. The meanings of these extensions are device specific.
  1422. Comments: To be implemented in Tier 2
  1423. ******************************************************************************/
  1424. LONG
  1425. TSPIAPI
  1426. TSPI_phoneDevSpecific(
  1427. DRV_REQUESTID dwRequestID,
  1428. HDRVPHONE hdPhone,
  1429. LPVOID lpParams,
  1430. DWORD dwSize
  1431. )
  1432. {
  1433. LOG((PHONESP_TRACE, "TSPI_phoneDevSpecific - enter"));
  1434. LOG((PHONESP_TRACE, "TSPI_phoneDevSpecific - exit"));
  1435. return PHONEERR_OPERATIONUNAVAIL;
  1436. }
  1437. /***************************TSPI_phoneDevSpecific -End ***********************/
  1438. /******************************************************************************
  1439. TSPI_phoneGetButtonInfo:
  1440. This function returns information about a specified button.
  1441. Arguments:
  1442. IN HDRVPHONE hdPhone - The handle to the phone to be queried.
  1443. IN DWORD dwButtonLampID - A button on the phone device.
  1444. IN OUT LPPHONEBUTTONINFO lpButtonInfo - A pointer to memory into which
  1445. the TSP writes a variably sized structure of type PHONEBUTTONINFO.
  1446. This data structure describes the mode and function, and provides
  1447. additional descriptive text corresponding to the button.
  1448. Return Values
  1449. Returns zero if the function succeeds, or
  1450. An error number if an error occurs. Possible return values are as follows:
  1451. PHONEERR_INVALPHONEHANDLE, _INVALBUTTONLAMPID,_INVALPHONESTATE
  1452. ******************************************************************************/
  1453. LONG
  1454. TSPIAPI
  1455. TSPI_phoneGetButtonInfo(
  1456. HDRVPHONE hdPhone,
  1457. DWORD dwButtonLampID,
  1458. LPPHONEBUTTONINFO lpButtonInfo
  1459. )
  1460. {
  1461. PPHONESP_PHONE_INFO pPhone;
  1462. PPHONESP_BUTTONINFO pButtonInfo;
  1463. DWORD dwNeededSize;
  1464. LOG((PHONESP_TRACE, "TSPI_phoneGetButtonInfo - enter"));
  1465. if (lpButtonInfo->dwTotalSize < sizeof(PHONEBUTTONINFO))
  1466. {
  1467. LOG((PHONESP_ERROR, "TSPI_phoneGetButtonInfo - structure too small"));
  1468. return PHONEERR_STRUCTURETOOSMALL;
  1469. }
  1470. EnterCriticalSection(&csAllPhones);
  1471. pPhone = (PPHONESP_PHONE_INFO) gpPhone[ (DWORD_PTR) hdPhone ];
  1472. // Check if pPhone points to a valid memory location - if not handle is
  1473. // invalid
  1474. if ( IsBadReadPtr( pPhone,sizeof(PHONESP_PHONE_INFO) ) )
  1475. {
  1476. LeaveCriticalSection(&csAllPhones);
  1477. LOG((PHONESP_ERROR, "TSPI_phoneGetButtonInfo - Phone handle invalid"));
  1478. return PHONEERR_INVALPHONEHANDLE;
  1479. }
  1480. EnterCriticalSection(&pPhone->csThisPhone);
  1481. LeaveCriticalSection(&csAllPhones);
  1482. // Check whether the phone handle is still in use
  1483. if ( !pPhone->bAllocated )
  1484. {
  1485. LeaveCriticalSection(&pPhone->csThisPhone);
  1486. LOG((PHONESP_ERROR, "TSPI_GetButtonInfo - phone not allocated"));
  1487. return PHONEERR_NODEVICE;
  1488. }
  1489. // verify whether the phone is open
  1490. if ( ! (pPhone->bPhoneOpen) )
  1491. {
  1492. LeaveCriticalSection(&pPhone->csThisPhone);
  1493. LOG((PHONESP_ERROR,"TSPI_GetButtonInfo - Phone not open"));
  1494. return PHONEERR_INVALPHONESTATE;
  1495. }
  1496. // Get the Button structure for the queried button id if it exists
  1497. // else pButtonInfo will be NULL
  1498. if ( ! ( pButtonInfo = GetButtonFromID(pPhone, dwButtonLampID) ) )
  1499. {
  1500. LeaveCriticalSection(&pPhone->csThisPhone);
  1501. LOG((PHONESP_TRACE, "TSPI_phoneGetButtonInfo - Invalid Button ID"));
  1502. return PHONEERR_INVALBUTTONLAMPID;
  1503. }
  1504. // The needed size to store all the available information on the button
  1505. lpButtonInfo->dwNeededSize = sizeof(PHONEBUTTONINFO) +
  1506. (lstrlen(pButtonInfo->szButtonText) + 1) *
  1507. sizeof (WCHAR); // size of the Button Text
  1508. // Whether the button is a Feature Button, Keypad, etc
  1509. lpButtonInfo->dwButtonMode = pButtonInfo->dwButtonMode;
  1510. // The function associated with this button - will be _NONE for keypad
  1511. // buttons and _FLASH, _HOLD, etc for feature buttons
  1512. lpButtonInfo->dwButtonFunction = pButtonInfo->dwButtonFunction;
  1513. // The current button state
  1514. lpButtonInfo->dwButtonState = pButtonInfo->dwButtonState;
  1515. if (lpButtonInfo->dwTotalSize >= lpButtonInfo->dwNeededSize)
  1516. {
  1517. lpButtonInfo->dwUsedSize = lpButtonInfo->dwNeededSize;
  1518. // ButtonTextSize is the memory required to copy the string stored in
  1519. // szButtonText field of the PHONESP_BUTTON_INFO structure for this
  1520. // Button
  1521. lpButtonInfo->dwButtonTextSize = (lstrlen(pButtonInfo->szButtonText)+1)
  1522. * sizeof (WCHAR);
  1523. // Offset of the button text from the PHONEBUTTONINFO structure
  1524. lpButtonInfo->dwButtonTextOffset = sizeof(PHONEBUTTONINFO);
  1525. // Copy the button text at the lpButtonInfo->dwButtonTextOffset offset
  1526. // from the ButtonText stored in the PHONESP_BUTTON_INFO structure for
  1527. // this Button.
  1528. CopyMemory(
  1529. (LPBYTE)lpButtonInfo + lpButtonInfo->dwButtonTextOffset,
  1530. pButtonInfo->szButtonText,
  1531. lpButtonInfo->dwButtonTextSize
  1532. );
  1533. }
  1534. else
  1535. {
  1536. // no space to the store the button text info
  1537. lpButtonInfo->dwUsedSize = sizeof(PHONEBUTTONINFO);
  1538. lpButtonInfo->dwButtonTextSize = 0;
  1539. lpButtonInfo->dwButtonTextOffset = 0;
  1540. }
  1541. LeaveCriticalSection(&pPhone->csThisPhone);
  1542. LOG((PHONESP_TRACE, "TSPI_phoneGetButtonInfo - exit"));
  1543. return 0;
  1544. }
  1545. /********************TSPI_phoneGetButtonInfo - end****************************/
  1546. /******************************************************************************
  1547. TSPI_phoneGetDevCaps:
  1548. This function queries a specified phone device to determine its telephony
  1549. capabilities.
  1550. Arguments:
  1551. DWORD dwDeviceID - The phone device to be queried.
  1552. DWORD dwTSPIVersion - The negotiated TSPI version number. This value is
  1553. negotiated for this device through the
  1554. TSPI_phoneNegotiateTSPIVersion function.
  1555. DWORD dwExtVersion - The negotiated extension version number. This
  1556. value is negotiated for this device through the
  1557. TSPI_phoneNegotiateExtVersion function.
  1558. PHONECAPS lpPhoneCaps - A pointer to memory into which the TSP writes a
  1559. variably sized structure of type PHONECAPS.
  1560. Upon successful completion of the request, this
  1561. structure is filled with phone device capability
  1562. information.
  1563. Returns LONG:
  1564. Zero if success
  1565. PHONEERR_ constants if an error occurs. Possible return values are:
  1566. _BADDEVICEID,
  1567. ******************************************************************************/
  1568. LONG
  1569. TSPIAPI
  1570. TSPI_phoneGetDevCaps(
  1571. DWORD dwDeviceID,
  1572. DWORD dwTSPIVersion,
  1573. DWORD dwExtVersion,
  1574. LPPHONECAPS lpPhoneCaps
  1575. )
  1576. {
  1577. PPHONESP_PHONE_INFO pPhone;
  1578. PPHONESP_BUTTONINFO pButtonInfo;
  1579. LOG((PHONESP_TRACE, "TSPI_phoneGetDevCaps - enter"));
  1580. if (lpPhoneCaps->dwTotalSize < sizeof(PHONECAPS))
  1581. {
  1582. LOG((PHONESP_ERROR, "TSPI_phoneGetDevCaps - structure too small"));
  1583. return PHONEERR_STRUCTURETOOSMALL;
  1584. }
  1585. EnterCriticalSection(&csAllPhones);
  1586. // Given the deviceID retrieve the structure that contains the information
  1587. // for this device
  1588. pPhone = GetPhoneFromID(dwDeviceID, NULL);
  1589. if ( ! pPhone)
  1590. {
  1591. LeaveCriticalSection(&csAllPhones);
  1592. LOG((PHONESP_ERROR,"TSPI_phoneGetDevCaps - Bad Device ID"));
  1593. return PHONEERR_BADDEVICEID;
  1594. }
  1595. EnterCriticalSection(&pPhone->csThisPhone);
  1596. LeaveCriticalSection(&csAllPhones);
  1597. // Check whether the phone handle is still in use
  1598. if ( !pPhone->bAllocated )
  1599. {
  1600. LeaveCriticalSection(&pPhone->csThisPhone);
  1601. LOG((PHONESP_ERROR, "TSPI_phoneGetDevCaps - phone not allocated"));
  1602. return PHONEERR_NODEVICE;
  1603. }
  1604. //
  1605. // The size in bytes for this data structure that is needed to hold all the
  1606. // returned information. The returned includes the providerInfo string,
  1607. // PhoneInfo string and Phone Name string and Buttons Info - Button Function
  1608. // and Button Mode.
  1609. //
  1610. lpPhoneCaps->dwNeededSize = sizeof (PHONECAPS) +
  1611. sizeof (WCHAR) *
  1612. ( (lstrlenW(gszProviderInfo) + 1) +
  1613. (lstrlenW(pPhone->wszPhoneInfo) + 1) +
  1614. (lstrlenW(pPhone->wszPhoneName) + 1) ) +
  1615. (sizeof(DWORD) * pPhone->dwNumButtons * 2);
  1616. lpPhoneCaps->dwUsedSize = sizeof(PHONECAPS);
  1617. // lpPhoneCaps->dwPermanentPhoneID = ;
  1618. //The string format to be used with this phone device
  1619. lpPhoneCaps->dwStringFormat = STRINGFORMAT_UNICODE;
  1620. // The state changes for this phone device for which the application can be
  1621. // notified in a PHONE_STATE message. The Phone Info structure for each
  1622. // maintains this information
  1623. lpPhoneCaps->dwPhoneStates = pPhone->dwPhoneStates;
  1624. // Specifies the phone's hookswitch devices. Again the Phone Info structure
  1625. // maintains this information
  1626. lpPhoneCaps->dwHookSwitchDevs = pPhone->dwHookSwitchDevs;
  1627. // Specifies that we are a generic phone device. This means that in TAPI 3.1
  1628. // we will be able to function on a variety of addresses.
  1629. lpPhoneCaps->dwPhoneFeatures = PHONEFEATURE_GENERICPHONE;
  1630. if(pPhone->dwHandset)
  1631. { // Specifies the phone's hookswitch mode capabilities of the handset.
  1632. // The member is only meaningful if the hookswitch device is listed in
  1633. // dwHookSwitchDevs.
  1634. lpPhoneCaps->dwHandsetHookSwitchModes = PHONEHOOKSWITCHMODE_ONHOOK | PHONEHOOKSWITCHMODE_MICSPEAKER;
  1635. lpPhoneCaps->dwPhoneFeatures |= PHONEFEATURE_GETHOOKSWITCHHANDSET;
  1636. }
  1637. if(pPhone->dwSpeaker)
  1638. {
  1639. // Specifies the phone's hookswitch mode capabilities of the speaker.
  1640. // The member is only meaningful if the hookswitch device is listed in
  1641. // dwHookSwitchDevs.
  1642. lpPhoneCaps->dwSpeakerHookSwitchModes = PHONEHOOKSWITCHMODE_ONHOOK | PHONEHOOKSWITCHMODE_MICSPEAKER;
  1643. lpPhoneCaps->dwPhoneFeatures |= PHONEFEATURE_GETHOOKSWITCHSPEAKER |
  1644. PHONEFEATURE_SETHOOKSWITCHSPEAKER;
  1645. }
  1646. // The ring capabilities of the phone device. The phone is able to ring
  1647. // with dwNumRingModes different ring patterns, identified as 1, 2, through
  1648. // dwNumRingModes minus one. If the value of this member is 0, applications
  1649. // have no control over the ring mode of the phone. If the value of this
  1650. // member is greater than 0, it indicates the number of ring modes in
  1651. // addition to silence that are supported by the TSP. In this case, only one
  1652. // mode is supported.
  1653. if(pPhone->dwRing)
  1654. {
  1655. lpPhoneCaps->dwNumRingModes = 1;
  1656. lpPhoneCaps->dwPhoneFeatures |= PHONEFEATURE_GETRING |
  1657. PHONEFEATURE_SETRING;
  1658. }
  1659. if(pPhone->dwNumButtons)
  1660. {
  1661. // Specifies the number of button/lamps on the phone device that are
  1662. // detectable in TAPI. Button/lamps are identified by their identifier.
  1663. lpPhoneCaps->dwNumButtonLamps = pPhone->dwNumButtons;
  1664. lpPhoneCaps->dwPhoneFeatures |= PHONEFEATURE_GETBUTTONINFO;
  1665. }
  1666. if(lpPhoneCaps->dwTotalSize >= lpPhoneCaps->dwNeededSize)
  1667. {
  1668. DWORD dwAlignedSize;
  1669. DWORD dwRealSize;
  1670. ///////////////////
  1671. // Provider Info
  1672. ///////////////////
  1673. // Size of the Provider Info string in bytes
  1674. lpPhoneCaps->dwProviderInfoSize = ( lstrlen(gszProviderInfo) + 1) *
  1675. sizeof (WCHAR);
  1676. dwRealSize = lpPhoneCaps->dwProviderInfoSize;
  1677. // Offset of the Provider Info String from the PHONECAPS structure
  1678. lpPhoneCaps->dwProviderInfoOffset = lpPhoneCaps->dwUsedSize;
  1679. // Align it across DWORD boundary
  1680. if (dwRealSize % sizeof(DWORD))
  1681. {
  1682. dwAlignedSize = dwRealSize - (dwRealSize % sizeof(DWORD)) +
  1683. sizeof(DWORD);
  1684. }
  1685. else
  1686. {
  1687. dwAlignedSize = dwRealSize;
  1688. }
  1689. // Copy the provider Info string at the offset specified by
  1690. // lpPhoneCaps->dwProviderInfoOffset
  1691. CopyMemory(
  1692. ((LPBYTE)lpPhoneCaps) + lpPhoneCaps->dwProviderInfoOffset,
  1693. gszProviderInfo,
  1694. lpPhoneCaps->dwProviderInfoSize
  1695. );
  1696. lpPhoneCaps->dwNeededSize += dwAlignedSize - dwRealSize;
  1697. ///////////////////
  1698. // Phone Info
  1699. ///////////////////
  1700. // Size of the Phone Info string in bytes
  1701. lpPhoneCaps->dwPhoneInfoSize = (lstrlen(pPhone->wszPhoneInfo) + 1) *
  1702. sizeof(WCHAR);
  1703. dwRealSize = lpPhoneCaps->dwPhoneInfoSize;
  1704. // Offset of the Phone Info String from the PHONECAPS structure
  1705. lpPhoneCaps->dwPhoneInfoOffset = lpPhoneCaps->dwProviderInfoOffset +
  1706. dwAlignedSize;
  1707. // Align it across DWORD boundary
  1708. if (dwRealSize % sizeof(DWORD))
  1709. {
  1710. dwAlignedSize = dwRealSize - (dwRealSize % sizeof(DWORD)) +
  1711. sizeof(DWORD);
  1712. }
  1713. else
  1714. {
  1715. dwAlignedSize = dwRealSize;
  1716. }
  1717. // Copy the Phone Info string at the offset specified by
  1718. // lpPhoneCaps->dwPhoneInfoOffset
  1719. CopyMemory(
  1720. ((LPBYTE)lpPhoneCaps) + lpPhoneCaps->dwPhoneInfoOffset,
  1721. pPhone->wszPhoneInfo,
  1722. lpPhoneCaps->dwPhoneInfoSize
  1723. );
  1724. lpPhoneCaps->dwNeededSize += dwAlignedSize - dwRealSize;
  1725. ///////////////////
  1726. // Phone Name
  1727. ///////////////////
  1728. // Size of the Phone Name string in bytes
  1729. lpPhoneCaps->dwPhoneNameSize = (lstrlen(pPhone->wszPhoneName)+ 1) *
  1730. sizeof (WCHAR);
  1731. dwRealSize = lpPhoneCaps->dwPhoneNameSize;
  1732. // Offset of the Phone Name String from the PHONECAPS structure
  1733. lpPhoneCaps->dwPhoneNameOffset = lpPhoneCaps->dwPhoneInfoOffset +
  1734. dwAlignedSize;
  1735. // Align it across DWORD boundary
  1736. if (dwRealSize % sizeof(DWORD))
  1737. {
  1738. dwAlignedSize = dwRealSize - (dwRealSize % sizeof(DWORD)) +
  1739. sizeof(DWORD);
  1740. }
  1741. else
  1742. {
  1743. dwAlignedSize = dwRealSize;
  1744. }
  1745. // Copy the phone name string at the offset specified by
  1746. // lpPhoneCaps->dwPhoneNameOffset
  1747. CopyMemory(
  1748. ((LPBYTE)lpPhoneCaps) + lpPhoneCaps->dwPhoneNameOffset,
  1749. pPhone->wszPhoneName,
  1750. lpPhoneCaps->dwPhoneNameSize
  1751. );
  1752. lpPhoneCaps->dwNeededSize += dwAlignedSize - dwRealSize;
  1753. ////////////////////////////
  1754. // Button Modes & Functions
  1755. ////////////////////////////
  1756. // If the phone has buttons, dial, feature, etc
  1757. if(pPhone->dwNumButtons)
  1758. {
  1759. DWORD i;
  1760. // The size in bytes of the variably sized field containing the
  1761. // button modes of the phone's buttons, and the offset in bytes
  1762. // from the beginning of this data structure. This member uses the
  1763. // values specified by the PHONEBUTTONMODE_ constants. The
  1764. // array is indexed by button/lamp identifier.
  1765. lpPhoneCaps->dwButtonModesSize = (pPhone->dwNumButtons) *
  1766. sizeof (DWORD);
  1767. lpPhoneCaps->dwButtonModesOffset = lpPhoneCaps->dwPhoneNameOffset +
  1768. dwAlignedSize;
  1769. //
  1770. // The size in bytes of the variably sized field containing the
  1771. // button modes of the phone's buttons, and the offset in bytes
  1772. // from the beginning of this data structure. This member uses the
  1773. // values specified by the PHONEBUTTONFUNCTION_ constants. The
  1774. // array is indexed by button/lamp identifier.
  1775. //
  1776. lpPhoneCaps->dwButtonFunctionsSize = pPhone->dwNumButtons *
  1777. sizeof (DWORD);
  1778. lpPhoneCaps->dwButtonFunctionsOffset =
  1779. lpPhoneCaps->dwButtonModesOffset +
  1780. lpPhoneCaps->dwButtonModesSize;
  1781. pButtonInfo = pPhone->pButtonInfo;
  1782. //
  1783. // For each button on the phone copy the Button Function and Mode
  1784. // at the appropriate position
  1785. //
  1786. for ( i = 0; i < pPhone->dwNumButtons; i++, pButtonInfo++)
  1787. {
  1788. CopyMemory(
  1789. ((LPBYTE)lpPhoneCaps) +
  1790. lpPhoneCaps->dwButtonModesOffset + i*sizeof(DWORD),
  1791. &pButtonInfo->dwButtonMode,
  1792. sizeof (DWORD)
  1793. );
  1794. CopyMemory(
  1795. ((LPBYTE)lpPhoneCaps) +
  1796. lpPhoneCaps->dwButtonFunctionsOffset + i*sizeof(DWORD),
  1797. &pButtonInfo->dwButtonFunction,
  1798. sizeof (DWORD)
  1799. );
  1800. }
  1801. }
  1802. LeaveCriticalSection(&pPhone->csThisPhone);
  1803. lpPhoneCaps->dwNumGetData = 0;
  1804. lpPhoneCaps->dwNumSetData = 0;
  1805. lpPhoneCaps->dwDevSpecificSize = 0;
  1806. lpPhoneCaps->dwUsedSize = lpPhoneCaps->dwNeededSize;
  1807. }
  1808. else
  1809. {
  1810. LeaveCriticalSection(&pPhone->csThisPhone);
  1811. LOG((PHONESP_ERROR, "TSPI_phoneGetDevCaps - "
  1812. "Not enough memory for Phonecaps [needed %d] [total %d]",
  1813. lpPhoneCaps->dwNeededSize, lpPhoneCaps->dwTotalSize));
  1814. }
  1815. LOG((PHONESP_TRACE, "TSPI_phoneGetDevCaps - exit"));
  1816. return 0;
  1817. }
  1818. /**************************TSPI_phoneGetDevCaps - end*************************/
  1819. /******************************************************************************
  1820. TSPI_phoneGetDisplay:
  1821. This function returns the current contents of the specified phone display.
  1822. Comments: To be implemented in Tier 2
  1823. ******************************************************************************/
  1824. LONG
  1825. TSPIAPI
  1826. TSPI_phoneGetDisplay(
  1827. HDRVPHONE hdPhone,
  1828. LPVARSTRING lpDisplay
  1829. )
  1830. {
  1831. LOG((PHONESP_TRACE, "TSPI_phoneGetDisplay - enter"));
  1832. LOG((PHONESP_TRACE, "TSPI_phoneGetDisplay - exit"));
  1833. return PHONEERR_OPERATIONUNAVAIL;
  1834. }
  1835. /***********************TSPI_phoneGetDisplay - end****************************/
  1836. /******************************************************************************
  1837. TSPI_phoneGetExtensionID:
  1838. This function retrieves the extension identifier that the TSP supports for
  1839. the indicated phone device.
  1840. Comments: To be implemented in Tier 2
  1841. ******************************************************************************/
  1842. LONG
  1843. TSPIAPI
  1844. TSPI_phoneGetExtensionID(
  1845. DWORD dwDeviceID,
  1846. DWORD dwTSPIVersion,
  1847. LPPHONEEXTENSIONID lpExtensionID
  1848. )
  1849. {
  1850. LOG((PHONESP_TRACE, "TSPI_phoneGetExtensionID - enter"));
  1851. LOG((PHONESP_TRACE, "TSPI_phoneGetExtensionID - exit"));
  1852. return 0;
  1853. }
  1854. /**********************TSPI_phoneGetExtensionID - end*************************/
  1855. /******************************************************************************
  1856. TSPI_phoneGetHookSwitch:
  1857. This function returns the current hookswitch mode of the specified open
  1858. phone device.
  1859. Arguments:
  1860. HDRVPHONE hdPhone - The handle to the phone
  1861. LPDWORD lpdwHookSwitchDevs - The TSP writes the mode of the phone's
  1862. hookswitch devices. This parameter uses the
  1863. PHONEHOOKSWITCHDEV_ constants. If a bit position is False,
  1864. the corresponding hookswitch device is onhook.
  1865. Returns LONG:
  1866. Zero is the function succeeded
  1867. else PHONEERR_ constants for error conditions
  1868. *******************************************************************************/
  1869. LONG
  1870. TSPIAPI
  1871. TSPI_phoneGetHookSwitch(
  1872. HDRVPHONE hdPhone,
  1873. LPDWORD lpdwHookSwitchDevs
  1874. )
  1875. {
  1876. PPHONESP_PHONE_INFO pPhone;
  1877. LOG((PHONESP_TRACE, "TSPI_phoneGetHookSwitch - enter"));
  1878. EnterCriticalSection(&csAllPhones);
  1879. pPhone = (PPHONESP_PHONE_INFO) gpPhone[ (DWORD_PTR) hdPhone ];
  1880. // check whether the phone handle is valid
  1881. if ( IsBadReadPtr(pPhone,sizeof(PHONESP_PHONE_INFO) ) )
  1882. {
  1883. LeaveCriticalSection(&csAllPhones);
  1884. LOG((PHONESP_ERROR, "TSPI_phoneGetHookSwitch - Invalid Phone Handle"));
  1885. return PHONEERR_INVALPHONEHANDLE;
  1886. }
  1887. EnterCriticalSection(&pPhone->csThisPhone);
  1888. LeaveCriticalSection(&csAllPhones);
  1889. // Check whether the phone handle is still in use
  1890. if ( !pPhone->bAllocated )
  1891. {
  1892. LeaveCriticalSection(&pPhone->csThisPhone);
  1893. LOG((PHONESP_ERROR, "TSPI_phoneGetHookSwitch - phone not allocated"));
  1894. return PHONEERR_NODEVICE;
  1895. }
  1896. // Check whether the phone is open
  1897. if (! (pPhone->bPhoneOpen) )
  1898. {
  1899. LeaveCriticalSection(&pPhone->csThisPhone);
  1900. LOG((PHONESP_ERROR, "TSPI_phoneGetHookSwitch - Phone Not Open"));
  1901. return PHONEERR_INVALPHONESTATE;
  1902. }
  1903. *lpdwHookSwitchDevs = 0;
  1904. // We are interested in only handset and speaker hookswitch - headset is not
  1905. // supported
  1906. if (pPhone->dwHandset)
  1907. {
  1908. if ( (pPhone->dwHandsetHookSwitchMode != PHONEHOOKSWITCHMODE_ONHOOK) )
  1909. {
  1910. *lpdwHookSwitchDevs = PHONEHOOKSWITCHDEV_HANDSET;
  1911. }
  1912. }
  1913. if (pPhone->dwSpeaker)
  1914. {
  1915. if( pPhone->dwSpeakerHookSwitchMode != PHONEHOOKSWITCHMODE_ONHOOK)
  1916. {
  1917. *lpdwHookSwitchDevs |= PHONEHOOKSWITCHDEV_SPEAKER;
  1918. }
  1919. }
  1920. LeaveCriticalSection(&pPhone->csThisPhone);
  1921. LOG((PHONESP_TRACE, "TSPI_phoneGetHookSwitch - exit"));
  1922. return 0;
  1923. }
  1924. /************************TSPI_phoneGetHookSwitch - end************************/
  1925. /******************************************************************************
  1926. TSPI_phoneGetID:
  1927. This function returns a device identifier for the given device class
  1928. associated with the specified phone device.
  1929. Arguments:
  1930. HDRVPHONE hdPhone - The handle to the phone to be queried.
  1931. LPVARSTRING lpDeviceID - Pointer to the data structure of type VARSTRING
  1932. where the device idnetifier is returned.
  1933. LPCWSTR lpszDeviceClass - Specifies the device class of the device whose
  1934. identiifer is requested
  1935. HANDLE hTargetProcess - The process handle of the application on behalf
  1936. of which this function is being invoked.
  1937. Returns LONG:
  1938. Zero if the function succeeds
  1939. PHONEERR_ constants if an error occurs.
  1940. Comments: Currently supporting wave/in and wave/out only.
  1941. ******************************************************************************/
  1942. LONG
  1943. TSPIAPI
  1944. TSPI_phoneGetID(
  1945. HDRVPHONE hdPhone,
  1946. LPVARSTRING lpDeviceID,
  1947. LPCWSTR lpszDeviceClass,
  1948. HANDLE hTargetProcess
  1949. )
  1950. {
  1951. PPHONESP_PHONE_INFO pPhone;
  1952. HRESULT hr;
  1953. LOG((PHONESP_TRACE, "TSPI_phoneGetID - enter"));
  1954. if (lpDeviceID->dwTotalSize < sizeof(VARSTRING))
  1955. {
  1956. LOG((PHONESP_ERROR, "TSPI_phoneGetID - structure too small"));
  1957. return PHONEERR_STRUCTURETOOSMALL;
  1958. }
  1959. EnterCriticalSection(&csAllPhones);
  1960. pPhone = (PPHONESP_PHONE_INFO) gpPhone[ (DWORD_PTR) hdPhone ];
  1961. // Verify whether the phone handle is valid
  1962. if ( IsBadReadPtr(pPhone, sizeof(PHONESP_PHONE_INFO) ) )
  1963. {
  1964. LeaveCriticalSection(&csAllPhones);
  1965. LOG((PHONESP_ERROR,"TSPI_phoneGetID - Invalid Phone Handle"));
  1966. return PHONEERR_INVALPHONEHANDLE;
  1967. }
  1968. EnterCriticalSection(&pPhone->csThisPhone);
  1969. LeaveCriticalSection(&csAllPhones);
  1970. // Check whether the phone handle is still in use
  1971. if ( !pPhone->bAllocated )
  1972. {
  1973. LeaveCriticalSection(&pPhone->csThisPhone);
  1974. LOG((PHONESP_ERROR, "TSPI_phoneGetID - phone not allocated"));
  1975. return PHONEERR_NODEVICE;
  1976. }
  1977. // verify whether the phone is open
  1978. if ( ! pPhone->bPhoneOpen )
  1979. {
  1980. LeaveCriticalSection(&pPhone->csThisPhone);
  1981. LOG((PHONESP_ERROR,"TSPI_phoneGetID - Phone not open"));
  1982. return PHONEERR_INVALPHONESTATE;
  1983. }
  1984. lpDeviceID->dwNeededSize = sizeof(VARSTRING) + sizeof (DWORD);
  1985. lpDeviceID->dwStringFormat = STRINGFORMAT_BINARY;
  1986. if ( lpDeviceID->dwTotalSize >= lpDeviceID->dwNeededSize )
  1987. {
  1988. // whether the requested ID is capture class
  1989. if ( ! lstrcmpi(lpszDeviceClass, _T("wave/in") ) )
  1990. {
  1991. LOG((PHONESP_TRACE,"TSPI_phoneGetID - 'wave/in'"));
  1992. if(pPhone->bCapture == TRUE)
  1993. {
  1994. // Discover Capture Wave ID
  1995. hr = DiscoverAssociatedWaveId(pPhone->pHidDevice->dwDevInst,
  1996. FALSE,
  1997. &pPhone->dwCaptureWaveId);
  1998. if (hr != S_OK)
  1999. {
  2000. LOG((PHONESP_ERROR, "TSPI_phoneGetID - "
  2001. "DiscoverAssociatedWaveID failed %0x", hr));
  2002. }
  2003. lpDeviceID->dwStringOffset = sizeof(VARSTRING);
  2004. lpDeviceID->dwStringSize = sizeof(DWORD);
  2005. CopyMemory (
  2006. (LPBYTE) lpDeviceID + lpDeviceID->dwStringOffset,
  2007. &pPhone->dwCaptureWaveId,
  2008. sizeof(DWORD)
  2009. );
  2010. }
  2011. else
  2012. {
  2013. LeaveCriticalSection(&pPhone->csThisPhone);
  2014. LOG((PHONESP_ERROR,"TSPI_phoneGetID - No Capture Device"));
  2015. return PHONEERR_NODEVICE;
  2016. }
  2017. }
  2018. else
  2019. {
  2020. // the wave ID is render class
  2021. if ( ! lstrcmpi(lpszDeviceClass, _T("wave/out") ) )
  2022. {
  2023. LOG((PHONESP_TRACE,"TSPI_phoneGetID - 'wave/out'"));
  2024. if(pPhone->bRender == TRUE)
  2025. {
  2026. // Discover Render Wave ID
  2027. hr = DiscoverAssociatedWaveId(pPhone->pHidDevice->dwDevInst,
  2028. TRUE,
  2029. &pPhone->dwRenderWaveId);
  2030. if (hr != S_OK)
  2031. {
  2032. LOG((PHONESP_ERROR, "TSPI_phoneGetID - "
  2033. "DiscoverAssociatedWaveID failed %0x", hr));
  2034. }
  2035. lpDeviceID->dwStringOffset = sizeof(VARSTRING);
  2036. lpDeviceID->dwStringSize = sizeof(DWORD);
  2037. CopyMemory (
  2038. (LPBYTE) lpDeviceID + lpDeviceID->dwStringOffset,
  2039. &pPhone->dwRenderWaveId,
  2040. sizeof(DWORD)
  2041. );
  2042. }
  2043. else
  2044. {
  2045. LeaveCriticalSection(&pPhone->csThisPhone);
  2046. LOG((PHONESP_ERROR,"TSPI_phoneGetID - No Render Device"));
  2047. return PHONEERR_NODEVICE;
  2048. }
  2049. }
  2050. else
  2051. { // the other classes are not supported or the phone does not have the
  2052. // specified device
  2053. LeaveCriticalSection(&pPhone->csThisPhone);
  2054. LOG((PHONESP_TRACE,"TSPI_phoneGetID - unsupported device class '%ws'", lpszDeviceClass));
  2055. return PHONEERR_INVALDEVICECLASS;
  2056. }
  2057. }
  2058. lpDeviceID->dwUsedSize = lpDeviceID->dwNeededSize;
  2059. }
  2060. else
  2061. {
  2062. LOG((PHONESP_ERROR,"TSPI_phoneGetID : not enough total size"));
  2063. lpDeviceID->dwUsedSize = sizeof(VARSTRING);
  2064. }
  2065. LeaveCriticalSection(&pPhone->csThisPhone);
  2066. LOG((PHONESP_TRACE, "TSPI_phoneGetID - exit"));
  2067. return 0;
  2068. }
  2069. /************************TSPI_phoneGetID - end*******************************/
  2070. /******************************************************************************
  2071. TSPI_phoneGetLamp:
  2072. This function returns the current lamp mode of the specified lamp.
  2073. Comments: To be implememted in Tier 2
  2074. ******************************************************************************/
  2075. LONG
  2076. TSPIAPI
  2077. TSPI_phoneGetLamp(
  2078. HDRVPHONE hdPhone,
  2079. DWORD dwButtonLampID,
  2080. LPDWORD lpdwLampMode
  2081. )
  2082. {
  2083. LOG((PHONESP_TRACE, "TSPI_phoneGetLamp - enter"));
  2084. LOG((PHONESP_TRACE, "TSPI_phoneGetLamp - exit"));
  2085. return PHONEERR_OPERATIONUNAVAIL;
  2086. }
  2087. /********************TSPI_phoneGetLamp - end**********************************/
  2088. /******************************************************************************
  2089. TSPI_phoneGetRing:
  2090. This function enables an application to query the specified open phone
  2091. device as to its current ring mode.
  2092. Arguments:
  2093. HDRVPHONE hdPhone - The handle to the phone whose ring mode is to be
  2094. queried.
  2095. LPDWORD lpdwRingMode - The ringing pattern with which the phone is
  2096. ringing. Zero indicates that the phone is not ringing.
  2097. LPDWORD lpdwVolume - The volume level with which the phone is ringing.
  2098. This is a number in the range from 0x00000000 (silence)
  2099. through 0x0000FFFF (maximum volume).
  2100. Returns LONG:
  2101. Zero on Success
  2102. PHONEERR_ constants on error
  2103. ******************************************************************************/
  2104. LONG
  2105. TSPIAPI
  2106. TSPI_phoneGetRing(
  2107. HDRVPHONE hdPhone,
  2108. LPDWORD lpdwRingMode,
  2109. LPDWORD lpdwVolume
  2110. )
  2111. {
  2112. PPHONESP_PHONE_INFO pPhone;
  2113. LOG((PHONESP_TRACE, "TSPI_phoneGetRing - enter"));
  2114. EnterCriticalSection(&csAllPhones);
  2115. pPhone = (PPHONESP_PHONE_INFO) gpPhone[ (DWORD_PTR) hdPhone ];
  2116. // if the phone handle is valid
  2117. if ( IsBadReadPtr(pPhone, sizeof(PHONESP_PHONE_INFO) ) )
  2118. {
  2119. LeaveCriticalSection(&csAllPhones);
  2120. LOG((PHONESP_ERROR, "TSPI_phoneGetRing - Invalid Phone Handle"));
  2121. return PHONEERR_INVALPHONEHANDLE;
  2122. }
  2123. EnterCriticalSection(&pPhone->csThisPhone);
  2124. LeaveCriticalSection(&csAllPhones);
  2125. // Check whether the phone handle is still in use
  2126. if ( !pPhone->bAllocated )
  2127. {
  2128. LeaveCriticalSection(&pPhone->csThisPhone);
  2129. LOG((PHONESP_ERROR, "TSPI_phoneGetRing - phone not allocated"));
  2130. return PHONEERR_NODEVICE;
  2131. }
  2132. // whether the phone is open
  2133. if ( ! pPhone->bPhoneOpen )
  2134. {
  2135. LeaveCriticalSection(&pPhone->csThisPhone);
  2136. LOG((PHONESP_ERROR, "TSPI_phoneGetRing - Phone Not Open"));
  2137. return PHONEERR_INVALPHONESTATE;
  2138. }
  2139. // if the phone has a ringer attached to it
  2140. if( ! pPhone->dwRing)
  2141. {
  2142. LeaveCriticalSection(&pPhone->csThisPhone);
  2143. LOG((PHONESP_ERROR, "TSPI_phoneGetRing - "
  2144. "Phone does not have a ringer"));
  2145. return PHONEERR_RESOURCEUNAVAIL;
  2146. }
  2147. *lpdwRingMode = pPhone->dwRingMode;
  2148. // if ringmode is 0, it indicates that the phone is not ringing
  2149. if(pPhone->dwRingMode)
  2150. {
  2151. // The ring volume is maximum if the phone is ringing
  2152. *lpdwVolume = 0x0000FFFF;
  2153. }
  2154. else
  2155. {
  2156. // If the phone is not ringing the ring volume is 0
  2157. *lpdwVolume = 0;
  2158. }
  2159. LeaveCriticalSection(&pPhone->csThisPhone);
  2160. LOG((PHONESP_TRACE, "TSPI_phoneGetRing - exit"));
  2161. return 0;
  2162. }
  2163. /******************************TSPI_phoneGetRing - end************************/
  2164. /******************************************************************************
  2165. TSPI_phoneGetStatus:
  2166. This function queries the specified open phone device for its overall
  2167. status.
  2168. Arguments:
  2169. hdPhone - The handle to the phone to be queried.
  2170. lpPhoneStatus - A pointer to a variably sized data structure of type
  2171. PHONESTATUS, into which the TSP writes information about the
  2172. phone's status. Prior to calling TSPI_phoneGetStatus, the
  2173. application sets the dwTotalSize member of this structure to
  2174. indicate the amount of memory available to TAPI for returning
  2175. information.
  2176. Returns LONG:
  2177. Zero if the function succeeds, or
  2178. An error number if an error occurs. Possible return values are as follows:
  2179. PHONEERR_INVALPHONEHANDLE.
  2180. ******************************************************************************/
  2181. LONG
  2182. TSPIAPI
  2183. TSPI_phoneGetStatus(
  2184. HDRVPHONE hdPhone,
  2185. LPPHONESTATUS lpPhoneStatus
  2186. )
  2187. {
  2188. PPHONESP_PHONE_INFO pPhone;
  2189. LOG((PHONESP_TRACE, "TSPI_phoneGetStatus - enter"));
  2190. if (lpPhoneStatus->dwTotalSize < sizeof(PHONESTATUS))
  2191. {
  2192. LOG((PHONESP_ERROR, "TSPI_phoneGetStatus - structure too small"));
  2193. return PHONEERR_STRUCTURETOOSMALL;
  2194. }
  2195. EnterCriticalSection(&csAllPhones);
  2196. pPhone = (PPHONESP_PHONE_INFO) gpPhone[ (DWORD_PTR) hdPhone ];
  2197. // check whether the phone handle is valid
  2198. if ( IsBadReadPtr(pPhone, sizeof(PHONESP_PHONE_INFO) ) )
  2199. {
  2200. LeaveCriticalSection(&csAllPhones);
  2201. LOG((PHONESP_TRACE,"TSPI_phoneGetStatus - INVALID PHONE HANDLE"));
  2202. return PHONEERR_INVALPHONEHANDLE;
  2203. }
  2204. EnterCriticalSection(&pPhone->csThisPhone);
  2205. LeaveCriticalSection(&csAllPhones);
  2206. // Check whether the phone handle is still in use
  2207. if ( !pPhone->bAllocated )
  2208. {
  2209. LeaveCriticalSection(&pPhone->csThisPhone);
  2210. LOG((PHONESP_ERROR, "TSPI_phoneGetStatus - phone not allocated"));
  2211. return PHONEERR_NODEVICE;
  2212. }
  2213. if( ! pPhone->bPhoneOpen)
  2214. {
  2215. LeaveCriticalSection(&pPhone->csThisPhone);
  2216. LOG((PHONESP_TRACE,"TSPI_phoneGetStatus - PHONE not Open"));
  2217. return PHONEERR_INVALPHONEHANDLE;
  2218. }
  2219. lpPhoneStatus->dwNeededSize = sizeof(PHONESTATUS);
  2220. if(lpPhoneStatus->dwTotalSize >= lpPhoneStatus->dwNeededSize)
  2221. {
  2222. lpPhoneStatus->dwUsedSize = sizeof (PHONESTATUS);
  2223. lpPhoneStatus->dwStatusFlags = PHONESTATUSFLAGS_CONNECTED;
  2224. // If the phone has a ringer
  2225. if(pPhone->dwRing)
  2226. {
  2227. lpPhoneStatus->dwRingMode = pPhone->dwRingMode;
  2228. // If the Ring Mode is 0, the phone is not ringing
  2229. if (pPhone->dwRingMode)
  2230. {
  2231. // by default the phone volume is 0xffff if it is ringing
  2232. lpPhoneStatus->dwRingVolume = 0xffff;
  2233. }
  2234. else
  2235. {
  2236. // the phone volume is 0 if not ringing
  2237. lpPhoneStatus->dwRingVolume = 0;
  2238. }
  2239. }
  2240. lpPhoneStatus->dwHandsetHookSwitchMode = pPhone->dwHandsetHookSwitchMode;
  2241. lpPhoneStatus->dwHandsetVolume = 0;
  2242. lpPhoneStatus->dwHandsetGain = 0;
  2243. if (pPhone->dwSpeaker)
  2244. {
  2245. lpPhoneStatus->dwSpeakerHookSwitchMode = pPhone->dwSpeakerHookSwitchMode;
  2246. lpPhoneStatus->dwSpeakerVolume = 0;
  2247. lpPhoneStatus->dwSpeakerGain = 0;
  2248. }
  2249. }
  2250. LeaveCriticalSection(&pPhone->csThisPhone);
  2251. LOG((PHONESP_TRACE, "TSPI_phoneGetStatus - exit"));
  2252. return 0;
  2253. }
  2254. /****************************TSPI_phoneGetStatus - end************************/
  2255. /******************************************************************************
  2256. TSPI_phoneNegotiateTSPIVersion:
  2257. This function returns the highest SPI version the TSP can operate under for
  2258. this device, given the range of possible SPI versions.
  2259. Arguments:
  2260. Return LONG:
  2261. ******************************************************************************/
  2262. LONG
  2263. TSPIAPI
  2264. TSPI_phoneNegotiateTSPIVersion(
  2265. DWORD dwDeviceID,
  2266. DWORD dwLowVersion,
  2267. DWORD dwHighVersion,
  2268. LPDWORD lpdwTSPIVersion
  2269. )
  2270. {
  2271. PPHONESP_PHONE_INFO pPhone;
  2272. LOG((PHONESP_TRACE, "TSPI_phoneNegotiateTSPIVersion - enter"));
  2273. if (dwHighVersion >= HIGH_VERSION)
  2274. {
  2275. if (dwLowVersion <= HIGH_VERSION)
  2276. {
  2277. *lpdwTSPIVersion = (DWORD) HIGH_VERSION;
  2278. }
  2279. else
  2280. { // the app is too new for us
  2281. return PHONEERR_INCOMPATIBLEAPIVERSION;
  2282. }
  2283. }
  2284. else
  2285. {
  2286. if(dwHighVersion >= LOW_VERSION)
  2287. {
  2288. *lpdwTSPIVersion = dwHighVersion;
  2289. }
  2290. else
  2291. {
  2292. //we are too new for the app
  2293. return PHONEERR_INCOMPATIBLEAPIVERSION;
  2294. }
  2295. }
  2296. EnterCriticalSection(&csAllPhones);
  2297. // Given the deviceID retrieve the structure that contains the information
  2298. // for this device
  2299. pPhone = GetPhoneFromID(dwDeviceID, NULL);
  2300. if ( ! pPhone)
  2301. {
  2302. LeaveCriticalSection(&csAllPhones);
  2303. LOG((PHONESP_ERROR,"TSPI_phoneNegotiateTSPIVersion - Bad Device ID"));
  2304. return PHONEERR_BADDEVICEID;
  2305. }
  2306. EnterCriticalSection(&pPhone->csThisPhone);
  2307. LeaveCriticalSection(&csAllPhones);
  2308. // Check whether the phone handle is still in use
  2309. if ( !pPhone->bAllocated )
  2310. {
  2311. LeaveCriticalSection(&pPhone->csThisPhone);
  2312. LOG((PHONESP_ERROR, "TSPI_phoneNegotiateTSPIVersion - phone not allocated"));
  2313. return PHONEERR_NODEVICE;
  2314. }
  2315. // Store the version negotiated for this phone
  2316. pPhone->dwVersion = *lpdwTSPIVersion;
  2317. LeaveCriticalSection(&pPhone->csThisPhone);
  2318. LOG((PHONESP_TRACE, "TSPI_phoneNegotiateTSPIVersion - exit"));
  2319. return 0;
  2320. }
  2321. /**********************TSPI_phoneNegotiateTSPIVersion - end*******************/
  2322. /******************************************************************************
  2323. TSPI_phoneOpen:
  2324. This function opens the phone device whose device identifier is given,
  2325. returning the TSP's opaque handle for the device and retaining TAPI's
  2326. opaque handle for the device for use in subsequent calls to the PHONEEVENT
  2327. procedure.
  2328. Arguments:
  2329. Returns:
  2330. ******************************************************************************/
  2331. LONG
  2332. TSPIAPI
  2333. TSPI_phoneOpen(
  2334. DWORD dwDeviceID,
  2335. HTAPIPHONE htPhone,
  2336. LPHDRVPHONE lphdPhone,
  2337. DWORD dwTSPIVersion,
  2338. PHONEEVENT lpfnEventProc
  2339. )
  2340. {
  2341. LPPHONEBUTTONINFO lpButtonInfo;
  2342. DWORD dwPhoneID;
  2343. PPHONESP_PHONE_INFO pPhone;
  2344. LOG((PHONESP_TRACE, "TSPI_phoneOpen - enter"));
  2345. EnterCriticalSection(&csAllPhones);
  2346. // if the device id is not valid return error condition
  2347. if ( ! ( pPhone = GetPhoneFromID(dwDeviceID, &dwPhoneID) ) )
  2348. {
  2349. LeaveCriticalSection(&csAllPhones);
  2350. LOG((PHONESP_ERROR,"TSPI_phoneOpen - Invalid Phone Handle"));
  2351. return PHONEERR_BADDEVICEID;
  2352. }
  2353. EnterCriticalSection(&pPhone->csThisPhone);
  2354. LeaveCriticalSection(&csAllPhones);
  2355. // Check whether the phone handle is still in use
  2356. if ( !pPhone->bAllocated )
  2357. {
  2358. LeaveCriticalSection(&pPhone->csThisPhone);
  2359. LOG((PHONESP_ERROR, "TSPI_phoneOpen - phone not allocated"));
  2360. return PHONEERR_NODEVICE;
  2361. }
  2362. // if the phone is already open then return error condition
  2363. if (pPhone->bPhoneOpen)
  2364. {
  2365. LeaveCriticalSection(&pPhone->csThisPhone);
  2366. LOG((PHONESP_ERROR,"TSPI_phoneOpen - Phone is open"));
  2367. return PHONEERR_INUSE;
  2368. }
  2369. // Create an event that signals the receipt of an input report from
  2370. // the phone device
  2371. if ( ! ( pPhone->hInputReportEvent =
  2372. CreateEvent ((LPSECURITY_ATTRIBUTES) NULL,
  2373. FALSE, // manual reset
  2374. FALSE, // non-signaled
  2375. NULL // unnamed
  2376. ) ) )
  2377. {
  2378. LeaveCriticalSection(&pPhone->csThisPhone);
  2379. LOG((PHONESP_ERROR,"TSPI_phoneOpen - Create Event: hInputReportEvent"
  2380. " Failed: %d", GetLastError()));
  2381. return PHONEERR_NOMEM;
  2382. }
  2383. // Create an event that we will signal when we close the phone to
  2384. // allow the read thread to exit
  2385. if ( ! ( pPhone->hCloseEvent =
  2386. CreateEvent ((LPSECURITY_ATTRIBUTES) NULL,
  2387. FALSE, // manual reset
  2388. FALSE, // non-signaled
  2389. NULL // unnamed
  2390. ) ) )
  2391. {
  2392. CloseHandle(pPhone->hInputReportEvent);
  2393. LeaveCriticalSection(&pPhone->csThisPhone);
  2394. LOG((PHONESP_ERROR,"TSPI_phoneOpen - Create Event: hWaitCompletionEvent"
  2395. " Failed: %d", GetLastError()));
  2396. return PHONEERR_NOMEM;
  2397. }
  2398. //
  2399. // The overlapped structure contains the event to be set when an input
  2400. // report is received. The event to be set is the hInputReportEvent
  2401. // which is part of the PHONESP_PHONE_INFO structure. This overlapped
  2402. // structure is passed to the ReadFile function call.
  2403. //
  2404. if( ! ( pPhone->lpOverlapped = (LPOVERLAPPED)
  2405. MemAlloc (sizeof(OVERLAPPED)) ))
  2406. {
  2407. CloseHandle(pPhone->hCloseEvent);
  2408. CloseHandle(pPhone->hInputReportEvent);
  2409. LeaveCriticalSection(&pPhone->csThisPhone);
  2410. LOG((PHONESP_ERROR,"TSPI_phoneOpen - Not enough memory for"
  2411. " lpOverlapped structure "));
  2412. return PHONEERR_NOMEM;
  2413. }
  2414. pPhone->lpOverlapped->Offset = 0;
  2415. pPhone->lpOverlapped->OffsetHigh = 0;
  2416. pPhone->lpOverlapped->hEvent = pPhone->hInputReportEvent;
  2417. //
  2418. // Open the HID file handle
  2419. //
  2420. if ( ! OpenHidFile(pPhone->pHidDevice) )
  2421. {
  2422. MemFree(pPhone->lpOverlapped);
  2423. CloseHandle(pPhone->hCloseEvent);
  2424. CloseHandle(pPhone->hInputReportEvent);
  2425. LeaveCriticalSection(&pPhone->csThisPhone);
  2426. LOG((PHONESP_ERROR,"TSPI_phoneOpen - HidOpenFile failed"));
  2427. return PHONEERR_OPERATIONFAILED;
  2428. }
  2429. // Increase the number of packets that the HID class driver ring buffer
  2430. // holds for the device
  2431. if ( ! HidD_SetNumInputBuffers(pPhone->pHidDevice->HidDevice,
  2432. 20) )
  2433. {
  2434. CloseHidFile(pPhone->pHidDevice);
  2435. MemFree(pPhone->lpOverlapped);
  2436. CloseHandle(pPhone->hCloseEvent);
  2437. CloseHandle(pPhone->hInputReportEvent);
  2438. LeaveCriticalSection(&pPhone->csThisPhone);
  2439. LOG((PHONESP_ERROR,"TSPI_phoneOpen - HidD_SetNumInputBuffers"
  2440. " Failed: %d", GetLastError()));
  2441. return PHONEERR_OPERATIONFAILED;
  2442. }
  2443. //
  2444. // Start a thread for waiting for input reports from the device. We
  2445. // cannot use the thread pool for this because we will need to cancel
  2446. // pending reads if we want to close the device.
  2447. //
  2448. if ( ! ( pPhone->hReadThread =
  2449. CreateThread ((LPSECURITY_ATTRIBUTES) NULL,
  2450. 0,
  2451. (LPTHREAD_START_ROUTINE) ReadThread,
  2452. pPhone,
  2453. 0,
  2454. NULL
  2455. ) ) )
  2456. {
  2457. CloseHidFile(pPhone->pHidDevice);
  2458. MemFree(pPhone->lpOverlapped);
  2459. CloseHandle(pPhone->hCloseEvent);
  2460. CloseHandle(pPhone->hInputReportEvent);
  2461. LeaveCriticalSection(&pPhone->csThisPhone);
  2462. LOG((PHONESP_ERROR,"TSPI_phoneOpen - Create Thread: hReadThread"
  2463. " Failed: %d", GetLastError()));
  2464. return PHONEERR_NOMEM;
  2465. }
  2466. //
  2467. // Set phone open
  2468. //
  2469. pPhone->bPhoneOpen = TRUE;
  2470. pPhone->htPhone = htPhone;
  2471. pPhone->lpfnPhoneEventProc = lpfnEventProc;
  2472. *lphdPhone = (HDRVPHONE)IntToPtr(dwPhoneID);
  2473. //
  2474. // Update values for phone features (such as hookswitch state)
  2475. //
  2476. UpdatePhoneFeatures( pPhone );
  2477. LeaveCriticalSection(&pPhone->csThisPhone);
  2478. LOG((PHONESP_TRACE, "TSPI_phoneOpen - exit"));
  2479. return 0;
  2480. }
  2481. /********************TSPI_phoneOpen - end*************************************/
  2482. /******************************************************************************
  2483. TSPI_phoneSelectExtVersion:
  2484. This function selects the indicated extension version for the indicated
  2485. phone device. Subsequent requests operate according to that extension
  2486. version.
  2487. Comments: To be implemented in Tier 2
  2488. ******************************************************************************/
  2489. LONG
  2490. TSPIAPI
  2491. TSPI_phoneSelectExtVersion(
  2492. HDRVPHONE hdPhone,
  2493. DWORD dwExtVersion
  2494. )
  2495. {
  2496. LOG((PHONESP_TRACE, "TSPI_phoneSelectExtVersion- enter"));
  2497. LOG((PHONESP_TRACE, "TSPI_phoneSelectExtVersion - exit"));
  2498. return PHONEERR_OPERATIONUNAVAIL;
  2499. }
  2500. /****************************TSPI_phoneSelectExtVersion - end*****************/
  2501. /******************************************************************************
  2502. TSPI_phoneSetDisplay:
  2503. This function causes the specified string to be displayed on the specified
  2504. open phone device.
  2505. Comments: To be implemented in Tier 2
  2506. ******************************************************************************/
  2507. LONG
  2508. TSPIAPI
  2509. TSPI_phoneSetDisplay(
  2510. DRV_REQUESTID dwRequestID,
  2511. HDRVPHONE hdPhone,
  2512. DWORD dwRow,
  2513. DWORD dwColumn,
  2514. LPCWSTR lpsDisplay,
  2515. DWORD dwSize
  2516. )
  2517. {
  2518. LOG((PHONESP_TRACE, "TSPI_phoneSetDisplay - enter"));
  2519. LOG((PHONESP_TRACE, "TSPI_phoneSetDisplay - exit"));
  2520. return PHONEERR_OPERATIONUNAVAIL;
  2521. }
  2522. /****************************TSPI_phoneSetDisplay - end***********************/
  2523. /******************************************************************************
  2524. TSPI_phoneSetHookSwitch_AsyncProc:
  2525. This function sets the hook state of the specified open phone's hookswitch
  2526. devices to the specified mode. Only the hookswitch state of the hookswitch
  2527. devices listed is affected.
  2528. Arguments:
  2529. PMYFUNC_INFO pAsyncFuncInfo - The parameters passed to this function
  2530. Param1 - Pointer to the phone structure
  2531. Param2 - dwRequestID which is needed while calling
  2532. ASYNC_COMPLETION to inform TAPI about the result
  2533. of the operation. This was passed by tapi when
  2534. calling TSPI_phoneSetHookSwitch
  2535. Param3 - PHONEHOOKSWITCHDEV_ constant. Currently only
  2536. _SPEAKER is supported.
  2537. Param4 - The HookSwitchMode that has to be set for
  2538. the HookSwitch. This again is supplied by TAPI
  2539. Currently only PHONEHOOKSWITCHMODE_ONHOOK and
  2540. _MICSPEAKER is supported.
  2541. RETURNS VOID:
  2542. ******************************************************************************/
  2543. VOID
  2544. CALLBACK
  2545. TSPI_phoneSetHookSwitch_AsyncProc(
  2546. PPHONESP_FUNC_INFO pAsyncFuncInfo
  2547. )
  2548. {
  2549. PPHONESP_PHONE_INFO pPhone;
  2550. LONG lResult = 0;
  2551. LOG((PHONESP_TRACE, "TSPI_phoneSetHookSwitch_AsyncProc - enter"));
  2552. EnterCriticalSection(&csAllPhones);
  2553. pPhone = (PPHONESP_PHONE_INFO)pAsyncFuncInfo->dwParam1;
  2554. // if the phone is not open
  2555. if( IsBadReadPtr(pPhone, sizeof(PHONESP_PHONE_INFO)) ||
  2556. ( ! pPhone->bAllocated) ||
  2557. ( ! pPhone->bPhoneOpen) ||
  2558. ( ! pPhone->pHidDevice) )
  2559. {
  2560. // This case may never arise since phone close waits for all
  2561. // asynchornous opreations on the phone to complete before closing the
  2562. // phone
  2563. LONG lResult = PHONEERR_INVALPHONEHANDLE;
  2564. LeaveCriticalSection(&csAllPhones);
  2565. // Notify TAPISRV about the error condition
  2566. (*(glpfnCompletionProc))(
  2567. (DRV_REQUESTID) pAsyncFuncInfo->dwParam2,
  2568. lResult
  2569. );
  2570. LOG((PHONESP_ERROR, "TSPI_phoneSetHookSwitch_AsyncProc - Invalid Phone"
  2571. " Handle"));
  2572. }
  2573. else
  2574. {
  2575. EnterCriticalSection(&pPhone->csThisPhone);
  2576. LeaveCriticalSection(&csAllPhones);
  2577. switch (pAsyncFuncInfo->dwParam4)
  2578. {
  2579. case PHONEHOOKSWITCHMODE_ONHOOK:
  2580. if ( pPhone->dwSpeakerHookSwitchMode != PHONEHOOKSWITCHMODE_ONHOOK )
  2581. {
  2582. //Inform tapi about the change in state of the hookswitch
  2583. SendPhoneEvent(
  2584. pPhone,
  2585. PHONE_STATE,
  2586. PHONESTATE_SPEAKERHOOKSWITCH,
  2587. PHONEHOOKSWITCHMODE_ONHOOK,
  2588. (DWORD) 0
  2589. );
  2590. pPhone->dwSpeakerHookSwitchMode = PHONEHOOKSWITCHMODE_ONHOOK;
  2591. }
  2592. lResult = ERROR_SUCCESS;
  2593. break;
  2594. case PHONEHOOKSWITCHMODE_MICSPEAKER:
  2595. if ( pPhone->dwSpeakerHookSwitchMode != PHONEHOOKSWITCHMODE_MICSPEAKER )
  2596. {
  2597. //Inform tapi about the change in state of the hookswitch
  2598. SendPhoneEvent(
  2599. pPhone,
  2600. PHONE_STATE,
  2601. PHONESTATE_SPEAKERHOOKSWITCH,
  2602. PHONEHOOKSWITCHMODE_MICSPEAKER,
  2603. (DWORD) 0
  2604. );
  2605. pPhone->dwSpeakerHookSwitchMode = PHONEHOOKSWITCHMODE_MICSPEAKER;
  2606. }
  2607. lResult = ERROR_SUCCESS;
  2608. break;
  2609. default:
  2610. lResult = PHONEERR_RESOURCEUNAVAIL;
  2611. break;
  2612. }
  2613. // Send the result of the operation to TAPI
  2614. (*(glpfnCompletionProc))(
  2615. (DRV_REQUESTID) pAsyncFuncInfo->dwParam2,
  2616. lResult // Result of the operation
  2617. );
  2618. LeaveCriticalSection(&pPhone->csThisPhone);
  2619. }
  2620. LOG((PHONESP_TRACE, "TSPI_phoneSetHookSwitch_AsyncProc - exit"));
  2621. }
  2622. /******************************************************************************
  2623. TSPI_phoneSetHookSwitch:
  2624. This function sets the hook state of the specified open phone's hookswitch
  2625. devices to the specified mode. Only the hookswitch state of the hookswitch
  2626. devices listed is affected.
  2627. Arguments:
  2628. dwRequestID - The identifier of the asynchronous request.
  2629. hdPhone - The handle to the phone containing the hookswitch
  2630. devices whose modes are to be set.
  2631. dwHookSwitchDevs - The device(s) whose hookswitch mode is to be set.
  2632. This parameter uses the following PHONEHOOKSWITCHDEV_
  2633. constants: PHONEHOOKSWITCHDEV_HANDSET,
  2634. PHONEHOOKSWITCHDEV_SPEAKER, PHONEHOOKSWITCHDEV_HEADSET
  2635. dwHookSwitchMode - The hookswitch mode to set. This parameter can have
  2636. only one of the following PHONEHOOKSWITCHMODE_ bits
  2637. set: PHONEHOOKSWITCHMODE_ONHOOK, _MIC, _SPEAKER,
  2638. _MICSPEAKER
  2639. Return LONG:
  2640. Returns dwRequestID or an error number if an error occurs.
  2641. The lResult actual parameter of the corresponding ASYNC_COMPLETION is
  2642. zero if the function succeeds or it is an error number if an error
  2643. occurs. Possible return values are as follows:
  2644. PHONEERR_INVALPHONEHANDLE, PHONEERR_RESOURCEUNAVAIL,
  2645. PHONEERR_INVALHOOKSWITCHMODE,
  2646. Remarks
  2647. A PHONE_STATE message is sent to the application after the hookswitch
  2648. state has changed.
  2649. ******************************************************************************/
  2650. LONG
  2651. TSPIAPI
  2652. TSPI_phoneSetHookSwitch(
  2653. DRV_REQUESTID dwRequestID,
  2654. HDRVPHONE hdPhone,
  2655. DWORD dwHookSwitchDevs,
  2656. DWORD dwHookSwitchMode
  2657. )
  2658. {
  2659. PPHONESP_PHONE_INFO pPhone;
  2660. //
  2661. // Since only mode should be selected. We are making sure that only one
  2662. // mode is selected at a time..
  2663. //
  2664. BOOL ONHOOK = ~(dwHookSwitchMode ^ PHONEHOOKSWITCHMODE_ONHOOK),
  2665. MIC = ~(dwHookSwitchMode ^ PHONEHOOKSWITCHMODE_MIC),
  2666. SPEAKER = ~(dwHookSwitchMode ^ PHONEHOOKSWITCHMODE_SPEAKER),
  2667. MICSPEAKER = ~(dwHookSwitchMode ^ PHONEHOOKSWITCHMODE_MICSPEAKER);
  2668. PPHONESP_ASYNC_REQ_INFO pAsyncReqInfo;
  2669. PPHONESP_FUNC_INFO pFuncInfo;
  2670. LOG((PHONESP_TRACE, "TSPI_phoneSetHookSwitch - enter"));
  2671. EnterCriticalSection(&csAllPhones);
  2672. pPhone = (PPHONESP_PHONE_INFO) gpPhone[ (DWORD_PTR) hdPhone ];
  2673. // if the phone handle is valid and the phone is open
  2674. if( IsBadReadPtr(pPhone, sizeof(PHONESP_PHONE_INFO) ) ||
  2675. (! pPhone->bPhoneOpen) )
  2676. {
  2677. LeaveCriticalSection(&csAllPhones);
  2678. return PHONEERR_INVALPHONEHANDLE;
  2679. }
  2680. EnterCriticalSection(&pPhone->csThisPhone);
  2681. LeaveCriticalSection(&csAllPhones);
  2682. // Check whether the phone handle is still in use
  2683. if ( !pPhone->bAllocated )
  2684. {
  2685. LeaveCriticalSection(&pPhone->csThisPhone);
  2686. LOG((PHONESP_ERROR, "TSPI_phoneSetHookSwitch - phone not allocated"));
  2687. return PHONEERR_NODEVICE;
  2688. }
  2689. //
  2690. // Only the speaker phone can be set, the other hookswitch types are error
  2691. // conditions
  2692. //
  2693. if( ! (dwHookSwitchDevs & PHONEHOOKSWITCHDEV_SPEAKER) )
  2694. {
  2695. LeaveCriticalSection(&pPhone->csThisPhone);
  2696. LOG((PHONESP_ERROR, "TSPI_phoneSetHookSwitch - only speaker hookswitch is supported"));
  2697. return PHONEERR_RESOURCEUNAVAIL;
  2698. }
  2699. LOG((PHONESP_TRACE, "PHONEHOOKSWITCHDEV_SPEAKER"));
  2700. //
  2701. // Make sure the phone supports a speakerphone
  2702. //
  2703. if ( ! ( pPhone->dwSpeaker ) )
  2704. {
  2705. LeaveCriticalSection(&pPhone->csThisPhone);
  2706. LOG((PHONESP_ERROR, "No speaker"));
  2707. return PHONEERR_RESOURCEUNAVAIL;
  2708. }
  2709. // Inorder to confirm that one mode is set
  2710. if( ! ( ONHOOK | MIC | SPEAKER| MICSPEAKER ) )
  2711. {
  2712. LeaveCriticalSection(&pPhone->csThisPhone);
  2713. LOG((PHONESP_ERROR, "Mulitple modes set for the speaker"));
  2714. return PHONEERR_INVALHOOKSWITCHMODE;
  2715. }
  2716. // Build the structure for queueing the request in the Async queue
  2717. if( ! (pFuncInfo = (PPHONESP_FUNC_INFO)
  2718. MemAlloc( sizeof (PHONESP_FUNC_INFO)) ) )
  2719. {
  2720. LeaveCriticalSection(&pPhone->csThisPhone);
  2721. return PHONEERR_NOMEM;
  2722. }
  2723. pFuncInfo->dwParam1 = (ULONG_PTR) pPhone;
  2724. pFuncInfo->dwParam2 = dwRequestID;
  2725. pFuncInfo->dwParam3 = (ULONG_PTR) PHONEHOOKSWITCHDEV_SPEAKER;
  2726. pFuncInfo->dwParam4 = (ULONG_PTR) dwHookSwitchMode;
  2727. pFuncInfo->dwNumParams = 4;
  2728. if ( ! ( pAsyncReqInfo = (PPHONESP_ASYNC_REQ_INFO)
  2729. MemAlloc(sizeof (PHONESP_ASYNC_REQ_INFO)) ) )
  2730. {
  2731. LeaveCriticalSection(&pPhone->csThisPhone);
  2732. MemFree(pFuncInfo);
  2733. return PHONEERR_NOMEM;
  2734. }
  2735. pAsyncReqInfo->pfnAsyncProc = TSPI_phoneSetHookSwitch_AsyncProc;
  2736. pAsyncReqInfo->pFuncInfo = pFuncInfo;
  2737. //
  2738. // if Queue the request to perform asynchronously fails then we need to
  2739. // decrement the counter of number of pending requests on the phone
  2740. //
  2741. if( AsyncRequestQueueIn(pAsyncReqInfo) )
  2742. {
  2743. // Reset the event for number of pending requests in the queue for this
  2744. // phone and increment the counter
  2745. if (pPhone->dwNumPendingReqInQueue == 0)
  2746. {
  2747. ResetEvent(pPhone->hNoPendingReqInQueueEvent);
  2748. }
  2749. pPhone->dwNumPendingReqInQueue++;
  2750. LeaveCriticalSection(&pPhone->csThisPhone);
  2751. }
  2752. else
  2753. {
  2754. LeaveCriticalSection(&pPhone->csThisPhone);
  2755. MemFree(pAsyncReqInfo);
  2756. MemFree(pFuncInfo);
  2757. // maybe need to free the request memory
  2758. return PHONEERR_NOMEM;
  2759. }
  2760. LOG((PHONESP_TRACE, "TSPI_phoneSetHookSwitch - exit"));
  2761. return dwRequestID;
  2762. }
  2763. /*******************TSPI_phoneSetHookSwitch - end****************************/
  2764. /*****************************************************************************
  2765. TSPI_phoneSetLamp:
  2766. This function causes the specified lamp to be set on the specified open
  2767. phone device in the specified lamp mode.
  2768. Comments: To be implemented in Tier 2
  2769. ******************************************************************************/
  2770. LONG
  2771. TSPIAPI
  2772. TSPI_phoneSetLamp(
  2773. DRV_REQUESTID dwRequestID,
  2774. HDRVPHONE hdPhone,
  2775. DWORD dwButtonLampID,
  2776. DWORD dwLampMode
  2777. )
  2778. {
  2779. LOG((PHONESP_TRACE, "TSPI_phoneSetLamp - enter"));
  2780. LOG((PHONESP_TRACE, "TSPI_phoneSetLamp - exit"));
  2781. return PHONEERR_OPERATIONUNAVAIL;
  2782. }
  2783. /****************************TSPI_phoneSetLamp - end**************************/
  2784. /******************************************************************************
  2785. TSPI_phoneSetRing_AsyncProc:
  2786. Arguments:
  2787. Returns:
  2788. Comments: To be implemented. currently there is no corresponding usage in
  2789. Hid hence no output report is sent.
  2790. ******************************************************************************/
  2791. VOID
  2792. CALLBACK
  2793. TSPI_phoneSetRing_AsyncProc(
  2794. PPHONESP_FUNC_INFO pAsyncFuncInfo
  2795. )
  2796. {
  2797. PPHONESP_PHONE_INFO pPhone;
  2798. LONG lResult = 0;
  2799. LOG((PHONESP_TRACE,"TSPI_phoneSetRing_AsyncProc - enter"));
  2800. EnterCriticalSection(&csAllPhones);
  2801. pPhone = (PPHONESP_PHONE_INFO)pAsyncFuncInfo->dwParam1;
  2802. // if the phone is not open
  2803. if( IsBadReadPtr(pPhone, sizeof(PHONESP_PHONE_INFO)) ||
  2804. ( ! pPhone->bPhoneOpen) ||
  2805. ( ! pPhone->bAllocated) ||
  2806. ( ! pPhone->pHidDevice) )
  2807. {
  2808. // This case may never arise since phone close waits for all
  2809. // asynchornous opreations on the phone to complete before closing the
  2810. // phone
  2811. LONG lResult = PHONEERR_INVALPHONEHANDLE;
  2812. LeaveCriticalSection(&csAllPhones);
  2813. // Notify TAPISRV about the error condition
  2814. (*(glpfnCompletionProc))(
  2815. (DRV_REQUESTID) pAsyncFuncInfo->dwParam2,
  2816. lResult
  2817. );
  2818. LOG((PHONESP_ERROR, "TSPI_phoneSetRing_AsyncProc - Invalid Phone"
  2819. " Handle"));
  2820. }
  2821. else
  2822. {
  2823. EnterCriticalSection(&pPhone->csThisPhone);
  2824. LeaveCriticalSection(&csAllPhones);
  2825. lResult = SendOutputReport(
  2826. pPhone->pHidDevice,
  2827. HID_USAGE_TELEPHONY_RINGER,
  2828. ((pAsyncFuncInfo->dwParam3 == 0) ? FALSE : TRUE)
  2829. );
  2830. if(lResult == ERROR_SUCCESS)
  2831. {
  2832. lResult = 0;
  2833. pPhone->dwRingMode = (DWORD)pAsyncFuncInfo->dwParam3;
  2834. //Inform tapi about the change in state of the hookswitch
  2835. SendPhoneEvent(
  2836. pPhone,
  2837. PHONE_STATE,
  2838. PHONESTATE_RINGMODE,
  2839. (DWORD) pAsyncFuncInfo->dwParam3,
  2840. (DWORD) pAsyncFuncInfo->dwParam4
  2841. );
  2842. }
  2843. else
  2844. {
  2845. LOG((PHONESP_ERROR, "TSPI_phoneSetHookSwitch_AsyncProc - "
  2846. "SendOutputReport Failed"));
  2847. lResult = PHONEERR_RESOURCEUNAVAIL;
  2848. }
  2849. // Send the result of the operation to TAPI
  2850. (*(glpfnCompletionProc))(
  2851. (DRV_REQUESTID) pAsyncFuncInfo->dwParam2,
  2852. lResult // Result of the operation
  2853. );
  2854. LeaveCriticalSection(&pPhone->csThisPhone);
  2855. }
  2856. LOG((PHONESP_TRACE,"TSPI_phoneSetRing_AsyncProc - exit"));
  2857. }
  2858. /*******************TSPI_phoneSetRing_AsyncProc - end*************************/
  2859. /******************************************************************************
  2860. TSPI_phoneSetRing:
  2861. This function rings the specified open phone device using the specified
  2862. ring mode and volume.
  2863. Arguments:
  2864. DRV_REQUESTID dwRequestID - Identifier of the asynchronous request.
  2865. HDRVPHONE hdPhone - Handle to the phone to be rung.
  2866. DWORD dwRingMode - The ringing pattern with which to ring the phone.
  2867. This parameter must be within the range from zero
  2868. through the value of the dwNumRingModes member in the
  2869. PHONECAPS structure. If dwNumRingModes is zero, the
  2870. ring mode of the phone cannot be controlled; if
  2871. dwNumRingModes is 1, a value of 0 for dwRingMode
  2872. indicates that the phone should not be rung (silence),
  2873. and other values from 1 through dwNumRingModes are
  2874. valid ring modes for the phone device.
  2875. DWORD dwVolume - The volume level with which the phone is to be rung.
  2876. This is a number in the range from 0x00000000
  2877. (silence) through 0x0000FFFF (maximum volume).
  2878. Returns LONG:
  2879. Zero if success
  2880. PHONEERR_ constants if an error occurs
  2881. ******************************************************************************/
  2882. LONG
  2883. TSPIAPI
  2884. TSPI_phoneSetRing(
  2885. DRV_REQUESTID dwRequestID,
  2886. HDRVPHONE hdPhone,
  2887. DWORD dwRingMode,
  2888. DWORD dwVolume
  2889. )
  2890. {
  2891. PPHONESP_PHONE_INFO pPhone = (PPHONESP_PHONE_INFO)gpPhone[ (DWORD_PTR) hdPhone ];
  2892. LOG((PHONESP_TRACE, "TSPI_phoneSetRing - enter"));
  2893. EnterCriticalSection(&csAllPhones);
  2894. // to confirm that the phone is open
  2895. if( ! (pPhone && pPhone->htPhone) )
  2896. {
  2897. LeaveCriticalSection(&csAllPhones);
  2898. return PHONEERR_INVALPHONEHANDLE;
  2899. }
  2900. EnterCriticalSection(&pPhone->csThisPhone);
  2901. LeaveCriticalSection(&csAllPhones);
  2902. // Check whether the phone handle is still in use
  2903. if ( !pPhone->bAllocated )
  2904. {
  2905. LeaveCriticalSection(&pPhone->csThisPhone);
  2906. LOG((PHONESP_ERROR, "TSPI_phoneSetRing - phone not allocated"));
  2907. return PHONEERR_NODEVICE;
  2908. }
  2909. // The ringer can only be set if the phone has an output feature for this
  2910. // usage
  2911. if( ! (pPhone->dwRing & OUTPUT_REPORT) )
  2912. {
  2913. // The phone has a ringer but no output feature
  2914. if(pPhone->dwRing)
  2915. {
  2916. LeaveCriticalSection(&pPhone->csThisPhone);
  2917. return PHONEERR_OPERATIONUNAVAIL;
  2918. }
  2919. // The phone does not have a ringer
  2920. else
  2921. {
  2922. LeaveCriticalSection(&pPhone->csThisPhone);
  2923. return PHONEERR_RESOURCEUNAVAIL;
  2924. }
  2925. }
  2926. if ( (dwRingMode == 0) || (dwRingMode == 1) )
  2927. {
  2928. // Check whether the volume is within range
  2929. if(dwVolume <= 0x0000FFFF)
  2930. {
  2931. PPHONESP_ASYNC_REQ_INFO pAsyncReqInfo;
  2932. PPHONESP_FUNC_INFO pFuncInfo;
  2933. // Build the structure for the queueing the request in Async queue
  2934. if ( ! (pFuncInfo = (PPHONESP_FUNC_INFO)
  2935. MemAlloc(sizeof (PHONESP_FUNC_INFO)) ) )
  2936. {
  2937. LeaveCriticalSection(&pPhone->csThisPhone);
  2938. return PHONEERR_NOMEM;
  2939. }
  2940. pFuncInfo->dwNumParams = 4;
  2941. pFuncInfo->dwParam1 = (ULONG_PTR) pPhone;
  2942. pFuncInfo->dwParam2 = dwRequestID;
  2943. pFuncInfo->dwParam3 = (ULONG_PTR) dwRingMode;
  2944. pFuncInfo->dwParam4 = (ULONG_PTR) dwVolume;
  2945. if ( ! ( pAsyncReqInfo = (PPHONESP_ASYNC_REQ_INFO)
  2946. MemAlloc(sizeof(PHONESP_ASYNC_REQ_INFO))))
  2947. {
  2948. LeaveCriticalSection(&pPhone->csThisPhone);
  2949. MemFree(pFuncInfo);
  2950. return PHONEERR_NOMEM;
  2951. }
  2952. pAsyncReqInfo->pfnAsyncProc = TSPI_phoneSetRing_AsyncProc;
  2953. pAsyncReqInfo->pFuncInfo = pFuncInfo;
  2954. // Queue the request to perform the operation asynchronously
  2955. if( AsyncRequestQueueIn(pAsyncReqInfo) )
  2956. {
  2957. // Reset the event for number of pending requests in the queue
  2958. // for this phone and increment the counter
  2959. if (pPhone->dwNumPendingReqInQueue == 0)
  2960. {
  2961. ResetEvent(pPhone->hNoPendingReqInQueueEvent);
  2962. }
  2963. pPhone->dwNumPendingReqInQueue++;
  2964. LeaveCriticalSection(&pPhone->csThisPhone);
  2965. }
  2966. else
  2967. {
  2968. LeaveCriticalSection(&pPhone->csThisPhone);
  2969. MemFree(pFuncInfo);
  2970. MemFree(pAsyncReqInfo);
  2971. return PHONEERR_NOMEM;
  2972. }
  2973. }
  2974. else
  2975. {
  2976. LeaveCriticalSection(&pPhone->csThisPhone);
  2977. return PHONEERR_INVALPARAM;
  2978. }
  2979. }
  2980. else
  2981. {
  2982. LeaveCriticalSection(&pPhone->csThisPhone);
  2983. return PHONEERR_INVALRINGMODE;
  2984. }
  2985. LOG((PHONESP_TRACE, "TSPI_phoneSetRing - exit"));
  2986. return 0;
  2987. }
  2988. /********************TSPI_phoneSetRing - end**********************************/
  2989. /******************************************************************************
  2990. TSPI_phoneSetStatusMessages:
  2991. This function causes the TSP to filter status messages that are not
  2992. currently of interest to any application.
  2993. Arguments:
  2994. Returns:
  2995. ******************************************************************************/
  2996. LONG
  2997. TSPIAPI
  2998. TSPI_phoneSetStatusMessages(
  2999. HDRVPHONE hdPhone,
  3000. DWORD dwPhoneStates,
  3001. DWORD dwButtonModes,
  3002. DWORD dwButtonStates
  3003. )
  3004. {
  3005. PPHONESP_PHONE_INFO pPhone = (PPHONESP_PHONE_INFO)gpPhone[ (DWORD_PTR) hdPhone ];
  3006. LOG((PHONESP_TRACE, "TSPI_phoneSetStatusMessages - enter"));
  3007. EnterCriticalSection(&csAllPhones);
  3008. if( ! (pPhone && pPhone->htPhone) )
  3009. {
  3010. LeaveCriticalSection(&csAllPhones);
  3011. return PHONEERR_INVALPHONEHANDLE;
  3012. }
  3013. EnterCriticalSection(&pPhone->csThisPhone);
  3014. LeaveCriticalSection(&csAllPhones);
  3015. // Check whether the phone handle is still in use
  3016. if ( !pPhone->bAllocated )
  3017. {
  3018. LeaveCriticalSection(&pPhone->csThisPhone);
  3019. LOG((PHONESP_ERROR, "TSPI_phoneSetStatusMessages - phone not allocated"));
  3020. return PHONEERR_NODEVICE;
  3021. }
  3022. pPhone->dwPhoneStateMsgs = dwPhoneStates;
  3023. if (dwButtonModes)
  3024. {
  3025. if(dwButtonStates)
  3026. {
  3027. pPhone->dwButtonModesMsgs = dwButtonModes;
  3028. pPhone->dwButtonStateMsgs = dwButtonStates;
  3029. }
  3030. }
  3031. LeaveCriticalSection(&pPhone->csThisPhone);
  3032. LOG((PHONESP_TRACE, "TSPI_phoneSetStatusMessages - exit"));
  3033. return 0;
  3034. }
  3035. /********************TSPI_phoneSetStatusMessages - end************************/
  3036. //
  3037. // ------------------------- TSPI_providerXxx funcs ---------------------------
  3038. /******************************************************************************
  3039. TSPI_providerCreatePhoneDevice
  3040. The TSP will use this function to implement PNP support. TapiSrv will call
  3041. the TSP back with this function when the TSP sends the PHONE_CREATE message
  3042. to Tapisrv, which allows the dynamic creation of a new phone device.
  3043. Arguments:
  3044. dwTempID - The temporary device identifier that the TSP passed to
  3045. TAPI in the PHONE_CREATE message.
  3046. dwDeviceID - The device identifier that TAPI assigns to this device if
  3047. this function succeeds.
  3048. Returns LONG:
  3049. Zero if the request succeeds
  3050. An error number if an error occurs.
  3051. Comments:
  3052. ******************************************************************************/
  3053. LONG
  3054. TSPIAPI
  3055. TSPI_providerCreatePhoneDevice(
  3056. DWORD_PTR dwTempID,
  3057. DWORD dwDeviceID
  3058. )
  3059. {
  3060. PPHONESP_PHONE_INFO pPhone;
  3061. LOG((PHONESP_TRACE, "TSPI_providerCreatePhoneDevice - enter"));
  3062. EnterCriticalSection(&csAllPhones);
  3063. pPhone = (PPHONESP_PHONE_INFO)gpPhone[ (DWORD_PTR) dwTempID ];
  3064. // check whether the phone handle is valid
  3065. if ( IsBadReadPtr(pPhone, sizeof(PHONESP_PHONE_INFO) ) )
  3066. {
  3067. LeaveCriticalSection(&csAllPhones);
  3068. LOG((PHONESP_ERROR,"TSPI_providerCreatePhoneDevice - invalid temp id"));
  3069. return PHONEERR_INVALPHONEHANDLE;
  3070. }
  3071. EnterCriticalSection(&pPhone->csThisPhone);
  3072. LeaveCriticalSection(&csAllPhones);
  3073. if (pPhone->bCreatePending)
  3074. {
  3075. //
  3076. // Set the device ID and mark create complete
  3077. //
  3078. pPhone->dwDeviceID = dwDeviceID;
  3079. pPhone->bCreatePending = FALSE;
  3080. }
  3081. else
  3082. {
  3083. LOG((PHONESP_ERROR, "TSPI_providerCreatePhoneDevice - phone is not marked create pending"));
  3084. }
  3085. LOG((PHONESP_TRACE, "TSPI_providerCreatePhoneDevice - phone create complete [dwTempID %d] [dwDeviceID %d] ", dwTempID, dwDeviceID));
  3086. LeaveCriticalSection(&pPhone->csThisPhone);
  3087. LOG((PHONESP_TRACE, "TSPI_providerCreatePhoneDevice - exit"));
  3088. return 0;
  3089. }
  3090. /*****************TSPI_providerCreatePhoneDevice - end************************/
  3091. /******************************************************************************
  3092. TSPI_providerEnumDevices:
  3093. TAPI calls the this function before TSPI_providerInit to determine the
  3094. number of line and phone devices supported by the TSP.
  3095. Arguments:
  3096. dwPermanentProviderID - The permanent identifier,unique within the TSPs
  3097. on this system, of the TSP being initialized.
  3098. lpdwNumLines(ignored) - TAPI initializes the value to 0.
  3099. lpdwNumPhones - A pointer to a DWORD-sized memory location into
  3100. which the TSP must write the number of phone
  3101. devices it is configured to support. TAPI
  3102. initializes the value to 0.
  3103. hProvider - An opaque DWORD-sized value that uniquely
  3104. identifies this instance of this TSP during this
  3105. execution of the Win32 Telephony environment.
  3106. lpfnLineCreateProc(ignored)- A pointer to the LINEEVENT callback
  3107. procedure supplied by TAPI. Ignored by this TSP
  3108. lpfnPhoneCreateProc - A pointer to the PHONEEVENT callback procedure
  3109. supplied by TAPI. The TSP uses this function to
  3110. send PHONE_CREATE messages when a new phone
  3111. device needs to be created.
  3112. Returns LONG:
  3113. Zero if the request succeeds or
  3114. An error number if an error occurs.
  3115. Comments:Gets a pointer to the Hid Devices belonging to the telephony page.
  3116. ******************************************************************************/
  3117. LONG
  3118. TSPIAPI
  3119. TSPI_providerEnumDevices(
  3120. DWORD dwPermanentProviderID,
  3121. LPDWORD lpdwNumLines,
  3122. LPDWORD lpdwNumPhones,
  3123. HPROVIDER hProvider,
  3124. LINEEVENT lpfnLineCreateProc,
  3125. PHONEEVENT lpfnPhoneCreateProc
  3126. )
  3127. {
  3128. PPHONESP_PHONE_INFO *pPhone;
  3129. DWORD dwPhoneCnt, dwNumChars, dwCount;
  3130. LONG lResult = 0;
  3131. PHID_DEVICE pHidDevice;
  3132. PHID_DEVICE pHidDevices;
  3133. ULONG NumHidDevices;
  3134. HRESULT hr;
  3135. LOG((PHONESP_TRACE, "TSPI_providerEnumDevices - enter"));
  3136. //
  3137. // Initialise critical section for all phones which is the global object.
  3138. // Before accessing the phone structure, the thread must grab this object
  3139. //
  3140. __try
  3141. {
  3142. InitializeCriticalSection(&csAllPhones);
  3143. }
  3144. __except(1)
  3145. {
  3146. LOG((PHONESP_ERROR, "TSPI_providerEnumDevices - Initialize Critical Section"
  3147. " Failed for csAllPhones"));
  3148. return PHONEERR_NOMEM;
  3149. }
  3150. //
  3151. // Initialise critical section for all hid devices which is the global object.
  3152. // Before accessing the hid list, the thread must grab this object
  3153. //
  3154. __try
  3155. {
  3156. InitializeCriticalSection(&csHidList);
  3157. }
  3158. __except(1)
  3159. {
  3160. DeleteCriticalSection(&csAllPhones);
  3161. LOG((PHONESP_ERROR, "TSPI_providerEnumDevices - Initialize Critical Section"
  3162. " Failed for csHidList"));
  3163. return PHONEERR_NOMEM;
  3164. }
  3165. #if DBG
  3166. //Initialize critical section for memory tracing
  3167. __try
  3168. {
  3169. InitializeCriticalSection(&csMemoryList);
  3170. }
  3171. __except(1)
  3172. {
  3173. DeleteCriticalSection(&csAllPhones);
  3174. DeleteCriticalSection(&csHidList);
  3175. LOG((PHONESP_ERROR, "TSPI_providerEnumDevices - Initialize Critical Section"
  3176. " Failed for csMemoryList"));
  3177. return PHONEERR_NOMEM;
  3178. }
  3179. #endif
  3180. EnterCriticalSection(&csHidList);
  3181. // Find Telephony hid Devices
  3182. lResult = FindKnownHidDevices (&pHidDevices,
  3183. &NumHidDevices);
  3184. if (lResult != ERROR_SUCCESS)
  3185. {
  3186. LOG((PHONESP_ERROR, "TSPI_providerEnumDevices - FindKnownHidDevices failed %d", lResult));
  3187. LeaveCriticalSection(&csHidList);
  3188. DeleteCriticalSection(&csHidList);
  3189. DeleteCriticalSection(&csAllPhones);
  3190. #if DBG
  3191. DeleteCriticalSection(&csMemoryList);
  3192. #endif
  3193. if (lResult == ERROR_OUTOFMEMORY)
  3194. {
  3195. return PHONEERR_NOMEM;
  3196. }
  3197. else
  3198. {
  3199. return PHONEERR_OPERATIONFAILED;
  3200. }
  3201. }
  3202. LOG((PHONESP_TRACE, "TSPI_providerEnumDevices - number of Hid Devices : %d ", NumHidDevices));
  3203. // Allocate memory for the array of pointers where each pointer points to
  3204. // one of the phone discovered
  3205. pPhone = MemAlloc(NumHidDevices * sizeof(PPHONESP_PHONE_INFO));
  3206. if ( pPhone == NULL )
  3207. {
  3208. LOG((PHONESP_ERROR, "TSPI_providerEnumDevices - OUT OF MEMORY allocating pPhone"));
  3209. CloseHidDevices();
  3210. LeaveCriticalSection(&csHidList);
  3211. DeleteCriticalSection(&csHidList);
  3212. DeleteCriticalSection(&csAllPhones);
  3213. #if DBG
  3214. DeleteCriticalSection(&csMemoryList);
  3215. #endif
  3216. return PHONEERR_NOMEM;
  3217. }
  3218. //
  3219. // for each phone discovered, gather the capabilities of the phone and
  3220. // initialize the phone structure
  3221. //
  3222. dwPhoneCnt = 0;
  3223. for (pHidDevice = pHidDevices; pHidDevice != NULL; pHidDevice = pHidDevice->Next)
  3224. {
  3225. pHidDevice->bNew = FALSE;
  3226. // Allocate memory for this phone
  3227. pPhone[dwPhoneCnt] = (PPHONESP_PHONE_INFO)MemAlloc(sizeof(PHONESP_PHONE_INFO));
  3228. if ( pPhone[dwPhoneCnt] == NULL )
  3229. {
  3230. LOG((PHONESP_ERROR, "TSPI_providerEnumDevices - OUT OF MEMORY allocating PPHONESP_PHONE_INFO"
  3231. " for Phone %d", dwPhoneCnt));
  3232. // Release memory allocated to other phones
  3233. for(dwCount = 0; dwCount < dwPhoneCnt ; dwCount++)
  3234. {
  3235. FreePhone(pPhone[dwCount]);
  3236. MemFree((LPVOID)pPhone[dwCount]);
  3237. DeleteCriticalSection(&pPhone[dwCount]->csThisPhone);
  3238. }
  3239. MemFree((LPVOID)pPhone);
  3240. CloseHidDevices();
  3241. LeaveCriticalSection(&csHidList);
  3242. DeleteCriticalSection(&csHidList);
  3243. DeleteCriticalSection(&csAllPhones);
  3244. #if DBG
  3245. DeleteCriticalSection(&csMemoryList);
  3246. #endif
  3247. return PHONEERR_NOMEM;
  3248. }
  3249. LOG((PHONESP_TRACE, "TSPI_ProviderEnumDevices: Initializing Device: %d",dwPhoneCnt+1));
  3250. ZeroMemory( pPhone[dwPhoneCnt], sizeof(PHONESP_PHONE_INFO));
  3251. //
  3252. // Initialize the critical section object for this phone. only the
  3253. // thread that owns this object can access the structure for this phone
  3254. //
  3255. __try
  3256. {
  3257. InitializeCriticalSection(&pPhone[dwPhoneCnt]->csThisPhone);
  3258. }
  3259. __except(1)
  3260. {
  3261. // Release memory allocated to the phones
  3262. for(dwCount = 0; dwCount < dwPhoneCnt; dwCount++)
  3263. {
  3264. FreePhone(pPhone[dwCount]);
  3265. MemFree((LPVOID)pPhone[dwCount]);
  3266. DeleteCriticalSection(&pPhone[dwCount]->csThisPhone);
  3267. }
  3268. MemFree((LPVOID)pPhone[dwPhoneCnt]);
  3269. MemFree((LPVOID)pPhone);
  3270. CloseHidDevices();
  3271. LeaveCriticalSection(&csHidList);
  3272. DeleteCriticalSection(&csHidList);
  3273. DeleteCriticalSection(&csAllPhones);
  3274. #if DBG
  3275. DeleteCriticalSection(&csMemoryList);
  3276. #endif
  3277. LOG((PHONESP_ERROR,"TSPI_providerEnumDevices - Initialize Critical Section"
  3278. " Failed for Phone %d", dwPhoneCnt));
  3279. return PHONEERR_NOMEM;
  3280. }
  3281. lResult = CreatePhone( pPhone[dwPhoneCnt], pHidDevice, dwPhoneCnt );
  3282. if ( lResult != ERROR_SUCCESS )
  3283. {
  3284. LOG((PHONESP_ERROR,"TSPI_providerEnumDevices - CreatePhone"
  3285. " Failed for Phone %d: error: %d", dwPhoneCnt, lResult));
  3286. }
  3287. else
  3288. {
  3289. // Phone created successfully, increase phone count
  3290. dwPhoneCnt++;
  3291. }
  3292. }
  3293. LeaveCriticalSection(&csHidList);
  3294. *lpdwNumPhones = gdwNumPhones = dwPhoneCnt;
  3295. //
  3296. // If the space allocated previously was greater than the actual number of
  3297. // supported phones
  3298. //
  3299. if(NumHidDevices != gdwNumPhones)
  3300. {
  3301. gpPhone = MemAlloc(gdwNumPhones * sizeof(PPHONESP_PHONE_INFO));
  3302. if ( gpPhone == NULL )
  3303. {
  3304. for(dwCount = 0; dwCount < dwPhoneCnt ; dwCount++)
  3305. {
  3306. FreePhone(pPhone[dwCount]);
  3307. MemFree((LPVOID)pPhone[dwCount]);
  3308. DeleteCriticalSection(&pPhone[dwCount]->csThisPhone);
  3309. }
  3310. MemFree(pPhone);
  3311. CloseHidDevices();
  3312. DeleteCriticalSection(&csAllPhones);
  3313. #if DBG
  3314. DeleteCriticalSection(&csMemoryList);
  3315. #endif
  3316. DeleteCriticalSection(&csHidList);
  3317. LOG((PHONESP_ERROR,"TSPI_providerEnumDevices - OUT OF MEMORY allocating gpPhone"));
  3318. return PHONEERR_NOMEM;
  3319. }
  3320. CopyMemory(
  3321. gpPhone,
  3322. pPhone,
  3323. sizeof(PPHONESP_PHONE_INFO) * gdwNumPhones
  3324. );
  3325. MemFree(pPhone);
  3326. }
  3327. else
  3328. {
  3329. gpPhone = pPhone;
  3330. }
  3331. glpfnPhoneCreateProc = lpfnPhoneCreateProc;
  3332. ghProvider = hProvider;
  3333. LOG((PHONESP_TRACE, "TSPI_providerEnumDevices - exit"));
  3334. return 0;
  3335. }
  3336. /*************************TSPI_providerEnumDevices - end*********************/
  3337. /******************************************************************************
  3338. TSPI_providerInit:
  3339. The TSPI_providerInit function initializes the service provider and gives
  3340. it parameters required for subsequent operation.
  3341. Arguments:
  3342. dwTSPIVersion - The version of the TSPI definition under which
  3343. this function must operate.
  3344. dwPermanentProviderID - The permanent identifier, unique within the TSP
  3345. on this system, of the TSP being initialized.
  3346. dwLineDeviceIDBase - Ignored by this TSP
  3347. dwPhoneDeviceIDBase - The lowest device identifier for the phone
  3348. devices supported by this service provider.
  3349. dwNumLines(Ignored) - The number of line devices this TSP supports.
  3350. dwNumPhones - The number of phone devices this TSP supports.
  3351. The value returned is the number of phone
  3352. devices reported in TSPI_providerEnumDevices.
  3353. lpfnCompletionProc - The procedure the TSP calls to report
  3354. completion of all asynchronously operating
  3355. procedures on line and phone devices.
  3356. lpdwTSPIOptions - A pointer to a DWORD-sized memory location,into
  3357. which the TSP can write a value specifying
  3358. LINETSPIOPTIONS_ values. This parameter allows
  3359. the TSP to return bits indicating optional
  3360. behaviors desired of TAPI. TAPI sets the
  3361. options DWORD to 0.
  3362. Returns LONG:
  3363. Zero if the request succeeds or
  3364. An error number if an error occurs.
  3365. Comments:
  3366. ******************************************************************************/
  3367. LONG
  3368. TSPIAPI
  3369. TSPI_providerInit(
  3370. DWORD dwTSPIVersion,
  3371. DWORD dwPermanentProviderID,
  3372. DWORD dwLineDeviceIDBase,
  3373. DWORD dwPhoneDeviceIDBase,
  3374. DWORD_PTR dwNumLines,
  3375. DWORD_PTR dwNumPhones,
  3376. ASYNC_COMPLETION lpfnCompletionProc,
  3377. LPDWORD lpdwTSPIOptions
  3378. )
  3379. {
  3380. DWORD dwThreadID;
  3381. LONG lResult = 0;
  3382. LOGREGISTERTRACING(_T("hidphone"));
  3383. LOG((PHONESP_TRACE, "TSPI_providerInit - enter"));
  3384. // Load Provider Info From String Table
  3385. gszProviderInfo = PHONESP_LoadString(
  3386. IDS_PROVIDER_INFO,
  3387. &lResult
  3388. );
  3389. if(lResult != ERROR_SUCCESS)
  3390. {
  3391. DWORD dwPhoneCnt;
  3392. LOG((PHONESP_ERROR,"TSPI_providerEnumDevices - PHONESP_LoadString failed %d", lResult));
  3393. for(dwPhoneCnt = 0; dwPhoneCnt < gdwNumPhones; dwPhoneCnt++)
  3394. {
  3395. FreePhone(gpPhone[dwPhoneCnt]);
  3396. DeleteCriticalSection(&gpPhone[dwPhoneCnt]->csThisPhone);
  3397. MemFree(gpPhone[dwPhoneCnt]);
  3398. }
  3399. EnterCriticalSection(&csHidList);
  3400. CloseHidDevices();
  3401. LeaveCriticalSection(&csHidList);
  3402. DeleteCriticalSection(&csHidList);
  3403. DeleteCriticalSection(&csAllPhones);
  3404. #if DBG
  3405. DeleteCriticalSection(&csMemoryList);
  3406. #endif
  3407. if(lResult == ERROR_OUTOFMEMORY)
  3408. {
  3409. return PHONEERR_NOMEM;
  3410. }
  3411. else
  3412. {
  3413. return lResult;
  3414. }
  3415. }
  3416. glpfnCompletionProc = lpfnCompletionProc;
  3417. gdwPhoneDeviceIDBase = dwPhoneDeviceIDBase;
  3418. gdwPermanentProviderID = dwPermanentProviderID;
  3419. //
  3420. // Assign device IDs to the phones
  3421. //
  3422. {
  3423. DWORD dwPhoneCnt;
  3424. for(dwPhoneCnt = 0; dwPhoneCnt < gdwNumPhones; dwPhoneCnt++)
  3425. {
  3426. gpPhone[dwPhoneCnt]->dwDeviceID = gdwPhoneDeviceIDBase + dwPhoneCnt;
  3427. }
  3428. }
  3429. //
  3430. // Alloc a queue for storing async requests for async completion,
  3431. // and start a thread to service that queue
  3432. //
  3433. //Initialize critical section for the async queue
  3434. __try
  3435. {
  3436. InitializeCriticalSection(&gAsyncQueue.AsyncEventQueueCritSec);
  3437. }
  3438. __except(1)
  3439. {
  3440. DWORD dwPhoneCnt;
  3441. LOG((PHONESP_ERROR, "TSPI_providerInit - Initialize Critical Section"
  3442. " Failed for gAsyncQueue.AsyncEventQueueCritSec"));
  3443. for(dwPhoneCnt = 0; dwPhoneCnt < gdwNumPhones; dwPhoneCnt++)
  3444. {
  3445. FreePhone(gpPhone[dwPhoneCnt]);
  3446. MemFree(gpPhone[dwPhoneCnt]);
  3447. DeleteCriticalSection(&gpPhone[dwPhoneCnt]->csThisPhone);
  3448. }
  3449. EnterCriticalSection(&csHidList);
  3450. CloseHidDevices();
  3451. LeaveCriticalSection(&csHidList);
  3452. MemFree((LPVOID) gszProviderInfo);
  3453. DeleteCriticalSection(&csHidList);
  3454. DeleteCriticalSection(&csAllPhones);
  3455. #if DBG
  3456. DeleteCriticalSection(&csMemoryList);
  3457. #endif
  3458. return PHONEERR_NOMEM;
  3459. }
  3460. gAsyncQueue.dwNumTotalQueueEntries = MAX_QUEUE_ENTRIES;
  3461. gAsyncQueue.dwNumUsedQueueEntries = 0;
  3462. //
  3463. // Alloc memory for the queue to accomodate dwNumTotalQueueEntries ot begin
  3464. // with. The size of the queue can later be increased as required
  3465. //
  3466. gAsyncQueue.pAsyncRequestQueue =
  3467. MemAlloc(gAsyncQueue.dwNumTotalQueueEntries * sizeof(PPHONESP_ASYNC_REQ_INFO));
  3468. if ( gAsyncQueue.pAsyncRequestQueue == NULL )
  3469. {
  3470. DWORD dwPhoneCnt;
  3471. LOG((PHONESP_ERROR, "TSPI_providerInit - OUT OF MEMORY allocating"
  3472. " gAsyncQueue.pAsyncRequestQueue"));
  3473. for(dwPhoneCnt = 0; dwPhoneCnt < gdwNumPhones; dwPhoneCnt++)
  3474. {
  3475. FreePhone(gpPhone[dwPhoneCnt]);
  3476. MemFree(gpPhone[dwPhoneCnt]);
  3477. DeleteCriticalSection(&gpPhone[dwPhoneCnt]->csThisPhone);
  3478. }
  3479. EnterCriticalSection(&csHidList);
  3480. CloseHidDevices();
  3481. LeaveCriticalSection(&csHidList);
  3482. MemFree((LPVOID) gszProviderInfo);
  3483. DeleteCriticalSection(&gAsyncQueue.AsyncEventQueueCritSec);
  3484. DeleteCriticalSection(&csHidList);
  3485. DeleteCriticalSection(&csAllPhones);
  3486. #if DBG
  3487. DeleteCriticalSection(&csMemoryList);
  3488. #endif
  3489. return PHONEERR_NOMEM;
  3490. }
  3491. gAsyncQueue.pAsyncRequestQueueIn =
  3492. gAsyncQueue.pAsyncRequestQueueOut = gAsyncQueue.pAsyncRequestQueue;
  3493. //
  3494. // the thread associated waits on this event when there are no requests
  3495. // pending in the queue. This event informs the thread when a request is
  3496. // entered in an empty queue so the thread can exit the wait state and
  3497. // process the request
  3498. //
  3499. gAsyncQueue.hAsyncEventsPendingEvent = CreateEvent (
  3500. (LPSECURITY_ATTRIBUTES) NULL,
  3501. TRUE, // manual reset
  3502. FALSE, // non-signaled
  3503. NULL // unnamed
  3504. );
  3505. if ( gAsyncQueue.hAsyncEventsPendingEvent == NULL )
  3506. {
  3507. DWORD dwPhoneCnt;
  3508. LOG((PHONESP_ERROR, "TSPI_providerInit - CreateEvent failed"
  3509. " for gAsyncQueue.hAsyncEventsPendingEvent"));
  3510. for(dwPhoneCnt = 0; dwPhoneCnt < gdwNumPhones; dwPhoneCnt++)
  3511. {
  3512. FreePhone(gpPhone[dwPhoneCnt]);
  3513. MemFree(gpPhone[dwPhoneCnt]);
  3514. DeleteCriticalSection(&gpPhone[dwPhoneCnt]->csThisPhone);
  3515. }
  3516. EnterCriticalSection(&csHidList);
  3517. CloseHidDevices();
  3518. LeaveCriticalSection(&csHidList);
  3519. MemFree((LPVOID) gszProviderInfo);
  3520. DeleteCriticalSection(&gAsyncQueue.AsyncEventQueueCritSec);
  3521. MemFree((LPVOID)gAsyncQueue.pAsyncRequestQueue);
  3522. DeleteCriticalSection(&csHidList);
  3523. DeleteCriticalSection(&csAllPhones);
  3524. #if DBG
  3525. DeleteCriticalSection(&csMemoryList);
  3526. #endif
  3527. return PHONEERR_NOMEM;
  3528. }
  3529. //
  3530. // Create the thread to service the requests in the queue
  3531. //
  3532. gAsyncQueue.hAsyncEventQueueServiceThread =
  3533. CreateThread (
  3534. (LPSECURITY_ATTRIBUTES) NULL,
  3535. 0, // default stack size
  3536. (LPTHREAD_START_ROUTINE) AsyncEventQueueServiceThread,
  3537. NULL, // thread param
  3538. 0, // creation flags
  3539. &dwThreadID // &dwThreadID
  3540. );
  3541. if ( gAsyncQueue.hAsyncEventQueueServiceThread == NULL )
  3542. {
  3543. DWORD dwPhoneCnt;
  3544. LOG((PHONESP_ERROR, "TSPI_providerInit - CreateThread failed"
  3545. " for gAsyncQueue.hAsyncEventQueueServiceThread"));
  3546. for(dwPhoneCnt = 0; dwPhoneCnt < gdwNumPhones; dwPhoneCnt++)
  3547. {
  3548. FreePhone(gpPhone[dwPhoneCnt]);
  3549. MemFree(gpPhone[dwPhoneCnt]);
  3550. DeleteCriticalSection(&gpPhone[dwPhoneCnt]->csThisPhone);
  3551. }
  3552. EnterCriticalSection(&csHidList);
  3553. CloseHidDevices();
  3554. LeaveCriticalSection(&csHidList);
  3555. MemFree((LPVOID) gszProviderInfo);
  3556. DeleteCriticalSection(&gAsyncQueue.AsyncEventQueueCritSec);
  3557. CloseHandle(gAsyncQueue.hAsyncEventsPendingEvent);
  3558. MemFree((LPVOID)gAsyncQueue.pAsyncRequestQueue);
  3559. DeleteCriticalSection(&csHidList);
  3560. DeleteCriticalSection(&csAllPhones);
  3561. #if DBG
  3562. DeleteCriticalSection(&csMemoryList);
  3563. #endif
  3564. return PHONEERR_NOMEM;
  3565. }
  3566. LOG((PHONESP_TRACE, "TSPI_providerInit - exit"));
  3567. return 0;
  3568. }
  3569. /***************************TSPI_providerInit - end***************************/
  3570. /******************************************************************************
  3571. TSPI_providerInstall:
  3572. This function is obsolete. However due to a bug in TAPI, the TSP must
  3573. provide a do-nothing implementation of this function and export it (along
  3574. with the superseding function TUISPI_providerInstall)
  3575. *******************************************************************************/
  3576. LONG
  3577. TSPIAPI
  3578. TSPI_providerInstall(
  3579. HWND hwndOwner,
  3580. DWORD dwPermanentProviderID
  3581. )
  3582. {
  3583. LOG((PHONESP_TRACE, "TSPI_providerInstall - enter"));
  3584. LOG((PHONESP_TRACE, "TSPI_providerInstall - exit"));
  3585. return 0;
  3586. }
  3587. /*********************TSPI_providerInstall - end******************************/
  3588. /******************************************************************************
  3589. TSPI_providerRemove:
  3590. This function is obsolete. However due to a bug in TAPI, the TSP must
  3591. provide a do-nothing implementation of this function and export it (along
  3592. with the superseding function TUISPI_providerRemove)
  3593. *******************************************************************************/
  3594. LONG
  3595. TSPIAPI
  3596. TSPI_providerRemove (
  3597. HWND hwndOwner,
  3598. DWORD dwPermanentProviderId
  3599. )
  3600. {
  3601. LOG((PHONESP_TRACE, "TSPI_providerRemove - enter"));
  3602. LOG((PHONESP_TRACE, "TSPI_providerRemove - exit"));
  3603. return 0;
  3604. }
  3605. /*********************TSPI_providerRemove - end******************************/
  3606. /******************************************************************************
  3607. TSPI_providerShutdown:
  3608. This function shuts down the TSP. The TSP terminates any activities it has
  3609. in progress and releases any resources it has allocated.
  3610. Arguments:
  3611. dwTSPIVersion - The version of the TSPI definition under which
  3612. this function must operate.
  3613. dwPermanentProviderID - This parameter allows the TSP to determine which
  3614. among multiple possible instances of the TSP is
  3615. being shut down. The value of the parameter is
  3616. identical to that passed in the parameter of
  3617. the same name in TSPI_providerInit.
  3618. Returns LONG:
  3619. Zero if the request succeeds or
  3620. An error number if an error occurs. Possible return values are as follows:
  3621. LINEERR_INCOMPATIBLEAPIVERSION, LINEERR_NOMEM.
  3622. Comments: Whenever TAPI API call PhoneShutdown is called , it first shuts
  3623. down all the phones that are currently open using TSPI_phoneClose
  3624. and then calls TSPI_providerShutdown
  3625. ******************************************************************************/
  3626. LONG
  3627. TSPIAPI
  3628. TSPI_providerShutdown(
  3629. DWORD dwTSPIVersion,
  3630. DWORD dwPermanentProviderID
  3631. )
  3632. {
  3633. DWORD dwPhoneCnt = 0;
  3634. LOG((PHONESP_TRACE, "TSPI_providerShutdown - enter"));
  3635. // this will terminate the queue service thread once all the operations
  3636. // pending in the queue are serviced
  3637. gbProviderShutdown = TRUE;
  3638. // the queue service waits for this event when the queue. By setting
  3639. // this event,the thread wakes up and realises that the queue is empty and
  3640. // hence exists since gbProviderShutdown is true
  3641. SetEvent(gAsyncQueue.hAsyncEventsPendingEvent);
  3642. // Wait for the queue thread to terminate.
  3643. WaitForSingleObject(gAsyncQueue.hAsyncEventQueueServiceThread, INFINITE);
  3644. // Free all the associated memory with the providerinfo
  3645. MemFree((LPVOID) gszProviderInfo);
  3646. EnterCriticalSection(&csAllPhones);
  3647. // Free all memory associated with the phones
  3648. for(dwPhoneCnt = 0; dwPhoneCnt < gdwNumPhones; dwPhoneCnt++)
  3649. {
  3650. EnterCriticalSection(&gpPhone[dwPhoneCnt]->csThisPhone);
  3651. FreePhone(gpPhone[dwPhoneCnt]);
  3652. LeaveCriticalSection(&gpPhone[dwPhoneCnt]->csThisPhone);
  3653. DeleteCriticalSection(&gpPhone[dwPhoneCnt]->csThisPhone);
  3654. MemFree(gpPhone[dwPhoneCnt]);
  3655. }
  3656. gdwNumPhones = 0;
  3657. LeaveCriticalSection(&csAllPhones);
  3658. CloseHandle (gAsyncQueue.hAsyncEventQueueServiceThread);
  3659. CloseHandle (gAsyncQueue.hAsyncEventsPendingEvent);
  3660. EnterCriticalSection(&csHidList);
  3661. CloseHidDevices();
  3662. LeaveCriticalSection(&csHidList);
  3663. LOG((PHONESP_TRACE, "Free Heap taken by phone"));
  3664. MemFree (gpPhone);
  3665. LOG((PHONESP_TRACE, "Free Heap taken by queue"));
  3666. MemFree (gAsyncQueue.pAsyncRequestQueue);
  3667. #if DBG
  3668. LOG((PHONESP_TRACE, "Dumping Memory Trace"));
  3669. DumpMemoryList();
  3670. DeleteCriticalSection (&csMemoryList);
  3671. #endif
  3672. DeleteCriticalSection (&gAsyncQueue.AsyncEventQueueCritSec);
  3673. DeleteCriticalSection (&csHidList);
  3674. DeleteCriticalSection (&csAllPhones);
  3675. LOG((PHONESP_TRACE, "TSPI_providerShutdown - exit"));
  3676. LOGDEREGISTERTRACING();
  3677. return 0;
  3678. }
  3679. /***************TSPI_providerShutdown*****************************************/
  3680. /******************************************************************************
  3681. TSPI_providerUIIdentify:
  3682. This function extracts from the TSP, the fully qualified path to load
  3683. the TSP's UI DLL component.
  3684. Arguments:
  3685. lpszUIDLLName - Pointer to a block of memory at least MAX_PATH in length,
  3686. into which the TSP must copy a NULL-terminated string
  3687. specifying the fully-qualified path for the DLL
  3688. containing the TSP functions which must execute in the
  3689. process of the calling application.
  3690. Return LONG:
  3691. Returns zero if successful.
  3692. Shouldn't ever fail, but if it does returns one of these negative
  3693. error values: LINEERR_NOMEM, LINEERR_OPERATIONFAILED.
  3694. ******************************************************************************/
  3695. LONG
  3696. TSPIAPI
  3697. TSPI_providerUIIdentify(
  3698. LPWSTR lpszUIDLLName
  3699. )
  3700. {
  3701. LOG((PHONESP_TRACE, "TSPI_providerUIIdentify - enter"));
  3702. //
  3703. // If we ever want to specify some other dll to handle ui, we
  3704. // would do it here.
  3705. //
  3706. GetModuleFileName(ghInst,
  3707. lpszUIDLLName,
  3708. MAX_PATH);
  3709. LOG((PHONESP_TRACE, "TSPI_providerUIIdentify - exit"));
  3710. return 0;
  3711. }
  3712. /***********************TSPI_providerUIIdentify - end ************************/
  3713. /******************************************************************************
  3714. TUISPI_providerInstall:
  3715. The TSP exports this function and provides a do-nothing implementation.
  3716. The Advanced tab of the Phone and Modem Options control panel will call
  3717. this function when the provider is to be installed, to give the TSP a
  3718. chance to do custom UI. There is no requirement for custom configuration
  3719. UI. The only requirement is that the control panel be able to
  3720. automatically install the TSP.
  3721. *******************************************************************************/
  3722. LONG
  3723. TSPIAPI
  3724. TUISPI_providerInstall(
  3725. TUISPIDLLCALLBACK lpfnUIDLLCallback,
  3726. HWND hwndOwner,
  3727. DWORD dwPermanentProviderID
  3728. )
  3729. {
  3730. LOG((PHONESP_TRACE, "TUISPI_providerInstall - enter"));
  3731. // check for previous instance
  3732. if (IsTSPAlreadyInstalled())
  3733. {
  3734. // cannot be installed twice
  3735. LOG((PHONESP_TRACE, "TUISPI_providerInstall - cannot be installed twice"));
  3736. return LINEERR_NOMULTIPLEINSTANCE;
  3737. }
  3738. LOG((PHONESP_TRACE, "TUISPI_providerInstall - exit"));
  3739. return 0;
  3740. }
  3741. /***********************TUISPI_providerInstall - end ************************/
  3742. /******************************************************************************
  3743. TUISPI_providerRemove:
  3744. The TSP exports this function and provides a do-nothing implementation.
  3745. The Advanced tab of the Phone and Modem Options control panel will call
  3746. this function when the provider is to be removed, to give the TSP a
  3747. chance to do custom UI. There is no requirement for custom configuration
  3748. UI. The only requirement is that the control panel be able to
  3749. automatically remove the TSP.
  3750. *******************************************************************************/
  3751. LONG
  3752. TSPIAPI
  3753. TUISPI_providerRemove(
  3754. TUISPIDLLCALLBACK lpfnUIDLLCallback,
  3755. HWND hwndOwner,
  3756. DWORD dwPermanentProviderID
  3757. )
  3758. {
  3759. LOG((PHONESP_TRACE, "TUISPI_providerRemove - enter"));
  3760. LOG((PHONESP_TRACE, "TUISPI_providerRemove - exit"));
  3761. return 0;
  3762. }
  3763. /***********************TUISPI_providerRemove - end ************************/
  3764. //----------------------------PRIVATE FUNCTIONS-------------------------------
  3765. /******************************************************************************
  3766. AsyncRequestQueueIn:
  3767. This function adds the new incoming request from the tapisrv to the async
  3768. queue.
  3769. Arguments:
  3770. IN PPHONESP_ASYNC_REQ_INFO pAsyncReqInfo - Pointer to the request info.
  3771. Returns BOOL:
  3772. TRUE if the function is successful
  3773. FALSE if it is not
  3774. ******************************************************************************/
  3775. BOOL
  3776. AsyncRequestQueueIn (
  3777. PPHONESP_ASYNC_REQ_INFO pAsyncReqInfo
  3778. )
  3779. {
  3780. //LOG((PHONESP_TRACE, "AsyncRequestQueueIn - enter "));
  3781. EnterCriticalSection (&gAsyncQueue.AsyncEventQueueCritSec);
  3782. if (gAsyncQueue.dwNumUsedQueueEntries == gAsyncQueue.dwNumTotalQueueEntries)
  3783. {
  3784. //
  3785. // We've max'd out our ring buffer, so try to grow it
  3786. //
  3787. DWORD dwMoveSize;
  3788. PPHONESP_ASYNC_REQ_INFO *pNewAsyncRequestQueue;
  3789. if ( ! ( pNewAsyncRequestQueue =
  3790. MemAlloc(2 * gAsyncQueue.dwNumTotalQueueEntries
  3791. * sizeof (PPHONESP_ASYNC_REQ_INFO)) ) )
  3792. {
  3793. LeaveCriticalSection( &gAsyncQueue.AsyncEventQueueCritSec);
  3794. LOG((PHONESP_ERROR,"AsyncRequestQueueIn - Not enough memory to"
  3795. " queue request"));
  3796. return FALSE;
  3797. }
  3798. dwMoveSize = (DWORD) ((gAsyncQueue.pAsyncRequestQueue +
  3799. gAsyncQueue.dwNumTotalQueueEntries) -
  3800. gAsyncQueue.pAsyncRequestQueueOut) *
  3801. sizeof (PPHONESP_ASYNC_REQ_INFO);
  3802. CopyMemory(
  3803. pNewAsyncRequestQueue,
  3804. gAsyncQueue.pAsyncRequestQueueOut,
  3805. dwMoveSize
  3806. );
  3807. CopyMemory(
  3808. ((LPBYTE) pNewAsyncRequestQueue) + dwMoveSize,
  3809. gAsyncQueue.pAsyncRequestQueue,
  3810. (gAsyncQueue.pAsyncRequestQueueOut -
  3811. gAsyncQueue.pAsyncRequestQueue) *
  3812. sizeof (PPHONESP_ASYNC_REQ_INFO)
  3813. );
  3814. MemFree (gAsyncQueue.pAsyncRequestQueue);
  3815. gAsyncQueue.pAsyncRequestQueue =
  3816. gAsyncQueue.pAsyncRequestQueueOut = pNewAsyncRequestQueue;
  3817. gAsyncQueue.pAsyncRequestQueueIn = pNewAsyncRequestQueue +
  3818. gAsyncQueue.dwNumTotalQueueEntries;
  3819. gAsyncQueue.dwNumTotalQueueEntries *= 2;
  3820. }
  3821. *(gAsyncQueue.pAsyncRequestQueueIn) = pAsyncReqInfo;
  3822. gAsyncQueue.pAsyncRequestQueueIn++;
  3823. // The queue is maintained as a circular list - if the queue in pointer
  3824. // has reached the bottom of the queue, reset it to point it to the top
  3825. // of the queue
  3826. if (gAsyncQueue.pAsyncRequestQueueIn == (gAsyncQueue.pAsyncRequestQueue +
  3827. gAsyncQueue.dwNumTotalQueueEntries))
  3828. {
  3829. gAsyncQueue.pAsyncRequestQueueIn = gAsyncQueue.pAsyncRequestQueue;
  3830. }
  3831. // Increment the number of outstanding requests in the queue
  3832. gAsyncQueue.dwNumUsedQueueEntries++;
  3833. // If this is the first request in the queue - set event to resume the
  3834. // thread to process the queue
  3835. if (gAsyncQueue.dwNumUsedQueueEntries == 1)
  3836. {
  3837. SetEvent (gAsyncQueue.hAsyncEventsPendingEvent);
  3838. }
  3839. LeaveCriticalSection (&gAsyncQueue.AsyncEventQueueCritSec);
  3840. //LOG((PHONESP_TRACE, "AsyncRequestQueueIn - exit"));
  3841. return TRUE;
  3842. }
  3843. /********************AsyncRequestQueueIn - end********************************/
  3844. /******************************************************************************
  3845. CreateButtonsAndAssignID
  3846. This function creates button structures for the phone from the capability
  3847. array. It also determines whether the phone has a keypad. It assigns IDs to
  3848. the buttons discovered.
  3849. Arguments:
  3850. PPHONESP_PHONE_INFO pPhone
  3851. Returns LONG:
  3852. ERROR_SUCCESS if the function succeeds
  3853. ERROR_OUTOFMEMORY if error occurs while allocating memory
  3854. ******************************************************************************/
  3855. LONG
  3856. CreateButtonsAndAssignID (
  3857. PPHONESP_PHONE_INFO pPhone
  3858. )
  3859. {
  3860. DWORD i,j, dwNextFreeID = 0;
  3861. BOOL KEYPAD = TRUE;
  3862. BOOL KEYPAD_ABCD = TRUE;
  3863. PPHONESP_BUTTONINFO pButtonInfo;
  3864. DWORD lResult = 0;
  3865. LOG((PHONESP_TRACE, "CreateButtonsAndAssignID - enter"));
  3866. // First determine the number of buttons available on this phone
  3867. // If all the 12 basic key pad buttons are present
  3868. // then phone has a Keypad, else all the key pad buttons are ignored
  3869. for(i = PHONESP_PHONE_KEY_0; i <= PHONESP_PHONE_KEY_POUND; i++)
  3870. {
  3871. if(!pPhone->dwReportTypes[i])
  3872. {
  3873. KEYPAD = FALSE;
  3874. break;
  3875. }
  3876. }
  3877. // Also determine if phone had ABCD buttons on its keypad
  3878. for(i = PHONESP_PHONE_KEY_A; i <= PHONESP_PHONE_KEY_D; i++)
  3879. {
  3880. if(!pPhone->dwReportTypes[i])
  3881. {
  3882. KEYPAD_ABCD = FALSE;
  3883. break;
  3884. }
  3885. }
  3886. if (KEYPAD)
  3887. {
  3888. if (KEYPAD_ABCD)
  3889. {
  3890. // keypad with ABCD
  3891. pPhone->dwNumButtons = PHONESP_NUMBER_PHONE_KEYS;
  3892. }
  3893. else
  3894. {
  3895. // basic keypad
  3896. pPhone->dwNumButtons = 12;
  3897. }
  3898. }
  3899. else
  3900. {
  3901. pPhone->dwNumButtons = 0;
  3902. }
  3903. for(i = PHONESP_NUMBER_PHONE_KEYS; i < PHONESP_NUMBER_BUTTONS; i++)
  3904. {
  3905. if(pPhone->dwReportTypes[i])
  3906. {
  3907. pPhone->dwNumButtons++;
  3908. }
  3909. }
  3910. // Allocate memory for all the buttons
  3911. if ( ! (pPhone->pButtonInfo = (PPHONESP_BUTTONINFO)
  3912. MemAlloc( pPhone->dwNumButtons *
  3913. sizeof(PHONESP_BUTTONINFO)
  3914. ) ) )
  3915. {
  3916. return ERROR_OUTOFMEMORY;
  3917. }
  3918. pButtonInfo = pPhone->pButtonInfo;
  3919. // if the phone has a keypad with all the 16 buttons
  3920. if (KEYPAD)
  3921. {
  3922. LOG((PHONESP_TRACE, "Phone Has a Keypad"));
  3923. for( i = PHONESP_PHONE_KEY_0; i <= (DWORD)(KEYPAD_ABCD ? PHONESP_PHONE_KEY_D : PHONESP_PHONE_KEY_POUND) ; i++, pButtonInfo++)
  3924. {
  3925. pButtonInfo->dwButtonID = i;
  3926. pButtonInfo->dwButtonMode = PHONEBUTTONMODE_KEYPAD;
  3927. pButtonInfo->dwButtonFunction = PHONEBUTTONFUNCTION_NONE;
  3928. pButtonInfo->dwButtonState = PHONEBUTTONSTATE_UP;
  3929. pPhone->dwButtonIds[i] = pButtonInfo->dwButtonID;
  3930. pButtonInfo->szButtonText = PHONESP_LoadString(
  3931. gdwButtonText[i],
  3932. &lResult
  3933. );
  3934. if(lResult != ERROR_SUCCESS)
  3935. {
  3936. DWORD dwCount;
  3937. for(dwCount =0; dwCount < i; dwCount++)
  3938. {
  3939. MemFree(pPhone->pButtonInfo->szButtonText);
  3940. pPhone->pButtonInfo++;
  3941. }
  3942. MemFree(pPhone->pButtonInfo);
  3943. return lResult;
  3944. }
  3945. LOG((PHONESP_TRACE,"Button Found '%ws' at %d", pButtonInfo->szButtonText, i));
  3946. }
  3947. dwNextFreeID = i;
  3948. pPhone->bKeyPad = TRUE;
  3949. }
  3950. else
  3951. {
  3952. // If phone has no keypad - the button ID for the feature buttons start
  3953. // from 0 else they start from 16
  3954. dwNextFreeID = 0;
  3955. }
  3956. // assign appropriate button ids for the feature buttons if they exist
  3957. for (i = PHONESP_NUMBER_PHONE_KEYS, j = 0; i < PHONESP_NUMBER_BUTTONS; i++, j++)
  3958. {
  3959. if(pPhone->dwReportTypes[i])
  3960. {
  3961. pButtonInfo->dwButtonID = dwNextFreeID;
  3962. pButtonInfo->dwButtonMode = PHONEBUTTONMODE_FEATURE;
  3963. pButtonInfo->dwButtonFunction = gdwButtonFunction[j];
  3964. pButtonInfo->dwButtonState = PHONEBUTTONSTATE_UP;
  3965. pPhone->dwButtonIds[i] = pButtonInfo->dwButtonID;
  3966. pButtonInfo->szButtonText = PHONESP_LoadString(
  3967. gdwButtonText[i],
  3968. &lResult
  3969. );
  3970. if(lResult != ERROR_SUCCESS)
  3971. {
  3972. DWORD dwCount;
  3973. DWORD dwStartID = 0;
  3974. if(KEYPAD)
  3975. {
  3976. for(dwCount = PHONESP_PHONE_KEY_0;
  3977. dwCount <= (DWORD)(KEYPAD_ABCD ? PHONESP_PHONE_KEY_D : PHONESP_PHONE_KEY_POUND); dwCount++)
  3978. {
  3979. MemFree(pPhone->pButtonInfo->szButtonText);
  3980. pPhone->pButtonInfo++;
  3981. }
  3982. dwStartID = dwCount;
  3983. }
  3984. for(dwCount = dwStartID; dwCount < dwNextFreeID; dwCount++)
  3985. {
  3986. MemFree(pPhone->pButtonInfo->szButtonText);
  3987. pPhone->pButtonInfo++;
  3988. }
  3989. MemFree(pPhone->pButtonInfo);
  3990. return lResult;
  3991. }
  3992. LOG((PHONESP_TRACE,"Button Found '%ws' at %d", pButtonInfo->szButtonText, dwNextFreeID));
  3993. dwNextFreeID++;
  3994. pButtonInfo++;
  3995. }
  3996. }
  3997. LOG((PHONESP_TRACE, "CreateButtonsAndAssignID - exit"));
  3998. return ERROR_SUCCESS;
  3999. }
  4000. /********************CreateButtonsAndAssignID - end****************************/
  4001. /*****************************************************************************
  4002. GetButtonFromID
  4003. This function will retrieve the structure for the Button from it's ID
  4004. Arguments:
  4005. IN PPHONESP_PHONE_INFO pPhone - Pointer to the phone whose button
  4006. structure has to be retrieved.
  4007. IN DWORD dwButtonID - The Button ID
  4008. Returns:
  4009. PBUTTONINFO - Pointer to the button structure if successful
  4010. NULL - If Button not found
  4011. ******************************************************************************/
  4012. PPHONESP_BUTTONINFO
  4013. GetButtonFromID (
  4014. PPHONESP_PHONE_INFO pPhone,
  4015. DWORD dwButtonID
  4016. )
  4017. {
  4018. PPHONESP_BUTTONINFO pButtonInfo;
  4019. DWORD i;
  4020. // if the phone has any buttons
  4021. if (pPhone->pButtonInfo)
  4022. {
  4023. pButtonInfo = pPhone->pButtonInfo;
  4024. // search the list of buttons to find the button corresponding to the
  4025. // button id provided
  4026. for( i = 0; i < pPhone->dwNumButtons; i++)
  4027. {
  4028. if (pButtonInfo->dwButtonID == dwButtonID)
  4029. {
  4030. return pButtonInfo;
  4031. }
  4032. pButtonInfo++;
  4033. }
  4034. }
  4035. return (PPHONESP_BUTTONINFO) NULL;
  4036. }
  4037. /*************************GetButtonFromID - end*******************************/
  4038. /******************************************************************************
  4039. GetPhoneFromID:
  4040. This function returns the structure that contains the information on the
  4041. phone whose device ID is passed to this function.
  4042. Arguments:
  4043. dwDeviceID - The device ID of the phone to be retrieved
  4044. pdwPhoneID - The to a DWORD to store the index into gpPhone,
  4045. this parameter can be NULL
  4046. Returns PPHONESP_PHONE_INFO
  4047. Pointer to the phone structure if successful
  4048. NULL if phone not found
  4049. ******************************************************************************/
  4050. PPHONESP_PHONE_INFO
  4051. GetPhoneFromID(
  4052. DWORD dwDeviceID,
  4053. DWORD * pdwPhoneID
  4054. )
  4055. {
  4056. DWORD dwPhone;
  4057. PPHONESP_PHONE_INFO pPhone;
  4058. LOG((PHONESP_TRACE, " GetPhoneFromID - enter"));
  4059. for (dwPhone = 0; dwPhone < gdwNumPhones; dwPhone++)
  4060. {
  4061. pPhone = (PPHONESP_PHONE_INFO) gpPhone[ dwPhone ];
  4062. EnterCriticalSection(&pPhone->csThisPhone);
  4063. if ( pPhone->bAllocated )
  4064. {
  4065. if ( pPhone->dwDeviceID == dwDeviceID )
  4066. {
  4067. // check pdwPhoneID, NULL is valid if the caller doesn't
  4068. // want us to return the phone index
  4069. if (pdwPhoneID != NULL)
  4070. {
  4071. *pdwPhoneID = dwPhone;
  4072. }
  4073. LeaveCriticalSection(&pPhone->csThisPhone);
  4074. return pPhone;
  4075. }
  4076. }
  4077. LeaveCriticalSection(&pPhone->csThisPhone);
  4078. }
  4079. LOG((PHONESP_TRACE, " GetPhoneFromID - exit"));
  4080. return NULL;
  4081. }
  4082. /*****************************GetPhoneFromID - end****************************/
  4083. /******************************************************************************
  4084. GetPhoneFromHid:
  4085. This function returns the structure that contains the information on the
  4086. phone whose HidDevice is passed to this function.
  4087. Arguments:
  4088. HidDevice - Pointer to a hid device
  4089. Returns PPHONESP_PHONE_INFO
  4090. Pointer to the phone structure if successful
  4091. NULL if phone not found
  4092. ******************************************************************************/
  4093. PPHONESP_PHONE_INFO
  4094. GetPhoneFromHid (
  4095. PHID_DEVICE HidDevice
  4096. )
  4097. {
  4098. DWORD dwPhone;
  4099. PPHONESP_PHONE_INFO pPhone;
  4100. LOG((PHONESP_TRACE, " GetPhoneFromHid - enter"));
  4101. for (dwPhone = 0; dwPhone < gdwNumPhones; dwPhone++)
  4102. {
  4103. pPhone = (PPHONESP_PHONE_INFO) gpPhone[ dwPhone ];
  4104. EnterCriticalSection(&pPhone->csThisPhone);
  4105. if ( pPhone->bAllocated )
  4106. {
  4107. if ( pPhone->pHidDevice == HidDevice )
  4108. {
  4109. LeaveCriticalSection(&pPhone->csThisPhone);
  4110. return pPhone;
  4111. }
  4112. }
  4113. LeaveCriticalSection(&pPhone->csThisPhone);
  4114. }
  4115. LOG((PHONESP_TRACE, " GetPhoneFromHid - exit"));
  4116. return NULL;
  4117. }
  4118. /******************************************************************************
  4119. GetButtonUsages:
  4120. This function parses the PHIDP_BUTTON_CAPS structure to retrieve the usages
  4121. present for the phone and records them in the capabilities array of the
  4122. phone structure.
  4123. Arguments:
  4124. PPHONESP_PHONE_INFO pPhone - The phone structure to be updated
  4125. PHIDP_BUTTON_CAPS pButtonCaps - The Button Caps structure to be parsed
  4126. DWORD dwNumberCaps - The number of Button Caps structure of the Report
  4127. Type
  4128. DWORD ReportType - Whether the usage within the Button Caps structure is
  4129. associated with an INPUT, OUTPUT or FEATURE Report.
  4130. Returns VOID.
  4131. ******************************************************************************/
  4132. VOID
  4133. GetButtonUsages(
  4134. PPHONESP_PHONE_INFO pPhone,
  4135. PHIDP_BUTTON_CAPS pButtonCaps,
  4136. DWORD dwNumberCaps,
  4137. DWORD ReportType
  4138. )
  4139. {
  4140. DWORD cNumCaps;
  4141. USAGE Usage;
  4142. for (cNumCaps = 0; cNumCaps < dwNumberCaps; pButtonCaps++,cNumCaps++)
  4143. { // if the button caps structure has a list of usages
  4144. if(pButtonCaps->IsRange)
  4145. {
  4146. for(Usage = (USAGE) pButtonCaps->Range.UsageMin;
  4147. Usage <= (USAGE) pButtonCaps->Range.UsageMax; Usage++)
  4148. {
  4149. InitPhoneAttribFromUsage(
  4150. ReportType,
  4151. pButtonCaps->UsagePage,
  4152. Usage,
  4153. pPhone,
  4154. 0,
  4155. 0
  4156. );
  4157. }
  4158. }
  4159. else // if the button caps structure has a single usage
  4160. {
  4161. InitPhoneAttribFromUsage(
  4162. ReportType,
  4163. pButtonCaps->UsagePage,
  4164. pButtonCaps->NotRange.Usage,
  4165. pPhone,
  4166. 0,
  4167. 0
  4168. );
  4169. }
  4170. }
  4171. }
  4172. /*****************************GetUsages - end********************************/
  4173. /******************************************************************************
  4174. GetReportID
  4175. This function returns the HidData structure that contains the usage
  4176. provided. The HidData structure contains the report ID for this usage
  4177. Arguments:
  4178. IN PHID_DEVICE pHidDevice - the device whose usage is provided
  4179. IN USAGE Usage - The usage whose report Id is to be discovered
  4180. OUT PHID_DATA pHidData - If the function succeeds, this structure
  4181. contains the report id for the usage, else
  4182. it is NULL
  4183. Returns LONG:
  4184. ERROR_SUCCESS - if the functions succeeds
  4185. MY_RESOURCENOTFOUND - if the usage was not found in the pHidDevice
  4186. structure provided
  4187. ******************************************************************************/
  4188. LONG
  4189. GetReportID (
  4190. IN PHID_DEVICE pHidDevice,
  4191. IN USAGE Usage,
  4192. OUT PHID_DATA pHidData
  4193. )
  4194. {
  4195. PHID_DATA pData;
  4196. USAGE ButtonUsage;
  4197. pData = pHidDevice->OutputData;
  4198. while (pData)
  4199. {
  4200. // if the hid data structure has button data
  4201. if (pData->IsButtonData)
  4202. {
  4203. for(ButtonUsage = (USAGE) pData->ButtonData.UsageMin;
  4204. ButtonUsage <= (USAGE) pData->ButtonData.UsageMax; ButtonUsage++)
  4205. {
  4206. if (Usage == ButtonUsage)
  4207. {
  4208. pHidData = pData;
  4209. return ERROR_SUCCESS;
  4210. }
  4211. }
  4212. }
  4213. else
  4214. { // if the hid data structure has value data
  4215. if (Usage == pData->ValueData.Usage)
  4216. {
  4217. pHidData = pData;
  4218. return ERROR_SUCCESS;
  4219. }
  4220. }
  4221. pData++;
  4222. }
  4223. pHidData = NULL;
  4224. return ERROR_INVALID_DATA;
  4225. }
  4226. /*************************GetReportID - end **********************************/
  4227. /******************************************************************************
  4228. GetValueUsages:
  4229. This function parses the PHIDP_VALUE_CAPS structure to retrieve the usages
  4230. present for the phone and records them in the capabilities array of the
  4231. phone structure.
  4232. Arguments:
  4233. PPHONESP_PHONE_INFO pPhone - The phone structure to be updated
  4234. PHIDP_VALUE_CAPS pValueCaps - The Value Caps structure to be parsed
  4235. DWORD dwNumberCaps - The number of Button Caps structure of the Report
  4236. Type
  4237. DWORD ReportType - Whether the usage within the Button Caps structure is
  4238. associated with an INPUT, OUTPUT or FEATURE Report.
  4239. Returns VOID.
  4240. ******************************************************************************/
  4241. VOID
  4242. GetValueUsages(
  4243. PPHONESP_PHONE_INFO pPhone,
  4244. PHIDP_VALUE_CAPS pValueCaps,
  4245. DWORD dwNumberCaps,
  4246. DWORD ReportType
  4247. )
  4248. {
  4249. DWORD cNumCaps;
  4250. USAGE Usage;
  4251. for (cNumCaps=0; cNumCaps < dwNumberCaps; pValueCaps++, cNumCaps++)
  4252. {
  4253. if(pValueCaps->IsRange)
  4254. {
  4255. for(Usage = (USAGE) pValueCaps->Range.UsageMin;
  4256. Usage <= (USAGE) pValueCaps->Range.UsageMax; Usage++)
  4257. {
  4258. InitPhoneAttribFromUsage(
  4259. ReportType,
  4260. pValueCaps->UsagePage,
  4261. Usage,
  4262. pPhone,
  4263. pValueCaps->LogicalMin,
  4264. pValueCaps->LogicalMax
  4265. );
  4266. }
  4267. }
  4268. else
  4269. {
  4270. InitPhoneAttribFromUsage(
  4271. ReportType,
  4272. pValueCaps->UsagePage,
  4273. pValueCaps->NotRange.Usage,
  4274. pPhone,
  4275. pValueCaps->LogicalMin,
  4276. pValueCaps->LogicalMax
  4277. );
  4278. }
  4279. }
  4280. }
  4281. /**********************GetValueUsages - end***********************************/
  4282. /******************************************************************************
  4283. InitPhoneAttribFromUsages:
  4284. This function is called by providerInit to determine the capabilities of
  4285. the device
  4286. Arguments:
  4287. IN DWORD ReportType - Whether the usage is a input/feature/output
  4288. IN USAGE Usage - A Usage of the device
  4289. IN OUT PPHONESP_PHONE_INFO pPhone - The pointer to the phone whose
  4290. capabilities are being determined.
  4291. Returns VOID
  4292. ******************************************************************************/
  4293. VOID
  4294. InitPhoneAttribFromUsage (
  4295. DWORD ReportType,
  4296. USAGE UsagePage,
  4297. USAGE Usage,
  4298. PPHONESP_PHONE_INFO pPhone,
  4299. LONG Min,
  4300. LONG Max
  4301. )
  4302. {
  4303. PPHONESP_BUTTONINFO pButtonInfo;
  4304. //LOG((PHONESP_TRACE, "InitPhoneAttribFromUsage - enter"));
  4305. switch (UsagePage)
  4306. {
  4307. case HID_USAGE_PAGE_TELEPHONY:
  4308. {
  4309. switch (Usage)
  4310. {
  4311. case HID_USAGE_TELEPHONY_HOOKSWITCH:
  4312. pPhone->dwHandset |= ReportType;
  4313. pPhone->dwHookSwitchDevs |= PHONEHOOKSWITCHDEV_HANDSET;
  4314. pPhone->dwHandsetHookSwitchMode = PHONEHOOKSWITCHMODE_ONHOOK; //Assume handset is on hook
  4315. LOG((PHONESP_TRACE,"HOOKSWITCH USAGE, ReportType 0x%04x", ReportType));
  4316. break;
  4317. case HID_USAGE_TELEPHONY_RINGER:
  4318. pPhone->dwRing |= ReportType;
  4319. pPhone->dwRingMode = 0; //Assume the phone is not ringing
  4320. LOG((PHONESP_TRACE,"RINGER USAGE, ReportType: %d", ReportType));
  4321. break;
  4322. case HID_USAGE_TELEPHONY_SPEAKER_PHONE:
  4323. pPhone->dwSpeaker |= ReportType;
  4324. pPhone->dwHookSwitchDevs |= PHONEHOOKSWITCHDEV_SPEAKER;
  4325. pPhone->dwSpeakerHookSwitchMode = PHONEHOOKSWITCHMODE_ONHOOK; //Assume speaker is on hook
  4326. LOG((PHONESP_TRACE,"SPEAKERPHONE USAGE, ReportType 0x%04x", ReportType));
  4327. break;
  4328. default:
  4329. // Key Pad buttons
  4330. if ( (Usage >= HID_USAGE_TELEPHONY_PHONE_KEY_0) &&
  4331. (Usage <= HID_USAGE_TELEPHONY_PHONE_KEY_D) )
  4332. {
  4333. pPhone->dwReportTypes[Usage - HID_USAGE_TELEPHONY_PHONE_KEY_0] |= ReportType;
  4334. LOG((PHONESP_TRACE,"PHONE_KEY_%d USAGE, ReportType 0x%04x",
  4335. Usage - HID_USAGE_TELEPHONY_PHONE_KEY_0, ReportType));
  4336. }
  4337. else
  4338. { // Feature Buttons
  4339. DWORD Index;
  4340. if (LookupIndexForUsage(Usage, &Index) == ERROR_SUCCESS)
  4341. {
  4342. pPhone->dwReportTypes[Index] |= ReportType;
  4343. LOG((PHONESP_TRACE,"PHONE USAGE: 0x%04x, ReportType 0x%04x",
  4344. Usage, ReportType));
  4345. }
  4346. else
  4347. {
  4348. LOG((PHONESP_TRACE, "Unsupported PHONE USAGE: 0x%04x", Usage ));
  4349. }
  4350. }
  4351. break;
  4352. }
  4353. }
  4354. case HID_USAGE_PAGE_CONSUMER:
  4355. {
  4356. switch (Usage)
  4357. {
  4358. case HID_USAGE_CONSUMER_VOLUME:
  4359. if ((Min == -1) && (Max == 1))
  4360. {
  4361. // Phone has volume controls
  4362. pPhone->dwReportTypes[PHONESP_FEATURE_VOLUMEUP] |= ReportType;
  4363. pPhone->dwReportTypes[PHONESP_FEATURE_VOLUMEDOWN] |= ReportType;
  4364. pPhone->dwVolume |= ReportType;
  4365. LOG((PHONESP_TRACE,"VOLUME USAGE, ReportType 0x%04x", ReportType));
  4366. }
  4367. break;
  4368. }
  4369. }
  4370. }
  4371. //LOG((PHONESP_TRACE, "InitPhoneAttribFromUsage - exit"));
  4372. }
  4373. /**************************InitPhoneAttribFromUsage - end ********************/
  4374. /******************************************************************************
  4375. InitUsage
  4376. This function takes the usage retrieved in the input report and updates the
  4377. device status and sends an appropriate Phone event
  4378. Arguments:
  4379. PPHONESP_PHONE_INFO pPhone - Pointer to phone whose input report is
  4380. received
  4381. USAGE Usage - The usage whose value is recieved
  4382. BOOL bON - The status of the usage Received
  4383. Returns VOID
  4384. ******************************************************************************/
  4385. VOID
  4386. InitUsage (
  4387. PPHONESP_PHONE_INFO pPhone,
  4388. USAGE Usage,
  4389. BOOL bON
  4390. )
  4391. {
  4392. DWORD Index;
  4393. DWORD dwMode;
  4394. LOG((PHONESP_TRACE, "InitUsage - enter"));
  4395. switch (Usage)
  4396. {
  4397. case HID_USAGE_TELEPHONY_HOOKSWITCH:
  4398. if (bON)
  4399. {
  4400. LOG((PHONESP_TRACE, "HANDSET OFFHOOK"));
  4401. pPhone->dwHandsetHookSwitchMode = PHONEHOOKSWITCHMODE_MICSPEAKER;
  4402. }
  4403. else
  4404. {
  4405. LOG((PHONESP_TRACE, "HANDSET ONHOOK"));
  4406. pPhone->dwHandsetHookSwitchMode = PHONEHOOKSWITCHMODE_ONHOOK;
  4407. }
  4408. break;
  4409. case HID_USAGE_TELEPHONY_SPEAKER_PHONE:
  4410. if (bON == TRUE)
  4411. {
  4412. pPhone->bSpeakerHookSwitchButton = TRUE;
  4413. }
  4414. else
  4415. {
  4416. pPhone->bSpeakerHookSwitchButton = FALSE;
  4417. }
  4418. break;
  4419. default:
  4420. // Feature & Phone Key Buttons
  4421. // Find the index of the usage
  4422. if (LookupIndexForUsage(Usage, &Index) == ERROR_SUCCESS)
  4423. {
  4424. PPHONESP_BUTTONINFO pButtonInfo;
  4425. //
  4426. // The index retrieved when indexed in the dwButtonIds array of the
  4427. // phone structure gives the Button ID. With this ID get the Button
  4428. // Info for that button id
  4429. //
  4430. pButtonInfo = GetButtonFromID(pPhone,pPhone->dwButtonIds[Index]);
  4431. if(pButtonInfo != NULL)
  4432. {
  4433. if(bON == TRUE)
  4434. {
  4435. // This feature button is currently on
  4436. LOG((PHONESP_TRACE, "BUTTON '%ws' DOWN", pButtonInfo->szButtonText ));
  4437. pButtonInfo->dwButtonState = PHONEBUTTONSTATE_DOWN;
  4438. }
  4439. else
  4440. {
  4441. // This feature button is currently off
  4442. LOG((PHONESP_TRACE, "BUTTON '%ws' UP", pButtonInfo->szButtonText ));
  4443. pButtonInfo->dwButtonState = PHONEBUTTONSTATE_UP;
  4444. }
  4445. }
  4446. }
  4447. break;
  4448. }
  4449. LOG((PHONESP_TRACE, "InitUsage - exit"));
  4450. }
  4451. /*************************InitUsage - end*************************************/
  4452. /******************************************************************************
  4453. LookupIndexForUsage
  4454. This function retrieves the index of the usage provided. Only the Feature
  4455. Button usages are present in this Lookup Table. Therefore only the index
  4456. for the feature buttons can be retrieved.
  4457. Arguments:
  4458. DWORD Usage - THe usage whose index is to be retrieved
  4459. DWORD *Index - The Index of the Usage retrieved
  4460. Returns LONG:
  4461. ERROR_SUCCESS - if the usage was found in the table
  4462. ERROR_INVALID_DATA - if the usage was not found in the Lookup Table
  4463. ******************************************************************************/
  4464. LONG
  4465. LookupIndexForUsage(
  4466. IN DWORD Usage,
  4467. OUT DWORD *Index
  4468. )
  4469. {
  4470. DWORD cnt;
  4471. for(cnt = 0; cnt < PHONESP_NUMBER_FEATURE_BUTTONS; cnt++)
  4472. {
  4473. if(gdwLookupFeatureIndex[cnt].Usage == Usage)
  4474. {
  4475. *Index = gdwLookupFeatureIndex[cnt].Index;
  4476. return ERROR_SUCCESS;
  4477. }
  4478. }
  4479. return ERROR_INVALID_DATA;
  4480. }
  4481. /***************LookupIndexForUsage - end*************************************/
  4482. /******************************************************************************
  4483. PHONESP_LoadString:
  4484. This function loads the string from the String Table.
  4485. Arguments:
  4486. IN UINT ResourceID - Specifies the integer identifier of the string to
  4487. be loaded from the resource table
  4488. OUT WCHAR *szBuffer- The pointer to the Buffer that contains the string
  4489. Returns LONG
  4490. ERROR_SUCCESS if operation successful else
  4491. MY_NOMEM if operation failed because of not enough memory.
  4492. MY_RESOURCENOTFOUND - if the resource was not found in the string table
  4493. ******************************************************************************/
  4494. LPWSTR
  4495. PHONESP_LoadString(
  4496. IN UINT ResourceID,
  4497. PLONG lResult
  4498. )
  4499. {
  4500. DWORD dwNumBytes;
  4501. DWORD dwNumChars;
  4502. DWORD dwBufferChars = 100;
  4503. WCHAR *wszBuffer;
  4504. WCHAR *szBuffer;
  4505. while (1)
  4506. {
  4507. if (! ( wszBuffer = (WCHAR *) MemAlloc(dwBufferChars * sizeof(WCHAR))))
  4508. {
  4509. LOG((PHONESP_ERROR,"PHONESP_LoadString - Not enough Memory"));
  4510. *lResult = ERROR_OUTOFMEMORY;
  4511. return (LPWSTR) NULL;
  4512. }
  4513. // load string into buffer
  4514. dwNumChars = LoadString(
  4515. ghInst,
  4516. ResourceID,
  4517. wszBuffer,
  4518. dwBufferChars
  4519. );
  4520. if( dwNumChars < dwBufferChars)
  4521. {
  4522. break;
  4523. }
  4524. // LoadString returns 0 in the dwNumChars if string resource does not exist
  4525. if (dwNumChars == 0)
  4526. {
  4527. MemFree(wszBuffer);
  4528. *lResult = ERROR_INVALID_DATA;
  4529. return (LPWSTR) NULL;
  4530. }
  4531. dwBufferChars *= 2;
  4532. MemFree(wszBuffer);
  4533. }
  4534. // determine memory needed
  4535. dwNumBytes = (dwNumChars + 1) * sizeof(WCHAR);
  4536. // allocate memory for unicode string
  4537. if ( ! ( szBuffer = (WCHAR *) MemAlloc(dwNumBytes) ) )
  4538. {
  4539. MemFree(wszBuffer);
  4540. LOG((PHONESP_ERROR,"PHONESP_LoadString - Not enough Memory"));
  4541. *lResult = ERROR_OUTOFMEMORY;
  4542. return (LPWSTR) NULL;
  4543. }
  4544. // copy loaded string into buffer
  4545. CopyMemory (
  4546. szBuffer,
  4547. wszBuffer,
  4548. dwNumBytes
  4549. );
  4550. MemFree(wszBuffer);
  4551. *lResult = ERROR_SUCCESS;
  4552. return (LPWSTR) szBuffer;
  4553. }
  4554. /*******************MyLoadString - end ***************************************/
  4555. /******************************************************************************
  4556. ReportUsage
  4557. This function takes the usage retrieved in the input report and updates the
  4558. device status and sends an appropriate Phone event
  4559. Arguments:
  4560. PPHONESP_PHONE_INFO pPhone - Pointer to phone whose input report is
  4561. received
  4562. USAGE Usage - The usage whose value is recieved
  4563. BOOL bON - The status of the usage Received
  4564. Returns VOID
  4565. ******************************************************************************/
  4566. VOID
  4567. ReportUsage (
  4568. PPHONESP_PHONE_INFO pPhone,
  4569. USAGE UsagePage,
  4570. USAGE Usage,
  4571. ULONG Value
  4572. )
  4573. {
  4574. DWORD Index;
  4575. //LOG((PHONESP_TRACE, "ReportUsage - enter"));
  4576. EnterCriticalSection(&csAllPhones);
  4577. if ( ! ( pPhone && pPhone->htPhone ) )
  4578. {
  4579. LeaveCriticalSection(&csAllPhones);
  4580. return; // exception handling
  4581. }
  4582. EnterCriticalSection(&pPhone->csThisPhone);
  4583. LeaveCriticalSection(&csAllPhones);
  4584. switch (UsagePage)
  4585. {
  4586. case HID_USAGE_PAGE_TELEPHONY:
  4587. {
  4588. switch (Usage)
  4589. {
  4590. case HID_USAGE_TELEPHONY_HOOKSWITCH:
  4591. if (Value == TRUE)
  4592. {
  4593. if (pPhone->dwHandsetHookSwitchMode != PHONEHOOKSWITCHMODE_MICSPEAKER)
  4594. {
  4595. LOG((PHONESP_TRACE, "HANDSET OFFHOOK "));
  4596. pPhone->dwHandsetHookSwitchMode = PHONEHOOKSWITCHMODE_MICSPEAKER;
  4597. SendPhoneEvent(
  4598. pPhone,
  4599. PHONE_STATE,
  4600. PHONESTATE_HANDSETHOOKSWITCH,
  4601. PHONEHOOKSWITCHMODE_MICSPEAKER,
  4602. 0
  4603. );
  4604. }
  4605. }
  4606. else
  4607. {
  4608. if (pPhone->dwHandsetHookSwitchMode != PHONEHOOKSWITCHMODE_ONHOOK)
  4609. {
  4610. LOG((PHONESP_TRACE, "HANDSET ONHOOK"));
  4611. pPhone->dwHandsetHookSwitchMode = PHONEHOOKSWITCHMODE_ONHOOK;
  4612. SendPhoneEvent(
  4613. pPhone,
  4614. PHONE_STATE,
  4615. PHONESTATE_HANDSETHOOKSWITCH,
  4616. PHONEHOOKSWITCHMODE_ONHOOK,
  4617. 0
  4618. );
  4619. }
  4620. }
  4621. break;
  4622. case HID_USAGE_TELEPHONY_SPEAKER_PHONE:
  4623. if (Value == TRUE)
  4624. {
  4625. if (pPhone->bSpeakerHookSwitchButton == FALSE)
  4626. {
  4627. pPhone->bSpeakerHookSwitchButton = TRUE;
  4628. if (pPhone->dwSpeakerHookSwitchMode != PHONEHOOKSWITCHMODE_ONHOOK)
  4629. {
  4630. LOG((PHONESP_TRACE, "SPEAKER ONHOOK"));
  4631. pPhone->dwSpeakerHookSwitchMode = PHONEHOOKSWITCHMODE_ONHOOK;
  4632. SendPhoneEvent(
  4633. pPhone,
  4634. PHONE_STATE,
  4635. PHONESTATE_SPEAKERHOOKSWITCH,
  4636. PHONEHOOKSWITCHMODE_ONHOOK,
  4637. 0
  4638. );
  4639. }
  4640. else
  4641. {
  4642. LOG((PHONESP_TRACE, "SPEAKER OFFHOOK "));
  4643. pPhone->dwSpeakerHookSwitchMode = PHONEHOOKSWITCHMODE_MICSPEAKER;
  4644. SendPhoneEvent(
  4645. pPhone,
  4646. PHONE_STATE,
  4647. PHONESTATE_SPEAKERHOOKSWITCH,
  4648. PHONEHOOKSWITCHMODE_MICSPEAKER,
  4649. 0
  4650. );
  4651. }
  4652. }
  4653. }
  4654. else
  4655. {
  4656. pPhone->bSpeakerHookSwitchButton = FALSE;
  4657. }
  4658. break;
  4659. // Feature Buttons with on-off control
  4660. case HID_USAGE_TELEPHONY_HOLD:
  4661. case HID_USAGE_TELEPHONY_PARK:
  4662. case HID_USAGE_TELEPHONY_FORWARD_CALLS:
  4663. case HID_USAGE_TELEPHONY_CONFERENCE:
  4664. case HID_USAGE_TELEPHONY_PHONE_MUTE:
  4665. case HID_USAGE_TELEPHONY_DONOTDISTURB:
  4666. case HID_USAGE_TELEPHONY_SEND:
  4667. if (LookupIndexForUsage(Usage, &Index) == ERROR_SUCCESS)
  4668. {
  4669. PPHONESP_BUTTONINFO pButtonInfo;
  4670. pButtonInfo = GetButtonFromID(pPhone,pPhone->dwButtonIds[Index]);
  4671. if (pButtonInfo != NULL)
  4672. {
  4673. if (Value == TRUE)
  4674. {
  4675. if (pButtonInfo->dwButtonState != PHONEBUTTONSTATE_DOWN)
  4676. {
  4677. LOG((PHONESP_TRACE, "BUTTON '%ws' DOWN", pButtonInfo->szButtonText));
  4678. pButtonInfo->dwButtonState = PHONEBUTTONSTATE_DOWN;
  4679. SendPhoneEvent(
  4680. pPhone,
  4681. PHONE_BUTTON,
  4682. pPhone->dwButtonIds[Index],
  4683. PHONEBUTTONMODE_FEATURE,
  4684. PHONEBUTTONSTATE_DOWN
  4685. );
  4686. }
  4687. }
  4688. else
  4689. {
  4690. if (pButtonInfo->dwButtonState != PHONEBUTTONSTATE_UP)
  4691. {
  4692. LOG((PHONESP_TRACE, "BUTTON '%ws' UP", pButtonInfo->szButtonText));
  4693. pButtonInfo->dwButtonState = PHONEBUTTONSTATE_UP;
  4694. SendPhoneEvent(
  4695. pPhone,
  4696. PHONE_BUTTON,
  4697. pPhone->dwButtonIds[Index],
  4698. PHONEBUTTONMODE_FEATURE,
  4699. PHONEBUTTONSTATE_UP
  4700. );
  4701. }
  4702. }
  4703. }
  4704. }
  4705. break;
  4706. default:
  4707. // Key Pad buttons
  4708. if ( (pPhone->bKeyPad) &&
  4709. (Usage >= HID_USAGE_TELEPHONY_PHONE_KEY_0) &&
  4710. (Usage <= HID_USAGE_TELEPHONY_PHONE_KEY_D) )
  4711. {
  4712. PPHONESP_BUTTONINFO pButtonInfo;
  4713. pButtonInfo = GetButtonFromID(pPhone,pPhone->dwButtonIds[Usage - HID_USAGE_TELEPHONY_PHONE_KEY_0]);
  4714. if (pButtonInfo != NULL)
  4715. {
  4716. if (Value == TRUE)
  4717. {
  4718. if (pButtonInfo->dwButtonState != PHONEBUTTONSTATE_DOWN)
  4719. {
  4720. if (pButtonInfo->dwButtonState != PHONEBUTTONSTATE_DOWN)
  4721. {
  4722. LOG((PHONESP_TRACE, "BUTTON '%ws' DOWN", pButtonInfo->szButtonText));
  4723. pButtonInfo->dwButtonState = PHONEBUTTONSTATE_DOWN;
  4724. SendPhoneEvent(
  4725. pPhone,
  4726. PHONE_BUTTON,
  4727. Usage - HID_USAGE_TELEPHONY_PHONE_KEY_0,
  4728. PHONEBUTTONMODE_KEYPAD,
  4729. PHONEBUTTONSTATE_DOWN
  4730. );
  4731. }
  4732. }
  4733. }
  4734. else
  4735. {
  4736. if (pButtonInfo->dwButtonState != PHONEBUTTONSTATE_UP)
  4737. {
  4738. LOG((PHONESP_TRACE, "BUTTON '%ws' UP", pButtonInfo->szButtonText));
  4739. pButtonInfo->dwButtonState = PHONEBUTTONSTATE_UP;
  4740. SendPhoneEvent(
  4741. pPhone,
  4742. PHONE_BUTTON,
  4743. Usage - HID_USAGE_TELEPHONY_PHONE_KEY_0,
  4744. PHONEBUTTONMODE_KEYPAD,
  4745. PHONEBUTTONSTATE_UP
  4746. );
  4747. }
  4748. }
  4749. }
  4750. }
  4751. else
  4752. { // Feature Buttons - with one-shot control
  4753. if (LookupIndexForUsage(Usage, &Index) == ERROR_SUCCESS)
  4754. {
  4755. if (Value == TRUE)
  4756. {
  4757. PPHONESP_BUTTONINFO pButtonInfo;
  4758. pButtonInfo = GetButtonFromID(pPhone,pPhone->dwButtonIds[Index]);
  4759. if ( pButtonInfo != NULL )
  4760. {
  4761. LOG((PHONESP_TRACE, "BUTTON '%ws' DOWN", pButtonInfo->szButtonText));
  4762. SendPhoneEvent(
  4763. pPhone,
  4764. PHONE_BUTTON,
  4765. pPhone->dwButtonIds[Index],
  4766. PHONEBUTTONMODE_FEATURE,
  4767. PHONEBUTTONSTATE_DOWN
  4768. );
  4769. LOG((PHONESP_TRACE, "BUTTON '%ws' UP", pButtonInfo->szButtonText));
  4770. SendPhoneEvent(
  4771. pPhone,
  4772. PHONE_BUTTON,
  4773. pPhone->dwButtonIds[Index],
  4774. PHONEBUTTONMODE_FEATURE,
  4775. PHONEBUTTONSTATE_UP
  4776. );
  4777. }
  4778. }
  4779. }
  4780. else
  4781. {
  4782. LOG((PHONESP_TRACE, "Unsupported PHONE USAGE: 0x%04x",Usage));
  4783. }
  4784. }
  4785. break;
  4786. }
  4787. }
  4788. break;
  4789. case HID_USAGE_PAGE_CONSUMER:
  4790. {
  4791. switch (Usage)
  4792. {
  4793. case HID_USAGE_CONSUMER_VOLUME:
  4794. {
  4795. if (pPhone->dwVolume)
  4796. {
  4797. PPHONESP_BUTTONINFO pUpButtonInfo;
  4798. PPHONESP_BUTTONINFO pDownButtonInfo;
  4799. pUpButtonInfo = GetButtonFromID(pPhone,pPhone->dwButtonIds[PHONESP_FEATURE_VOLUMEUP]);
  4800. pDownButtonInfo = GetButtonFromID(pPhone,pPhone->dwButtonIds[PHONESP_FEATURE_VOLUMEDOWN]);
  4801. if ((pUpButtonInfo != NULL) && (pDownButtonInfo != NULL))
  4802. {
  4803. switch (Value) // 2-bit signed
  4804. {
  4805. case 0x0:
  4806. if (pUpButtonInfo->dwButtonState != PHONEBUTTONSTATE_UP)
  4807. {
  4808. LOG((PHONESP_TRACE, "BUTTON '%ws' UP", pUpButtonInfo->szButtonText));
  4809. pUpButtonInfo->dwButtonState = PHONEBUTTONSTATE_UP;
  4810. SendPhoneEvent(
  4811. pPhone,
  4812. PHONE_BUTTON,
  4813. pPhone->dwButtonIds[PHONESP_FEATURE_VOLUMEUP],
  4814. PHONEBUTTONMODE_FEATURE,
  4815. PHONEBUTTONSTATE_UP
  4816. );
  4817. }
  4818. if (pDownButtonInfo->dwButtonState != PHONEBUTTONSTATE_UP)
  4819. {
  4820. LOG((PHONESP_TRACE, "BUTTON '%ws' UP", pDownButtonInfo->szButtonText));
  4821. pDownButtonInfo->dwButtonState = PHONEBUTTONSTATE_UP;
  4822. SendPhoneEvent(
  4823. pPhone,
  4824. PHONE_BUTTON,
  4825. pPhone->dwButtonIds[PHONESP_FEATURE_VOLUMEDOWN],
  4826. PHONEBUTTONMODE_FEATURE,
  4827. PHONEBUTTONSTATE_UP
  4828. );
  4829. }
  4830. break;
  4831. case 0x1:
  4832. if (pUpButtonInfo->dwButtonState != PHONEBUTTONSTATE_DOWN)
  4833. {
  4834. LOG((PHONESP_TRACE, "BUTTON '%ws' DOWN", pUpButtonInfo->szButtonText));
  4835. pUpButtonInfo->dwButtonState = PHONEBUTTONSTATE_DOWN;
  4836. SendPhoneEvent(
  4837. pPhone,
  4838. PHONE_BUTTON,
  4839. pPhone->dwButtonIds[PHONESP_FEATURE_VOLUMEUP],
  4840. PHONEBUTTONMODE_FEATURE,
  4841. PHONEBUTTONSTATE_DOWN
  4842. );
  4843. }
  4844. if (pDownButtonInfo->dwButtonState != PHONEBUTTONSTATE_UP)
  4845. {
  4846. LOG((PHONESP_TRACE, "BUTTON '%ws' UP", pDownButtonInfo->szButtonText));
  4847. pDownButtonInfo->dwButtonState = PHONEBUTTONSTATE_UP;
  4848. SendPhoneEvent(
  4849. pPhone,
  4850. PHONE_BUTTON,
  4851. pPhone->dwButtonIds[PHONESP_FEATURE_VOLUMEDOWN],
  4852. PHONEBUTTONMODE_FEATURE,
  4853. PHONEBUTTONSTATE_UP
  4854. );
  4855. }
  4856. break;
  4857. case 0x3:
  4858. if (pUpButtonInfo->dwButtonState != PHONEBUTTONSTATE_UP)
  4859. {
  4860. LOG((PHONESP_TRACE, "BUTTON '%ws' UP", pUpButtonInfo->szButtonText));
  4861. pUpButtonInfo->dwButtonState = PHONEBUTTONSTATE_UP;
  4862. SendPhoneEvent(
  4863. pPhone,
  4864. PHONE_BUTTON,
  4865. pPhone->dwButtonIds[PHONESP_FEATURE_VOLUMEUP],
  4866. PHONEBUTTONMODE_FEATURE,
  4867. PHONEBUTTONSTATE_UP
  4868. );
  4869. }
  4870. if (pDownButtonInfo->dwButtonState != PHONEBUTTONSTATE_DOWN)
  4871. {
  4872. LOG((PHONESP_TRACE, "BUTTON '%ws' DOWN", pDownButtonInfo->szButtonText));
  4873. pDownButtonInfo->dwButtonState = PHONEBUTTONSTATE_DOWN;
  4874. SendPhoneEvent(
  4875. pPhone,
  4876. PHONE_BUTTON,
  4877. pPhone->dwButtonIds[PHONESP_FEATURE_VOLUMEDOWN],
  4878. PHONEBUTTONMODE_FEATURE,
  4879. PHONEBUTTONSTATE_DOWN
  4880. );
  4881. }
  4882. break;
  4883. }
  4884. }
  4885. break;
  4886. }
  4887. }
  4888. }
  4889. }
  4890. break;
  4891. }
  4892. LeaveCriticalSection(&pPhone->csThisPhone);
  4893. //LOG((PHONESP_TRACE, "ReportUsage - exit"));
  4894. }
  4895. /**********************ReportUsage - end**************************************/
  4896. /******************************************************************************
  4897. SendPhoneEvent:
  4898. This function determines whether TAPI had requested the receipt of this
  4899. message and if requested, then sends the phone device message .
  4900. Arguments:
  4901. PMYPHONE pPhone - The pointer to the phone
  4902. DWORD dwMsg - Type of Phone Event such as PHONE_BUTTON, etc
  4903. ULONG_PTR Param1 - Details relating to the Phone Event
  4904. ULONG_PTR Param2 - "
  4905. ULONG_PTR Param3 - "
  4906. Returns VOID
  4907. ******************************************************************************/
  4908. VOID
  4909. SendPhoneEvent(
  4910. PPHONESP_PHONE_INFO pPhone,
  4911. DWORD dwMsg,
  4912. ULONG_PTR Param1,
  4913. ULONG_PTR Param2,
  4914. ULONG_PTR Param3
  4915. )
  4916. {
  4917. LOG((PHONESP_TRACE, "SendPhoneEvent - enter"));
  4918. switch (dwMsg)
  4919. {
  4920. case PHONE_BUTTON:
  4921. if ( ((Param2) & pPhone->dwButtonModesMsgs ) &&
  4922. ((Param3) & pPhone->dwButtonStateMsgs) )
  4923. {
  4924. (*(pPhone->lpfnPhoneEventProc))(
  4925. pPhone->htPhone,
  4926. dwMsg,
  4927. Param1,
  4928. Param2,
  4929. Param3
  4930. );
  4931. }
  4932. break;
  4933. case PHONE_REMOVE:
  4934. (*(glpfnPhoneCreateProc))(
  4935. 0,
  4936. dwMsg,
  4937. Param1,
  4938. Param2,
  4939. Param3
  4940. );
  4941. break;
  4942. case PHONE_CREATE:
  4943. (*(glpfnPhoneCreateProc))(
  4944. 0,
  4945. dwMsg,
  4946. Param1,
  4947. Param2,
  4948. Param3
  4949. );
  4950. break;
  4951. case PHONE_STATE:
  4952. if (Param1 & pPhone->dwPhoneStateMsgs)
  4953. {
  4954. (*(pPhone->lpfnPhoneEventProc))(
  4955. pPhone->htPhone,
  4956. dwMsg,
  4957. Param1,
  4958. Param2,
  4959. Param3
  4960. );
  4961. }
  4962. break;
  4963. default:
  4964. break;
  4965. }
  4966. LOG((PHONESP_TRACE, "SendPhoneEvent - exit"));
  4967. }
  4968. /****************************SendPhoneEvent - end*****************************/
  4969. /******************************************************************************
  4970. SendOutputReport
  4971. This function forms an output report for the usage provided and sends it to
  4972. the device
  4973. Arguments:
  4974. PHID_DEVICE pHidDevice - The hid device to which the output report is
  4975. be sent
  4976. USAGE Usage - The Usage for which the output report is to be
  4977. sent
  4978. BOOL bSet - Whether the usage has to be set or reset
  4979. Returns LONG:
  4980. ERROR_SUCCESS if the function succeeded
  4981. ERROR_INVALID_DATA on error
  4982. ******************************************************************************/
  4983. LONG
  4984. SendOutputReport(
  4985. PHID_DEVICE pHidDevice,
  4986. USAGE Usage,
  4987. BOOL bSet
  4988. )
  4989. {
  4990. HID_DATA HidData;
  4991. PUSAGE UsageList = &Usage;
  4992. LONG NumUsages = 1;
  4993. if ( GetReportID(pHidDevice, Usage, &HidData) == ERROR_SUCCESS)
  4994. {
  4995. NTSTATUS Result;
  4996. memset ( pHidDevice->OutputReportBuffer,
  4997. (UCHAR) 0,
  4998. pHidDevice->Caps.OutputReportByteLength
  4999. );
  5000. if (HidData.IsButtonData)
  5001. {
  5002. if (bSet)
  5003. {
  5004. Result = HidP_SetUsages (
  5005. HidP_Output,
  5006. HidData.UsagePage,
  5007. 0,
  5008. UsageList,
  5009. &NumUsages,
  5010. pHidDevice->Ppd,
  5011. pHidDevice->OutputReportBuffer,
  5012. pHidDevice->Caps.OutputReportByteLength
  5013. );
  5014. if(Result != HIDP_STATUS_SUCCESS)
  5015. {
  5016. return ERROR_INVALID_DATA;
  5017. }
  5018. }
  5019. else
  5020. {
  5021. Result = HidP_UnsetUsages (
  5022. HidP_Output,
  5023. HidData.UsagePage,
  5024. 0,
  5025. UsageList,
  5026. &NumUsages,
  5027. pHidDevice->Ppd,
  5028. pHidDevice->OutputReportBuffer,
  5029. pHidDevice->Caps.OutputReportByteLength
  5030. );
  5031. if(Result != HIDP_STATUS_SUCCESS)
  5032. {
  5033. return ERROR_INVALID_DATA;
  5034. }
  5035. }
  5036. }
  5037. else
  5038. {
  5039. Result = HidP_SetUsageValue (
  5040. HidP_Output,
  5041. HidData.UsagePage,
  5042. 0,
  5043. Usage,
  5044. HidData.ValueData.Value,
  5045. pHidDevice->Ppd,
  5046. pHidDevice->OutputReportBuffer,
  5047. pHidDevice->Caps.OutputReportByteLength
  5048. );
  5049. if(Result != HIDP_STATUS_SUCCESS)
  5050. {
  5051. return ERROR_INVALID_DATA;
  5052. }
  5053. }
  5054. Write(pHidDevice);
  5055. }
  5056. else
  5057. {
  5058. return ERROR_INVALID_DATA;
  5059. }
  5060. return ERROR_SUCCESS;
  5061. }
  5062. /************************SendOutputReport - end*******************************/
  5063. /******************************************************************************
  5064. ShowData
  5065. This function is called by the queue service thread when the request queued
  5066. is an input report. This function retrieves the Usages present in this
  5067. structure and passes them on to ReportUsage which performs appropriate
  5068. actions.
  5069. ******************************************************************************/
  5070. VOID
  5071. CALLBACK
  5072. ShowData(
  5073. PPHONESP_FUNC_INFO pAsyncFuncInfo
  5074. )
  5075. {
  5076. PPHONESP_PHONE_INFO pPhone = (PPHONESP_PHONE_INFO) pAsyncFuncInfo->dwParam1;
  5077. BOOL bButton;
  5078. if( (DWORD) pAsyncFuncInfo->dwParam2 == PHONESP_BUTTON)
  5079. {
  5080. USAGE UsagePage = (USAGE) pAsyncFuncInfo->dwParam3;
  5081. USAGE UsageMin = (USAGE) pAsyncFuncInfo->dwParam4;
  5082. USAGE UsageMax = (USAGE) pAsyncFuncInfo->dwParam5;
  5083. DWORD MaxUsageLength = (DWORD) pAsyncFuncInfo->dwParam6;
  5084. PUSAGE Usages = (PUSAGE) pAsyncFuncInfo->dwParam7;
  5085. USAGE Usage;
  5086. for ( Usage = UsageMin; Usage <= UsageMax; Usage++ )
  5087. {
  5088. DWORD i;
  5089. for ( i = 0; i < MaxUsageLength; i++ )
  5090. {
  5091. if ( Usage == Usages[i] )
  5092. {
  5093. //LOG((PHONESP_TRACE,"ShowData - UsagePage 0x%04x Usage 0x%04x BUTTON DOWN", UsagePage, Usage));
  5094. ReportUsage(pPhone, UsagePage, Usage, TRUE);
  5095. break;
  5096. }
  5097. }
  5098. if ( i == MaxUsageLength )
  5099. {
  5100. //LOG((PHONESP_TRACE,"ShowData - UsagePage 0x%04x Usage 0x%04x BUTTON UP", UsagePage, Usage));
  5101. ReportUsage(pPhone, UsagePage, Usage, FALSE);
  5102. }
  5103. }
  5104. MemFree(Usages);
  5105. }
  5106. else
  5107. {
  5108. USAGE UsagePage = (USAGE) pAsyncFuncInfo->dwParam3;
  5109. USAGE Usage = (USAGE) pAsyncFuncInfo->dwParam4;
  5110. ULONG Value = (ULONG) pAsyncFuncInfo->dwParam5;
  5111. //LOG((PHONESP_TRACE,"ShowData - UsagePage 0x%04x Usage 0x%04x VALUE %d", UsagePage, Usage, Value));
  5112. ReportUsage(pPhone, UsagePage, Usage, Value);
  5113. }
  5114. }
  5115. /*******************ShowData - end********************************************/