pcsc_pinpad_modify (int slot, int class, int ins, int p0, int p1,
                    pininfo_t *pininfo)
{
  int sw;
  unsigned char *pin_modify;
  int len = PIN_MODIFY_STRUCTURE_SIZE + 2 * pininfo->fixedlen;
  unsigned char result[2];
  pcsc_dword_t resultlen = 2;
  int no_lc;

  if (!reader_table[slot].atrlen
      && (sw = reset_pcsc_reader (slot)))
    return sw;

  if (pininfo->fixedlen < 0 || pininfo->fixedlen >= 16)
    return SW_NOT_SUPPORTED;

  pin_modify = xtrymalloc (len);
  if (!pin_modify)
    return SW_HOST_OUT_OF_CORE;

  no_lc = (!pininfo->fixedlen && reader_table[slot].is_spr532);

  pin_modify[0] = 0x00; /* bTimeOut */
  pin_modify[1] = 0x00; /* bTimeOut2 */
  pin_modify[2] = 0x82; /* bmFormatString: Byte, pos=0, left, ASCII. */
  pin_modify[3] = pininfo->fixedlen; /* bmPINBlockString */
  pin_modify[4] = 0x00; /* bmPINLengthFormat */
  pin_modify[5] = 0x00; /* bInsertionOffsetOld */
  pin_modify[6] = pininfo->fixedlen; /* bInsertionOffsetNew */
  pin_modify[7] = pininfo->maxlen; /* wPINMaxExtraDigit */
  pin_modify[8] = pininfo->minlen; /* wPINMaxExtraDigit */
  pin_modify[9] = (p0 == 0 ? 0x03 : 0x01);
                  /* bConfirmPIN
                   *    0x00: new PIN once
                   *    0x01: new PIN twice (confirmation)
                   *    0x02: old PIN and new PIN once
                   *    0x03: old PIN and new PIN twice (confirmation)
                   */
  pin_modify[10] = 0x02; /* bEntryValidationCondition: Validation key pressed */
  if (pininfo->minlen && pininfo->maxlen && pininfo->minlen == pininfo->maxlen)
    pin_modify[10] |= 0x01; /* Max size reached.  */
  pin_modify[11] = 0x03; /* bNumberMessage: Three messages */
  pin_modify[12] = 0x09; /* wLangId: 0x0409: US English */
  pin_modify[13] = 0x04; /* wLangId: 0x0409: US English */
  pin_modify[14] = 0x00; /* bMsgIndex1 */
  pin_modify[15] = 0x01; /* bMsgIndex2 */
  pin_modify[16] = 0x02; /* bMsgIndex3 */
  pin_modify[17] = 0x00; /* bTeoPrologue[0] */
  pin_modify[18] = 0x00; /* bTeoPrologue[1] */
  pin_modify[19] = 2 * pininfo->fixedlen + 0x05 - no_lc; /* bTeoPrologue[2] */
  pin_modify[20] = 2 * pininfo->fixedlen + 0x05 - no_lc; /* ulDataLength */
  pin_modify[21] = 0x00; /* ulDataLength */
  pin_modify[22] = 0x00; /* ulDataLength */
  pin_modify[23] = 0x00; /* ulDataLength */
  pin_modify[24] = class; /* abData[0] */
  pin_modify[25] = ins; /* abData[1] */
  pin_modify[26] = p0; /* abData[2] */
  pin_modify[27] = p1; /* abData[3] */
  pin_modify[28] = 2 * pininfo->fixedlen; /* abData[4] */
  if (pininfo->fixedlen)
    memset (&pin_modify[29], 0xff, 2 * pininfo->fixedlen);
  else if (no_lc)
    len--;

  if (DBG_CARD_IO)
    log_debug ("send secure: c=%02X i=%02X p1=%02X p2=%02X len=%d pinmax=%d\n",
	       class, ins, p0, p1, len, (int)pininfo->maxlen);

  sw = control_pcsc (slot, reader_table[slot].pcsc.modify_ioctl,
                     pin_modify, len, result, &resultlen);
  xfree (pin_modify);
  if (sw || resultlen < 2)
    {
      log_error ("control_pcsc failed: %d\n", sw);
      return sw? sw : SW_HOST_INCOMPLETE_CARD_RESPONSE;
    }
  sw = (result[resultlen-2] << 8) | result[resultlen-1];
  if (DBG_CARD_IO)
    log_debug (" response: sw=%04X  datalen=%d\n", sw, (unsigned int)resultlen);
  return sw;
}