Practica trabajando con neumáticos personalizados del complejo Redd

En el último artículo, examinamos la teoría de manejar mil pequeñas cosas en el complejo Redd, pero para no inflar el volumen, posponemos la práctica la próxima vez. Ha llegado el momento de realizar experimentos prácticos. Aquellos que no usan el complejo Redd también podrán encontrar conocimientos útiles en este artículo, a saber, la metodología para enviar comandos de proveedor a unidades USB desde Linux, porque, como ya se mencionó, el controlador STM32 en el complejo realiza la función de un lector SD, es decir, conducir




Clasificación de unidades por sistemas de comando


Al trabajar con unidades, debe distinguir entre una interfaz física y un sistema de comando. En particular, unidades de CD / DVD / BD y otras ópticas. Tradicionalmente, se conectan a un cable SATA (anteriormente IDE). Pero específicamente en este cable, solo los comandos PACKET se ejecutan durante la operación, en el bloque de datos de los cuales se colocan los comandos codificados de acuerdo con un principio completamente diferente (pronto descubriremos por cuál). Por lo tanto, ahora hablaremos no tanto de cables, sino de los equipos que corren en ellos. Sé de tres sistemas de comando comunes para trabajar con unidades.

  • MMC Se entiende por tarjetas SD. Honestamente, para mí este es el sistema de comando más misterioso. Al parecer, cómo enviarlos es claro, pero cómo administrar la unidad sin leer cuidadosamente el documento que contiene muchos gráficos de transición, siempre estoy confundido. Afortunadamente, esto no nos molesta hoy, ya que aunque trabajamos con una tarjeta SD, el controlador STM32 en el modo de "caja negra" funciona con ella.
  • ATA Inicialmente, estos comandos se ejecutaron en el bus IDE, luego en SATA. Un maravilloso sistema de comando, pero hoy también mencionamos que existe.
  • SCSI Este sistema de comando se utiliza en una amplia gama de dispositivos. Considere su uso en unidades. Hoy en día, los equipos SCSI se ejecutan, en primer lugar, a lo largo de los cables del bus SAS (por cierto, incluso los SSD con interfaz SAS ahora están de moda). Curiosamente, las unidades ópticas físicamente conectadas al bus SATA también funcionan a través de comandos SCSI. En el bus USB cuando se trabaja de acuerdo con el estándar del dispositivo de almacenamiento masivo, los comandos también van en formato SCSI. El microcontrolador STM32 está conectado al complejo Redd a través del bus USB, es decir, en nuestro caso, los comandos siguen la siguiente ruta:



Desde la PC al controlador, a través de USB, los comandos están en formato SCSI. El controlador transcodifica los comandos de acuerdo con la regla MMC y los envía a través del bus SDIO. Pero tenemos que escribir un programa para la PC, por lo que los equipos nos dejan en formato SCSI. Los prepara el controlador de dispositivo del dispositivo de almacenamiento masivo, con el que nos comunicamos a través del controlador del sistema de archivos. ¿Es posible mezclar solicitudes con otros dispositivos para estas solicitudes? Vamos a hacerlo bien.

Detalles del sistema de comando SCSI


Si aborda el asunto formalmente, la descripción del estándar SCSI está disponible en t10.org, pero seremos realistas. Nadie lo leerá voluntariamente. Más precisamente, no el suyo, sino el de ellos: hay un montón de documentos abiertos y una montaña de documentos cerrados. Solo una necesidad extrema hará que te sumerjas en el lenguaje complejo en el que está escrito el estándar (esto, por cierto, se aplica al estándar ATA en t13.org). Es mucho más fácil leer la documentación de las unidades reales. Está escrito en un lenguaje más animado, y partes hipotéticas pero no realmente usadas están recortadas. Mientras preparaba el artículo, me encontré con un documento bastante nuevo (2016) del Manual de referencia de comandos SCSI de Seagate (enlace directo www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf pero, como siempre, No sé cuánto tiempo vivirá). Creo que si alguien quiere dominar este sistema de comandos, debería comenzar con este documento. Solo recordamos que los lectores SD implementan un subconjunto aún más pequeño de los comandos de esa descripción.

Hablando muy brevemente, una unidad de comando con una longitud de 6 a 16 bytes se envía a la unidad. Se puede conectar un bloque de datos al bloque de comando desde la PC al disco, o desde el disco a la PC (el estándar SCSI también permite el intercambio bidireccional, pero para el dispositivo de almacenamiento masivo a través de USB solo se permite un bloque, lo que significa que la dirección es solo uno). En el bloque de instrucciones, el primer byte es siempre el código de comando. Los bytes restantes son sus argumentos. Las reglas para completar los argumentos se describen exclusivamente por los detalles de la implementación del comando.



