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 29libusb_control_transfer 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 = libusb_control_transfer(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 <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 83static 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 107static 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 141int 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 226