/** * Initialize the signal handlers, catch * those signals we are interested in and sets SIGPIPE to be ignored. * @return true if initialization was sucessful. */ bool Signals_Init(void) { size_t i; #ifdef HAVE_SIGACTION struct sigaction saction; #endif if (signalpipe[0] > 0 || signalpipe[1] > 0) return true; if (pipe(signalpipe)) return false; if (!io_setnonblock(signalpipe[0]) || !io_setnonblock(signalpipe[1])) return false; if (!io_setcloexec(signalpipe[0]) || !io_setcloexec(signalpipe[1])) return false; #ifdef HAVE_SIGACTION memset( &saction, 0, sizeof( saction )); saction.sa_handler = Signal_Handler; #ifdef SA_RESTART saction.sa_flags |= SA_RESTART; #endif #ifdef SA_NOCLDWAIT saction.sa_flags |= SA_NOCLDWAIT; #endif for (i=0; i < C_ARRAY_SIZE(signals_catch) ; i++) sigaction(signals_catch[i], &saction, NULL); /* we handle write errors properly; ignore SIGPIPE */ saction.sa_handler = SIG_IGN; sigaction(SIGPIPE, &saction, NULL); #else for (i=0; i < C_ARRAY_SIZE(signals_catch) ; i++) signal(signals_catch[i], Signal_Handler); signal(SIGPIPE, SIG_IGN); #endif return io_event_create(signalpipe[0], IO_WANTREAD, Signal_Callback); } /* Signals_Init */
/** * Restores signals to their default behaviour. * * This should be called after a fork() in the new * child prodcess, especially when we are about to call * 3rd party code (e.g. PAM). */ void Signals_Exit(void) { size_t i; #ifdef HAVE_SIGACTION struct sigaction saction; memset(&saction, 0, sizeof(saction)); saction.sa_handler = SIG_DFL; for (i=0; i < C_ARRAY_SIZE(signals_catch) ; i++) sigaction(signals_catch[i], &saction, NULL); sigaction(SIGPIPE, &saction, NULL); #else for (i=0; i < C_ARRAY_SIZE(signals_catch) ; i++) signal(signals_catch[i], SIG_DFL); signal(SIGPIPE, SIG_DFL); #endif close(signalpipe[1]); close(signalpipe[0]); signalpipe[0] = signalpipe[1] = 0; }
static dc_status_t dc_descriptor_iterator_next (dc_iterator_t *abstract, void *out) { dc_descriptor_iterator_t *iterator = (dc_descriptor_iterator_t *) abstract; dc_descriptor_t **item = (dc_descriptor_t **) out; if (iterator->current >= C_ARRAY_SIZE (g_descriptors)) return DC_STATUS_DONE; /* * The explicit cast from a const to a non-const pointer is safe here. The * public interface doesn't support write access, and therefore descriptor * objects are always read-only. However, the cast allows to return a direct * reference to the entries in the table, avoiding the overhead of * allocating (and freeing) memory for a deep copy. */ *item = (dc_descriptor_t *) &g_descriptors[iterator->current++]; return DC_STATUS_SUCCESS; }
/* * Think twice before modifying the code for updating the ostc firmware! * It has been carefully developed and tested with assistance from * Heinrichs-Weikamp, using a special development unit. If you start * experimenting with a normal unit and accidentally screw up, you might * brick the device permanently and turn it into an expensive * paperweight. You have been warned! */ dc_status_t hw_ostc_device_fwupdate (dc_device_t *abstract, const char *filename) { dc_status_t rc = DC_STATUS_SUCCESS; hw_ostc_device_t *device = (hw_ostc_device_t *) abstract; dc_context_t *context = (abstract ? abstract->context : NULL); if (!ISINSTANCE (abstract)) return DC_STATUS_INVALIDARGS; // Allocate memory for the firmware data. hw_ostc_firmware_t *firmware = (hw_ostc_firmware_t *) malloc (sizeof (hw_ostc_firmware_t)); if (firmware == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; } // Read the hex file. rc = hw_ostc_firmware_readfile (firmware, context, filename); if (rc != DC_STATUS_SUCCESS) { ERROR (context, "Failed to read the firmware file."); free (firmware); return rc; } // Temporary set a relative short timeout. The command to setup the // bootloader needs to be send repeatedly, until the response packet is // received. Thus the time between each two attempts is directly controlled // by the timeout value. serial_set_timeout (device->port, 300); // Setup the bootloader. const unsigned int baudrates[] = {19200, 115200}; for (unsigned int i = 0; i < C_ARRAY_SIZE(baudrates); ++i) { // Adjust the baudrate. if (serial_configure (device->port, baudrates[i], 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE) == -1) { ERROR (abstract->context, "Failed to set the terminal attributes."); free (firmware); return DC_STATUS_IO; } // Try to setup the bootloader. unsigned int maxretries = (i == 0 ? 1 : MAXRETRIES); rc = hw_ostc_firmware_setup (device, maxretries); if (rc == DC_STATUS_SUCCESS) break; } if (rc != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to setup the bootloader."); free (firmware); return rc; } // Increase the timeout again. serial_set_timeout (device->port, 1000); // Enable progress notifications. dc_event_progress_t progress = EVENT_PROGRESS_INITIALIZER; progress.maximum = C_ARRAY_SIZE(firmware->bitmap); device_event_emit (abstract, DC_EVENT_PROGRESS, &progress); for (unsigned int i = 0; i < C_ARRAY_SIZE(firmware->bitmap); ++i) { // Skip empty blocks. if (firmware->bitmap[i] == 0) continue; // Create the packet. unsigned int address = i * SZ_BLOCK; unsigned char packet[4 + SZ_BLOCK + 1] = { (address >> 16) & 0xFF, (address >> 8) & 0xFF, (address ) & 0xFF, SZ_BLOCK }; memcpy (packet + 4, firmware->data + address, SZ_BLOCK); packet[sizeof (packet) - 1] = ~checksum_add_uint8 (packet, 4 + SZ_BLOCK, 0x00) + 1; // Send the packet. rc = hw_ostc_firmware_write (device, packet, sizeof (packet)); if (rc != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the packet."); free (firmware); return rc; } // Update and emit a progress event. progress.current = i + 1; device_event_emit (abstract, DC_EVENT_PROGRESS, &progress); } free (firmware); return DC_STATUS_SUCCESS; }
static dc_status_t hw_ostc_firmware_readfile (hw_ostc_firmware_t *firmware, dc_context_t *context, const char *filename) { dc_status_t rc = DC_STATUS_SUCCESS; if (firmware == NULL) { ERROR (context, "Invalid arguments."); return DC_STATUS_INVALIDARGS; } // Initialize the buffers. memset (firmware->data, 0xFF, sizeof (firmware->data)); memset (firmware->bitmap, 0x00, sizeof (firmware->bitmap)); // Open the hex file. dc_ihex_file_t *file = NULL; rc = dc_ihex_file_open (&file, context, filename); if (rc != DC_STATUS_SUCCESS) { ERROR (context, "Failed to open the hex file."); return rc; } // Read the hex file. unsigned int lba = 0; dc_ihex_entry_t entry; while ((rc = dc_ihex_file_read (file, &entry)) == DC_STATUS_SUCCESS) { if (entry.type == 0) { // Data record. unsigned int address = (lba << 16) + entry.address; if (address + entry.length > SZ_FIRMWARE) { WARNING (context, "Ignoring out of range record (0x%08x,%u).", address, entry.length); continue; } // Copy the record to the buffer. memcpy (firmware->data + address, entry.data, entry.length); // Mark the corresponding blocks in the bitmap. unsigned int begin = address / SZ_BLOCK; unsigned int end = (address + entry.length + SZ_BLOCK - 1) / SZ_BLOCK; for (unsigned int i = begin; i < end; ++i) { firmware->bitmap[i] = 1; } } else if (entry.type == 1) { // End of file record. break; } else if (entry.type == 4) { // Extended linear address record. lba = array_uint16_be (entry.data); } else { ERROR (context, "Unexpected record type."); dc_ihex_file_close (file); return DC_STATUS_DATAFORMAT; } } if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_DONE) { ERROR (context, "Failed to read the record."); dc_ihex_file_close (file); return rc; } // Close the file. dc_ihex_file_close (file); // Verify the presence of the first block. if (firmware->bitmap[0] == 0) { ERROR (context, "No first data block."); return DC_STATUS_DATAFORMAT; } // Setup the last block. // Copy the "goto main" instruction, stored in the first 8 bytes of the hex // file, to the end of the last block at address 0x17F38. This last block // needs to be present, regardless of whether it's included in the hex file // or not! memset (firmware->data + SZ_FIRMWARE - SZ_BLOCK, 0xFF, SZ_BLOCK - 8); memcpy (firmware->data + SZ_FIRMWARE - 8, firmware->data, 8); firmware->bitmap[C_ARRAY_SIZE(firmware->bitmap) - 1] = 1; // Setup the first block. // Copy the hardcoded "goto 0x17F40" instruction to the start of the first // block at address 0x00000. const unsigned char header[] = {0xA0, 0xEF, 0xBF, 0xF0}; memcpy (firmware->data, header, sizeof (header)); return rc; }