В прошлой статье я писал, как в линуксе написать драйвер для графического планшета. Но на том история не закончилась: вместе с планшетом я купил и ноутбук, на котором установлен сканер отпечатков. Сканер новый, такой, как повсеместно стоит на мобильных телефонах, маленькая прямоугольная площадка на тачпаде.
Драйвера только для Windows 10, и только на сайте производителя ноутбука. Сразу возникла мысль если и не завести его в линуксе, то хотя бы понять, как же он работает. Висит сканер на usb, вместе с тачпадом.
Для начала сделаем lsusb и посмотрим, как определяется наш сканер:
Bus 001 Device 006: ID 04f3:0c03 Elan Microelectronics Corp.
Bus 001 Device 006: ID 04f3:0c03 Elan Microelectronics Corp.
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 2.00
bDeviceClass 0
bDeviceSubClass 0
bDeviceProtocol 0
bMaxPacketSize0 8
idVendor 0x04f3 Elan Microelectronics Corp.
idProduct 0x0c03
bcdDevice 1.38
iManufacturer 1 ELAN
iProduct 2 ELAN:Fingerprint
iSerial 0
bNumConfigurations 1
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 62
bNumInterfaces 1
bConfigurationValue 1
iConfiguration 0
bmAttributes 0x80
(Bus Powered)
MaxPower 100mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 5
bInterfaceClass 255 Vendor Specific Class
bInterfaceSubClass 0
bInterfaceProtocol 0
iInterface 0
** UNRECOGNIZED: 09 21 10 01 00 01 22 15 00
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 1
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x01 EP 1 OUT
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 1
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x82 EP 2 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 1
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x83 EP 3 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 1
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x03 EP 3 OUT
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 1
can't get device qualifier: Resource temporarily unavailable
can't get debug descriptor: Resource temporarily unavailable
Device Status: 0x0000
(Bus Powered)
0000000: 4123 d328 4828 8d28 aa28 6028 5f29 a528
0000010: f028 1127 ef26 ff27 8129 2628 9d23 9621
0000020: 1d21 d126 db26 aa26 b128 2326 8826 d027
0000030: a226 8925 2120 af1c fa1c 341b b31f 1122
0000040: 1e27 8526 5026 ac26 4f26 fa26 1126 9225
...
convert -depth 16 -size 96x96+0 gray:image.raw ./out.png
CC = gcc
LD = gcc
OPT = -O1 -s
CFLAGS = $(OPT) -c -I/usr/include/libusb-1.0
LDFLAGS = -DPTW32_STATIC_LIB $(OPT)
LIBS = -lrt -lusb-1.0
all:
$(CC) $(CFLAGS) elanfp.c -o elanfp.o
$(LD) $(LDFLAGS) elanfp.o $(LIBS) -o elanfp
clean:
rm -f *.o elanfp
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <errno.h>
#include <string.h>
#include <libusb.h>
#define BULK_EP_OUT1 0x82
#define BULK_EP_OUT2 0x83
#define BULK_EP_IN 0x01
#define IMAGE_PACKET_SIZE (96 * 96 * 2)
char img_buf[IMAGE_PACKET_SIZE];
char cmd01[2] = { 0x40, 0x3f };
char cmd02[2] = { 0x00, 0x09 };
int write_to_file(char* buf, int size) {
FILE *fp;
fp = fopen("./out.fp","w");
if (fp < 0) return 1;
fwrite(buf, 1, size, fp);
fclose(fp);
return 0;
}
int main() {
int r0, i, devs_count = 0, libusb_config = 0, transferred = 0;
struct libusb_device **devs;
struct libusb_device *dev;
struct libusb_device_descriptor desc;
struct libusb_device_handle *handle = NULL;
r0 = libusb_init(NULL);
if (r0 < 0) return 1;
devs_count = libusb_get_device_list(NULL, &devs);
if (devs_count < 0) {
libusb_exit(NULL);
printf("Error %d\n", r0);
return 2;
}
while (1) {
dev = devs[i];
if (dev != NULL) {
r0 = libusb_get_device_descriptor(dev, &desc);
if (r0 < 0) continue;
if ((desc.idVendor == 0x04f3) && (desc.idProduct == 0x0c03)) {
r0 = 0;
printf("Device with vid %x pid %x found.\n", desc.idVendor, desc.idProduct);
break;
}
} else {
r0 = 3;
break;
}
i++;
if (i > devs_count) {
r0 = 99;
goto app_exit;
}
}
if (r0 != 0) goto app_exit;
/*****************************************************/
r0 = libusb_open(dev, &handle);
if (r0 < 0) {
r0 = 5;
goto app_exit;
}
r0 = libusb_get_configuration(handle, &libusb_config);
if (r0 != 0) {
r0 = 98;
goto app_exit_2;
}
printf("Config number is %d\n", libusb_config);
if (libusb_config > 1) {
r0 = libusb_set_configuration(handle, 1);
if (r0 != 0) {
r0 = 97;
goto app_exit_2;
}
printf("Config set to 1\n");
}
if (libusb_kernel_driver_active(handle, 0) == 1) {
if(libusb_detach_kernel_driver(handle, 0) != 0) {
r0 = 96;
goto app_exit_2;
}
}
r0 = libusb_claim_interface(handle, 0);
if (r0 != 0) {
r0 = 95;
goto app_exit_2;
}
r0 = libusb_bulk_transfer(handle, BULK_EP_IN, cmd01, 2, &transferred, 0);
if((r0 == 0) && (transferred == 2)) {
printf("CMD1 sent\n");
}
r0 = libusb_bulk_transfer(handle, BULK_EP_OUT2, img_buf, 1, &transferred, 0); // wait for press
printf("Received byte %d\n", img_buf[0]);
r0 = libusb_bulk_transfer(handle, BULK_EP_IN, cmd02, 2, &transferred, 0);
if((r0 == 0) && (transferred == 2)) {
printf("CMD2 sent\n");
}
r0 = libusb_bulk_transfer(handle, BULK_EP_OUT1, img_buf, IMAGE_PACKET_SIZE, &transferred, 0);
printf("Received %d\n", transferred);
write_to_file(img_buf, IMAGE_PACKET_SIZE);
system("convert -depth 16 -size 96x96+0 gray:out.fp ./out.png");
system("rm ./out.fp");
app_exit_2:
libusb_close(handle);
/*****************************************************/
app_exit:
libusb_free_device_list(devs, 1);
libusb_exit(NULL);
if (r0 != 0) {
printf("Error %d\n", r0);
}
return r0;
}
К сожалению, не доступен сервер mySQL