我實際上正在研究一個插入USB的指紋識別器(FP閱讀器)。這款FP閱讀器也插在stm32f4板上。如果我理解正確,FP閱讀器包含一個非常小的數據庫FP模板。要修改這些模板,我們將FP閱讀器插在USB上,並使用Windows上的程序進行修改。由於我正在研究Linux(和好奇心),我試圖製作一個允許我們在Linux上修改模板的程序。如何向Linux中的scsi設備發送特定命令?
該FP閱讀器被視爲CD-ROM閱讀器。我正嘗試通過sg包的幫助與之交流(我正在關注此文檔http://www.tldp.org/HOWTO/SCSI-Generic-HOWTO/)。根據FP閱讀器的文檔(你可以在這裏找到它http://www.adh-tech.com.tw/files/GT-511C3_datasheet_V1%201_20131127.pdf),我應該發送一個類似[55 aa 0001 00000000 0001 0101]的緩衝區(12字節)來做「打開」命令。
這裏是我的代碼,以使此命令(我試圖讓一個可讀的小例子):
#include <errno.h>
#include <fcntl.h>
#include <scsi/sg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#define FP_PACKET_SZ 12
const uint8_t fp_packet_sz = FP_PACKET_SZ;
static unsigned char sense_buffer[32];
#define OPEN_CMD
static void init_snd(uint8_t buf[fp_packet_sz]) {
size_t offset = 0;
const uint16_t deviceID = 1;
const uint16_t cmd = 1;
const uint32_t parameter = 0;
buf[offset++] = 0x55;
buf[offset++] = 0xAA;
memcpy(buf + offset, &deviceID, sizeof(deviceID));
offset += sizeof(deviceID);
memcpy(buf + offset, ¶meter, sizeof(parameter));
offset += sizeof(parameter);
memcpy(buf + offset, &cmd, sizeof(cmd));
offset += sizeof(cmd);
uint16_t checksum = 0;
for (unsigned int i = 0 ; i < offset ; i++)
checksum += buf[i];
memcpy(buf + offset, &checksum, sizeof(checksum));
}
int main(int argc, char *argv[]) {
int fd = 0, res = 0;
char * filename = 0;
sg_io_hdr_t header;
uint8_t snd[fp_packet_sz];
uint8_t rcv[fp_packet_sz];
memset (snd, 0, sizeof(snd));
memset (rcv, 0, sizeof(rcv));
if (argc < 2) {
fprintf(stderr, "argument missing\n");
return EXIT_FAILURE;
}
filename = argv[1];
fd = open(filename, O_RDWR);
if (fd < 0) {
fprintf(stderr, "open %s failed\n", filename);
return EXIT_FAILURE;
}
init_snd(snd);
header.interface_id = 'S';
header.dxfer_direction = SG_DXFER_TO_FROM_DEV;
header.cmd_len = fp_packet_sz;
header.cmdp = snd;
header.mx_sb_len = sizeof (sense_buffer);
header.sbp = sense_buffer;
header.iovec_count = 0;
header.dxfer_len = fp_packet_sz;
header.dxferp = rcv;
header.timeout = 60000;
header.flags = 0;
if ((res = ioctl(fd, SG_IO, &header)) < 0) {
fprintf(stderr, "ioctl failed and return errno: %s \n", strerror(errno));
exit(EXIT_FAILURE);
}
fprintf(stdout, "receive buffer:");
for (int i = 0 ; i < fp_packet_sz ; i++)
fprintf(stdout, " %02x", rcv[i]);
fprintf(stdout, "\n");
fprintf(stdout, "sense data:");
for (int i = 0 ; i < header.sb_len_wr ; i++)
fprintf(stdout, " %02x", sense_buffer[i]);
fprintf(stdout, "\n");
return EXIT_SUCCESS;
}
我期待什麼是rcv
有以下值[55 aa 00 01 00 00 00 00 00 30 01 30]
。
但是,相反,我沒有得到任何(或東西我不理解)和sense_data
得到以下值:70 00 05 00 00 00 00 0A 00 00 00 00 20 00 00 00 00 00
對應於一個Illegal Request
(根據http://blog.disksurvey.org/knowledge-base/scsi-sense/博客)。我也試圖使用與該論壇http://www.linuxquestions.org/questions/programming-9/linux-scsi-passthrough-porting-windows-routine-4175528749/中所述的scsi_inquiry.c
相同的方案,並且我得到相同的sense_data
。我想我不太瞭解sg驅動程序是如何工作的。那是給出sense_data
還是該設備的驅動程序?我也嘗試做一些read()
和write()
上/dev/sr1
但它沒有工作(好像我只可以閱讀有關FP讀者的內存格式的一些信息)在通過SG命令給出
一些額外的信息終端:
>sg_map
/dev/sg3 /dev/sr1
>sg_inq /dev/sg3
invalid VPD response; probably a STANDARD INQUIRY response
standard INQUIRY:
PQual=0 Device_type=5 RMB=1 LU_CONG=0 version=0x06 [SPC-4]
[AERC=0] [TrmTsk=0] NormACA=0 HiSUP=0 Resp_data_format=2
SCCS=0 ACC=0 TPGS=0 3PC=0 Protect=0 [BQue=0]
EncServ=0 MultiP=0 [MChngr=0] [ACKREQQ=0] Addr16=0
[RelAdr=0] WBus16=0 Sync=0 [Linked=0] [TranDis=0] CmdQue=0
length=36 (0x24) Peripheral device type: cd/dvd
Vendor identification:
Product identification: Fingerprint
Product revision level: 0.01
如果您需要了解更多信息,請告訴我,我將它添加到該職位。
問題簡述:如何在Linux(sg)或任何其他程序中使用scsi驅動程序將特定命令(緩衝區)發送到指紋讀取器?
謝謝你的(也許)未來的幫助。
EDIT1: 這裏是SND緩衝器的精確值發送到裝置(GDB給出)
gdb> x /3xw snd
0x0001aa55 0x00000000 0x01010001
它似乎你發送整數deviceID,cmd和參數的內存內容。你是否以適當的順應性發送這些內容?可能你是在一個小端機器上,而示例[55 aa 0001 00000000 0001 0101]似乎在大端存在這些字段 – nos
@nos我的機器處於小端,而指紋識別器也是小端。準備發送緩衝區的函數是'init_snd'。我使用的例子是這樣寫的,更具可讀性。我從來沒有真正善於忍耐。我會檢查是否可以,謝謝 – Missu
我添加了在'header.cmdp'上的snd緩衝區的值。這是否有可能這臺設備沒有與我的電腦相同的字大小,給出了不同的結果,具有相同的字頭? – Missu