Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

tty/serial_core: add ISO7816 infrastructure

Add the ISO7816 ioctl and associated accessors and data structure.
Drivers can then use this common implementation to handle ISO7816
(smart cards).

Signed-off-by: Nicolas Ferre <nicolas.ferre@microchip.com>
[ludovic.desroches@microchip.com: squash and rebase, removal of gpios, checkpatch fixes]
Signed-off-by: Ludovic Desroches <ludovic.desroches@microchip.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Nicolas Ferre and committed by
Greg Kroah-Hartman
ad8c0eaa c550f01c

+179
+83
Documentation/serial/serial-iso7816.txt
··· 1 + ISO7816 SERIAL COMMUNICATIONS 2 + 3 + 1. INTRODUCTION 4 + 5 + ISO/IEC7816 is a series of standards specifying integrated circuit cards (ICC) 6 + also known as smart cards. 7 + 8 + 2. HARDWARE-RELATED CONSIDERATIONS 9 + 10 + Some CPUs/UARTs (e.g., Microchip AT91) contain a built-in mode capable of 11 + handling communication with a smart card. 12 + 13 + For these microcontrollers, the Linux driver should be made capable of 14 + working in both modes, and proper ioctls (see later) should be made 15 + available at user-level to allow switching from one mode to the other, and 16 + vice versa. 17 + 18 + 3. DATA STRUCTURES ALREADY AVAILABLE IN THE KERNEL 19 + 20 + The Linux kernel provides the serial_iso7816 structure (see [1]) to handle 21 + ISO7816 communications. This data structure is used to set and configure 22 + ISO7816 parameters in ioctls. 23 + 24 + Any driver for devices capable of working both as RS232 and ISO7816 should 25 + implement the iso7816_config callback in the uart_port structure. The 26 + serial_core calls iso7816_config to do the device specific part in response 27 + to TIOCGISO7816 and TIOCSISO7816 ioctls (see below). The iso7816_config 28 + callback receives a pointer to struct serial_iso7816. 29 + 30 + 4. USAGE FROM USER-LEVEL 31 + 32 + From user-level, ISO7816 configuration can be get/set using the previous 33 + ioctls. For instance, to set ISO7816 you can use the following code: 34 + 35 + #include <linux/serial.h> 36 + 37 + /* Include definition for ISO7816 ioctls: TIOCSISO7816 and TIOCGISO7816 */ 38 + #include <sys/ioctl.h> 39 + 40 + /* Open your specific device (e.g., /dev/mydevice): */ 41 + int fd = open ("/dev/mydevice", O_RDWR); 42 + if (fd < 0) { 43 + /* Error handling. See errno. */ 44 + } 45 + 46 + struct serial_iso7816 iso7816conf; 47 + 48 + /* Reserved fields as to be zeroed */ 49 + memset(&iso7816conf, 0, sizeof(iso7816conf)); 50 + 51 + /* Enable ISO7816 mode: */ 52 + iso7816conf.flags |= SER_ISO7816_ENABLED; 53 + 54 + /* Select the protocol: */ 55 + /* T=0 */ 56 + iso7816conf.flags |= SER_ISO7816_T(0); 57 + /* or T=1 */ 58 + iso7816conf.flags |= SER_ISO7816_T(1); 59 + 60 + /* Set the guard time: */ 61 + iso7816conf.tg = 2; 62 + 63 + /* Set the clock frequency*/ 64 + iso7816conf.clk = 3571200; 65 + 66 + /* Set transmission factors: */ 67 + iso7816conf.sc_fi = 372; 68 + iso7816conf.sc_di = 1; 69 + 70 + if (ioctl(fd_usart, TIOCSISO7816, &iso7816conf) < 0) { 71 + /* Error handling. See errno. */ 72 + } 73 + 74 + /* Use read() and write() syscalls here... */ 75 + 76 + /* Close the device when finished: */ 77 + if (close (fd) < 0) { 78 + /* Error handling. See errno. */ 79 + } 80 + 81 + 5. REFERENCES 82 + 83 + [1] include/uapi/linux/serial.h
+2
arch/alpha/include/uapi/asm/ioctls.h
··· 102 102 #define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */ 103 103 #define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */ 104 104 #define TIOCGPTPEER _IO('T', 0x41) /* Safely open the slave */ 105 + #define TIOCGISO7816 _IOR('T', 0x42, struct serial_iso7816) 106 + #define TIOCSISO7816 _IOWR('T', 0x43, struct serial_iso7816) 105 107 106 108 #define TIOCSERCONFIG 0x5453 107 109 #define TIOCSERGWILD 0x5454
+2
arch/mips/include/uapi/asm/ioctls.h
··· 93 93 #define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */ 94 94 #define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */ 95 95 #define TIOCGPTPEER _IO('T', 0x41) /* Safely open the slave */ 96 + #define TIOCGISO7816 _IOR('T', 0x42, struct serial_iso7816) 97 + #define TIOCSISO7816 _IOWR('T', 0x43, struct serial_iso7816) 96 98 97 99 /* I hope the range from 0x5480 on is free ... */ 98 100 #define TIOCSCTTY 0x5480 /* become controlling tty */
+2
arch/parisc/include/uapi/asm/ioctls.h
··· 62 62 #define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */ 63 63 #define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */ 64 64 #define TIOCGPTPEER _IO('T', 0x41) /* Safely open the slave */ 65 + #define TIOCGISO7816 _IOR('T', 0x42, struct serial_iso7816) 66 + #define TIOCSISO7816 _IOWR('T', 0x43, struct serial_iso7816) 65 67 66 68 #define FIONCLEX 0x5450 /* these numbers need to be adjusted. */ 67 69 #define FIOCLEX 0x5451
+2
arch/powerpc/include/uapi/asm/ioctls.h
··· 102 102 #define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */ 103 103 #define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */ 104 104 #define TIOCGPTPEER _IO('T', 0x41) /* Safely open the slave */ 105 + #define TIOCGISO7816 _IOR('T', 0x42, struct serial_iso7816) 106 + #define TIOCSISO7816 _IOWR('T', 0x43, struct serial_iso7816) 105 107 106 108 #define TIOCSERCONFIG 0x5453 107 109 #define TIOCSERGWILD 0x5454
+2
arch/sh/include/uapi/asm/ioctls.h
··· 95 95 #define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */ 96 96 #define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */ 97 97 #define TIOCGPTPEER _IO('T', 0x41) /* Safely open the slave */ 98 + #define TIOCGISO7816 _IOR('T', 0x42, struct serial_iso7816) 99 + #define TIOCSISO7816 _IOWR('T', 0x43, struct serial_iso7816) 98 100 99 101 #define TIOCSERCONFIG _IO('T', 83) /* 0x5453 */ 100 102 #define TIOCSERGWILD _IOR('T', 84, int) /* 0x5454 */
+2
arch/sparc/include/uapi/asm/ioctls.h
··· 27 27 #define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */ 28 28 #define TIOCGRS485 _IOR('T', 0x41, struct serial_rs485) 29 29 #define TIOCSRS485 _IOWR('T', 0x42, struct serial_rs485) 30 + #define TIOCGISO7816 _IOR('T', 0x43, struct serial_iso7816) 31 + #define TIOCSISO7816 _IOWR('T', 0x44, struct serial_iso7816) 30 32 31 33 /* Note that all the ioctls that are not available in Linux have a 32 34 * double underscore on the front to: a) avoid some programs to
+2
arch/xtensa/include/uapi/asm/ioctls.h
··· 107 107 #define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */ 108 108 #define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */ 109 109 #define TIOCGPTPEER _IO('T', 0x41) /* Safely open the slave */ 110 + #define TIOCGISO7816 _IOR('T', 0x42, struct serial_iso7816) 111 + #define TIOCSISO7816 _IOWR('T', 0x43, struct serial_iso7816) 110 112 111 113 #define TIOCSERCONFIG _IO('T', 83) 112 114 #define TIOCSERGWILD _IOR('T', 84, int)
+60
drivers/tty/serial/serial_core.c
··· 1308 1308 return 0; 1309 1309 } 1310 1310 1311 + static int uart_get_iso7816_config(struct uart_port *port, 1312 + struct serial_iso7816 __user *iso7816) 1313 + { 1314 + unsigned long flags; 1315 + struct serial_iso7816 aux; 1316 + 1317 + if (!port->iso7816_config) 1318 + return -ENOIOCTLCMD; 1319 + 1320 + spin_lock_irqsave(&port->lock, flags); 1321 + aux = port->iso7816; 1322 + spin_unlock_irqrestore(&port->lock, flags); 1323 + 1324 + if (copy_to_user(iso7816, &aux, sizeof(aux))) 1325 + return -EFAULT; 1326 + 1327 + return 0; 1328 + } 1329 + 1330 + static int uart_set_iso7816_config(struct uart_port *port, 1331 + struct serial_iso7816 __user *iso7816_user) 1332 + { 1333 + struct serial_iso7816 iso7816; 1334 + int i, ret; 1335 + unsigned long flags; 1336 + 1337 + if (!port->iso7816_config) 1338 + return -ENOIOCTLCMD; 1339 + 1340 + if (copy_from_user(&iso7816, iso7816_user, sizeof(*iso7816_user))) 1341 + return -EFAULT; 1342 + 1343 + /* 1344 + * There are 5 words reserved for future use. Check that userspace 1345 + * doesn't put stuff in there to prevent breakages in the future. 1346 + */ 1347 + for (i = 0; i < 5; i++) 1348 + if (iso7816.reserved[i]) 1349 + return -EINVAL; 1350 + 1351 + spin_lock_irqsave(&port->lock, flags); 1352 + ret = port->iso7816_config(port, &iso7816); 1353 + spin_unlock_irqrestore(&port->lock, flags); 1354 + if (ret) 1355 + return ret; 1356 + 1357 + if (copy_to_user(iso7816_user, &port->iso7816, sizeof(port->iso7816))) 1358 + return -EFAULT; 1359 + 1360 + return 0; 1361 + } 1362 + 1311 1363 /* 1312 1364 * Called via sys_ioctl. We can use spin_lock_irq() here. 1313 1365 */ ··· 1443 1391 1444 1392 case TIOCSRS485: 1445 1393 ret = uart_set_rs485_config(uport, uarg); 1394 + break; 1395 + 1396 + case TIOCSISO7816: 1397 + ret = uart_set_iso7816_config(state->uart_port, uarg); 1398 + break; 1399 + 1400 + case TIOCGISO7816: 1401 + ret = uart_get_iso7816_config(state->uart_port, uarg); 1446 1402 break; 1447 1403 default: 1448 1404 if (uport->ops->ioctl)
+3
include/linux/serial_core.h
··· 144 144 void (*handle_break)(struct uart_port *); 145 145 int (*rs485_config)(struct uart_port *, 146 146 struct serial_rs485 *rs485); 147 + int (*iso7816_config)(struct uart_port *, 148 + struct serial_iso7816 *iso7816); 147 149 unsigned int irq; /* irq number */ 148 150 unsigned long irqflags; /* irq flags */ 149 151 unsigned int uartclk; /* base uart clock */ ··· 263 261 struct attribute_group *attr_group; /* port specific attributes */ 264 262 const struct attribute_group **tty_groups; /* all attributes (serial core use only) */ 265 263 struct serial_rs485 rs485; 264 + struct serial_iso7816 iso7816; 266 265 void *private_data; /* generic platform data pointer */ 267 266 }; 268 267
+2
include/uapi/asm-generic/ioctls.h
··· 79 79 #define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */ 80 80 #define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */ 81 81 #define TIOCGPTPEER _IO('T', 0x41) /* Safely open the slave */ 82 + #define TIOCGISO7816 _IOR('T', 0x42, struct serial_iso7816) 83 + #define TIOCSISO7816 _IOWR('T', 0x43, struct serial_iso7816) 82 84 83 85 #define FIONCLEX 0x5450 84 86 #define FIOCLEX 0x5451
+17
include/uapi/linux/serial.h
··· 132 132 are a royal PITA .. */ 133 133 }; 134 134 135 + /* 136 + * Serial interface for controlling ISO7816 settings on chips with suitable 137 + * support. Set with TIOCSISO7816 and get with TIOCGISO7816 if supported by 138 + * your platform. 139 + */ 140 + struct serial_iso7816 { 141 + __u32 flags; /* ISO7816 feature flags */ 142 + #define SER_ISO7816_ENABLED (1 << 0) 143 + #define SER_ISO7816_T_PARAM (0x0f << 4) 144 + #define SER_ISO7816_T(t) (((t) & 0x0f) << 4) 145 + __u32 tg; 146 + __u32 sc_fi; 147 + __u32 sc_di; 148 + __u32 clk; 149 + __u32 reserved[5]; 150 + }; 151 + 135 152 #endif /* _UAPI_LINUX_SERIAL_H */