Al principio inserté muchos ejemplos en el artículo, pero luego me di cuenta de que dificultan la lectura. Por lo tanto, sugiero a todos que comparen los campos del comando READ CAPACITY (10) de la tabla 119 del documento Seigate y los campos del comando READ (10) de la tabla 97 del mismo documento (vea el enlace de arriba). ¿Quién no encontró ninguna conexión? No se alarme. Eso es lo que quería mostrar. Además del campo "comando" en el byte cero, el propósito de todos los campos depende únicamente de los detalles de un comando en particular. Siempre necesita abrir el documento y estudiar el propósito de los campos restantes en él.

Entonces

  • Para comunicarse con la unidad, debe formar un bloque de comandos con una longitud de 6 a 16 bytes (dependiendo del formato del comando, el número exacto se indica en la documentación correspondiente).
  • El más importante es el byte cero del bloque: es él quien establece el código de comando.
  • Los bytes de bloque restantes no tienen un propósito claro. Para comprender cómo completarlos, debe abrir la documentación para un equipo específico.
  • Un bloque de datos que se puede transferir hacia o desde una unidad se puede adjuntar a un comando.

En realidad, eso es todo. Aprendimos las reglas para emitir comandos SCSI. Ahora podemos enviarlos, habría documentación sobre ellos. Pero, ¿cómo hacerlo a nivel del sistema operativo?

Comandos SCSI de Linux


Buscar dispositivo de destino


Para emitir comandos, abra el dispositivo de disco. Encontremos su nombre. Para hacer esto, iremos exactamente de la misma manera que en el artículo sobre puertos seriales . Veamos la lista de "archivos" en el directorio / dev (recuerde que en los dispositivos Linux también se muestran como archivos y su lista se muestra con el mismo comando ls ).

Hoy prestamos atención al disco del directorio virtual:



Nos fijamos en su contenido:



¡Un conjunto familiar de directorios anidados! Estamos tratando de considerar el directorio by-id , utilizando el modificador –l del comando ls , que ya nos resulta familiar en el artículo sobre puertos seriales:



Las palabras resaltadas hablan por sí mismas. Esta es una unidad que contiene la tarjeta SD interna del complejo Redd. Genial Ahora sabemos que el dispositivo MIR_Redd_Internal_SD corresponde al dispositivo / dev / sdb y / dev / sdb1 . El que no tiene el número es la unidad en sí, trabajaremos con él, y con el número es el sistema de archivos ubicado en el medio insertado en él. En términos de trabajar con una tarjeta SD, / dev / sdb es el lector, y / dev / sdb1 es el sistema de archivos en la tarjeta insertada en él.

Función del sistema operativo para emitir comandos


Por lo general, en cualquier sistema operativo, todas las cosas no estándar con dispositivos se realizan a través de solicitudes directas al controlador. En Linux, la función ioctl () está disponible para enviar tales solicitudes. Nuestro caso no es la excepción. Como argumento, pasamos la solicitud SG_IO descrita en el archivo de encabezado sg.h. La estructura sg_io_hdr_t que contiene los parámetros de solicitud también se describe allí. No daré la estructura completa, ya que no todos los campos deben completarse. Daré solo el más importante de ellos:

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) */ 

No tiene sentido describir aquellos campos que están bien documentados en los comentarios ( interface_id, dxfer_direction, timeout ). El artículo ya está creciendo.

El campo cmd_len contiene el número de bytes en el bloque de comando y cmdp contiene un puntero a este bloque. No puede prescindir de un comando, por lo que el número de bytes debe ser distinto de cero (de 6 a 16).

Los datos son opcionales. Si lo son, la longitud del búfer seleccionado se especifica en el campo dxfer_len , y se especifica un puntero en el campo dxferp . Una unidad puede transferir físicamente menos datos que el tamaño de búfer especificado. La dirección de transmisión se especifica en el campo dxfer_direction . Los valores válidos del dispositivo de almacenamiento masivo USB son: SG_DXFER_NONE, SG_DXFER_TO_DEV, SG_DXFER_FROM_DEV . Hay una cosa más en el archivo de encabezado, pero el estándar del Dispositivo de almacenamiento masivo no permite implementarlo físicamente.

También puede solicitar la devolución de un código de error extendido ( SENSE ). Lo que se puede encontrar en el documento de Segate, sección 2.4. La longitud del búfer asignado se indica en el campo mx_sb_len , y el puntero al búfer en sí se indica en el campo sbp .

