Initial commit
[platform/upstream/ccid.git] / contrib / Kobil_mIDentity_switch / Kobil_mIDentity_switch.c
1 /*
2     Activate the smartcard interface on the kobil midentity usb device
3     Copyright (C) 2006  Norbert Federa <norbert.federa@neoware.com>
4
5     This program is free software; you can redistribute it and/or
6     modify it under the terms of the GNU Lesser General Public
7     License as published by the Free Software Foundation; either
8     version 2.1 of the License, or (at your option) any later version.
9
10     This library is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13     Lesser General Public License for more details.
14
15         You should have received a copy of the GNU Lesser General Public License
16         along with this library; if not, write to the Free Software Foundation,
17         Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
18
19 Author: Norbert Federa <norbert.federa@neoware.com>
20 Date:   2006-04-06
21
22
23 Description:
24
25 This tool is needed to activate the smartcard interface on the kobil midentity
26 usb device (vendor 0x04D6 id 0x4081)
27
28 Kobil's own implementation was a kernel usb driver which did just send a
29 libusb_control_transfer in the probe routine.
30
31 We do the same via libusb and call this program from our /sbin/hotblug script
32 if the mIDentity gets added.
33
34 The kobil switcher driver was found inside this zip ...
35 http://www.kobil.com/download/partner/KOBIL_mIDentity_SDK_Build_20060320_RELEASE.zip
36 ... under Interfaces/Linux/module_with_binary_final.tar.gz.
37
38 Here the interesting part of the kernel driver inside the probe function:
39
40         if (dev->descriptor.idVendor == KOBIL_VENDOR_ID){
41                 printk("!!!!! DEVICE FOUND !!! !\n");
42                 ret = libusb_control_transfer(dev,
43                 send_pipe,
44                 0x09,
45                 0x22,
46                 0x0200,
47                 0x0001,
48                 switchCmd,
49                 sizeof(switchCmd),
50                 5000);
51         }
52
53 Initally the it did not work with libusb because the ioctl gets ignored with
54 the used RequestType of 0x22 in combination with index 0x0001, but index 0x0002
55 worked.  See usb/devio.c functions  proc_control() ->  check_ctrlrecip() ->
56 findintfep() in order to understand why.
57 */
58
59 #include <stdio.h>
60 #include <string.h>
61 #include <unistd.h>
62 #include <stdlib.h>
63 #include <libusb.h>
64 #include <errno.h>
65
66 #include "config.h"
67
68 #define KOBIL_VENDOR_ID         0x0D46
69 #define MID_DEVICE_ID           0x4081
70 #define KOBIL_TIMEOUT           5000
71 #define VAL_STARTUP_4080        1
72 #define VAL_STARTUP_4000        2
73 #define VAL_STARTUP_4020        3
74 #define VAL_STARTUP_40A0        4
75 #define HIDCMD_SWITCH_DEVICE    0x0004
76
77 #define bmRequestType           0x22
78 #define bRequest                0x09
79 #define wValue                  0x0200
80 #define wIndex                  0x0002  /* this was originally 0x0001 */
81
82
83 static int kobil_midentity_control_msg(libusb_device_handle *usb)
84 {
85         int ret;
86
87         unsigned char switchCmd[10];
88
89         unsigned char Sleep = 1;
90         unsigned char hardDisk = 1;
91
92         unsigned char param = ((hardDisk) << 4) | (Sleep);
93
94         memset(switchCmd, 0x0, sizeof(switchCmd));
95         switchCmd[0] = HIDCMD_SWITCH_DEVICE >> 8;
96         switchCmd[1] = HIDCMD_SWITCH_DEVICE;
97         switchCmd[5] = VAL_STARTUP_4000;
98         switchCmd[9] = param;
99
100         ret = libusb_control_transfer(usb, bmRequestType, bRequest, wValue, wIndex,
101                         switchCmd, sizeof(switchCmd), KOBIL_TIMEOUT);
102
103         return(!(ret==sizeof(switchCmd)));
104 }
105
106
107 static int kobil_midentity_claim_interface(libusb_device_handle *usb, int ifnum)
108 {
109         int rv;
110
111         printf("claiming interface #%d ... ", ifnum);
112         rv = libusb_claim_interface(usb, ifnum);
113         if (rv == 0)
114         {
115                 printf("success\n");
116                 return rv;
117         }
118         else
119                 printf("failed\n");
120
121         printf("failed with error %d, trying to detach kernel driver ....\n", rv);
122         rv = libusb_detach_kernel_driver(usb, ifnum);
123         if (rv == 0)
124         {
125                 printf("success, claiming interface again ...");
126                 rv = libusb_claim_interface(usb, ifnum);
127                 if (rv == 0)
128                 {
129                         printf("success\n");
130                         return rv;
131                 }
132                 else
133                         printf("failed\n");
134         }
135
136         printf("failed with error %d, giving up.\n", rv);
137         return rv;
138 }
139
140
141 int main(int argc, char *argv[])
142 {
143         libusb_device **devs, *dev;
144         libusb_device *found_dev = NULL;
145         struct libusb_device_handle *usb = NULL;
146         int rv, i;
147         ssize_t cnt;
148
149         (void)argc;
150         (void)argv;
151
152         rv = libusb_init(NULL);
153         if (rv < 0)
154         {
155                 (void)printf("libusb_init() failed\n");
156                 return rv;
157         }
158
159         cnt = libusb_get_device_list(NULL, &devs);
160         if (cnt < 0)
161         {
162                 (void)printf("libusb_get_device_list() failed\n");
163                 return (int)cnt;
164         }
165
166         /* for every device */
167         i = 0;
168         while ((dev = devs[i++]) != NULL)
169         {
170                 struct libusb_device_descriptor desc;
171
172                 rv = libusb_get_device_descriptor(dev, &desc);
173                 if (rv < 0) {
174                         (void)printf("failed to get device descriptor\n");
175                         continue;
176                 }
177
178                 printf("vendor/product: %04X %04X\n", desc.idVendor, desc.idProduct);
179                 if (desc.idVendor == KOBIL_VENDOR_ID && desc.idProduct == MID_DEVICE_ID)
180                         found_dev = dev;
181         }
182
183         if (found_dev == NULL)
184         {
185                 printf("device not found. aborting.\n");
186                 if (0 != geteuid())
187                         printf("Try to rerun this program as root.\n");
188                 exit(1);
189         }
190
191         printf("Device found, opening ... ");
192         rv = libusb_open(found_dev, &usb);
193         if (rv < 0)
194         {
195                 printf("failed, aborting.\n");
196                 exit(2);
197         }
198         printf("success\n");
199
200         rv = kobil_midentity_claim_interface(usb, 0);
201         if (rv < 0)
202         {
203                 libusb_close(usb);
204                 exit(3);
205         }
206
207         rv = kobil_midentity_claim_interface(usb, 1);
208         if (rv < 0)
209         {
210                 libusb_close(usb);
211                 exit(3);
212         }
213
214         printf("Activating the CCID configuration .... ");
215         rv = kobil_midentity_control_msg(usb);
216         if (rv == 0)
217                 printf("success\n");
218         else
219                 printf("failed with error %d, giving up.\n", rv);
220
221         libusb_close(usb);
222
223         return 0;
224 }
225