Dalam
artikel terakhir, kami memeriksa teori mengelola ribuan hal kecil di kompleks Redd, tetapi agar tidak menambah volume, kami menunda praktik di waktu berikutnya. Waktunya telah tiba untuk melakukan eksperimen praktis. Mereka yang tidak menggunakan kompleks Redd juga akan dapat menemukan pengetahuan yang berguna dalam artikel ini, yaitu, metodologi untuk mengirim perintah Vendor ke drive USB dari Linux, karena, sebagaimana telah disebutkan, pengontrol STM32 di kompleks melakukan fungsi pembaca SD, yaitu, berkendara.

Artikel siklus sebelumnya Drive klasifikasi dengan sistem perintah
Saat bekerja dengan drive, Anda harus membedakan antara antarmuka fisik dan sistem perintah. Khususnya, drive CD / DVD / BD dan optik lainnya. Secara tradisional, mereka terhubung ke kabel SATA (sebelumnya IDE). Tetapi secara khusus pada kawat ini, hanya perintah PACKET yang dijalankan selama operasi, di blok data yang perintahnya disandikan sesuai dengan prinsip yang sama sekali berbeda ditempatkan (kita akan segera mengetahui yang mana). Oleh karena itu, sekarang kita tidak akan berbicara banyak tentang kabel, tetapi tentang tim yang menjalankannya. Saya tahu tiga sistem perintah umum untuk bekerja dengan drive.
- MMC Ini dipahami oleh kartu SD. Jujur saja, bagi saya ini adalah sistem komando yang paling misterius. Cara mengirimkannya, tampaknya, jelas, tetapi cara mengelola drive tanpa hati-hati membaca dokumen yang mengandung banyak grafik transisi - Saya selalu bingung. Untungnya, ini tidak mengganggu kita hari ini, karena meskipun kita bekerja dengan kartu SD, pengendali STM32 dalam mode "kotak hitam" bekerja dengannya.
- ATA Awalnya, perintah-perintah ini dijalankan pada bus IDE, kemudian pada SATA. Sistem komando yang luar biasa, tetapi hari ini kami juga hanya menyebutkan bahwa itu ada.
- SCSI Sistem perintah ini digunakan pada berbagai perangkat. Pertimbangkan penggunaannya dalam drive. Di sana, hari ini tim SCSI menjalankan, pertama-tama, di sepanjang kabel bus SAS (omong-omong, bahkan SSD dengan antarmuka SAS kini sedang populer). Anehnya, drive optis yang terhubung secara fisik ke bus SATA juga berfungsi melalui perintah SCSI. Di bus USB saat bekerja sesuai dengan standar Mass Storage Device, perintah juga masuk dalam format SCSI. Mikrokontroler STM32 terhubung ke kompleks Redd melalui bus USB, yaitu, dalam kasus kami, perintah mengikuti jalur berikut:

