static void hfc_sys_chan_rx_work(void *data) { struct hfc_sys_chan *chan = data; struct hfc_card *card = chan->port->card; struct hfc_fifo *fifo = &chan->rx_fifo; int frame_size; struct sk_buff *skb; struct { u8 crc[2], stat; } __attribute((packed)) stat; hfc_card_lock(card); // FIFO selection has to be done for each frame to clear // internal buffer (see specs 4.4.4). hfc_fifo_select(fifo); if (!hfc_fifo_has_frames(fifo)) goto no_frames; // frame_size includes CRC+CRC+STAT frame_size = hfc_fifo_get_frame_size(fifo); if (frame_size < 3) { hfc_debug_sys_chan(chan, 3, "invalid frame received, just %d bytes\n", frame_size); visdn_leg_rx_error(&chan->visdn_chan.leg_b, VISDN_RX_ERROR_LENGTH); goto err_invalid_frame; } else if(frame_size == 3) { hfc_debug_sys_chan(chan, 3, "empty frame received\n"); visdn_leg_rx_error(&chan->visdn_chan.leg_b, VISDN_RX_ERROR_LENGTH); goto err_empty_frame; } skb = visdn_alloc_skb(frame_size - 3); if (!skb) { hfc_msg_sys_chan(chan, KERN_ERR, "cannot allocate skb: frame dropped\n"); visdn_leg_rx_error(&chan->visdn_chan.leg_b, VISDN_RX_ERROR_DROPPED); goto err_alloc_skb; } hfc_fifo_mem_read(fifo, skb_put(skb, frame_size - 3), frame_size - 3); hfc_fifo_mem_read(fifo, &stat, sizeof(stat)); #ifdef DEBUG_CODE if(debug_level == 3) { hfc_debug_sys_chan(chan, 3, "RX len %2d: ", frame_size); } else if(debug_level >= 4) { hfc_debug_sys_chan(chan, 4, "RX (f1=%02x, f2=%02x, z1(f1)=%04x, z2(f1)=%04x)" " len %2d: ", fifo->f1, fifo->f2, fifo->z1, fifo->z2, frame_size); } if (debug_level >= 3) { int i; for (i=0; i<frame_size - 3; i++) printk("%02x", ((u8 *)skb->data)[i]); printk("%02x%02x %02x\n", stat.crc[0], stat.crc[1], stat.stat); } #endif if (stat.stat == 0xff) { // Frame abort detected hfc_debug_sys_chan(chan, 3, "Frame abort detected\n"); visdn_leg_rx_error(&chan->visdn_chan.leg_b, VISDN_RX_ERROR_FR_ABORT); goto err_frame_abort; } else if (stat.stat != 0x00) { // CRC not ok, frame broken, skipping hfc_debug_sys_chan(chan, 2, "Received frame with wrong CRC\n"); visdn_leg_rx_error(&chan->visdn_chan.leg_b, VISDN_RX_ERROR_CRC); goto err_crc_error; } hfc_fifo_next_frame(fifo); visdn_leg_frame_xmit( &chan->visdn_chan.leg_b, skb); #if 0 if (chan->connected_e1_chan) { struct hfc_led *led = &card->leds[chan->connected_e1_chan->port->id]; led->alt_color = HFC_LED_OFF; led->flashing_freq = HZ / 10; led->flashes = 1; hfc_led_update(led); } #endif goto all_went_well; err_crc_error: err_frame_abort: kfree_skb(skb); err_alloc_skb: err_empty_frame: err_invalid_frame: hfc_fifo_drop_frame(fifo); no_frames: all_went_well: hfc_fifo_refresh_fz_cache(fifo); if (hfc_fifo_has_frames(fifo)) schedule_work(&chan->rx_work); hfc_card_unlock(card); }
int hfc_fifo_get_frame(struct hfc_chan_simplex *chan, void *data, int max_size) { int frame_size; u16 newz2 ; if (*chan->f1 == *chan->f2) { /* * nothing received, strange uh? */ printk(KERN_WARNING hfc_DRIVER_PREFIX "card %d: " "chan %s: " "get_frame called with no frame in FIFO.\n", chan->chan->card->cardnum, chan->chan->name); return -1; } /* * frame_size includes CRC+CRC+STAT */ frame_size = hfc_fifo_get_frame_size(chan); #ifdef DEBUG if (debug_level == 3) { printk(KERN_DEBUG hfc_DRIVER_PREFIX "card %d: " "chan %s: " "RX len %2d: ", chan->chan->card->cardnum, chan->chan->name, frame_size); } else if (debug_level >= 4) { printk(KERN_DEBUG hfc_DRIVER_PREFIX "card %d: " "chan %s: " "RX (f1=%02x, f2=%02x, z1=%04x, z2=%04x) len %2d: ", chan->chan->card->cardnum, chan->chan->name, *chan->f1, *chan->f2, *Z1_F2(chan), *Z2_F2(chan), frame_size); } if (debug_level >= 3) { int i; for (i = 0; i < frame_size; i++) { printk("%02x", hfc_fifo_u8(chan, Z_inc(chan, *Z2_F2(chan), i))); } printk("\n"); } #endif if (frame_size <= 0) { #ifdef DEBUG if (debug_level >= 2) { printk(KERN_DEBUG hfc_DRIVER_PREFIX "card %d: " "chan %s: " "invalid (empty) frame received.\n", chan->chan->card->cardnum, chan->chan->name); } #endif hfc_fifo_drop_frame(chan); return -1; } /* * STAT is not really received */ chan->bytes += frame_size - 1; /* * Calculate beginning of the next frame */ newz2 = Z_inc(chan, *Z2_F2(chan), frame_size); /* * We cannot use hfc_fifo_get because of different semantic of * "available bytes" and to avoid useless increment of Z2 */ hfc_fifo_mem_read(chan, *Z2_F2(chan), data, frame_size < max_size ? frame_size : max_size); if (hfc_fifo_u8(chan, Z_inc(chan, *Z2_F2(chan), frame_size - 1)) != 0x00) { /* * CRC not ok, frame broken, skipping */ #ifdef DEBUG if (debug_level >= 2) { printk(KERN_WARNING hfc_DRIVER_PREFIX "card %d: " "chan %s: " "Received frame with wrong CRC\n", chan->chan->card->cardnum, chan->chan->name); } #endif chan->crc++; hfc_fifo_drop_frame(chan); return -1; } chan->frames++; *chan->f2 = F_inc(chan, *chan->f2, 1); /* * Set Z2 for the next frame we're going to receive */ *Z2_F2(chan) = newz2; return frame_size; }