Como puede ver, todo lo que mencioné anteriormente se completa en esta estructura (además, puede obtener información extendida sobre el error). Lea más sobre cómo trabajar con la solicitud SG_IO aquí: sg.danny.cz/sg/sg_io.html

Enviamos un comando estándar a la unidad


Bueno, descubrimos el formato del comando, descubrimos a qué dispositivo enviarlo, descubrimos a qué función llamar. Intentemos enviar algún comando estándar a nuestro dispositivo. Deje que este sea el comando para obtener el nombre de la unidad. Así es como se describe en el documento de Sigeyt:



Tenga en cuenta que de acuerdo con la ideología SCSI, todos los campos en los comandos estándar se completan en notación Big Endian, es decir, el byte más alto hacia adelante. Por lo tanto, completamos el campo con la longitud del búfer no en el formato "0x80, 0x00", sino por el contrario - "0x00, 0x80". Pero esto está en los comandos estándar. En no estándar todo es posible, siempre debe consultar la descripción. En realidad, solo el código de comando ( 12h ) y la longitud que tenemos que completar. Solicitaremos una página cero, y los campos restantes están reservados, desactualizados o predeterminados a cero. Así que llénalos todos con ceros.

Hacemos un programa que da este comando:
 #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; } 



Cómo ejecutar dichos programas en un dispositivo Redd remoto, ya lo hemos discutido en uno de los artículos anteriores . Es cierto, al iniciarlo por primera vez, inmediatamente recibí un error al llamar a la función open () . Resultó que el usuario por defecto no tiene suficientes derechos para abrir dispositivos de disco. Cuál de mí es un especialista en Linux, escribí muchas veces, pero en la red logré encontrar que para resolver este problema, puede cambiar los derechos de acceso al dispositivo emitiendo el comando:

sudo chmod 666 / dev / sdb

Sin embargo, mi jefe (y él es un gran especialista en este sistema operativo) más tarde notó que la solución es válida hasta que se reinicie el sistema operativo. Para obtener los derechos con seguridad, debe agregar el usuario al grupo de discos .

Cualquiera de estos dos caminos vamos, pero después de que todo haya funcionado, coloque un punto de interrupción en la línea close (s_fd); e inspeccione los resultados cuando se logre en el entorno de desarrollo (dado que el programa no es de un solo día, lo que significa que no tenemos tiempo para invertir tiempo y esfuerzo en insertar mapeadores, si el entorno de desarrollo puede mostrarnos todo). El valor de res es cero. Entonces el equipo trabajó sin errores.



¿Qué vino al búfer? Cuando ingresé la palabra datos en la dirección del vertedero, me dijeron que no podían calcular el valor, tenía que ingresar & data; . Es extraño, porque los datos son un puntero, cuando la depuración en Windows todo funciona, pero solo noto este hecho, funciona así: mira el resultado obtenido de esta manera:



Así es, nos devolvieron el nombre y la revisión de la unidad. Puede encontrar más información sobre el formato de la estructura resultante en el documento de Segate (sección 3.6.2, tabla 59). El búfer de detección no se llenó, pero la descripción IOCTL de la solicitud dice que se llena solo cuando se produce un error que devuelve algo en este búfer. Literalmente: los datos de detección (solo se usan cuando el "estado" es CHECK CONDITION o (driver_status & DRIVER_SENSE) es verdadero) .

Formato de comando personalizado para la unidad SD interna de Redd


Ahora que no solo hemos estudiado la descripción seca del estándar, sino que también hemos intentado todo en la práctica, después de experimentar lo que es un bloque de comandos, ya podemos mostrar el formato de comando con el que puede llamar a funciones no estándar que se "flashean" al controlador STM32 en la placa compleja. Seleccioné el código de comando desde el principio del rango de comandos específicos del proveedor . Es igual a 0xC0. Tradicionalmente, en las descripciones de los comandos SCSI, escriba C0h . La longitud del comando siempre es de 10 bytes. El formato del equipo está unificado y se presenta en la tabla a continuación.

ByteCita
0 0Código de comando C0h
1Código de subcomando
2Argumento arg1. Establecer en notación Little Endian (byte bajo hacia adelante)
3
4 4
5 5
6 6Argumento arg2. Establecer en notación Little Endian (byte bajo hacia adelante)
7 7
8
9 9

Como puede ver, los argumentos se dan en la notación Little Endian. Esto le permitirá describir el comando en forma de estructura y acceder a sus campos directamente, sin recurrir a la función de permutación de bytes. Los problemas de alineación (las palabras dobles en la estructura tienen desplazamientos que no son múltiplos de cuatro) en arquitecturas x86 y x64 no valen la pena.

