|
Packit |
9f0df5 |
/*
|
|
Packit |
9f0df5 |
Activate the smartcard interface on the kobil midentity usb device
|
|
Packit |
9f0df5 |
Copyright (C) 2006 Norbert Federa <norbert.federa@neoware.com>
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
This program is free software; you can redistribute it and/or
|
|
Packit |
9f0df5 |
modify it under the terms of the GNU Lesser General Public
|
|
Packit |
9f0df5 |
License as published by the Free Software Foundation; either
|
|
Packit |
9f0df5 |
version 2.1 of the License, or (at your option) any later version.
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
This library is distributed in the hope that it will be useful,
|
|
Packit |
9f0df5 |
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
9f0df5 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
9f0df5 |
Lesser General Public License for more details.
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
You should have received a copy of the GNU Lesser General Public License
|
|
Packit |
9f0df5 |
along with this library; if not, write to the Free Software Foundation,
|
|
Packit |
9f0df5 |
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
Author: Norbert Federa <norbert.federa@neoware.com>
|
|
Packit |
9f0df5 |
Date: 2006-04-06
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
Description:
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
This tool is needed to activate the smartcard interface on the kobil midentity
|
|
Packit |
9f0df5 |
usb device (vendor 0x04D6 id 0x4081)
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
Kobil's own implementation was a kernel usb driver which did just send a
|
|
Packit |
9f0df5 |
libusb_control_transfer in the probe routine.
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
We do the same via libusb and call this program from our /sbin/hotblug script
|
|
Packit |
9f0df5 |
if the mIDentity gets added.
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
The kobil switcher driver was found inside this zip ...
|
|
Packit |
9f0df5 |
http://www.kobil.com/download/partner/KOBIL_mIDentity_SDK_Build_20060320_RELEASE.zip
|
|
Packit |
9f0df5 |
... under Interfaces/Linux/module_with_binary_final.tar.gz.
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
Here the interesting part of the kernel driver inside the probe function:
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
if (dev->descriptor.idVendor == KOBIL_VENDOR_ID){
|
|
Packit |
9f0df5 |
printk("!!!!! DEVICE FOUND !!! !\n");
|
|
Packit |
9f0df5 |
ret = libusb_control_transfer(dev,
|
|
Packit |
9f0df5 |
send_pipe,
|
|
Packit |
9f0df5 |
0x09,
|
|
Packit |
9f0df5 |
0x22,
|
|
Packit |
9f0df5 |
0x0200,
|
|
Packit |
9f0df5 |
0x0001,
|
|
Packit |
9f0df5 |
switchCmd,
|
|
Packit |
9f0df5 |
sizeof(switchCmd),
|
|
Packit |
9f0df5 |
5000);
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
Initally the it did not work with libusb because the ioctl gets ignored with
|
|
Packit |
9f0df5 |
the used RequestType of 0x22 in combination with index 0x0001, but index 0x0002
|
|
Packit |
9f0df5 |
worked. See usb/devio.c functions proc_control() -> check_ctrlrecip() ->
|
|
Packit |
9f0df5 |
findintfep() in order to understand why.
|
|
Packit |
9f0df5 |
*/
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
#include <stdio.h>
|
|
Packit |
9f0df5 |
#include <string.h>
|
|
Packit |
9f0df5 |
#include <unistd.h>
|
|
Packit |
9f0df5 |
#include <stdlib.h>
|
|
Packit |
9f0df5 |
#include <libusb.h>
|
|
Packit |
9f0df5 |
#include <errno.h>
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
#include "config.h"
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
#define KOBIL_VENDOR_ID 0x0D46
|
|
Packit |
9f0df5 |
#define MID_DEVICE_ID 0x4081
|
|
Packit |
9f0df5 |
#define KOBIL_TIMEOUT 5000
|
|
Packit |
9f0df5 |
#define VAL_STARTUP_4080 1
|
|
Packit |
9f0df5 |
#define VAL_STARTUP_4000 2
|
|
Packit |
9f0df5 |
#define VAL_STARTUP_4020 3
|
|
Packit |
9f0df5 |
#define VAL_STARTUP_40A0 4
|
|
Packit |
9f0df5 |
#define HIDCMD_SWITCH_DEVICE 0x0004
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
#define bmRequestType 0x22
|
|
Packit |
9f0df5 |
#define bRequest 0x09
|
|
Packit |
9f0df5 |
#define wValue 0x0200
|
|
Packit |
9f0df5 |
#define wIndex 0x0002 /* this was originally 0x0001 */
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
static int kobil_midentity_control_msg(libusb_device_handle *usb)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
int ret;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
unsigned char switchCmd[10];
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
unsigned char Sleep = 1;
|
|
Packit |
9f0df5 |
unsigned char hardDisk = 1;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
unsigned char param = ((hardDisk) << 4) | (Sleep);
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
memset(switchCmd, 0x0, sizeof(switchCmd));
|
|
Packit |
9f0df5 |
switchCmd[0] = HIDCMD_SWITCH_DEVICE >> 8;
|
|
Packit |
9f0df5 |
switchCmd[1] = HIDCMD_SWITCH_DEVICE;
|
|
Packit |
9f0df5 |
switchCmd[5] = VAL_STARTUP_4000;
|
|
Packit |
9f0df5 |
switchCmd[9] = param;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
ret = libusb_control_transfer(usb, bmRequestType, bRequest, wValue, wIndex,
|
|
Packit |
9f0df5 |
switchCmd, sizeof(switchCmd), KOBIL_TIMEOUT);
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
return(!(ret==sizeof(switchCmd)));
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
static int kobil_midentity_claim_interface(libusb_device_handle *usb, int ifnum)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
int rv;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
printf("claiming interface #%d ... ", ifnum);
|
|
Packit |
9f0df5 |
rv = libusb_claim_interface(usb, ifnum);
|
|
Packit |
9f0df5 |
if (rv == 0)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
printf("success\n");
|
|
Packit |
9f0df5 |
return rv;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
else
|
|
Packit |
9f0df5 |
printf("failed\n");
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
printf("failed with error %d, trying to detach kernel driver ....\n", rv);
|
|
Packit |
9f0df5 |
rv = libusb_detach_kernel_driver(usb, ifnum);
|
|
Packit |
9f0df5 |
if (rv == 0)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
printf("success, claiming interface again ...");
|
|
Packit |
9f0df5 |
rv = libusb_claim_interface(usb, ifnum);
|
|
Packit |
9f0df5 |
if (rv == 0)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
printf("success\n");
|
|
Packit |
9f0df5 |
return rv;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
else
|
|
Packit |
9f0df5 |
printf("failed\n");
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
printf("failed with error %d, giving up.\n", rv);
|
|
Packit |
9f0df5 |
return rv;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
int main(int argc, char *argv[])
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
libusb_device **devs, *dev;
|
|
Packit |
9f0df5 |
libusb_device *found_dev = NULL;
|
|
Packit |
9f0df5 |
struct libusb_device_handle *usb = NULL;
|
|
Packit |
9f0df5 |
int rv, i;
|
|
Packit |
9f0df5 |
ssize_t cnt;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
(void)argc;
|
|
Packit |
9f0df5 |
(void)argv;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
rv = libusb_init(NULL);
|
|
Packit |
9f0df5 |
if (rv < 0)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
(void)printf("libusb_init() failed\n");
|
|
Packit |
9f0df5 |
return rv;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
cnt = libusb_get_device_list(NULL, &devs);
|
|
Packit |
9f0df5 |
if (cnt < 0)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
(void)printf("libusb_get_device_list() failed\n");
|
|
Packit |
9f0df5 |
return (int)cnt;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
/* for every device */
|
|
Packit |
9f0df5 |
i = 0;
|
|
Packit |
9f0df5 |
while ((dev = devs[i++]) != NULL)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
struct libusb_device_descriptor desc;
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
rv = libusb_get_device_descriptor(dev, &desc);
|
|
Packit |
9f0df5 |
if (rv < 0) {
|
|
Packit |
9f0df5 |
(void)printf("failed to get device descriptor\n");
|
|
Packit |
9f0df5 |
continue;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
printf("vendor/product: %04X %04X\n", desc.idVendor, desc.idProduct);
|
|
Packit |
9f0df5 |
if (desc.idVendor == KOBIL_VENDOR_ID && desc.idProduct == MID_DEVICE_ID)
|
|
Packit |
9f0df5 |
found_dev = dev;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
if (found_dev == NULL)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
printf("device not found. aborting.\n");
|
|
Packit |
9f0df5 |
if (0 != geteuid())
|
|
Packit |
9f0df5 |
printf("Try to rerun this program as root.\n");
|
|
Packit |
9f0df5 |
exit(1);
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
printf("Device found, opening ... ");
|
|
Packit |
9f0df5 |
rv = libusb_open(found_dev, &usb;;
|
|
Packit |
9f0df5 |
if (rv < 0)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
printf("failed, aborting.\n");
|
|
Packit |
9f0df5 |
exit(2);
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
printf("success\n");
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
rv = kobil_midentity_claim_interface(usb, 0);
|
|
Packit |
9f0df5 |
if (rv < 0)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
libusb_close(usb);
|
|
Packit |
9f0df5 |
exit(3);
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
rv = kobil_midentity_claim_interface(usb, 1);
|
|
Packit |
9f0df5 |
if (rv < 0)
|
|
Packit |
9f0df5 |
{
|
|
Packit |
9f0df5 |
libusb_close(usb);
|
|
Packit |
9f0df5 |
exit(3);
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
printf("Activating the CCID configuration .... ");
|
|
Packit |
9f0df5 |
rv = kobil_midentity_control_msg(usb);
|
|
Packit |
9f0df5 |
if (rv == 0)
|
|
Packit |
9f0df5 |
printf("success\n");
|
|
Packit |
9f0df5 |
else
|
|
Packit |
9f0df5 |
printf("failed with error %d, giving up.\n", rv);
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
libusb_close(usb);
|
|
Packit |
9f0df5 |
|
|
Packit |
9f0df5 |
return 0;
|
|
Packit |
9f0df5 |
}
|
|
Packit |
9f0df5 |
|