diff options
author | Alexey 'Cluster' Avdyukhin <clusterrr@clusterrr.com> | 2019-01-29 17:45:43 +0300 |
---|---|---|
committer | Alexey 'Cluster' Avdyukhin <clusterrr@clusterrr.com> | 2019-01-29 17:45:43 +0300 |
commit | d36e0e7eb76ef9a5927380bab59a8a896472234f (patch) | |
tree | 7158b0e9d9d80d811aa28955a9cf1d5a1ebb498f | |
parent | 1fbc51a4793a449498a972934589fd94d78b5aec (diff) |
Formatting
-rw-r--r-- | clunet.c | 543 |
1 files changed, 277 insertions, 266 deletions
@@ -17,7 +17,7 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Cluster"); MODULE_DESCRIPTION("CLUNET driver"); -// Module parameters +/* Module parameters */ static u8 receive_pin = 2; static u8 transmit_pin = 3; static u8 transmit_value = 1; @@ -66,15 +66,14 @@ static u8 clunet_reading_current_byte = 0; static u8 clunet_reading_current_bit = 0; static u8 in_buffer[CLUNET_READ_BUFFER_SIZE]; +/* CRC check function */ static u8 check_crc(const char* data, const uint8_t size) { u8 crc = 0; u8 i, j; - for (i = 0; i < size; i++) - { + for (i = 0; i < size; i++) { uint8_t inbyte = data[i]; - for (j = 0 ; j < 8 ; j++) - { + for (j = 0 ; j < 8 ; j++) { uint8_t mix = (crc ^ inbyte) & 1; crc >>= 1; if (mix) crc ^= 0x8C; @@ -84,34 +83,45 @@ static u8 check_crc(const char* data, const uint8_t size) return crc; } +/* Function to schedule main timer */ static void set_send_timer(u16 t) { - if (data_send_timer) - { + if (data_send_timer) { hrtimer_try_to_cancel(data_send_timer); if (t) - hrtimer_start(data_send_timer, ktime_set(0, t * 1000UL), HRTIMER_MODE_REL); + hrtimer_start(data_send_timer, ktime_set(0, t * 1000UL), + HRTIMER_MODE_REL); } } -static void clunet_set_line(u8 value) +/* Function to outpud data */ +static inline void clunet_set_line(u8 value) { clunet_sending = value; - gpiod_direction_output(transmit_pin_desc, value ? transmit_value : !transmit_value); + gpiod_direction_output(transmit_pin_desc, + value ? transmit_value : !transmit_value); } -static void clunet_data_received(const uint8_t prio, const uint8_t src_address, const uint8_t dst_address, const uint8_t command, char* data, const uint8_t size) +/* Callback for received data */ +static void clunet_data_received( + const uint8_t prio, + const uint8_t src_address, + const uint8_t dst_address, + const uint8_t command, + char* data, + const uint8_t size) { int i, p; char* buffer; int d_address; - buffer = kmalloc(2 + 3 + 3 + 3 + size * 2 + 1 + 1, GFP_ATOMIC); // 'P SR DS CM DATA\n0' - if (!buffer) - { + /* 'P SR DS CM DATA\n0' */ + buffer = kmalloc(2 + 3 + 3 + 3 + size * 2 + 1 + 1, GFP_ATOMIC); + if (!buffer) { printk(KERN_ERR "CLUNET: can't allocatate memory"); return; } - sprintf(buffer, "%d %02X %02X %02X ", prio, src_address, dst_address, command); + sprintf(buffer, "%d %02X %02X %02X ", + prio, src_address, dst_address, command); for (i = 0; i < size; i++) sprintf(buffer + 2 + 3 + 3 + 3 + i*2, "%02X", data[i]); strcat(buffer, "\n"); @@ -119,17 +129,18 @@ static void clunet_data_received(const uint8_t prio, const uint8_t src_address, printk(KERN_DEBUG "CLUNET received: %s", buffer); #endif p = 0; - while (buffer[p]) - { - for (i = 0; i < clunet_bus_number_opens; i++) - { + while (buffer[p]) { + for (i = 0; i < clunet_bus_number_opens; i++) { if (!(opened_files[i]->f_mode & FMODE_READ)) continue; d_address = ((struct cfile_t*)opened_files[i]->private_data)->device_address; - if ((d_address < 0) // bus devices - || ((src_address == d_address) // source address matched - && ((dst_address == address) // destination address is my address - || (dst_address == CLUNET_BROADCAST_ADDRESS)) // or broadcast address - && (p >= 2 + 3 + 3)) // skip 'P SR DS ' + if ((d_address < 0) /* Bus devices */ + /* Source address matched, */ + || ((src_address == d_address) + /* destination address is my address, */ + && ((dst_address == address) + /* or broadcast address */ + || (dst_address == CLUNET_BROADCAST_ADDRESS)) + && (p >= 2 + 3 + 3)) /* skip 'P SR DS ' */ ) ((struct cfile_t*)opened_files[i]->private_data)->receiver_buffer[ ((struct cfile_t*)opened_files[i]->private_data)->receiver_write_pos++ @@ -140,88 +151,88 @@ static void clunet_data_received(const uint8_t prio, const uint8_t src_address, kfree(buffer); /* Some reserved commands */ - if (((dst_address == address) // destination address is my address - || (dst_address == CLUNET_BROADCAST_ADDRESS)) // or broadcast address - && ((clunet_sending_state == CLUNET_SENDING_STATE_IDLE) // Not busy - || (clunet_sending_priority <= CLUNET_PRIORITY_MESSAGE)) // Or not very busy - ) - { - /* Ответ на поиск устройств */ - if (command == CLUNET_COMMAND_DISCOVERY) - { + if (((dst_address == address) /* Destination address is my address */ + /* or broadcast address */ + || (dst_address == CLUNET_BROADCAST_ADDRESS)) + /* Not busy */ + && ((clunet_sending_state == CLUNET_SENDING_STATE_IDLE) + /* Or not very busy */ + || (clunet_sending_priority <= CLUNET_PRIORITY_MESSAGE)) + ) { + /* Device discovery reply */ + if (command == CLUNET_COMMAND_DISCOVERY) { uint8_t len = 0; while(device_name[len]) len++; - clunet_send(address, src_address, CLUNET_PRIORITY_MESSAGE, CLUNET_COMMAND_DISCOVERY_RESPONSE, device_name, len); + clunet_send(address, src_address, CLUNET_PRIORITY_MESSAGE, + CLUNET_COMMAND_DISCOVERY_RESPONSE, device_name, len); } - /* Ответ на пинг */ - else if (command == CLUNET_COMMAND_PING) - { - clunet_send(address, src_address, CLUNET_PRIORITY_COMMAND, CLUNET_COMMAND_PING_REPLY, data, size); + /* PING reply */ + else if (command == CLUNET_COMMAND_PING) { + clunet_send(address, src_address, CLUNET_PRIORITY_COMMAND, + CLUNET_COMMAND_PING_REPLY, data, size); } } wake_up_interruptible(&wq_data); } -static irq_handler_t clunet_irq_handler(unsigned int irq, void *dev_id, struct pt_regs *regs) +/* IRQ fired every rising/falling edge of receiver pin */ +static irq_handler_t clunet_irq_handler(unsigned int irq, + void *dev_id, struct pt_regs *regs) { u64 now = ktime_to_us(ktime_get_boottime()); u8 value = CLUNET_READING; uint64_t ticks; - if (value && last_rising_time > 0) - { - ticks = now - last_rising_time; // Idle time + if (value && last_rising_time > 0) { /* Line is low */ + ticks = now - last_rising_time; /* Idle time */ if (clunet_reading_state != CLUNET_READING_STATE_IDLE - && ticks >= CLUNET_IDLE_TIMEOUT_T) // Timeout - { + && ticks >= CLUNET_IDLE_TIMEOUT_T + ) { /* Timeout */ clunet_reading_state = CLUNET_READING_STATE_IDLE; printk(KERN_WARNING "CLUNET recv timeout\n"); } - if (clunet_sending_state && !clunet_sending) // Collision - { + if (clunet_sending_state && !clunet_sending) { /* Collision */ /* Stop transmission and wait for line */ set_send_timer(0); clunet_sending_state = CLUNET_SENDING_STATE_WAITING_LINE; } } - else if (!value && last_falling_time > 0) // high - { - /* Линия свободна, пробуем запланировать отправку */ - if (clunet_sending_state == CLUNET_SENDING_STATE_WAITING_LINE) - { + else if (!value && last_falling_time > 0) { /* Line is high */ + /* Line is free trying to schedule transmission */ + if (clunet_sending_state == CLUNET_SENDING_STATE_WAITING_LINE) { clunet_sending_state = CLUNET_SENDING_STATE_INIT; set_send_timer(CLUNET_SEND_PAUSE_T); } - ticks = now - last_falling_time; // Вычислим время сигнала + ticks = now - last_falling_time; /* Signal time calculated */ - /* Если кто-то долго жмёт линию (время >= 6.5Т) - это инициализация */ + /* Is it initialization? (time >= 6.5T?) */ if (ticks >= (CLUNET_INIT_T + CLUNET_1_T) / 2) clunet_reading_state = CLUNET_READING_STATE_PRIO1; - - /* Иначе если недолго, то смотрим на этап */ + /* Need to check stage otherwise */ else - switch (clunet_reading_state) - { + switch (clunet_reading_state) { - /* Чтение данных */ + /* Reading data */ case CLUNET_READING_STATE_DATA: - - /* Если бит значащий (время > 2Т), то установим его в приемном буфере */ + /* If time > 2T, need to set bit */ if (ticks > (CLUNET_0_T + CLUNET_1_T) / 2) - in_buffer[clunet_reading_current_byte] |= (1 << clunet_reading_current_bit); - - /* Инкрементируем указатель бита, и при полной обработке всех 8 бит в байте выполним: */ + in_buffer[clunet_reading_current_byte] + |= (1 << clunet_reading_current_bit); + /* Next bit, end of byte check */ if (++clunet_reading_current_bit & 8) { - - /* Проверка на окончание чтения пакета */ - if ((++clunet_reading_current_byte > CLUNET_OFFSET_SIZE) && (clunet_reading_current_byte > in_buffer[CLUNET_OFFSET_SIZE] + CLUNET_OFFSET_DATA)) - { + /* Is it end of the frame? */ + if ((++clunet_reading_current_byte > CLUNET_OFFSET_SIZE) + && (clunet_reading_current_byte > in_buffer[CLUNET_OFFSET_SIZE] + + CLUNET_OFFSET_DATA)) { clunet_reading_state = CLUNET_READING_STATE_IDLE; - - /* Проверяем CRC, при успехе начнем обработку принятого пакета */ - if (!check_crc((char*)in_buffer + CLUNET_OFFSET_SRC_ADDRESS, clunet_reading_current_byte - CLUNET_OFFSET_SRC_ADDRESS)) - clunet_data_received ( + /* Lets check CRC */ + if (!check_crc((char*)in_buffer + + CLUNET_OFFSET_SRC_ADDRESS, + clunet_reading_current_byte + - CLUNET_OFFSET_SRC_ADDRESS)) { + /* CRC is OK, lets proceed data */ + clunet_data_received( clunet_reading_priority, in_buffer[CLUNET_OFFSET_SRC_ADDRESS], in_buffer[CLUNET_OFFSET_DST_ADDRESS], @@ -229,36 +240,35 @@ static irq_handler_t clunet_irq_handler(unsigned int irq, void *dev_id, struct p (char*)(in_buffer + CLUNET_OFFSET_DATA), in_buffer[CLUNET_OFFSET_SIZE] ); - else - printk(KERN_WARNING "CLUNET CRC error: prio %d from %02X to %02X cmd %02X size %d\n", + } else { /* CRC check */ + /* CRC error, lets print error to kernel log */ + printk(KERN_WARNING "CLUNET CRC error: prio %d from %02X to %02X cmd %02X size %d\n", clunet_reading_priority, in_buffer[CLUNET_OFFSET_SRC_ADDRESS], in_buffer[CLUNET_OFFSET_DST_ADDRESS], in_buffer[CLUNET_OFFSET_COMMAND], in_buffer[CLUNET_OFFSET_SIZE]); + } } - - /* Иначе если пакет не прочитан и буфер не закончился - подготовимся к чтению следующего байта */ - else if (clunet_reading_current_byte < CLUNET_READ_BUFFER_SIZE) - { + /* This is not end of the packet, reading next byte */ + else if (clunet_reading_current_byte + < CLUNET_READ_BUFFER_SIZE) { clunet_reading_current_bit = 0; in_buffer[clunet_reading_current_byte] = 0; } - - /* Иначе - нехватка приемного буфера -> игнорируем пакет */ - else - { + /* Buffer overflow, discaring data */ + else { clunet_reading_state = CLUNET_READING_STATE_IDLE; printk(KERN_ERR "CLUNET out of revc buffer\n"); } } break; - /* Получение приоритета (младший бит), клиенту он не нужен */ + /* Reading priority (lower bit) */ case CLUNET_READING_STATE_PRIO2: - /* Если бит значащий (время > 2Т), то установим его в приемном буфере */ - clunet_reading_state++; + clunet_reading_state++; if (ticks > (CLUNET_0_T + CLUNET_1_T) / 2) + /* Logic 1 */ clunet_reading_priority |= 1; clunet_reading_priority++; clunet_reading_current_byte = CLUNET_OFFSET_SRC_ADDRESS; @@ -266,139 +276,145 @@ static irq_handler_t clunet_irq_handler(unsigned int irq, void *dev_id, struct p in_buffer[CLUNET_OFFSET_SRC_ADDRESS] = 0; break; - /* Получение приоритета (старший бит), клиенту он не нужен */ + /* Reading priority (higher bit) */ case CLUNET_READING_STATE_PRIO1: clunet_reading_state++; - /* Если бит значащий (время > 2Т), то установим его в приемном буфере */ if (ticks > (CLUNET_0_T + CLUNET_1_T) / 2) + /* Login 1 */ clunet_reading_priority = 1 << 1; else + /* Logic 0 */ clunet_reading_priority = 0; } } + /* Save current timestamp */ if (!value) last_rising_time = now; else last_falling_time = now; - return (irq_handler_t) IRQ_HANDLED; // Announce that the IRQ has been handled correctly + /* Announce that the IRQ has been handled correctly */ + return (irq_handler_t) IRQ_HANDLED; } -/* Таймер */ +/* Timer */ static enum hrtimer_restart send_timer_callback(struct hrtimer *timer) { - /* Если достигли фазы завершения передачи, то завершим ее и освободим передатчик */ - if (!clunet_sending_state || clunet_sending_state == CLUNET_SENDING_STATE_DONE) - { - clunet_sending_state = CLUNET_SENDING_STATE_IDLE; // Указываем, что передатчик свободен - clunet_set_line(0); // Отпускаем линию - wake_up_interruptible(&wq_data); // Wake up, i'm ready for new data! - } - /* Иначе если передачу необходимо продолжить, то сначала проверим на конфликт */ - else if (!clunet_sending && CLUNET_READING) - { - clunet_sending_state = CLUNET_SENDING_STATE_WAITING_LINE; // Переходим в режим ожидания линии - } - /* Все в порядке, можем продолжать */ - else - { - clunet_set_line(!clunet_sending); // Инвертируем значение сигнала - - /* Если отпустили линию, то запланируем время паузы перед следующей передачей длительностью 1Т */ - if (!clunet_sending) + /* If data sending is done, free transmitter */ + if (!clunet_sending_state + || clunet_sending_state == CLUNET_SENDING_STATE_DONE) { + /* Free transmitter */ + clunet_sending_state = CLUNET_SENDING_STATE_IDLE; + /* Release line */ + clunet_set_line(0); + /* Wake up, i'm ready for new data! */ + wake_up_interruptible(&wq_data); + } else if (!clunet_sending && CLUNET_READING) { + /* If transmitting data and line is already busy */ + /* Waiting for line */ + clunet_sending_state = CLUNET_SENDING_STATE_WAITING_LINE; + } else { + /* Continue transmission */ + clunet_set_line(!clunet_sending); /* Invert line value */ + + if (!clunet_sending) /* If line is released */ { + /* Scedule timer for T */ set_send_timer(CLUNET_T); - } - /* Если прижали линию к земле, то запланируем время передачи сигнала в зависимости от текущей фазы передачи */ - /* Фаза передачи данных */ - else if (clunet_sending_state == CLUNET_SENDING_STATE_DATA) - { - /* Планируем следующее прерывание в зависимости от значения бита */ - set_send_timer((out_buffer[clunet_sending_current_byte] & (1 << clunet_sending_current_bit)) ? CLUNET_1_T : CLUNET_0_T); - /* Если передан байт данных */ + } else if (clunet_sending_state == CLUNET_SENDING_STATE_DATA) { + /* Transferring data otherwise */ + /* Timer value depends on next bit value */ + set_send_timer((out_buffer[clunet_sending_current_byte] & + (1 << clunet_sending_current_bit)) ? CLUNET_1_T : CLUNET_0_T); + /* Every 8 bits... */ if (++clunet_sending_current_bit & 8) { - /* Если не все данные отосланы */ - if (++clunet_sending_current_byte < clunet_sending_data_length) - clunet_sending_current_bit = 0; // начинаем передачу следующего байта с бита 0 - /* Иначе передача всех данных закончена */ + /* If there are not more data */ + if (++clunet_sending_current_byte + < clunet_sending_data_length) + /* Next byte */ + clunet_sending_current_bit = 0; + /* End of transmission */ else - clunet_sending_state++; // переходим к следующей фазе завершения передачи пакета + /* Next stage */ + clunet_sending_state++; } - } - else + } else { /* Other stages */ switch (clunet_sending_state++) { - /* Фаза инициализации передачи пакета (время 10Т) */ + /* Init (holding line for 10Т) */ case CLUNET_SENDING_STATE_INIT: set_send_timer(CLUNET_INIT_T); break; - /* Фаза передачи приоритета (старший бит) */ + /* Priority (higher bit) */ case CLUNET_SENDING_STATE_PRIO1: - set_send_timer((clunet_sending_priority > 2) ? CLUNET_1_T : CLUNET_0_T); + set_send_timer((clunet_sending_priority > 2) + ? CLUNET_1_T + : CLUNET_0_T); break; - /* Фаза передачи приоритета (младший бит) */ + /* Priority (lower bit) */ case CLUNET_SENDING_STATE_PRIO2: - set_send_timer((clunet_sending_priority & 1) ? CLUNET_0_T : CLUNET_1_T); - clunet_sending_current_byte = clunet_sending_current_bit = 0; // Готовим счётчики передачи данных + set_send_timer((clunet_sending_priority & 1) + ? CLUNET_0_T + : CLUNET_1_T); + /* Reset counters */ + clunet_sending_current_byte + = clunet_sending_current_bit = 0; break; default: + /* Something weird happen */ clunet_set_line(0); - printk(KERN_ERR "CLUNET unknown sending state: %d\n", clunet_sending_state); + printk(KERN_ERR "CLUNET unknown sending state: %d\n", + clunet_sending_state); } + } } return HRTIMER_NORESTART; } -static void clunet_send(const uint8_t src_address, const uint8_t dst_address, const uint8_t prio, const uint8_t command, const char* data, const uint8_t size) +/* Function to schedule frame transmission */ +static void clunet_send(const uint8_t src_address, + const uint8_t dst_address, const uint8_t prio, + const uint8_t command, + const char* data, + const uint8_t size) { u8 i; - /* Если размер данных в пределах буфера передачи (максимально для протокола 250 байт) */ - if (size < (CLUNET_SEND_BUFFER_SIZE - CLUNET_OFFSET_DATA)) - { - /* Прерываем текущую передачу, если есть такая */ - if (clunet_sending_state) - { - if (data_send_timer) - hrtimer_try_to_cancel(data_send_timer); - clunet_set_line(0); - } - - /* Заполняем переменные */ - clunet_sending_priority = (prio > 4) ? 4 : prio ? : 1; // Ограничим приоритет диапазоном (1 ; 4) - out_buffer[CLUNET_OFFSET_SRC_ADDRESS] = src_address; - out_buffer[CLUNET_OFFSET_DST_ADDRESS] = dst_address; - out_buffer[CLUNET_OFFSET_COMMAND] = command; - out_buffer[CLUNET_OFFSET_SIZE] = size; - - /* Копируем данные в буфер */ - for (i = 0; i < size; i++) - out_buffer[CLUNET_OFFSET_DATA + i] = data[i]; - - /* Добавляем контрольную сумму */ - out_buffer[CLUNET_OFFSET_DATA + size] = check_crc((char*)out_buffer, CLUNET_OFFSET_DATA + size); - - clunet_sending_data_length = size + (CLUNET_OFFSET_DATA + 1); + /* Check data size */ + if (size >= (CLUNET_SEND_BUFFER_SIZE - CLUNET_OFFSET_DATA)) + return; + + /* Abort current transmission if any */ + if (clunet_sending_state) { + if (data_send_timer) + hrtimer_try_to_cancel(data_send_timer); + clunet_set_line(0); + } - // Если линия свободна, то запланируем передачу сразу - if (!CLUNET_READING) - { - clunet_sending_state = CLUNET_SENDING_STATE_INIT; - set_send_timer(CLUNET_SEND_PAUSE_T); - } - // Иначе будем ожидать когда освободится в процедуре внешнего прерывания - else - { - clunet_sending_state = CLUNET_SENDING_STATE_WAITING_LINE; - } + /* Fill the data */ + clunet_sending_priority = (prio > 4) ? 4 : prio ? : 1; + out_buffer[CLUNET_OFFSET_SRC_ADDRESS] = src_address; + out_buffer[CLUNET_OFFSET_DST_ADDRESS] = dst_address; + out_buffer[CLUNET_OFFSET_COMMAND] = command; + out_buffer[CLUNET_OFFSET_SIZE] = size; + for (i = 0; i < size; i++) + out_buffer[CLUNET_OFFSET_DATA + i] = data[i]; + /* Calculate checksum */ + out_buffer[CLUNET_OFFSET_DATA + size] + = check_crc((char*)out_buffer, CLUNET_OFFSET_DATA + size); + clunet_sending_data_length = size + (CLUNET_OFFSET_DATA + 1); + + /* Start transfer immidiatly if line is free */ + if (!CLUNET_READING) { + clunet_sending_state = CLUNET_SENDING_STATE_INIT; + set_send_timer(CLUNET_SEND_PAUSE_T); + } else { /* Schedule it otherwise */ + clunet_sending_state = CLUNET_SENDING_STATE_WAITING_LINE; } } -/** @brief The device open function that is called each time the device is opened - * @param inodep A pointer to an inode object (defined in linux/fs.h) - * @param filep A pointer to a file object (defined in linux/fs.h) - */ +/* The device open function that is called each time the device is opened */ static int clunet_dev_open(struct inode *inodep, struct file *filep) { int d_address = -1; @@ -417,24 +433,18 @@ static int clunet_dev_open(struct inode *inodep, struct file *filep) return 0; } -/** @brief This function is called whenever device is being read from user space i.e. data is - * being sent from the device to the user. In this case is uses the copy_to_user() function to - * send the buffer string to the user and captures any errors. - * @param filep A pointer to a file object (defined in linux/fs.h) - * @param buffer The pointer to the buffer to which this function writes the data - * @param len The length of the b - * @param offset The offset if required +/* This function is called whenever device is being read from user space i.e. data is + * being sent from the device to the user. In this case is uses the copy_to_user() function to + * send the buffer string to the user and captures any errors. */ static ssize_t clunet_dev_read(struct file *filep, char *buffer, size_t len, loff_t *offset) { ssize_t r; r = 0; - while (len) - { + while (len) { if (((struct cfile_t*)filep->private_data)->receiver_write_pos - (*offset) > RECEIVER_BUFFER_SIZE) return -ENOTRECOVERABLE; - if (*offset == ((struct cfile_t*)filep->private_data)->receiver_write_pos) - { + if (*offset == ((struct cfile_t*)filep->private_data)->receiver_write_pos) { if (r) return r; if (filep->f_flags & O_NONBLOCK) return -EAGAIN; @@ -453,13 +463,9 @@ static ssize_t clunet_dev_read(struct file *filep, char *buffer, size_t len, lof return r; } -/** @brief This function is called whenever the device is being written to from user space i.e. - * data is sent to the device from the user. The data is copied to the message[] array in this - * LKM using the sprintf() function along with the length of the string. - * @param filep A pointer to a file object - * @param buffer The buffer to that contains the string to write to the device - * @param len The length of the array of data that is being passed in the const char buffer - * @param offset The offset if required +/* This function is called whenever the device is being written to from user space i.e. + * data is sent to the device from the user. The data is copied to the message[] array in this + * LKM using the sprintf() function along with the length of the string. */ static ssize_t clunet_dev_write(struct file *filep, const char *buffer, size_t len, loff_t *offset) { @@ -471,11 +477,9 @@ static ssize_t clunet_dev_write(struct file *filep, const char *buffer, size_t l int d_address; r = 0; d_address = ((struct cfile_t*)filep->private_data)->device_address; - while (r < len) - { + while (r < len) { if (((struct cfile_t*)filep->private_data)->transmitter_write_pos - >= TRANSMITTER_BUFFER_SIZE) - { + >= TRANSMITTER_BUFFER_SIZE) { ((struct cfile_t*)filep->private_data)->transmitter_write_pos = 0; return -ENOBUFS; } @@ -483,25 +487,22 @@ static ssize_t clunet_dev_write(struct file *filep, const char *buffer, size_t l return -EIO; r++; buffer++; - if (ch == '\n') - { + if (ch == '\n') { /* End of line */ l = ((struct cfile_t*)filep->private_data)->transmitter_write_pos; - if (!l) break; // Empty line? Skip it. + if (!l) break; /* Empty line? Skip it */ decoded = kmalloc(l / 2 + 1, GFP_KERNEL); if (!decoded) - return -ENOMEM; - if (d_address < 0) // Bus? - { + return -ENOMEM; /* Can't allocate memory */ + if (d_address < 0) { /* Bus? */ p = 1; decoded[0] = 0; - } else { // Device? Skip priority, source address and dst address + } else { /* Device? Skip priority, source address and dst address */ p = 3 * 2; - decoded[0] = 4; // Always high priority - decoded[1] = address; // Our address - decoded[2] = d_address; // Device address + decoded[0] = 4; /* Always high priority */ + decoded[1] = address; /* Our address */ + decoded[2] = d_address; /* Device address */ } - for (i = 0; i < l; i++) - { + for (i = 0; i < l; i++) { ch = ((struct cfile_t*)filep->private_data)->transmitter_buffer[i]; if (ch >= '0' && ch <= '9') v = ch - '0'; @@ -519,41 +520,42 @@ static ssize_t clunet_dev_write(struct file *filep, const char *buffer, size_t l } ((struct cfile_t*)filep->private_data)->transmitter_write_pos = 0; p >>= 1; - if (p < 4 || decoded[0] == 0 || decoded[0] > 4) // Invalid command - { + if (p < 4 || decoded[0] == 0 || decoded[0] > 4) { + /* Invalid command */ kfree(decoded); return -EBADMSG; } - // Only one thread can really wait for free line - if (mutex_lock_interruptible(&m_wait_for_line)) - { + /* Only one thread can really wait for free line */ + if (mutex_lock_interruptible(&m_wait_for_line)) { + /* Interrupted, fine */ kfree(decoded); return -ERESTARTSYS; } - // Line is busy - if (clunet_sending_state != CLUNET_SENDING_STATE_IDLE) - { - if (filep->f_flags & O_NONBLOCK) - { - // Oh, we shouldn't wait for line, bye-bye + if (clunet_sending_state != CLUNET_SENDING_STATE_IDLE) { + /* Line is busy, should i block? */ + if (filep->f_flags & O_NONBLOCK) { + /* Oh, i shouldn't wait for line, bye-bye */ kfree(decoded); mutex_unlock(&m_wait_for_line); return -EBUSY; } - // Waiting... - if (wait_event_interruptible(wq_data, clunet_sending_state == CLUNET_SENDING_STATE_IDLE)) - { + /* Blocking and sleeping until transmitter ready */ + if (wait_event_interruptible( + wq_data, clunet_sending_state + == CLUNET_SENDING_STATE_IDLE)) { kfree(decoded); mutex_unlock(&m_wait_for_line); return -ERESTARTSYS; } } - // Ok, it's time to enqueue data + /* Ok, it's time to enqueue data */ clunet_send(decoded[1], decoded[2], decoded[0], decoded[3], decoded+4, p-4); - // Cleanup + /* Cleanup */ kfree(decoded); + /* Unlocking mutex */ mutex_unlock(&m_wait_for_line); - break; // Stop it + /* Return to userspace */ + break; } ((struct cfile_t*)filep->private_data)->transmitter_buffer[ ((struct cfile_t*)filep->private_data)->transmitter_write_pos++ @@ -562,10 +564,8 @@ static ssize_t clunet_dev_write(struct file *filep, const char *buffer, size_t l return r; } -/** @brief The device release function that is called whenever the device is closed/released by - * the userspace program - * @param inodep A pointer to an inode object (defined in linux/fs.h) - * @param filep A pointer to a file object (defined in linux/fs.h) +/* The device release function that is called whenever the device is closed/released by + * the userspace program */ static int clunet_dev_release(struct inode *inodep, struct file *filep) { @@ -578,6 +578,7 @@ static int clunet_dev_release(struct inode *inodep, struct file *filep) return 0; } +/* File operations */ static struct file_operations fops = { .open = clunet_dev_open, @@ -586,98 +587,104 @@ static struct file_operations fops = .release = clunet_dev_release, }; +/* Main init function */ static int __init clunet_init(void) { int r; dev_t dev; + /* Allocate and prepare memory */ memset(opened_files, 0, sizeof(opened_files)); + /* Allocate and init the timer */ data_send_timer = kzalloc(sizeof(struct hrtimer), GFP_KERNEL); - if (!data_send_timer) - { + if (!data_send_timer) { printk(KERN_ERR "CLUNET: can't allocate memory for timer\n"); clunet_free(); return -1; } hrtimer_init(data_send_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); data_send_timer->function = send_timer_callback; + /* Allocate the receiver pin */ receive_pin_desc = gpio_to_desc(receive_pin); - if (IS_ERR(receive_pin_desc)) - { + if (IS_ERR(receive_pin_desc)) { printk(KERN_ERR "CLUNET: receive_pin gpiod_request error: %ld\n", PTR_ERR(receive_pin_desc)); clunet_free(); return -1; } gpiod_direction_input(receive_pin_desc); + /* Allocate the transmitter pin */ transmit_pin_desc = gpio_to_desc(transmit_pin); - if (IS_ERR(transmit_pin_desc)) - { + if (IS_ERR(transmit_pin_desc)) { printk(KERN_ERR "CLUNET: transmit_pin gpiod_request error: %ld\n", PTR_ERR(transmit_pin_desc)); clunet_free(); return -1; } clunet_set_line(0); + /* Prepare the IRQ for receiver */ irq_number = gpiod_to_irq(receive_pin_desc); - r = request_irq(irq_number, // The interrupt number requested - (irq_handler_t) clunet_irq_handler, // The pointer to the handler function below - IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, // Interrupt on falling edge - "clunet_handler", // Used in /proc/interrupts to identify the owner - NULL); // The *dev_id for shared interrupt lines, NULL is okay - if (r) - { + r = request_irq( + /* The interrupt number requested */ + irq_number, + /* The pointer to the handler function below */ + (irq_handler_t) clunet_irq_handler, + /* Interrupt on falling edge */ + IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, + /* Used in /proc/interrupts to identify the owner */ + "clunet_handler", + NULL); + if (r) { printk(KERN_ERR "CLUNET: receive_pin request_irq error: %d\n", r); clunet_free(); return -1; } - // Register the device class + /* Register the device class */ clunet_class = class_create(THIS_MODULE, CLASS_NAME); - if (clunet_class == NULL) - { + if (clunet_class == NULL) { printk(KERN_ERR "CLUNET: failed to register device class\n"); clunet_free(); return -1; } + /* Allocate character device region for bus (1 device) */ r = alloc_chrdev_region(&dev, 0, 1, DEVICE_NAME_BUS); - if (r) - { + if (r) { printk(KERN_ERR "CLUNET: failed to allocate chrdev region: %d\n", r); clunet_free(); return -1; } clunet_bus_major = MAJOR(dev); + /* Create the bus device in /dev */ clunet_bus_device = device_create(clunet_class, NULL, dev, NULL, DEVICE_NAME_BUS_FILE); - if (clunet_bus_device == NULL) - { + if (clunet_bus_device == NULL) { printk(KERN_ERR "CLUNET: failed to create /dev/%s\n", DEVICE_NAME_BUS_FILE); clunet_free(); return -1; } + /* Attach it to file operations */ cdev_init(&clunet_bus_cdev, &fops); clunet_bus_cdev.owner = THIS_MODULE; r = cdev_add(&clunet_bus_cdev, dev, 1); - if (r) - { + if (r) { printk(KERN_ERR "CLUNET: failed to add chrdev: %d\n", r); clunet_free(); return -1; } - + /* Allocate character device region for CLUNET devices (256 devices) */ r = alloc_chrdev_region(&dev, 0, 256, DEVICE_NAME_CUSTOM); - if (r) - { + if (r) { printk(KERN_ERR "CLUNET: failed to allocate chrdev region (device): %d\n", r); clunet_free(); return -1; } + /* Attach them to file operations */ clunet_device_major = MAJOR(dev); cdev_init(&clunet_device_cdev, &fops); clunet_device_cdev.owner = THIS_MODULE; r = cdev_add(&clunet_device_cdev, dev, 256); - if (r) - { + if (r) { printk(KERN_ERR "CLUNET: failed to add chrdev (device): %d\n", r); clunet_free(); return -1; } + /* Send startup message */ clunet_send ( address, CLUNET_BROADCAST_ADDRESS, @@ -691,40 +698,44 @@ static int __init clunet_init(void) return 0; } +/* Function to release all handles */ static void clunet_free(void) { - if (data_send_timer) - { + /* Timer */ + if (data_send_timer) { hrtimer_try_to_cancel(data_send_timer); kfree(data_send_timer); } - if (clunet_class && clunet_bus_major) - { + /* Devices */ + if (clunet_class && clunet_bus_major) { cdev_del(&clunet_bus_cdev); - device_destroy(clunet_class, MKDEV(clunet_bus_major, 0)); // remove the device + device_destroy(clunet_class, MKDEV(clunet_bus_major, 0)); } - if (clunet_device_major) - { + /* chrdev regions */ + if (clunet_device_major) { cdev_del(&clunet_device_cdev); unregister_chrdev_region(MKDEV(clunet_device_major, 0), 256); } if (clunet_bus_major) - { unregister_chrdev_region(MKDEV(clunet_bus_major, 0), 1); + /* Class */ + if (clunet_class) { + /* Unregister the device class */ + class_unregister(clunet_class); + /* Remove the device class */ + class_destroy(clunet_class); } - if (clunet_class) - { - class_unregister(clunet_class); // unregister the device class - class_destroy(clunet_class); // remove the device class - } + /* IRQ */ if (irq_number != 0xffff) free_irq(irq_number, NULL); + /* GPIO pins */ if (!IS_ERR_OR_NULL(receive_pin_desc)) gpiod_put(receive_pin_desc); if (!IS_ERR_OR_NULL(transmit_pin_desc)) gpiod_put(transmit_pin_desc); } +/* Exit function */ static void __exit clunet_exit(void) { clunet_free(); |