Los códigos de subcomando se describen mediante la siguiente enumeración:
 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 }; 

Se pueden dividir en grupos.

Cambiar dispositivos a modos internos y externos


Los comandos subCmdSdEnable y subCmdSpiFlashEnable cambian la tarjeta SD y el flash SPI, respectivamente. El parámetro arg1 pasa uno de los siguientes valores:

 enum enableMode { enableModeToPC = 0, enableModeOutside }; 

Por defecto, ambos dispositivos están conectados a una PC.

Cambio de potencia


El protocolo SDIO requiere mucha manipulación durante la inicialización. A veces es útil restablecer la tarjeta SD a su estado inicial (por ejemplo, al cambiar sus líneas a un conector externo). Para hacer esto, apague, luego encienda su energía. Esto se puede hacer usando el comando subCmdSdPower . En el argumento arg1, se pasa uno de los siguientes valores: 0 - apagado, 1 - encendido. Recuerde dar tiempo para descargar los condensadores en la línea de alimentación.

Después de encender la alimentación, la tarjeta, si está conectada a la PC, debe reiniciarse. Para hacer esto, use el comando subCmdSdReinit (no tiene argumentos).

Trabajar con unidad flash SPI


Si la tarjeta SD está conectada al sistema como una unidad completa, el chip de acceso en la versión actual es bastante limitado. Puede acceder solo a sus páginas individuales (256 bytes) y solo una a la vez. La cantidad de memoria en el microcircuito es tal que incluso cuando se trabaja en la página, el proceso no tomará mucho tiempo de todos modos, pero este enfoque simplifica enormemente el "firmware" del microcontrolador.

El comando subCmdSpiFlashReadPage lee la página. La dirección se especifica en el parámetro arg1, el número de páginas a transmitir en el parámetro arg2. Pero en la versión actual, el número de páginas debe ser igual a uno. El comando devolverá 256 bytes de datos.

Reflejado para ella está el comando subCmdSpiFlashWritePage . Los argumentos a favor de ella se completan con el mismo principio. La dirección de la transferencia de datos es al dispositivo.

La peculiaridad de la memoria flash es que solo los bits individuales se pueden reemplazar con bits cero durante la grabación. Para devolverlos a un solo valor, las páginas deben borrarse. Hay un comando subCmdSpiFlashErasePage para esto . Es cierto que, debido a las características del microcircuito utilizado, no se establece una sola página en el parámetro arg1 que se borra, sino un bloque de 4 kilobytes que lo contiene.

Gestión de relés de estado sólido


El complejo tiene seis relés de estado sólido. Hay tres equipos para gestionarlos.

subCmdRelaysSet : establece el valor de los seis relés simultáneamente. En el parámetro arg1, se pasa un valor, cada bit del cual corresponde a su propio relé (bit cero - relé con índice 0, primer bit con índice 1, etc.). Un solo valor de bit cierra el relé, un valor cero hace que se abra.

Este método de operación es bueno cuando todos los relés funcionan como un solo grupo. Si funcionan independientemente el uno del otro, con este enfoque debe iniciar una variable de búfer que almacena el valor de estado de todos los relés. Si diferentes programas son controlados por diferentes programas, el problema de almacenar el valor agregado se vuelve extremadamente agudo. En este caso, puede usar otros dos comandos:

subCmdRelaysOn : habilita los relés seleccionados por máscara. Se habilitarán los relés que corresponden a los bits unitarios en el argumento arg1 . Los relés que corresponden a ceros en la máscara conservarán su estado actual.

El comando subCmdRelaysOff que lo refleja apagará los relés seleccionados por máscara. Los relés que corresponden a los bits individuales en el argumento arg1 se apagarán . Los relés que corresponden a ceros en la máscara conservarán su estado actual.

Restablecer controladores FTDI y Maxim


Para enviar señales de reinicio a los microcircuitos FTDI y Maxim, se usa el grupo de comandos subCmdFT4222_1_Reset , subCmdFT4222_2_Reset , subCmdFT4222_3_Reset , subCmdFT4232_Reset , subCmdFT2232_Reset y subCmdMAX3421_ . A partir de sus nombres, puede ver qué chips controlan mediante señales de reinicio. Los puentes FT4222, como consideramos anteriormente, son dos en el circuito (sus índices son 1 y 2), otro puente FT4222 transfiere datos al chip MAX3421, que consideraremos en el próximo artículo.

