Some smart card applications need to detect when a card is inserted or a reader is added to the system. One way to solve the problem is to call 
SCardListReaders() and 
SCardGetStatusChange() in a loop.
SCardListReaders()
SCardListReaders() is a function to list the smart card reader(s) connected to the system.
The function API is:
LONG SCardListReaders(
  SCARDCONTEXT  hContext,
  LPCSTR   mszGroups,
  LPSTR   mszReaders,
  LPDWORD   pcchReaders
)
The result in 
mszReaders is a multi-string containing the list of readers.
SCardGetStatusChange()
SCardGetStatusChange() is a function to get the status of a list of readers and wait for events.
The function API is:
LONG SCardGetStatusChange(
  SCARDCONTEXT        hContext,
  DWORD               dwTimeout,
  SCARD_READERSTATE * rgReaderStates,
  DWORD               cReaders 
)
The function will return any change from the reader(s) listed in the parameter 
rgReaderStates. See the 
function documentation for more details.
dwTimeout is a timeout in milliseconds. The function will block until the timeout expires or a change is reported.
Real world (bad) application
Here is a PC/SC log trace (see "
PCSC API spy, third try") of an real world (non Free Software) application:
SCardEstablishContext
 i dwScope: SCARD_SCOPE_SYSTEM (0x00000002)
 o hContext: 0x40DB4852
 => Command successful. (SCARD_S_SUCCESS [0x00000000])  [0.000189]
SCardListReaders
 i hContext: 0x40DB4852
 i mszGroups: (null)
 o pcchReaders: 0x00000001
 o mszReaders: 
 => Cannot find a smart card reader. (SCARD_E_NO_READERS_AVAILABLE [0x8010002E])  [0.000090]
SCardReleaseContext
 i hContext: 0x40DB4852
 => Command successful. (SCARD_S_SUCCESS [0x00000000])  [0.000032]
    SCardEstablishContext
     i dwScope: SCARD_SCOPE_SYSTEM (0x00000002)
     o hContext: 0x21793B9A
     => Command successful. (SCARD_S_SUCCESS [0x00000000])  [0.000294]
    SCardListReaders
     i hContext: 0x21793B9A
     i mszGroups: (null)
     o pcchReaders: 0x00000001
     o mszReaders: 
     => Cannot find a smart card reader. (SCARD_E_NO_READERS_AVAILABLE [0x8010002E])  [0.000124]
    SCardGetStatusChange
     i hContext: 0x21793B9A
     i dwTimeout: 0x000000C8 (200)
     i cReaders: 0
     => Command successful. (SCARD_S_SUCCESS [0x00000000])  [0.000014]
    SCardGetStatusChange
     i hContext: 0x21793B9A
     i dwTimeout: 0x000000C8 (200)
     i cReaders: 0
     => Command successful. (SCARD_S_SUCCESS [0x00000000])  [0.000047]
    SCardGetStatusChange
     i hContext: 0x21793B9A
     i dwTimeout: 0x000000C8 (200)
     i cReaders: 0
     => Command successful. (SCARD_S_SUCCESS [0x00000000])  [0.000035]
    SCardGetStatusChange
     i hContext: 0x21793B9A
     i dwTimeout: 0x000000C8 (200)
     i cReaders: 0
     => Command successful. (SCARD_S_SUCCESS [0x00000000])  [0.000037]
    SCardListReaders
     i hContext: 0x21793B9A
     i mszGroups: (null)
     o pcchReaders: 0x00000001
     o mszReaders: 
     => Cannot find a smart card reader. (SCARD_E_NO_READERS_AVAILABLE [0x8010002E])  [0.000186]
[... lots of similar lines removed...]
    SCardGetStatusChange
     i hContext: 0x21793B9A
     i dwTimeout: 0x000000C8 (200)
     i cReaders: 0
     => Command successful. (SCARD_S_SUCCESS [0x00000000])  [0.000014]
    SCardGetStatusChange
     i hContext: 0x21793B9A
     i dwTimeout: 0x000000C8 (200)
     i cReaders: 0
     => Command successful. (SCARD_S_SUCCESS [0x00000000])  [0.000034]
    SCardGetStatusChange
     i hContext: 0x21793B9A
     i dwTimeout: 0x000000C8 (200)
     i cReaders: 0
     => Command successful. (SCARD_S_SUCCESS [0x00000000])  [0.000046]
    SCardGetStatusChange
     i hContext: 0x21793B9A
     i dwTimeout: 0x000000C8 (200)
     i cReaders: 0
     => Command successful. (SCARD_S_SUCCESS [0x00000000])  [0.000035]
    SCardListReaders
     i hContext: 0x21793B9A
     i mszGroups: (null)
     o pcchReaders: 0x00000001
     o mszReaders: 
     => Cannot find a smart card reader. (SCARD_E_NO_READERS_AVAILABLE [0x8010002E])  [0.000160]
    SCardGetStatusChange
     i hContext: 0x21793B9A
     i dwTimeout: 0x000000C8 (200)
     i cReaders: 0
     => Command successful. (SCARD_S_SUCCESS [0x00000000])  [0.000014]
    SCardGetStatusChange
     i hContext: 0x21793B9A
     i dwTimeout: 0x000000C8 (200)
     i cReaders: 0
     => Command successful. (SCARD_S_SUCCESS [0x00000000])  [0.000036]
    SCardGetStatusChange
     i hContext: 0x21793B9A
     i dwTimeout: 0x000000C8 (200)
     i cReaders: 0
     => Command successful. (SCARD_S_SUCCESS [0x00000000])  [0.000035]
    SCardGetStatusChange
     i hContext: 0x21793B9A
     i dwTimeout: 0x000000C8 (200)
     i cReaders: 0
     => Command successful. (SCARD_S_SUCCESS [0x00000000])  [0.000037]
Thread 1/2
Results sorted by total execution time
total time: 10.209201 sec
0.000189 sec (  1 calls)  0.00% SCardEstablishContext
0.000090 sec (  1 calls)  0.00% SCardListReaders
0.000032 sec (  1 calls)  0.00% SCardReleaseContext
Thread 2/2
Results sorted by total execution time
total time: 10.209201 sec
0.002053 sec ( 13 calls)  0.02% SCardListReaders
0.001655 sec ( 52 calls)  0.02% SCardGetStatusChange
0.000294 sec (  1 calls)  0.00% SCardEstablishContext
The application was executed during 10 seconds. The application made 14 calls to SCardListReaders() and 52 calls to SCardGetStatusChange().
No reader was connected at the beginning and nothing happened during the 10 seconds. So all the PC/SC calls were made to detect... nothing.
Real world (good) application
For this second example I will use my pcsc_scan application (from 
pcsc-tools):
SCardEstablishContext
 i dwScope: SCARD_SCOPE_SYSTEM (0x00000002)
 o hContext: 0x4D0F7F8C
 => Command successful. (SCARD_S_SUCCESS [0x00000000])  [0.000321]
SCardGetStatusChange
 i hContext: 0x4D0F7F8C
 i dwTimeout: 0x00000000 (0)
 i cReaders: 1
 i szReader: \\?PnP?\Notification
 i  dwCurrentState:  (0x00000000)
 i  dwEventState: SCARD_STATE_UNKNOWN, SCARD_STATE_UNAVAILABLE, SCARD_STATE_EXCLUSIVE, SCARD_STATE_INUSE, SCARD_STATE_MUTE, SCARD_STATE_PRESENT, SCARD_STATE_ATRMATCH (0x55FD66A4FBEC)
 i  Atr length: 0x55FD66A4FBF2 (94546837175282)
 i  Atr: NULL
 o szReader: \\?PnP?\Notification
 o  dwCurrentState:  (0x00000000)
 o  dwEventState:  (0x00000000)
 o  Atr length: 0x55FD66A4FBF2 (94546837175282)
 o  Atr: NULL
 => Command timeout. (SCARD_E_TIMEOUT [0x8010000A])  [0.000379]
SCardListReaders
 i hContext: 0x4D0F7F8C
 i mszGroups: (null)
 o pcchReaders: 0x00000001
 o mszReaders: NULL
 => Cannot find a smart card reader. (SCARD_E_NO_READERS_AVAILABLE [0x8010002E])  [0.000129]
SCardListReaders
 i hContext: 0x4D0F7F8C
 i mszGroups: (null)
 o pcchReaders: 0x00000001
 o mszReaders: 
 => Cannot find a smart card reader. (SCARD_E_NO_READERS_AVAILABLE [0x8010002E])  [0.000098]
SCardGetStatusChange
 i hContext: 0x4D0F7F8C
 i dwTimeout: 0xFFFFFFFF (4294967295)
 i cReaders: 1
 i szReader: \\?PnP?\Notification
 i  dwCurrentState:  (0x00000000)
 i  dwEventState:  (0x00000000)
 i  Atr length: 0x55FD66A4FBF2 (94546837175282)
 i  Atr: NULL
Thread 1/1
Results sorted by total execution time
total time: -1.000000 sec
0.000379 sec (  1 calls) -0.04% SCardGetStatusChange
0.000321 sec (  1 calls) -0.03% SCardEstablishContext
0.000227 sec (  2 calls) -0.02% SCardListReaders
The execution conditions are the same as in the previous case: no reader connected at the beginning and no change during 10 seconds.
pcsc_scan made 2 initial calls to 
SCardListReaders() and 2 calls to 
SCardGetStatusChange(). The second 
SCardGetStatusChange() call was interrupted after 10 seconds of execution (using Control-C). That is why the returned values of 
SCardGetStatusChange() are not logged.
\\?PnP?\Notification reader name
The difference between the 2 applications is the use of the special reader name 
\\?PnP?\Notification by pcsc_scan.
SCardGetStatusChange() is perfect to detect card events in the selected readers. But how to know when a new reader has been connected? When PC/SC was designed (PC/SC specification 1.0 
released in 1996) most smart card readers were (mostly) serial readers. USB was not yet deployed (USB 1.0 specification were also 
released in 1996). (Serial) reader hotplug was not a use case at that time. So it is not surprising this use case is not handled by PC/SC.
To solve this problem a special reader name is used. This is (still) NOT documented in the PC/SC workgroup specification, even in the version 2 (
PC/SC v2 part 5 page 18), and I guess it is a Microsoft invention.
The special reader name will tell 
SCardGetStatusChange() to generate associated events when a reader is added or removed. So no need to continuously call 
SCardListReaders() as it is the case with the first application.
macOS case
Windows WinSCard does support 
\\?PnP?\Notification since a long time.
pcsc-lite (WinSCard for Unix) does support 
\\?PnP?\Notification since version 1.6.0 released in May 2010.
Apple has no support of 
\\?PnP?\Notification reader name. I opened a bug for that in 2015 (see "
OS X El Capitan missing feature: SCardGetStatusChange() and "\\?PnP?\Notification"") but nothing changed since then.
So on macOS you have to regularly call 
SCardListReaders() to detect a reader connection or disconnection.
CPU consumption
To reduce the CPU and battery usage an efficient PC/SC application should always use 
\\?PnP?\Notification when possible (so on Windows and Unix except macOS).
pcsc-tools 1.5.0
Since its version 1.5.0 
pcsc_scan provides a graphical animation when nothing happens. To update the animation every second a timeout of 1 second is used in 
SCardGetStatusChange(). So if you redo the experiment with a recent 
pcsc_scan you will see one 
SCardGetStatusChange() call every second.
Since a new reader connection is detected using 
SCardGetStatusChange() no need to also call 
SCardListReaders() every second.
SCardCancel()
To force 
SCardGetStatusChange() to return before the end of the timeout you must use 
SCardCancel() from another thread of the application.
You can use a very long timeout (or even the special value 
INFINITE) and use 
SCardCancel() when needed.
Conclusion
PC/SC provides functions to be notified of events. I invested a lot of time and work to make pcsc-lite efficient regarding events management. Every pcsc-lite internal polling has been removed.
Please use 
\\?PnP?\Notification in your applications. You may not save the world but you will save a few CPU cycles.