2017-06-09 185 views
0

我實際上正在研究一個插入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, &parameter, 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 
+0

它似乎你發送整數deviceID,cmd和參數的內存內容。你是否以適當的順應性發送這些內容?可能你是在一個小端機器上,而示例[55 aa 0001 00000000 0001 0101]似乎在大端存在這些字段 – nos

+0

@nos我的機器處於小端,而指紋識別器也是小端。準備發送緩衝區的函數是'init_snd'。我使用的例子是這樣寫的,更具可讀性。我從來沒有真正善於忍耐。我會檢查是否可以,謝謝 – Missu

+0

我添加了在'header.cmdp'上的snd緩衝區的值。這是否有可能這臺設備沒有與我的電腦相同的字大小,給出了不同的結果,具有相同的字頭? – Missu

回答

1

恢復的問題:如何發送的特定命令(緩衝液) 到在Linux(sg)或任何其他程序中使用scsi驅動程序的指紋識別器?

不要。不幸的是,「SCSI」通常是「模糊地像SCSI一樣,但並不完全符合SCSI」的同義詞。並且USB設備通常提供多個接口(例如,當OS沒有有用的驅動程序時加上當存在用於該設備的驅動程序時使用的本地接口)的情況下,「模糊地像SCSI而不是SCSI」接口,具有損壞的功能。

這意味着您很可能需要爲該設備專門編寫USB設備驅動程序。請注意,如果你看一下這個設備的數據表,你會發現沒有任何命令與SCSI有關,唯一看起來像CD的是「升級ISO CD映像()」函數記錄爲「不受支持」。

+0

謝謝。實際上,我談到了SCSI,因爲我擁有使用Windows上的指紋的程序的源代碼,並且它使用了類似'direct_buffer_pass_through'的SCSI。我會看看如何創建一個驅動程序。這將會產生良好的體驗。 – Missu