Dari PC ke controller, melalui USB, perintahnya dalam format SCSI. Pengontrol mentranskode perintah sesuai dengan aturan MMC dan mengirimkannya melalui bus SDIO. Tetapi kita harus menulis sebuah program untuk PC, sehingga tim meninggalkan kita dalam format SCSI. Mereka disiapkan oleh driver perangkat Mass Storage Device, yang kami berkomunikasi dengan melalui driver sistem file. Apakah mungkin untuk menggabungkan permintaan dengan perangkat lain untuk permintaan ini? Mari kita perbaiki.
Detail Sistem Perintah SCSI
Jika Anda mendekati masalah ini secara formal, maka deskripsi standar SCSI tersedia di t10.org, tetapi kami akan realistis. Tidak ada yang akan membacanya dengan sukarela. Lebih tepatnya, bukan miliknya, tetapi milik mereka: ada setumpuk dokumen terbuka dan segunung dokumen tertutup. Hanya kebutuhan ekstrem yang akan membuat Anda membenamkan diri dalam bahasa rumit yang menjadi standar penulisan ini (ini, omong-omong, berlaku untuk standar ATA di t13.org). Jauh lebih mudah untuk membaca dokumentasi untuk drive nyata. Itu ditulis dalam bahasa yang lebih hidup, dan bagian hipotetis tetapi tidak benar-benar digunakan dipotong dari itu. Dalam mempersiapkan artikel, saya menemukan dokumen (2016) yang agak baru dari Seagate's
Commands Reference Manual Manual (tautan langsung
www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf tetapi, seperti biasa, Saya tidak tahu berapa lama dia akan hidup). Saya pikir jika seseorang ingin menguasai sistem perintah ini, ia harus mulai dengan dokumen ini. Kami hanya ingat bahwa pembaca SD menerapkan subset perintah yang bahkan lebih kecil dari deskripsi itu.
Secara singkat, unit perintah dengan panjang 6 hingga 16 byte dikirim ke drive. Blok data dapat dilampirkan ke blok perintah baik dari PC ke drive, atau dari drive ke PC (standar SCSI juga memungkinkan pertukaran dua arah, tetapi untuk Mass Storage Device via USB hanya satu blok yang diizinkan, yang berarti bahwa arahnya hanya satu). Dalam blok instruksi, byte pertama selalu merupakan kode perintah. Byte yang tersisa adalah argumennya. Aturan untuk mengisi argumen dijelaskan secara eksklusif oleh rincian implementasi perintah.

Pada awalnya saya memasukkan banyak contoh ke dalam artikel, tetapi kemudian saya menyadari bahwa mereka membuat sulit membaca. Oleh karena itu, saya menyarankan semua orang untuk membandingkan bidang perintah READ CAPACITY (10) dari tabel 119 dari dokumen Seigate dan bidang-bidang perintah READ (10) dari tabel 97 dari dokumen yang sama (lihat tautan di atas). Siapa yang tidak menemukan koneksi - jangan khawatir. Itulah yang ingin saya tunjukkan. Selain bidang "perintah" dalam byte nol, tujuan semua bidang hanya bergantung pada spesifikasi perintah tertentu. Anda selalu perlu membuka dokumen dan mempelajari tujuan dari bidang yang tersisa di dalamnya.
Jadi:
- Untuk berkomunikasi dengan drive, Anda harus membentuk blok perintah dengan panjang 6 hingga 16 byte (tergantung pada format perintah, angka yang tepat ditunjukkan dalam dokumentasi untuk itu).
- Yang paling penting adalah byte nol dari blok: dialah yang menetapkan kode perintah.
- Bytes blok yang tersisa tidak memiliki tujuan yang jelas. Untuk memahami cara mengisinya, Anda harus membuka dokumentasi untuk tim tertentu.
- Blok data yang dapat ditransfer ke atau dari drive dapat dilampirkan ke perintah.
Sebenarnya itu saja. Kami mempelajari aturan untuk mengeluarkan perintah SCSI. Sekarang kita bisa mengirimkannya, akan ada dokumentasi tentang mereka. Tetapi bagaimana melakukannya di tingkat sistem operasi?
Perintah Linux SCSI
Cari perangkat target
Untuk mengeluarkan perintah, buka perangkat disk. Ayo cari namanya. Untuk melakukan ini, kita akan pergi dengan cara yang persis sama seperti pada
artikel tentang port serial . Mari kita lihat daftar "file" di
direktori / dev (ingat bahwa pada perangkat Linux juga ditampilkan sebagai file dan daftar mereka ditampilkan dengan
perintah ls yang sama).
Hari ini kami memperhatikan
disk direktori virtual:

Kami melihat isinya:

Kumpulan direktori bersarang yang familier! Kami mencoba untuk mempertimbangkan direktori
by-id , menggunakan
–l switch dari
perintah ls , yang sudah akrab bagi kami dari artikel di port serial:

