121 122 if ((strcmp(lpcReader, lpcStripReader) == 0) && 123 (dwPort == (sReadersContexts[i])->dwPort)) 124 { 125 Log1(PCSC_LOG_ERROR, "Duplicate reader found."); 126 return SCARD_E_DUPLICATE_READER; 127 } 128 } 129 } 130 } 131 |
121~127 行,表示如果读卡器名字相同,读卡器 port 也相同,则失败。
132 /* We must find an empty slot to put the reader structure */ 133 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++) 134 { 135 if ((sReadersContexts[i])->vHandle == 0) 136 { 137 dwContext = i; 138 break; 139 } 140 } 141 142 if (i == PCSCLITE_MAX_READERS_CONTEXTS) 143 { 144 /* No more spots left return */ 145 return SCARD_E_NO_MEMORY; 146 } 147 |
132~147 行,寻找可用的读卡器上下文。没有找到也就是读卡器上下文数组都被占用,则失败。
148 /* Check and set the readername to see if it must be enumerated */ 149 parentNode = RFSetReaderName(sReadersContexts[dwContext], lpcReader, 150 lpcLibrary, dwPort, 0); 151 if (parentNode < -1) 152 return SCARD_E_NO_MEMORY; |
RFSetReaderName 实现什么?
定义在 readerfactory.c 中,
实现如下:
480 LONG RFSetReaderName(PREADER_CONTEXT rContext, LPSTR readerName, 481 LPSTR libraryName, DWORD dwPort, DWORD dwSlot) 482 { 483 LONG parent = -1; /* reader number of the parent of the clone */ 484 DWORD valueLength; 485 int currentDigit = -1; 486 int supportedChannels = 0; 487 int usedDigits[PCSCLITE_MAX_READERS_CONTEXTS]; 488 int i; 489 490 /* Clear the list */ 491 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++) 492 usedDigits[i] = FALSE; |
492 行, usedDigits 做什么用?对于使用相同读卡器驱动库的读卡器进行编号 .
493 494 if ((0 == dwSlot) && (dwNumReadersContexts != 0)) 495 { 496 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++) 497 { 498 if ((sReadersContexts[i])->vHandle != 0) 499 { 500 if (strcmp((sReadersContexts[i])->lpcLibrary, libraryName) == 0) 501 { |
493~501 行开始用驱动库名字遍历读卡器上下文,
494 行, 0==dwSlot ,因为调用这个函数的唯一函数是 RFAddReader, RFAddReader 会处理多 slot 的情况。这里仅仅需要判断是否为 0
502 UCHAR tagValue[1]; 503 LONG ret; 504 505 /* Ask the driver if it supports multiple channels */ 506 valueLength = sizeof(tagValue); 507 ret = IFDGetCapabilities((sReadersContexts[i]), 508 TAG_IFD_SIMULTANEOUS_ACCESS, 509 &valueLength, tagValue); 510 511 if ((ret == IFD_SUCCESS) && (valueLength == 1) && 512 (tagValue[0] > 1)) 513 { 514 supportedChannels = tagValue[0]; 515 Log2(PCSC_LOG_INFO, 516 "Support %d simultaneous readers", tagValue[0]); 517 } 518 else 519 supportedChannels = 1; |
507 行,查询驱动的能力,同一个驱动能否支持几个读卡器的并发访问。如果能支持,那么
最多能支持 supportedChannels 个使用相同驱动的读卡器。
520 521 /* Check to see if it is a hotplug reader and different */ 522 if (((((sReadersContexts[i])->dwPort & 0xFFFF0000) == 523 PCSCLITE_HP_BASE_PORT) 524 && ((sReadersContexts[i])->dwPort != dwPort)) 525 || (supportedChannels > 1)) 526 { |
520~526 行,
#define PCSCLITE_HP_BASE_PORT 0x200000
522 行, sReadersContexts[i])->dwPort & 0xFFFF0000 ,则代表热插拔设备,只要 dwPort 不等,就可以找到 parent 来共享一些内部资源 . supportedChannels > 1 ,主要用在非热插拔设备,只要驱动支持,也可以多个读卡器共用一些资源。
527 char *lpcReader = sReadersContexts[i]->lpcReader; 528 529 /* 530 * tells the caller who the parent of this 531 * clone is so it can use it's shared 532 * resources like mutex/etc. 533 */ 534 parent = i; 535 536 /* 537 * If the same reader already exists and it is 538 * hotplug then we must look for others and 539 * enumerate the readername 540 */ 541 currentDigit = strtol(lpcReader + strlen(lpcReader) - 5, N ULL , 16); 542 543 /* This spot is taken */ 544 usedDigits[currentDigit] = TRUE; 545 } 546 } 547 } 548 } 549 } |
534 行,体现了享元模式,一会就能看到享了哪些内容。
541 行, currentDigit 记录目前使用相同驱动的读卡器号。
550 551 /* default value */ 552 i = 0; 553 554 /* Other identical readers exist on the same bus */ 555 if (currentDigit != -1) 556 { 557 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++) 558 { 559 /* get the first free digit */ 560 if (usedDigits[i] == FALSE) 561 break; 562 } 563 564 if (i == PCSCLITE_MAX_READERS_CONTEXTS) 565 { 566 Log2(PCSC_LOG_ERROR, "Max number of readers reached: %d", PCSCLITE_MAX_READERS_CON TEXTS); 567 return -2; 568 } 569 570 if (i >= supportedChannels) 571 { 572 Log3(PCSC_LOG_ERROR, "Driver %s does not support more than " 573 "%d reader(s). Maybe the driver should support " 574 "TAG_IFD_SIMULTANEOUS_ACCESS", libraryName, supportedChannels); |
550~574 行,进行检查,一切都是为了得到相对使用同一个驱动的不同读卡器的唯一的读卡器号。即使使用相同驱动的每一个读卡器也各自占用一个 reader 上下文。
579 snprintf(rContext->lpcReader, sizeof(rContext->lpcReader), "%s %02X %02lX", 580 readerName, i, dwSlot); 581 582 /* Set the slot in 0xDDDDCCCC */ 583 rContext->dwSlot = (i << 16) + dwSlot; 584 585 return parent; 586 } |
579 行,构造读卡器名字, 583 行可以知道 dwslot 的高 16 位 (31~16bit) ,放置读卡器编号。
回到 RFAddReader
153 154 (void)strlcpy((sReadersContexts[dwContext])->lpcLibrary, lpcLibrary, 155 sizeof((sReadersContexts[dwContext])->lpcLibrary)); 156 (void)strlcpy((sReadersContexts[dwContext])->lpcDevice, lpcDevice, 157 sizeof((sReadersContexts[dwContext])->lpcDevice)); 158 (sReadersContexts[dwContext])->dwVersion = 0; 159 (sReadersContexts[dwContext])->dwPort = dwPort; 160 (sReadersContexts[dwContext])->mMutex = NULL; 161 (sReadersContexts[dwContext])->dwBlockStatus = 0; 162 (sReadersContexts[dwContext])->dwContexts = 0; 163 (sReadersContexts[dwContext])->pthThread = 0; 164 (sReadersContexts[dwContext])->dwLockId = 0; 165 (sReadersContexts[dwContext])->LockCount = 0; 166 (sReadersContexts[dwContext])->vHandle = NULL; 167 (sReadersContexts[dwContext])->pdwFeeds = NULL; 168 (sReadersContexts[dwContext])->pdwMutex = NULL; 169 (sReadersContexts[dwContext])->dwIdentity = 170 (dwContext + 1) << IDENTITY_SHIFT; 171 (sReadersContexts[dwContext])->readerState = NULL; 172 173 for (i = 0; i < PCSCLITE_MAX_READER_CONTEXT_CHANNELS; i++) 174 (sReadersContexts[dwContext])->psHandles[i].hCard = 0; 175 |
153~175 继续初始化。
176 /* If a clone to this reader exists take some values from that clone */ 177 if (parentNode >= 0 && parentNode < PCSCLITE_MAX_READERS_CONTEXTS) 178 { 179 (sReadersContexts[dwContext])->pdwFeeds = 180 (sReadersContexts[parentNode])->pdwFeeds; 181 *(sReadersContexts[dwContext])->pdwFeeds += 1; 182 (sReadersContexts[dwContext])->vHandle = 183 (sReadersContexts[parentNode])->vHandle; 184 (sReadersContexts[dwContext])->mMutex = 185 (sReadersContexts[parentNode])->mMutex; 186 (sReadersContexts[dwContext])->pdwMutex = 187 (sReadersContexts[parentNode])->pdwMutex; 188 189 /* Call on the driver to see if it is thread safe */ 190 dwGetSize = sizeof(ucThread); 191 rv = IFDGetCapabilities((sReadersContexts[parentNode]), 192 TAG_IFD_THREAD_SAFE, &dwGetSize, ucThread); 193 194 if (rv == IFD_SUCCESS && dwGetSize == 1 && ucThread[0] == 1) 195 { 196 Log1(PCSC_LOG_INFO, "Driver is thread safe"); 197 (sReadersContexts[dwContext])->mMutex = NULL; 198 (sReadersContexts[dwContext])->pdwMutex = NULL; 199 } 200 else 201 *(sReadersContexts[dwContext])->pdwMutex += 1; 202 } |
前面提到了享元,使用同一个驱动的读卡器可以共享一些内存。包括 pdwFeeds, vHandle, pdwMutex.
pdwFeeds 表示驱动库的共享计数。
pdwMutex 表示驱动库的锁共享计数。
190~199 行,如果驱动本身支持多线程,则 mMutex 和 pdwMutex 就不需要了。这些多线程的事情就有驱动去做, APPLICATION 不再为此头痛。
204 if ((sReadersContexts[dwContext])->pdwFeeds == NULL) 205 { 206 (sReadersContexts[dwContext])->pdwFeeds = malloc(sizeof(DWORD)); 207 208 /* Initialize pdwFeeds to 1, otherwise multiple 209 cloned readers will cause pcscd to crash when 210 RFUnloadReader unloads the driver library 211 and there are still devices attached using it --mikeg*/ 212 *(sReadersContexts[dwContext])->pdwFeeds = 1; 213 } 214 215 if ((sReadersContexts[dwContext])->mMutex == 0) 216 { 217 (sReadersContexts[dwContext])->mMutex = 218 malloc(sizeof(PCSCLITE_MUTEX)); 219 (void)SYS_MutexInit((sReadersContexts[dwContext])->mMutex); 220 } 221 222 if ((sReadersContexts[dwContext])->pdwMutex == NULL) 223 { 224 (sReadersContexts[dwContext])->pdwMutex = malloc(sizeof(DWORD)); 225 *(sReadersContexts[dwContext])->pdwMutex = 1; 226 } 227 228 dwNumReadersContexts += 1; |
204~228 行,还是要说说。记得上面 197~198 行吗?
这样对于系统中可共享驱动的读卡器,就多此一举了。 mMutex ,
pdwMutex 没有必要再初始化了。
228 行,已经使用读卡器上下文计数加 1.
真的这样吗?
实际上,不是这样的。在后面 RFUnloadReader 中,调用
RFRemoveReader 的时候,
423 if ((NULL == sContext->pdwMutex) || (NULL == sContext->pdwFeeds)) |
这两个字段拿来判断该 reader 对应的上下文是否已经移除。还有,使用同一个驱动的所有
reader 上下文是否都移除了。
另外,可以进一步减小锁粒度,相同驱动的不同读卡器 ( 槽 ) 采用各自的锁。而不是同一个计数锁。增加并发访问的能力。
dwNumReadersContexts 表示正被使用的 reader 上下文计数。
229 rv = RFInitializeReader(sReadersContexts[dwContext]); 230 if (rv != SCARD_S_SUCCESS) 231 { 232 /* Cannot connect to reader. Exit gracefully */ 233 Log2(PCSC_LOG_ERROR, "%s init failed.", lpcReader); 234 (void)RFRemoveReader(lpcReader, dwPort); 235 return rv; 236 } |
230 行, RFInitializeReader 定义在 readerfactory.c
实现如下:
1019 LONG RFInitializeReader(PREADER_CONTEXT rContext) 1020 { 1021 LONG rv; 1022 1023 /* Spawn the event handler thread */ 1024 Log3(PCSC_LOG_INFO, "Attempting startup of %s using %s", 1025 rContext->lpcReader, rContext->lpcLibrary); 1026 1027 /* loads the library */ 1028 rv = RFLoadReader(rContext); 1029 if (rv != SCARD_S_SUCCESS) 1030 { 1031 Log2(PCSC_LOG_ERROR, "RFLoadReader failed: %X", rv); 1032 return rv; 1033 } 1034 1035 /* binds the functions */ 1036 rv = RFBindFunctions(rContext); 1037 1038 if (rv != SCARD_S_SUCCESS) 1039 { 1040 Log2(PCSC_LOG_ERROR, "RFBindFunctions failed: %X", rv); 1041 (void)RFUnloadReader(rContext); 1042 return rv; 1043 } 1044 1045 /* tries to open the port */ 1046 rv = IFDOpenIFD(rContext); 1047 1048 if (rv != IFD_SUCCESS) 1049 { 1050 Log3(PCSC_LOG_CRITICAL, " Open Port %X Failed (%s)", 1051 rContext->dwPort, rContext->lpcDevice); 1052 (void)RFUnBindFunctions(rContext); 1053 (void)RFUnloadReader(rContext); 1054 if (IFD_NO_SUCH_DEVICE == rv) 1055 return SCARD_E_UNKNOWN_READER; 1056 else 1057 return SCARD_E_INVALID_TARGET; 1058 } 1059 1060 return SCARD_S_SUCCESS; 1061 } |
这么多行,其实主要的有 3 步。
RFLoadReader, RFBindFunctions, IFDOpenIFD