source: trunk/src/ifd/ifd-smph.c @ 967

Revision 967, 9.7 KB checked in by aj, 5 years ago (diff)

use sleep/usleep instead of udelay (kernel only).

Line 
1/*
2 * Driver for SmartMouse/Phoenix readers
3 *
4 * Thanks to Alexandre Becoulet and its SCTK project ;)
5 * In agreement with him, this project's license has been changed to LGPL.
6 * URL: http://freshmeat.net/projects/sctk/
7 *
8 * 2005, Antoine Nguyen <ngu.antoine@gmail.com>
9 */
10
11#include "internal.h"
12#include <errno.h>
13#include <unistd.h>
14#include <stdio.h>
15#include <string.h>
16#include <stdlib.h>
17#include <sys/ioctl.h>
18#include <termios.h>
19#include <sys/poll.h>
20
21#define PHS_CONV_DIRECT 0
22#define PHS_CONV_INDIRECT 1
23#define TIMEOUT 1000
24
25/* table for indirect to direct byte mode conversion */
26static const uint8_t dir_conv_table[0x100] =
27{
28  0xff, 0x7f, 0xbf, 0x3f, 0xdf, 0x5f, 0x9f, 0x1f,
29  0xef, 0x6f, 0xaf, 0x2f, 0xcf, 0x4f, 0x8f, 0xf,
30  0xf7, 0x77, 0xb7, 0x37, 0xd7, 0x57, 0x97, 0x17,
31  0xe7, 0x67, 0xa7, 0x27, 0xc7, 0x47, 0x87, 0x7,
32  0xfb, 0x7b, 0xbb, 0x3b, 0xdb, 0x5b, 0x9b, 0x1b,
33  0xeb, 0x6b, 0xab, 0x2b, 0xcb, 0x4b, 0x8b, 0xb,
34  0xf3, 0x73, 0xb3, 0x33, 0xd3, 0x53, 0x93, 0x13,
35  0xe3, 0x63, 0xa3, 0x23, 0xc3, 0x43, 0x83, 0x3,
36  0xfd, 0x7d, 0xbd, 0x3d, 0xdd, 0x5d, 0x9d, 0x1d,
37  0xed, 0x6d, 0xad, 0x2d, 0xcd, 0x4d, 0x8d, 0xd,
38  0xf5, 0x75, 0xb5, 0x35, 0xd5, 0x55, 0x95, 0x15,
39  0xe5, 0x65, 0xa5, 0x25, 0xc5, 0x45, 0x85, 0x5,
40  0xf9, 0x79, 0xb9, 0x39, 0xd9, 0x59, 0x99, 0x19,
41  0xe9, 0x69, 0xa9, 0x29, 0xc9, 0x49, 0x89, 0x9,
42  0xf1, 0x71, 0xb1, 0x31, 0xd1, 0x51, 0x91, 0x11,
43  0xe1, 0x61, 0xa1, 0x21, 0xc1, 0x41, 0x81, 0x1,
44  0xfe, 0x7e, 0xbe, 0x3e, 0xde, 0x5e, 0x9e, 0x1e,
45  0xee, 0x6e, 0xae, 0x2e, 0xce, 0x4e, 0x8e, 0xe,
46  0xf6, 0x76, 0xb6, 0x36, 0xd6, 0x56, 0x96, 0x16,
47  0xe6, 0x66, 0xa6, 0x26, 0xc6, 0x46, 0x86, 0x6,
48  0xfa, 0x7a, 0xba, 0x3a, 0xda, 0x5a, 0x9a, 0x1a,
49  0xea, 0x6a, 0xaa, 0x2a, 0xca, 0x4a, 0x8a, 0xa,
50  0xf2, 0x72, 0xb2, 0x32, 0xd2, 0x52, 0x92, 0x12,
51  0xe2, 0x62, 0xa2, 0x22, 0xc2, 0x42, 0x82, 0x2,
52  0xfc, 0x7c, 0xbc, 0x3c, 0xdc, 0x5c, 0x9c, 0x1c,
53  0xec, 0x6c, 0xac, 0x2c, 0xcc, 0x4c, 0x8c, 0xc,
54  0xf4, 0x74, 0xb4, 0x34, 0xd4, 0x54, 0x94, 0x14,
55  0xe4, 0x64, 0xa4, 0x24, 0xc4, 0x44, 0x84, 0x4,
56  0xf8, 0x78, 0xb8, 0x38, 0xd8, 0x58, 0x98, 0x18,
57  0xe8, 0x68, 0xa8, 0x28, 0xc8, 0x48, 0x88, 0x8,
58  0xf0, 0x70, 0xb0, 0x30, 0xd0, 0x50, 0x90, 0x10,
59  0xe0, 0x60, 0xa0, 0x20, 0xc0, 0x40, 0x80, 0x0
60};
61
62enum prot_e
63{
64  prot_phoenix,         /* phoenix smartcard interface */
65  prot_smartmouse,      /* smartmouse smartcard interface */
66};
67
68typedef struct smph_priv
69{
70  enum prot_e prot;
71  unsigned int mode;
72} smph_priv_t;
73
74static int smph_card_reset(ifd_reader_t *, int, void *, size_t);
75static int smph_recv(ifd_reader_t *, unsigned int, unsigned char *, size_t, long);
76
77/*
78 * Common functions
79 */
80static int smph_setctrl(ifd_device_t *dev, const int  ctrl)
81{
82  int tmp;
83 
84  if (ioctl(dev->fd, TIOCMGET, &tmp) == -1)
85    return -1;
86  tmp &= ~(TIOCM_RTS | TIOCM_CTS | TIOCM_DTR);
87  tmp |= ctrl;
88  return (ioctl(dev->fd, TIOCMSET, &tmp));
89}
90
91/*
92 * Initialize the reader
93 */
94static int _smph_open(ifd_reader_t *reader, const char *device_name,
95                      smph_priv_t *privd)
96{
97  ifd_device_params_t params;
98  ifd_device_t *dev;
99
100  reader->nslots = 1;
101  if (!(dev = ifd_device_open(device_name)))
102    return -1;
103  reader->device = dev;
104
105  if (dev->type == IFD_DEVICE_TYPE_SERIAL)
106    {
107      if (ifd_device_get_parameters(dev, &params) < 0)
108        return -1;
109
110      params.serial.speed = 9600;
111      params.serial.bits = 8;
112      params.serial.stopbits = 1;
113      params.serial.parity = IFD_SERIAL_PARITY_NONE;
114      params.serial.dtr = 1;
115      params.serial.rts = 1;
116
117      if (ifd_device_set_parameters(dev, &params) < 0)
118        return -1;
119    }
120  dev->user_data = (void *)privd;
121  dev->timeout = TIMEOUT;
122  return 0;
123}
124
125static int phx_open(ifd_reader_t * reader, const char *device_name)
126{
127  smph_priv_t *privd = NULL;
128
129  ifd_debug(1, "device=%s", device_name);
130  reader->name = "Phoenix reader";
131  if (!(privd = (smph_priv_t *)malloc(sizeof (smph_priv_t))))
132    {
133      ct_error("out of memory");
134      return IFD_ERROR_NO_MEMORY;
135    }
136  privd->mode = PHS_CONV_DIRECT;
137  privd->prot = prot_phoenix;
138  return _smph_open(reader, device_name, privd);
139}
140
141static int smtm_open(ifd_reader_t * reader, const char *device_name)
142{
143  smph_priv_t *privd = NULL;
144
145  ifd_debug(1, "device=%s", device_name);
146  reader->name = "SmartMouse reader";
147  if (!(privd = (smph_priv_t *)malloc(sizeof (smph_priv_t))))
148    {
149      ct_error("out of memory");
150      return IFD_ERROR_NO_MEMORY;
151    }
152  privd->mode = PHS_CONV_DIRECT;
153  privd->prot = prot_smartmouse;
154  return _smph_open(reader, device_name, privd);
155}
156
157/*
158 * Change the parity
159 */
160static int smph_change_parity(ifd_reader_t *reader, int parity)
161{
162  ifd_device_t *dev = reader->device;
163  ifd_device_params_t params;
164 
165  if (dev->type != IFD_DEVICE_TYPE_SERIAL)
166    return IFD_ERROR_NOT_SUPPORTED;
167 
168  if (ifd_device_get_parameters(dev, &params) < 0)
169    return -1;
170   
171  params.serial.parity = parity;
172  return ifd_device_set_parameters(dev, &params);
173}
174
175/*
176 * Activate the reader
177 */
178static int smph_activate(ifd_reader_t * reader)
179{
180  ifd_device_t *dev = reader->device;
181  smph_priv_t *privd = (smph_priv_t *)dev->user_data;
182  int tmp;
183  uint8_t mode;
184
185  if (smph_card_reset(reader, 0, &mode, 1) < 0)
186    return -1;
187
188  ifd_debug(1, "Mode received: 0x%x\n", mode);
189  switch (mode)
190    {
191    case 0x03:
192      privd->mode = PHS_CONV_INDIRECT;
193      tmp = IFD_SERIAL_PARITY_ODD;
194      break;
195    case 0x3B:
196      privd->mode = PHS_CONV_DIRECT;
197      tmp = IFD_SERIAL_PARITY_EVEN;
198      break;
199    default:
200      return -1;
201    }
202  smph_change_parity(reader, tmp);
203
204  return 0;
205}
206
207static int smph_deactivate(ifd_reader_t * reader)
208{
209  ifd_device_t *dev = reader->device;
210
211  tcflush(dev->fd, TCIOFLUSH);
212  if (smph_setctrl(dev, TIOCM_CTS))
213    return -1;
214  return 0;
215}
216
217/*
218 * Check card status
219 */
220static int smph_card_status(ifd_reader_t * reader, int slot, int *status)
221{
222  ifd_device_t *dev = reader->device;
223  int tmp;
224
225  if (slot)
226    {
227      ct_error("smph: bad slot index %u", slot);
228      return IFD_ERROR_INVALID_SLOT;
229    }
230 
231  tcflush(dev->fd, TCIOFLUSH);
232  if (ioctl(dev->fd, TIOCMGET, &tmp) < 0)
233    return -1;
234
235  *status = 0;
236  *status |= ((tmp & TIOCM_CTS) != TIOCM_CTS) ? IFD_CARD_PRESENT : 0;
237  return 0;
238}
239
240/*
241 * Reset the card and get the ATR
242 */
243static int smph_card_reset(ifd_reader_t *reader, int slot, void *atr,
244                           size_t size)
245{
246  ifd_device_t *dev = reader->device;
247  smph_priv_t *privd = dev->user_data;
248  int res;
249
250  if (slot)
251    {
252      ct_error("%s: bad slot index %u", 
253               (privd->prot == prot_phoenix) ? "phoenix" : "smartmouse", slot);
254      return IFD_ERROR_INVALID_SLOT;
255    }
256
257  tcflush(dev->fd, TCIOFLUSH);
258  if (smph_setctrl(dev, (privd->prot == prot_phoenix) 
259                   ? TIOCM_RTS | TIOCM_CTS | TIOCM_DTR
260                   : TIOCM_CTS | TIOCM_DTR) < 0)
261    return -1;
262
263  /* FIXME: use ifd_serial_reset instead? */
264  sleep(1);
265
266  if (smph_setctrl(dev, (privd->prot == prot_phoenix) 
267                   ? TIOCM_CTS | TIOCM_DTR :
268                   TIOCM_RTS | TIOCM_CTS | TIOCM_DTR) < 0)
269    return -1;
270
271  /* FIXME: use ifd_serial_reset instead? */
272  usleep(200);
273
274  if ((res = smph_recv(reader, 0, (unsigned char *)atr, size, dev->timeout)) < 1)
275    return -1;
276
277  ifd_debug(1, "Bytes received %i\n", res);
278  return res;
279}
280
281/*
282 * Send command to IFD
283 */
284static int _smph_send(ifd_device_t *dev, const unsigned char *buffer, 
285                      size_t len)
286{
287  unsigned char tmp;
288  unsigned int i;
289  struct pollfd pfd;
290 
291  ifd_debug(3, "data:%s", ct_hexdump(buffer, len));
292  for (i = 0; i < len; i++)
293    {
294      if (write(dev->fd, buffer + i, 1) < 1)
295        return -1;
296      tcdrain(dev->fd);
297    }
298
299  for (i = 0; i < len; i++)
300    {
301      pfd.fd = dev->fd;
302      pfd.events = POLLIN;
303      if (poll(&pfd, 1, dev->timeout) < 1)
304        return -1;
305      if (read(dev->fd, &tmp, 1) < 1)
306        return -1;
307      if (tmp != *(buffer + i))
308        return -1;
309    }
310  return 0;
311}
312
313static int smph_send(ifd_reader_t * reader, unsigned int dad,
314                     const unsigned char *buffer, size_t len)
315{
316  smph_priv_t *privd;
317  ifd_device_t *dev = reader->device;
318  uint8_t *fbuff = NULL;
319  int i;
320 
321  if (!dev)
322    return -1;
323  privd = (smph_priv_t *)dev->user_data;
324  if (privd->mode == PHS_CONV_INDIRECT)
325    {
326      if (!(fbuff = (uint8_t *)malloc(len * sizeof (uint8_t))))
327        {
328          ct_error("out of memory");
329          return IFD_ERROR_NO_MEMORY;
330        }
331      for (i = 0; i < len; i++)
332        fbuff[i] = dir_conv_table[buffer[i]];
333      i = _smph_send(dev, fbuff, len);
334      free(fbuff);
335      return i;
336    }
337  return _smph_send(dev, buffer, len);
338}
339
340/*
341 * Receive data from IFD
342 */
343static int smph_recv(ifd_reader_t * reader, unsigned int dad,
344                     unsigned char *buffer, size_t len, long timeout)
345{
346  ifd_device_t *dev = reader->device;
347  smph_priv_t *privd;
348  int n;
349  int i;
350
351  for (i = 0; i < len; i++)
352    {
353      n = ifd_device_recv(dev, buffer + i, 1, timeout);
354      if (n == IFD_ERROR_TIMEOUT)
355        break;
356      if (n == -1)
357        return -1;
358    }
359
360  privd = (smph_priv_t *)dev->user_data;
361  if (privd->mode == PHS_CONV_INDIRECT)
362    for (i = 0; i < len; i++)
363      buffer[i] = dir_conv_table[buffer[i]];
364 
365  ifd_debug(3, "data:%s", ct_hexdump(buffer, len));
366  return i;
367}
368
369/*
370 * Driver operations
371 */
372static struct ifd_driver_ops phx_driver;
373static struct ifd_driver_ops smtm_driver;
374
375void ifd_smph_register(void)
376{
377  phx_driver.open = phx_open;
378  //smph_driver.change_parity = smph_change_parity;
379  phx_driver.activate = smph_activate;
380  phx_driver.deactivate = smph_deactivate;
381  phx_driver.card_status = smph_card_status;
382  phx_driver.card_reset = smph_card_reset;
383  phx_driver.send = smph_send;
384  phx_driver.recv = smph_recv;
385  ifd_driver_register("phoenix", &phx_driver);
386
387  smtm_driver.open = smtm_open;
388  //smph_driver.change_parity = smph_change_parity;
389  smtm_driver.activate = smph_activate;
390  smtm_driver.deactivate = smph_deactivate;
391  smtm_driver.card_status = smph_card_status;
392  smtm_driver.card_reset = smph_card_reset;
393  smtm_driver.send = smph_send;
394  smtm_driver.recv = smph_recv;
395  ifd_driver_register("smartmouse", &smtm_driver);
396}
Note: See TracBrowser for help on using the repository browser.