/* At the card level there is no offset manipulation to get to the second port on each card. If you would like to pass in a register offset and get the appropriate address on a port basis use the fscc_port_* functions. */ void fscc_card_get_register_rep(struct fscc_card *card, unsigned bar, unsigned offset, char *buf, unsigned byte_count) { void *address = 0; unsigned leftover_count = 0; UINT32 incoming_data = 0; unsigned chunks = 0; unsigned i = 0; return_if_untrue(card); return_if_untrue(bar <= 2); return_if_untrue(buf); return_if_untrue(byte_count > 0); address = fscc_card_get_BAR(card, bar); leftover_count = byte_count % 4; chunks = (byte_count - leftover_count) / 4; for (i = 0; i < chunks; i++) { UINT32 value = 0; value = io_read(card, bar, (ULONG *)((char *)address + offset)); memcpy(&buf[i * 4], &value, sizeof(value)); } if (leftover_count) { incoming_data = io_read(card, bar, (ULONG *)((char *)address + offset)); memmove(buf + (byte_count - leftover_count), (char *)(&incoming_data), leftover_count); } #ifdef __BIG_ENDIAN { unsigned i = 0; for (i = 0; i < (int)(byte_count / 2); i++) { char first, last; first = buf[i]; last = buf[byte_count - i - 1]; buf[i] = last; buf[byte_count - i - 1] = first; } } #endif }
/* At the card level there is no offset manipulation to get to the second port on each card. If you would like to pass in a register offset and get the appropriate address on a port basis use the fscc_port_* functions. */ void fscc_card_set_register_rep(struct fscc_card *card, unsigned bar, unsigned offset, const char *data, unsigned byte_count) { void *address = 0; unsigned leftover_count = 0; unsigned chunks = 0; char *reversed_data = 0; const char *outgoing_data = 0; unsigned i = 0; return_if_untrue(card); return_if_untrue(bar <= 2); return_if_untrue(data); return_if_untrue(byte_count > 0); address = fscc_card_get_BAR(card, bar); leftover_count = byte_count % 4; chunks = (byte_count - leftover_count) / 4; outgoing_data = data; #ifdef __BIG_ENDIAN { unsigned i = 0; reversed_data = (char *)ExAllocatePoolWithTag(NonPagedPool, byte_count, 'ataD'); for (i = 0; i < byte_count; i++) reversed_data[i] = data[byte_count - i - 1]; outgoing_data = reversed_data; } #endif for (i = 0; i < chunks; i++) io_write(card, bar, (ULONG *)((char *)address + offset), chars_to_u32(outgoing_data + (i * 4))); if (leftover_count) io_write(card, bar, (ULONG *)((char *)address + offset), chars_to_u32(outgoing_data + (byte_count - leftover_count))); if (reversed_data) ExFreePoolWithTag (reversed_data, 'ataD'); }
void fscc_frame_delete(struct fscc_frame *frame) { return_if_untrue(frame); fscc_frame_update_buffer_size(frame, 0); ExFreePoolWithTag(frame, 'marF'); }
void oframe_worker(unsigned long data) { struct fscc_port *port = 0; int result; unsigned long board_flags = 0; unsigned long frame_flags = 0; unsigned long sent_flags = 0; unsigned long queued_flags = 0; port = (struct fscc_port *)data; return_if_untrue(port); spin_lock_irqsave(&port->board_tx_spinlock, board_flags); spin_lock_irqsave(&port->pending_oframe_spinlock, frame_flags); /* Check if exists and if so, grabs the frame to transmit. */ if (!port->pending_oframe) { spin_lock_irqsave(&port->queued_oframes_spinlock, queued_flags); port->pending_oframe = fscc_flist_remove_frame(&port->queued_oframes); spin_unlock_irqrestore(&port->queued_oframes_spinlock, queued_flags); /* No frames in queue to transmit */ if (!port->pending_oframe) { spin_unlock_irqrestore(&port->pending_oframe_spinlock, frame_flags); spin_unlock_irqrestore(&port->board_tx_spinlock, board_flags); return; } } result = fscc_port_transmit_frame(port, port->pending_oframe); if (result == 2) { spin_lock_irqsave(&port->sent_oframes_spinlock, sent_flags); fscc_flist_add_frame(&port->sent_oframes, port->pending_oframe); spin_unlock_irqrestore(&port->sent_oframes_spinlock, sent_flags); port->pending_oframe = 0; } spin_unlock_irqrestore(&port->pending_oframe_spinlock, frame_flags); spin_unlock_irqrestore(&port->board_tx_spinlock, board_flags); if (result == 2) wake_up_interruptible(&port->output_queue); }
void iframe_worker(unsigned long data) { struct fscc_port *port = 0; int receive_length = 0; /* Needs to be signed */ unsigned finished_frame = 0; unsigned long board_flags = 0; unsigned long frame_flags = 0; unsigned long queued_flags = 0; static int rejected_last_frame = 0; unsigned current_memory = 0; unsigned memory_cap = 0; unsigned rfcnt = 0; port = (struct fscc_port *)data; return_if_untrue(port); do { current_memory = fscc_port_get_input_memory_usage(port); memory_cap = fscc_port_get_input_memory_cap(port); spin_lock_irqsave(&port->board_rx_spinlock, board_flags); spin_lock_irqsave(&port->pending_iframe_spinlock, frame_flags); rfcnt = fscc_port_get_RFCNT(port); finished_frame = (rfcnt > 0) ? 1 : 0; if (finished_frame) { unsigned bc_fifo_l = 0; unsigned current_length = 0; bc_fifo_l = fscc_port_get_register(port, 0, BC_FIFO_L_OFFSET); if (port->pending_iframe) current_length = fscc_frame_get_length(port->pending_iframe); receive_length = bc_fifo_l - current_length; } else { unsigned rxcnt = 0; // Refresh rfcnt, if the frame is now complete, reloop through // This prevents the situation where the frame has finished being // received between the original rfcnt and now, causing a possible // read of a larger byte count than in the actual frame due to // another incoming frame rxcnt = fscc_port_get_RXCNT(port); rfcnt = fscc_port_get_RFCNT(port); if (rfcnt) { spin_unlock_irqrestore(&port->pending_iframe_spinlock, frame_flags); spin_unlock_irqrestore(&port->board_rx_spinlock, board_flags); break; } /* We choose a safe amount to read due to more data coming in after we get our values. The rest will be read on the next interrupt. */ receive_length = max((int)(rxcnt - rxcnt % 4), (int)0); } if (receive_length <= 0) { spin_unlock_irqrestore(&port->pending_iframe_spinlock, frame_flags); spin_unlock_irqrestore(&port->board_rx_spinlock, board_flags); return; } /* Make sure we don't go over the user's memory constraint. */ if (current_memory + receive_length > memory_cap) { if (rejected_last_frame == 0) { dev_warn(port->device, "Rejecting frames (memory constraint)\n"); rejected_last_frame = 1; /* Track that we dropped a frame so we don't have to warn the user again. */ } if (port->pending_iframe) { fscc_frame_delete(port->pending_iframe); port->pending_iframe = 0; } spin_unlock_irqrestore(&port->pending_iframe_spinlock, frame_flags); spin_unlock_irqrestore(&port->board_rx_spinlock, board_flags); return; } if (!port->pending_iframe) { port->pending_iframe = fscc_frame_new(port); if (!port->pending_iframe) { spin_unlock_irqrestore(&port->pending_iframe_spinlock, frame_flags); spin_unlock_irqrestore(&port->board_rx_spinlock, board_flags); return; } } fscc_frame_add_data_from_port(port->pending_iframe, port, receive_length); #ifdef __BIG_ENDIAN { char status[STATUS_LENGTH]; /* Moves the status bytes to the end. */ memmove(&status, port->pending_iframe->data, STATUS_LENGTH); memmove(port->pending_iframe->data, port->pending_iframe->data + STATUS_LENGTH, port->pending_iframe->current_length - STATUS_LENGTH); memmove(port->pending_iframe->data + port->pending_iframe->current_length - STATUS_LENGTH, &status, STATUS_LENGTH); } #endif dev_dbg(port->device, "F#%i <= %i byte%s (%sfinished)\n", port->pending_iframe->number, receive_length, (receive_length == 1) ? "" : "s", (finished_frame) ? "" : "un"); if (!finished_frame) { spin_unlock_irqrestore(&port->pending_iframe_spinlock, frame_flags); spin_unlock_irqrestore(&port->board_rx_spinlock, board_flags); return; } if (port->pending_iframe) { #ifdef RELEASE_PREVIEW getnstimeofday(&port->pending_iframe->timestamp); #else do_gettimeofday(&port->pending_iframe->timestamp); #endif spin_lock_irqsave(&port->queued_iframes_spinlock, queued_flags); fscc_flist_add_frame(&port->queued_iframes, port->pending_iframe); spin_unlock_irqrestore(&port->queued_iframes_spinlock, queued_flags); } rejected_last_frame = 0; /* Track that we received a frame to reset the memory constraint warning print message. */ port->pending_iframe = 0; spin_unlock_irqrestore(&port->pending_iframe_spinlock, frame_flags); spin_unlock_irqrestore(&port->board_rx_spinlock, board_flags); wake_up_interruptible(&port->input_queue); } while (receive_length); }
void istream_worker(unsigned long data) { struct fscc_port *port = 0; int receive_length = 0; /* Needs to be signed */ unsigned rxcnt = 0; unsigned long board_flags = 0; unsigned long stream_flags = 0; unsigned current_memory = 0; unsigned memory_cap = 0; static int rejected_last_stream = 0; unsigned status; port = (struct fscc_port *)data; return_if_untrue(port); current_memory = fscc_port_get_input_memory_usage(port); memory_cap = fscc_port_get_input_memory_cap(port); /* Leave the interrupt handler if we are at our memory cap. */ if (current_memory >= memory_cap) { if (rejected_last_stream == 0) { dev_warn(port->device, "Rejecting stream (memory constraint)\n"); rejected_last_stream = 1; /* Track that we dropped stream data so we don't have to warn the user again. */ } return; } spin_lock_irqsave(&port->board_rx_spinlock, board_flags); rxcnt = fscc_port_get_RXCNT(port); /* We choose a safe amount to read due to more data coming in after we get our values. The rest will be read on the next interrupt. */ receive_length = rxcnt - MAX_LEFTOVER_BYTES; receive_length -= receive_length % 4; /* Leave the interrupt handler if there is no data to read. */ if (receive_length <= 0) { spin_unlock_irqrestore(&port->board_rx_spinlock, board_flags); return; } /* Trim the amount to read if there isn't enough memory space to read all of it. */ if (receive_length + current_memory > memory_cap) receive_length = memory_cap - current_memory; spin_lock_irqsave(&port->istream_spinlock, stream_flags); status = fscc_frame_add_data_from_port(port->istream, port, receive_length); spin_unlock_irqrestore(&port->istream_spinlock, stream_flags); if (status == 0) { dev_err(port->device, "Error adding stream data"); spin_unlock_irqrestore(&port->board_rx_spinlock, board_flags); return; } spin_unlock_irqrestore(&port->board_rx_spinlock, board_flags); rejected_last_stream = 0; /* Track that we received stream data to reset the memory constraint warning print message. */ dev_dbg(port->device, "Stream <= %i byte%s\n", receive_length, (receive_length == 1) ? "" : "s"); wake_up_interruptible(&port->input_queue); }