Kata-kata yang disorot berbicara sendiri. Ini adalah drive yang berisi kartu SD internal kompleks Redd. Hebat! Sekarang kita tahu bahwa perangkat
MIR_Redd_Internal_SD sesuai dengan perangkat
/ dev / sdb dan / dev / sdb1 . Yang tanpa nomor adalah drive itu sendiri, kami akan bekerja dengannya, dan dengan nomor itu adalah sistem file yang terletak pada media yang dimasukkan ke dalamnya. Dalam hal bekerja dengan kartu SD,
/ dev / sdb adalah pembaca, dan
/ dev / sdb1 adalah sistem file pada kartu yang dimasukkan ke dalamnya.
Fungsi sistem operasi untuk mengeluarkan perintah
Biasanya, dalam OS apa pun, semua hal non-standar dengan perangkat dilakukan melalui permintaan langsung ke pengemudi. Di Linux, fungsi
ioctl () tersedia untuk mengirim permintaan tersebut. Kasus kami tidak terkecuali. Sebagai argumen, kami meneruskan permintaan SG_IO yang dijelaskan dalam file header
sg.h. Struktur
sg_io_hdr_t yang berisi parameter permintaan juga dijelaskan di sana. Saya tidak akan memberikan struktur penuh, karena tidak semua bidangnya harus diisi. Saya hanya akan memberikan yang paling penting di antara mereka:
typedef struct sg_io_hdr { int interface_id; /* [i] 'S' for SCSI generic (required) */ int dxfer_direction; /* [i] data transfer direction */ unsigned char cmd_len; /* [i] SCSI command length ( <= 16 bytes) */ unsigned char mx_sb_len; /* [i] max length to write to sbp */ unsigned short int iovec_count; /* [i] 0 implies no scatter gather */ unsigned int dxfer_len; /* [i] byte count of data transfer */ void * dxferp; /* [i], [*io] points to data transfer memory or scatter gather list */ unsigned char * cmdp; /* [i], [*i] points to command to perform */ unsigned char * sbp; /* [i], [*o] points to sense_buffer memory */ unsigned int timeout; /* [i] MAX_UINT->no timeout (unit: millisec) */
Tidak masuk akal untuk menggambarkan bidang-bidang yang didokumentasikan dengan baik dalam komentar (
interface_id, dxfer_direction, timeout ). Artikel sudah berkembang.
Bidang
cmd_len berisi jumlah byte di blok perintah, dan
cmdp berisi pointer ke blok ini. Anda tidak dapat melakukannya tanpa perintah, sehingga jumlah byte harus nol (dari 6 hingga 16).
Data bersifat opsional. Jika ya, maka panjang buffer yang dipilih ditentukan dalam bidang
dxfer_len , dan penunjuknya ditentukan dalam bidang
dxferp . Drive secara fisik dapat mentransfer lebih sedikit data daripada ukuran buffer yang ditentukan. Arah transmisi ditentukan dalam bidang
dxfer_direction . Nilai Perangkat Mass Storage USB yang valid adalah:
SG_DXFER_NONE, SG_DXFER_TO_DEV, SG_DXFER_FROM_DEV . Ada satu hal lagi dalam file header, tetapi standar Mass Storage Device tidak memungkinkan untuk mengimplementasikannya secara fisik.
Anda juga dapat meminta pengembalian kode kesalahan yang diperluas (
SENSE ). Apa itu dapat ditemukan di dokumen Segate, bagian 2.4. Panjang buffer yang dialokasikan ditunjukkan di bidang
mx_sb_len , dan pointer ke buffer itu sendiri ditunjukkan di bidang
sbp .
Seperti yang Anda lihat, semua yang saya bicarakan di atas terisi dalam struktur ini (ditambah Anda dapat memperoleh informasi tambahan tentang kesalahan). Baca lebih lanjut tentang bekerja dengan permintaan
SG_IO di sini:
sg.danny.cz/sg/sg_io.htmlKami mengirim perintah standar ke drive
Kami menemukan format perintah, kami mencari tahu perangkat mana yang akan dikirim, kami menemukan fungsi untuk menelepon. Mari kita coba mengirim beberapa perintah standar ke perangkat kita. Biarkan ini menjadi perintah untuk mendapatkan nama drive. Ini adalah bagaimana itu dijelaskan dalam dokumen Sigeyt:

Harap dicatat bahwa menurut ideologi-SCSI, semua bidang dalam perintah standar diisi dengan notasi Big Endian, yaitu byte maju ke depan. Oleh karena itu, kami mengisi bidang dengan panjang buffer tidak dalam format "0x80, 0x00", tetapi sebaliknya - "0x00, 0x80". Tapi ini dalam perintah standar. Dalam non-standar semuanya mungkin, Anda harus selalu berkonsultasi dengan deskripsi. Sebenarnya, hanya kode perintah (
12 jam ) dan panjang yang harus kita isi. Kami akan meminta halaman nol, dan bidang lainnya dicadangkan, atau kedaluwarsa, atau default ke nol. Jadi isi semuanya dengan nol.
Kami membuat program yang memberikan perintah ini: #include <cstdio> #include <stdint.h> #include <string.h> #include <fcntl.h> // open #include <unistd.h> // close #include <sys/ioctl.h> #include <scsi/scsi.h> #include <scsi/sg.h> int main() { printf("hello from SdAccessTest!\n"); int s_fd = open("/dev/sdb", O_NONBLOCK | O_RDWR); if (s_fd < 0) { printf("Cannot open file\n"); return -1; } sg_io_hdr_t header; memset(&header;, 0, sizeof(header)); uint8_t cmd12h[] = { 0x12,0x00,0x00,0x00,0x80,0x00}; uint8_t data[0x80]; uint8_t sense[0x80]; header.interface_id = 'S'; // 'S' // header.cmd_len = sizeof(cmd12h); header.cmdp = cmd12h; // header.dxfer_len = sizeof(data); header.dxferp = data; header.dxfer_direction = SG_DXFER_TO_FROM_DEV; // header.mx_sb_len = sizeof(sense); header.sbp = sense; // header.timeout = 100; // 100 int res = ioctl(s_fd, SG_IO, &header;); close(s_fd); return 0; }
Bagaimana menjalankan program tersebut pada perangkat Redd jarak jauh, kita telah membahas di salah satu
artikel sebelumnya . Benar, memulainya untuk pertama kalinya, saya segera menerima kesalahan memanggil fungsi
open () . Ternyata pengguna secara default tidak memiliki hak yang cukup untuk membuka perangkat disk. Yang mana dari saya adalah spesialis Linux, saya menulis berkali-kali, tetapi pada jaringan saya berhasil menemukan bahwa untuk mengatasi masalah ini, Anda dapat mengubah hak akses ke perangkat dengan mengeluarkan perintah:
sudo chmod 666 / dev / sdbNamun, bos saya (dan dia adalah spesialis hebat dalam OS ini) kemudian mencatat bahwa solusinya valid sampai sistem operasi di-boot ulang. Untuk mendapatkan hak pasti, Anda perlu menambahkan pengguna ke grup
disk .
Mana pun dari dua jalur ini yang kita tuju, tetapi setelah semuanya berhasil, letakkan breakpoint pada baris
tutup (s_fd); dan periksa hasilnya pada saat itu dicapai dalam lingkungan pengembangan (karena program ini bahkan bukan satu hari, yang berarti bahwa kita tidak punya waktu untuk menghabiskan waktu dan upaya memasukkan pembuat peta, jika lingkungan pengembangan dapat menunjukkan kepada kita segalanya). Nilai
res adalah nol. Jadi tim bekerja tanpa kesalahan.

Apa yang datang ke buffer? Ketika saya memasukkan kata
data di alamat untuk dump, mereka mengatakan kepada saya bahwa mereka tidak dapat menghitung nilainya, saya harus memasukkan
& data; . Aneh, karena
data adalah pointer, ketika debugging di Windows semuanya berfungsi, tapi saya perhatikan fakta ini, kerjanya seperti ini: lihat hasil yang didapat seperti ini:

Itu benar, mereka mengembalikan nama dan revisi drive kepada kami. Informasi lebih lanjut tentang format struktur yang dihasilkan dapat ditemukan dalam dokumen Segate (bagian 3.6.2, tabel 59). Buffer
indra tidak mengisi, tetapi deskripsi IOCTL dari permintaan mengatakan bahwa itu diisi hanya ketika kesalahan terjadi yang mengembalikan sesuatu di buffer ini. Secara harfiah:
Sense data (hanya digunakan ketika 'status' adalah PERIKSA KONDISI atau (driver_status & DRIVER_SENSE) adalah benar) .
Format Perintah Kustom untuk Redd Internal SD Drive
Sekarang kita tidak hanya mempelajari deskripsi kering dari standar, tetapi juga mencoba segala sesuatu dalam praktik, setelah mengalami apa itu command block, kita sudah dapat menunjukkan format perintah yang dengannya Anda dapat memanggil fungsi-fungsi non-standar yang "di-flash" ke pengontrol STM32 pada papan kompleks. Saya memilih kode perintah dari awal rentang
spesifik Vendor dari perintah. Itu sama dengan 0xC0. Secara tradisional, dalam deskripsi perintah SCSI, tulis
C0h . Panjang perintah selalu 10 byte. Format tim disatukan dan disajikan dalam tabel di bawah ini.
Seperti yang Anda lihat, argumen diberikan dalam notasi Little Endian. Ini akan memungkinkan Anda untuk menggambarkan perintah dalam bentuk struktur dan mengakses bidangnya secara langsung, tanpa menggunakan fungsi permutasi byte. Masalah perataan (kata-kata dobel dalam struktur memiliki offset yang bukan kelipatan empat) pada arsitektur x86 dan x64 tidak sepadan.
Kode sub-perintah dijelaskan oleh enumerasi berikut:
enum vendorSubCommands { subCmdSdEnable = 0, // 00 Switch SD card to PC or Outside subCmdSdPower, // 01 Switch Power of SD card On/Off subCmdSdReinit, // 02 Reinitialize SD card (for example, after Power Cycle) subCmdSpiFlashEnable, // 03 Switch SPI Flash to PC or Outside subCmdSpiFlashWritePage, // 04 Write Page to SPI Flash subCmdSpiFlashReadPage, // 05 Read Page from SPI Flash subCmdSpiFlashErasePage,// 06 Erase Pages on SPI Flash (4K block) subCmdRelaysOn, // 07 Switch relays On by mask subCmdRelaysOff, // 08 Switch relays off by mask subCmdRelaysSet, // 09 Set state of all relays by data subCmdFT4222_1_Reset, // 0A Activate Reset State or switch chip to normal mode subCmdFT4222_2_Reset, // 0B Activate Reset State or switch chip to normal mode subCmdFT4222_3_Reset, // 0C Activate Reset State or switch chip to normal mode subCmdFT4232_Reset, // 0D Activate Reset State or switch chip to normal mode subCmdFT2232_Reset, // 0E Activate Reset State or switch chip to normal mode subCmdMAX3421_Reset, // 0F Activate Reset State or switch chip to normal mode subCmdFT4222_1_Cfg, // 10 Write to CFG pins of FT4222_1 subCmdFT4222_2_Cfg, // 11 Write to CFG pins of FT4222_2 subCmdFT4222_3_Cfg, // 12 Write to CFG pins of FT4222_3 };
Mereka dapat dibagi menjadi beberapa kelompok.
Berpindah perangkat ke mode internal dan eksternal
Perintah
subCmdSdEnable dan
subCmdSpiFlashEnable masing-masing mengganti kartu SD dan flash SPI. Parameter
arg1 melewati salah satu nilai berikut:
enum enableMode { enableModeToPC = 0, enableModeOutside };
Secara default, kedua perangkat terhubung ke PC.
Peralihan daya
Protokol SDIO membutuhkan cukup banyak manipulasi selama inisialisasi. Kadang-kadang berguna untuk mengatur ulang kartu SD ke keadaan awal (misalnya, ketika mengganti jalurnya ke konektor eksternal). Untuk melakukan ini, matikan, lalu nyalakan daya. Ini dapat dilakukan dengan menggunakan
perintah subCmdSdPower . Dalam argumen
arg1, salah satu dari nilai berikut ini diteruskan: 0 - matikan, 1 - matikan. Ingatlah untuk memberikan waktu untuk melepaskan kapasitor pada saluran listrik.
Setelah menyalakan daya, kartu, jika terhubung ke PC, harus diinisialisasi ulang. Untuk melakukan ini, gunakan perintah
subCmdSdReinit (tidak memiliki argumen).
Bekerja dengan SPI flash drive
Jika kartu SD terhubung ke sistem sebagai drive penuh, chip akses dalam versi saat ini sangat terbatas. Anda hanya dapat mengakses halaman individualnya (256 byte) dan hanya satu per satu. Jumlah memori dalam rangkaian mikro sedemikian rupa sehingga bahkan ketika bekerja di halaman, prosesnya tidak akan memakan banyak waktu, tetapi pendekatan ini sangat menyederhanakan "firmware" dari mikrokontroler.
Perintah
subCmdSpiFlashReadPage membaca halaman. Alamatnya ditentukan dalam parameter arg1, jumlah halaman yang akan dikirim dalam parameter arg2. Tetapi dalam versi saat ini, jumlah halaman harus sama dengan satu. Perintah akan mengembalikan 256 byte data.
Dicerminkan baginya adalah perintah
subCmdSpiFlashWritePage . Argumen untuknya diisi oleh prinsip yang sama. Arah transfer data adalah ke perangkat.
Kekhasan memori flash adalah bahwa hanya bit tunggal yang dapat diganti dengan nol bit selama perekaman. Untuk mengembalikannya ke nilai tunggal, halaman harus dihapus. Ada perintah
subCmdSpiFlashErasePage untuk
ini . Benar, karena fitur dari sirkuit mikro yang digunakan, itu bukan halaman tunggal yang diatur dalam parameter
arg1 yang dihapus, tetapi blok 4 kilobyte yang mengandungnya.
Manajemen Relay Solid State
Kompleks ini memiliki enam relai keadaan padat. Ada tiga tim untuk mengelolanya.
subCmdRelaysSet - menetapkan nilai keenam relay secara bersamaan. Dalam parameter
arg1, nilai dilewatkan, setiap bit yang sesuai dengan relay sendiri (nol bit - relay dengan indeks 0, bit pertama dengan indeks 1, dll). Nilai bit tunggal menutup relai, nilai nol menyebabkannya terbuka.
Metode operasi ini bagus ketika semua relay bekerja sebagai satu kelompok. Jika mereka bekerja secara independen satu sama lain, dengan pendekatan ini Anda harus memulai variabel penyangga yang menyimpan nilai keadaan semua relay. Jika relay yang berbeda dikendalikan oleh program yang berbeda, masalah penyimpanan nilai agregat menjadi sangat akut. Dalam hal ini, Anda dapat menggunakan dua perintah lain:
subCmdRelaysOn - memungkinkan relay terpilih dengan mask. Relai yang sesuai dengan bit unit dalam argumen
arg1 akan diaktifkan. Relay yang sesuai dengan nol di topeng akan mempertahankan statusnya saat ini.
Perintah
subCmdRelaysOff yang mencerminkan perintah
itu akan mematikan relai yang dipilih oleh mask. Relai yang sesuai dengan bit tunggal dalam argumen
arg1 akan dimatikan. Relay yang sesuai dengan nol di topeng akan mempertahankan statusnya saat ini.
Setel ulang pengontrol FTDI dan Maxim
Untuk mengirim sinyal reset ke sirkuit mikro FTDI dan Maxim, kelompok perintah
subCmdFT4222_1_Reset ,
subCmdFT4222_2_Reset ,
subCmdFT4222_3_Reset ,
subCmdFT4232_Reset ,
subCmdFT2232_Reset ,
subCmdFT2232_Reset , dan
subCmdMA_21 digunakan . Dari namanya, Anda dapat melihat chip mana yang mereka kontrol dengan mengatur ulang sinyal. Jembatan FT4222, seperti yang kita bahas sebelumnya, adalah dua di sirkuit (indeksnya 1 dan 2), jembatan FT4222 lainnya mentransfer data ke chip MAX3421, yang akan kita bahas dalam artikel berikutnya.
Parameter
arg1 melewati salah satu nilai berikut:
enum ResetState { resetStateActive =0, resetStateNormalOperation };
Secara default, semua jembatan dalam kondisi kerja normal. Seperti yang sudah disebutkan dalam
artikel sebelumnya , kami sendiri tidak yakin apakah fungsi ini diperlukan, tetapi ketika tidak ada akses langsung ke perangkat, lebih baik untuk mengatur ulang semuanya dari jarak jauh.
Berpindah jalur konfigurasi chip FT4222
Chip FT4222 memiliki empat mode. Tidak mungkin ada orang yang memerlukan mode selain "00", tetapi jika Anda tiba-tiba membutuhkannya, Anda dapat menggunakan
subCmdFT4222_1_Cfg ,
subCmdFT4222_2_Cfg, dan
perintah subCmdFT4222_3_Cfg untuk
beralih untuk chip pertama, kedua, dan ketiga. Nilai garis CFG0 dan CFG1 diatur dalam dua bit lebih rendah dari parameter
arg1 .
Pengalaman praktis dalam mengeluarkan perintah ke pengontrol STM32
Untuk menguji materi teoretis yang diperoleh dalam praktik, kami akan mencoba untuk mematikan kartu SD. Untuk melakukan ini,
keluarkan perintah
subCmdSdEnable dengan kode 0x00 dengan argumen
enableModeOutside dengan kode 0x01. Bagus Kami menulis ulang program dari pengalaman masa lalu sebagai berikut.
Program ditulis ulang: #include <cstdio> #include <stdint.h> #include <string.h> #include <fcntl.h> // open #include <unistd.h> // close #include <sys/ioctl.h> #include <scsi/scsi.h> #include <scsi/sg.h> int main() { printf("hello from SdAccessTest!\n"); int s_fd = open("/dev/sdb", O_NONBLOCK | O_RDWR); if (s_fd < 0) { printf("Cannot open file\n"); return -1; } sg_io_hdr_t header; memset(&header;, 0, sizeof(header)); uint8_t cmdSdToOutside[] = { 0xC0,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; uint8_t cmdSdToPC[] = { 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; uint8_t sense[32]; memset(sense, 0, sizeof(sense)); header.interface_id = 'S'; // 'S' // header.cmd_len = sizeof(cmdSdToOutside); header.cmdp = cmdSdToOutside; // ( ) header.dxfer_len = 0; header.dxferp = 0; header.dxfer_direction = SG_DXFER_NONE; // header.mx_sb_len = sizeof(sense); header.sbp = sense; // header.timeout = 100; // 100 int res = ioctl(s_fd, SG_IO, &header;); // header.cmdp = cmdSdToPC; res = ioctl(s_fd, SG_IO, &header;); close(s_fd); return 0; }
Kami mengubah panjang perintah menjadi sepuluh byte dan menghapus blok data. Yah, mereka menuliskan kode perintah dengan argumen, sesuai kebutuhan. Kalau tidak, semuanya tetap sama. Kita mulai ... Dan ... Tidak ada yang berhasil. Fungsi
ioctl () mengembalikan kesalahan. Alasannya dijelaskan dalam
dokumen perintah
SG_IO . Faktanya adalah bahwa kita memberikan perintah Vendor Specific
C0h , dan berikut ini dikatakan tentang mereka secara harfiah:
Perintah SCSI (opcode) lainnya yang tidak disebutkan untuk driver sg membutuhkan O_RDWR. Perintah SCSI (opcode) lainnya yang tidak disebutkan untuk lapisan blok SG_IO ioctl membutuhkan pengguna dengan kemampuan CAP_SYS_RAWIO.
Seperti yang dijelaskan bos kepada saya (saya hanya menceritakan kembali kata-katanya), nilai
kapabilitas ditugaskan ke file yang dapat dieksekusi. Untuk alasan ini, saya harus melacak dari lingkungan pengembangan dengan masuk sebagai
root . Bukan solusi terbaik, tetapi setidaknya sesuatu. Bahkan, pada Windows, permintaan
IOCTL_SCSI_PASS_THROUGH_DIRECT juga memerlukan hak administrator. Mungkin di komentar seseorang akan memberikan saran tentang cara mengatasi masalah penelusuran tanpa langkah drastis seperti itu, tetapi Anda dapat menjalankan program yang sudah ditulis tanpa
root , jika Anda mendaftarkan
kemampuan yang benar
untuk itu . Sementara itu, ubah nama pengguna di lingkungan pengembangan dan atur breakpoint di telepon:
int res = ioctl(s_fd, SG_IO, &header;);
dan sebelum memanggil fungsi
ioctl () , kita melihat daftar perangkat penyimpanan:

Panggil
ioctl () dan lihat daftar lagi:

Perangkat
/ dev / sdb tetap (secara kasar, ini adalah pembaca kartu SD itu sendiri), dan
/ dev / sdb1 menghilang. Perangkat ini sesuai dengan sistem file di media. Pembawa terputus dari komputer - tidak lagi terlihat. Kami terus melacak. Setelah memanggil fungsi
ioctl () kedua, kami kembali melihat daftar perangkat:

Kartu SD dihubungkan kembali ke sistem, sehingga
/ dev / sdb1 kembali ke tempatnya. Sebenarnya, kami belajar cara mengeluarkan perintah khusus vendor dan mengelola perangkat berbasis mikrokontroler STM32 di kompleks Redd. Perintah lain akan diserahkan kepada pembaca untuk belajar mandiri. Anda dapat mengontrol operasi beberapa dari mereka dengan cara yang sama. Jika beberapa chip
ftdi masuk ke kondisi reset, perangkat yang sesuai akan menghilang dari sistem. Pengoperasian relai dan kontrol kaki konfigurasi harus dikontrol dengan alat ukur. Nah, Anda dapat memeriksa pekerjaan dengan flash drive dengan menulis halaman dengan kontrol bacaan berikutnya.
Kesimpulan
Kami memeriksa dua topik besar yang tidak terkait dengan FPGA di kompleks Redd. Yang ketiga tetap - bekerja dengan chip MAX3421, yang memungkinkan implementasi perangkat USB 2.0 FS. Sebenarnya, ada host juga, tetapi ada banyak host dan motherboard. Fungsionalitas perangkat akan memungkinkan kompleks untuk berpura-pura menjadi USB flash drive (untuk mengirim pembaruan "firmware"), keyboard USB (untuk mengontrol unit eksternal), dll. Kami akan mempertimbangkan topik ini di artikel selanjutnya.