El parámetro arg1 pasa uno de los siguientes valores:

 enum ResetState { resetStateActive =0, resetStateNormalOperation }; 

Por defecto, todos los puentes están en condiciones normales de trabajo. Como ya se señaló en un artículo anterior , nosotros mismos no estamos seguros de si se necesita esta funcionalidad, pero cuando no hay acceso directo al dispositivo, es mejor poder restablecer de forma remota todo y todo.

Cambio de líneas de configuración de chips FT4222


Los chips FT4222 tienen cuatro modos. Es poco probable que alguien necesite un modo que no sea "00", pero si de repente lo necesita, puede usar los comandos subCmdFT4222_1_Cfg , subCmdFT4222_2_Cfg y subCmdFT4222_3_Cfg para cambiar el primer, segundo y tercer chip. El valor de las líneas CFG0 y CFG1 se establece en los dos bits inferiores del parámetro arg1 .

Experiencia práctica en la emisión de comandos al controlador STM32


Para probar el material teórico obtenido en la práctica, intentaremos cambiar la tarjeta SD. Para hacer esto, emita el comando subCmdSdEnable con el código 0x00 con el argumento enableModeOutside con el código 0x01. Genial Reescribimos el programa de la experiencia pasada de la siguiente manera.

Programa reescrito:
 #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; } 


Cambiamos la longitud del comando a diez bytes y eliminamos el bloque de datos. Bueno, escribieron el código de comando con argumentos, según sea necesario. De lo contrario, todo sigue igual. Comenzamos ... Y ... Nada funciona. La función ioctl () devuelve un error. El motivo se describe en el documento de comando SG_IO . El hecho es que le damos al comando específico del proveedor C0h , y lo siguiente se dice sobre ellos literalmente:
Cualquier otro comando SCSI (código de operación) no mencionado para el controlador sg necesita O_RDWR. Cualquier otro comando SCSI (código de operación) no mencionado para la capa de bloques SG_IO ioctl necesita un usuario con capacidad CAP_SYS_RAWIO.

Como me explicó el jefe (solo estoy volviendo a contar sus palabras), los valores de capacidades se asignan a un archivo ejecutable. Por esta razón, tuve que rastrear desde el entorno de desarrollo iniciando sesión como root . No es la mejor solución, pero al menos algo. De hecho, en Windows, la solicitud IOCTL_SCSI_PASS_THROUGH_DIRECT también requiere derechos de administrador. Quizás en los comentarios alguien le dará consejos sobre cómo resolver el problema de rastreo sin pasos tan drásticos, pero puede ejecutar el programa ya escrito sin root , si registra las capacidades correctas para ello . Mientras tanto, cambie el nombre de usuario en el entorno de desarrollo y establezca un punto de interrupción en la línea:

 int res = ioctl(s_fd, SG_IO, &header;); 

y antes de llamar a la función ioctl () , miramos la lista de dispositivos de almacenamiento:



Llame a ioctl () y mire la lista nuevamente:



El dispositivo / dev / sdb permaneció (en términos generales, este es el lector de tarjetas SD), y / dev / sdb1 desapareció. Este dispositivo corresponde al sistema de archivos en los medios. El operador se desconectó de la computadora; ya no era visible. Seguimos rastreando. Después de llamar a la segunda función ioctl () , nuevamente miramos la lista de dispositivos:



La tarjeta SD se vuelve a conectar al sistema, por lo que / dev / sdb1 vuelve a estar en su lugar. En realidad, aprendimos cómo emitir comandos específicos del proveedor y administrar un dispositivo basado en el microcontrolador STM32 en el complejo Redd. Otros comandos se dejarán a los lectores para su estudio independiente. Puede controlar el funcionamiento de algunos de ellos de manera similar. Si algún chip ftdi entra en un estado de reinicio, el dispositivo correspondiente desaparecerá del sistema. El funcionamiento del relé y el control de las patas de la configuración deberán controlarse mediante instrumentos de medición. Bueno, puede verificar el trabajo con una unidad flash escribiendo páginas con su control de lectura posterior.

Conclusión


Examinamos dos grandes temas que no están relacionados con los FPGA en el complejo Redd. El tercero permaneció: trabajar con el chip MAX3421, que permite implementar dispositivos USB 2.0 FS. De hecho, también hay hosts, pero hay muchos hosts y la placa base. La funcionalidad del dispositivo permitirá que el complejo pretenda ser una unidad flash USB (para enviar actualizaciones de "firmware"), un teclado USB (para controlar unidades externas), etc. Consideraremos este tema en el próximo artículo.

Source: https://habr.com/ru/post/484706/


All Articles