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
19Author:	Norbert Federa <norbert.federa@neoware.com>
20Date:   2006-04-06
21
22
23Description:
24
25This tool is needed to activate the smartcard interface on the kobil midentity
26usb device (vendor 0x04D6 id 0x4081)
27
28Kobil's own implementation was a kernel usb driver which did just send a
29usb_control_msg in the probe routine.
30
31We do the same via libusb and call this program from our /sbin/hotblug script
32if the mIDentity gets added.
33
34The kobil switcher driver was found inside this zip ...
35http://www.kobil.com/download/partner/KOBIL_mIDentity_SDK_Build_20060320_RELEASE.zip
36... under Interfaces/Linux/module_with_binary_final.tar.gz.
37
38Here 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 = usb_control_msg(dev,
43		send_pipe,
44		0x09,
45		0x22,
46		0x0200,
47		0x0001,
48		switchCmd,
49		sizeof(switchCmd),
50		5000);
51	}
52
53Initally the it did not work with libusb because the ioctl gets ignored with
54the used RequestType of 0x22 in combination with index 0x0001, but index 0x0002
55worked.  See usb/devio.c functions  proc_control() ->  check_ctrlrecip() ->
56findintfep() in order to understand why.
57*/
58
59#include <stdio.h>
60#include <string.h>
61#include <usb.h>
62#include <errno.h>
63
64#include "config.h"
65
66#define KOBIL_VENDOR_ID		0x0D46
67#define MID_DEVICE_ID 		0x4081
68#define KOBIL_TIMEOUT		5000
69#define VAL_STARTUP_4080        1
70#define VAL_STARTUP_4000        2
71#define VAL_STARTUP_4020        3
72#define VAL_STARTUP_40A0        4
73#define HIDCMD_SWITCH_DEVICE    0x0004
74
75#define bmRequestType           0x22
76#define bRequest                0x09
77#define wValue                  0x0200
78#define wIndex                  0x0002  /* this was originally 0x0001 */
79
80
81static int kobil_midentity_control_msg(usb_dev_handle *usb)
82{
83    int ret;
84
85    char switchCmd[10];
86
87    unsigned char Sleep = 1;
88    unsigned char hardDisk = 1;
89
90    unsigned char param = ((hardDisk)<<4) | (Sleep);
91
92    memset(switchCmd, 0x0, sizeof(switchCmd));
93    switchCmd[0] = HIDCMD_SWITCH_DEVICE>>8;
94    switchCmd[1] = HIDCMD_SWITCH_DEVICE;
95    switchCmd[5] = VAL_STARTUP_4000;
96    switchCmd[9] = param;
97
98	ret = usb_control_msg(usb, bmRequestType, bRequest, wValue, wIndex,
99		switchCmd, sizeof(switchCmd), KOBIL_TIMEOUT);
100
101    return(!(ret==sizeof(switchCmd)));
102}
103
104
105static int kobil_midentity_claim_interface(usb_dev_handle *usb, int ifnum)
106{
107    int rv;
108
109    printf("claiming interface #%d ...\n", ifnum);
110    rv = usb_claim_interface(usb, ifnum);
111    if (rv == 0)
112	{
113		printf("success\n");
114		return(rv);
115    }
116
117#ifdef HAVE_USB_DETACH_KERNEL_DRIVER_NP
118    printf("failed with error %d, trying to detach kernel driver ....\n", rv);
119    rv = usb_detach_kernel_driver_np(usb, ifnum);
120    if (rv == 0)
121    {
122		printf("success, claiming interface again ...");
123		rv = usb_claim_interface(usb, ifnum);
124		if (rv == 0)
125		{
126			printf("success\n");
127			return(rv);
128		}
129    }
130#endif
131    printf("failed with error %d, giving up.\n", rv);
132    return(rv);
133}
134
135
136int main(int argc, char *argv[])
137{
138    struct usb_bus *bus;
139    struct usb_device *dev = NULL;
140    struct usb_device *found_dev = NULL;
141    usb_dev_handle *usb = NULL;
142    int rv;
143
144    usb_init();
145
146    usb_find_busses();
147    usb_find_devices();
148
149	for (bus = usb_busses; bus; bus = bus->next)
150	{
151		for (dev = bus->devices; dev; dev = dev->next)
152		{
153			printf("vendor/product: %04X %04X\n",
154				dev->descriptor.idVendor, dev->descriptor.idProduct);
155			if (dev->descriptor.idVendor == KOBIL_VENDOR_ID
156				&& dev->descriptor.idProduct ==MID_DEVICE_ID)
157			{
158				found_dev = dev;
159			}
160		}
161	}
162
163    if (found_dev == NULL)
164	{
165		printf("device not found. aborting.\n");
166		if (0 != geteuid())
167			printf("Try to rerun this program as root.\n");
168		exit(1);
169    }
170
171	printf("Device found, opening ... ");
172	usb = usb_open(found_dev);
173	if (!usb)
174	{
175		printf("failed, aborting.\n");
176		exit(2);
177	}
178	printf("success\n");
179
180	rv = kobil_midentity_claim_interface(usb, 0);
181	if (rv < 0)
182	{
183		usb_close(usb);
184		exit(3);
185	}
186	rv = kobil_midentity_claim_interface(usb, 1);
187	if (rv < 0)
188	{
189		usb_close(usb);
190		exit(3);
191	}
192
193	printf("Activating the CCID configuration .... ");
194	rv = kobil_midentity_control_msg(usb);
195	if (rv == 0)
196		printf("success\n");
197	else
198		printf("failed with error %d, giving up.\n", rv);
199
200    usb_close(usb);
201
202    return 0;
203}
204
205