Commit 928a7b8a authored by Tobias Mädel's avatar Tobias Mädel

zaphfc: Port support for HFC-S cards

This ports the current zaphfc driver from the Debian bullseye patchset.

Change-Id: Ifd09d82ea2b6d6245207609da849350db45d91f6
parent 4fad5eb9
......@@ -55,6 +55,10 @@ obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_ECHOCAN_STEVE2) += dahdi_echocan_sec2.o
obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_ECHOCAN_KB1) += dahdi_echocan_kb1.o
obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_ECHOCAN_MG2) += dahdi_echocan_mg2.o
ifdef CONFIG_PCI
obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_ZAPHFC) += zaphfc/
endif
obj-m += $(DAHDI_MODULES_EXTRA)
# If you want to build OSLEC, include the code in the standard location:
......
......@@ -264,3 +264,16 @@ config DAHDI_ICE1USB
source "drivers/dahdi/xpp/Kconfig"
config DAHDI_ZAPHFC
tristate "HFC-S DAHDI Driver"
depends on DAHDI && PCI
default DAHDI
---help---
This driver provides DAHDI support for various HFC-S single-port
ISDN (BRI) cards.
To compile this driver as a module, choose M here: the
module will be called zaphfc.
If unsure, say Y.
obj-m += zaphfc.o
EXTRA_CFLAGS := -I$(src)/.. -Wno-undef
zaphfc-objs := base.o fifo.o
$(obj)/base.o: $(src)/zaphfc.h
$(obj)/fifo.o: $(src)/fifo.h
This diff is collapsed.
/*
* fifo.c - HFC FIFO management routines
*
* Copyright (C) 2006 headissue GmbH; Jens Wilke
* Copyright (C) 2004 Daniele Orlandi
* Copyright (C) 2002, 2003, 2004, Junghanns.NET GmbH
*
* Original author of this code is
* Daniele "Vihai" Orlandi <daniele@orlandi.com>
*
* This program is free software and may be modified and
* distributed under the terms of the GNU General Public License.
*
*/
#include <linux/kernel.h>
#include <dahdi/kernel.h>
#include "fifo.h"
static void hfc_fifo_mem_read(struct hfc_chan_simplex *chan,
int z_start,
void *data, int size)
{
int bytes_to_boundary = chan->z_max - z_start + 1;
if (bytes_to_boundary >= size) {
memcpy(data,
chan->z_base + z_start,
size);
} else {
/*
* Buffer wrap
*/
memcpy(data,
chan->z_base + z_start,
bytes_to_boundary);
memcpy(data + bytes_to_boundary,
chan->fifo_base,
size - bytes_to_boundary);
}
}
static void hfc_fifo_mem_write(struct hfc_chan_simplex *chan,
void *data, int size)
{
int bytes_to_boundary = chan->z_max - *Z1_F1(chan) + 1;
if (bytes_to_boundary >= size) {
memcpy(chan->z_base + *Z1_F1(chan),
data,
size);
} else {
/*
* FIFO wrap
*/
memcpy(chan->z_base + *Z1_F1(chan),
data,
bytes_to_boundary);
memcpy(chan->fifo_base,
data + bytes_to_boundary,
size - bytes_to_boundary);
}
}
int hfc_fifo_get(struct hfc_chan_simplex *chan,
void *data, int size)
{
int available_bytes;
/*
* Some useless statistic
*/
chan->bytes += size;
available_bytes = hfc_fifo_used_rx(chan);
if (available_bytes < size && !chan->fifo_underrun++) {
/*
* print the warning only once
*/
printk(KERN_WARNING hfc_DRIVER_PREFIX
"card %d: "
"chan %s: "
"RX FIFO not enough (%d) bytes to receive!\n",
chan->chan->card->cardnum,
chan->chan->name,
available_bytes);
return -1;
}
hfc_fifo_mem_read(chan, *Z2_F2(chan), data, size);
*Z2_F2(chan) = Z_inc(chan, *Z2_F2(chan), size);
return available_bytes - size;
}
void hfc_fifo_put(struct hfc_chan_simplex *chan,
void *data, int size)
{
struct hfc_card *card = chan->chan->card;
int used_bytes = hfc_fifo_used_tx(chan);
int free_bytes = hfc_fifo_free_tx(chan);
if (!used_bytes && !chan->fifo_underrun++) {
/*
* print warning only once, to make timing not worse
*/
printk(KERN_WARNING hfc_DRIVER_PREFIX
"card %d: "
"chan %s: "
"TX FIFO has become empty\n",
card->cardnum,
chan->chan->name);
}
if (free_bytes < size) {
printk(KERN_CRIT hfc_DRIVER_PREFIX
"card %d: "
"chan %s: "
"TX FIFO full!\n",
chan->chan->card->cardnum,
chan->chan->name);
chan->fifo_full++;
hfc_clear_fifo_tx(chan);
}
hfc_fifo_mem_write(chan, data, size);
chan->bytes += size;
*Z1_F1(chan) = Z_inc(chan, *Z1_F1(chan), size);
}
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;
}
void hfc_fifo_drop_frame(struct hfc_chan_simplex *chan)
{
int available_bytes;
u16 newz2;
if (*chan->f1 == *chan->f2) {
/*
* nothing received, strange eh?
*/
printk(KERN_WARNING hfc_DRIVER_PREFIX
"card %d: "
"chan %s: "
"skip_frame called with no frame in FIFO.\n",
chan->chan->card->cardnum,
chan->chan->name);
return;
}
available_bytes = hfc_fifo_used_rx(chan) + 1;
/*
* Calculate beginning of the next frame
*/
newz2 = Z_inc(chan, *Z2_F2(chan), available_bytes);
*chan->f2 = F_inc(chan, *chan->f2, 1);
/*
* Set Z2 for the next frame we're going to receive
*/
*Z2_F2(chan) = newz2;
}
void hfc_fifo_put_frame(struct hfc_chan_simplex *chan,
void *data, int size)
{
u16 newz1;
int available_frames;
#ifdef DEBUG
if (debug_level == 3) {
printk(KERN_DEBUG hfc_DRIVER_PREFIX
"card %d: "
"chan %s: "
"TX len %2d: ",
chan->chan->card->cardnum,
chan->chan->name,
size);
} else if (debug_level >= 4) {
printk(KERN_DEBUG hfc_DRIVER_PREFIX
"card %d: "
"chan %s: "
"TX (f1=%02x, f2=%02x, z1=%04x, z2=%04x) len %2d: ",
chan->chan->card->cardnum,
chan->chan->name,
*chan->f1, *chan->f2, *Z1_F1(chan), *Z2_F1(chan),
size);
}
if (debug_level >= 3) {
int i;
for (i = 0; i < size; i++)
printk("%02x", ((u8 *)data)[i]);
printk("\n");
}
#endif
available_frames = hfc_fifo_free_frames(chan);
if (available_frames >= chan->f_num) {
printk(KERN_CRIT hfc_DRIVER_PREFIX
"card %d: "
"chan %s: "
"TX FIFO total number of frames exceeded!\n",
chan->chan->card->cardnum,
chan->chan->name);
chan->fifo_full++;
return;
}
hfc_fifo_put(chan, data, size);
newz1 = *Z1_F1(chan);
*chan->f1 = F_inc(chan, *chan->f1, 1);
*Z1_F1(chan) = newz1;
chan->frames++;
}
void hfc_clear_fifo_rx(struct hfc_chan_simplex *chan)
{
*chan->f2 = *chan->f1;
*Z2_F2(chan) = *Z1_F2(chan);
}
void hfc_clear_fifo_tx(struct hfc_chan_simplex *chan)
{
*chan->f1 = *chan->f2;
*Z1_F1(chan) = *Z2_F1(chan);
if (chan->chan->status == open_voice) {
/*
* Make sure that at least hfc_TX_FIFO_PRELOAD bytes are
* present in the TX FIFOs
* Create hfc_TX_FIFO_PRELOAD bytes of empty data
* (0x7f is mute audio)
*/
u8 empty_fifo[hfc_TX_FIFO_PRELOAD +
DAHDI_CHUNKSIZE + hfc_RX_FIFO_PRELOAD];
memset(empty_fifo, 0x7f, sizeof(empty_fifo));
hfc_fifo_put(chan, empty_fifo, sizeof(empty_fifo));
}
}
/*
* fifo.h - Dahdi driver for HFC-S PCI A based ISDN BRI cards
*
* Copyright (C) 2004 Daniele Orlandi
* Copyright (C) 2002, 2003, 2004, Junghanns.NET GmbH
*
* Daniele "Vihai" Orlandi <daniele@orlandi.com>
*
* Major rewrite of the driver made by
* Klaus-Peter Junghanns <kpj@junghanns.net>
*
* This program is free software and may be modified and
* distributed under the terms of the GNU General Public License.
*
*/
#ifndef _HFC_FIFO_H
#define _HFC_FIFO_H
#include "zaphfc.h"
static inline u16 *Z1_F1(struct hfc_chan_simplex *chan)
{
return chan->z1_base + (*chan->f1 * 4);
}
static inline u16 *Z2_F1(struct hfc_chan_simplex *chan)
{
return chan->z2_base + (*chan->f1 * 4);
}
static inline u16 *Z1_F2(struct hfc_chan_simplex *chan)
{
return chan->z1_base + (*chan->f2 * 4);
}
static inline u16 *Z2_F2(struct hfc_chan_simplex *chan)
{
return chan->z2_base + (*chan->f2 * 4);
}
static inline u16 Z_inc(struct hfc_chan_simplex *chan, u16 z, u16 inc)
{
/*
* declared as u32 in order to manage overflows
*/
u32 newz = z + inc;
if (newz > chan->z_max)
newz -= chan->fifo_size;
return newz;
}
static inline u8 F_inc(struct hfc_chan_simplex *chan, u8 f, u8 inc)
{
/*
* declared as u16 in order to manage overflows
*/
u16 newf = f + inc;
if (newf > chan->f_max)
newf -= chan->f_num;
return newf;
}
static inline u16 hfc_fifo_used_rx(struct hfc_chan_simplex *chan)
{
return (*Z1_F2(chan) - *Z2_F2(chan) +
chan->fifo_size) % chan->fifo_size;
}
static inline u16 hfc_fifo_get_frame_size(struct hfc_chan_simplex *chan)
{
/*
* This +1 is needed because in frame mode the available bytes are Z2-Z1+1
* while in transparent mode I wouldn't consider the byte pointed by Z2 to
* be available, otherwise, the FIFO would always contain one byte, even
* when Z1==Z2
*/
return hfc_fifo_used_rx(chan) + 1;
}
static inline u8 hfc_fifo_u8(struct hfc_chan_simplex *chan, u16 z)
{
return *((u8 *)(chan->z_base + z));
}
static inline u16 hfc_fifo_used_tx(struct hfc_chan_simplex *chan)
{
return (*Z1_F1(chan) - *Z2_F1(chan) +
chan->fifo_size) % chan->fifo_size;
}
static inline u16 hfc_fifo_free_rx(struct hfc_chan_simplex *chan)
{
u16 free_bytes = *Z2_F1(chan) - *Z1_F1(chan);
if (free_bytes > 0)
return free_bytes;
else
return free_bytes + chan->fifo_size;
}
static inline u16 hfc_fifo_free_tx(struct hfc_chan_simplex *chan)
{
u16 free_bytes = *Z2_F1(chan) - *Z1_F1(chan);
if (free_bytes > 0)
return free_bytes;
else
return free_bytes + chan->fifo_size;
}
static inline int hfc_fifo_has_frames(struct hfc_chan_simplex *chan)
{
return *chan->f1 != *chan->f2;
}
static inline u8 hfc_fifo_used_frames(struct hfc_chan_simplex *chan)
{
return (*chan->f1 - *chan->f2 + chan->f_num) % chan->f_num;
}
static inline u8 hfc_fifo_free_frames(struct hfc_chan_simplex *chan)
{
return (*chan->f2 - *chan->f1 + chan->f_num) % chan->f_num;
}
int hfc_fifo_get(struct hfc_chan_simplex *chan, void *data, int size);
void hfc_fifo_put(struct hfc_chan_simplex *chan, void *data, int size);
void hfc_fifo_drop(struct hfc_chan_simplex *chan, int size);
int hfc_fifo_get_frame(struct hfc_chan_simplex *chan, void *data, int max_size);
void hfc_fifo_drop_frame(struct hfc_chan_simplex *chan);
void hfc_fifo_put_frame(struct hfc_chan_simplex *chan, void *data, int size);
void hfc_clear_fifo_rx(struct hfc_chan_simplex *chan);
void hfc_clear_fifo_tx(struct hfc_chan_simplex *chan);
#endif
/*
* zaphfc.h - Dahdi driver for HFC-S PCI A based ISDN BRI cards
*
* Dahdi port by Jose A. Deniz <odicha@hotmail.com>
*
* Copyright (C) 2009 Jose A. Deniz
* Copyright (C) 2006 headissue GmbH; Jens Wilke
* Copyright (C) 2004 Daniele Orlandi
* Copyright (C) 2002, 2003, 2004, Junghanns.NET GmbH
*
* Jens Wilke <jw_vzaphfc@headissue.com>
*
* Orginal author of this code is
* Daniele "Vihai" Orlandi <daniele@orlandi.com>
*
* Major rewrite of the driver made by
* Klaus-Peter Junghanns <kpj@junghanns.net>
*
* This program is free software and may be modified and
* distributed under the terms of the GNU General Public License.
*
*/
#ifndef _HFC_ZAPHFC_H
#define _HFC_ZAPHFC_H
#include <asm/io.h>
#define hfc_DRIVER_NAME "vzaphfc"
#define hfc_DRIVER_PREFIX hfc_DRIVER_NAME ": "
#define hfc_DRIVER_DESCR "HFC-S PCI A ISDN"
#define hfc_DRIVER_VERSION "1.42"
#define hfc_DRIVER_STRING hfc_DRIVER_DESCR " (V" hfc_DRIVER_VERSION ")"
#define hfc_MAX_BOARDS 32
#ifndef PCI_DMA_32BIT
#define PCI_DMA_32BIT 0x00000000ffffffffULL
#endif
#ifndef PCI_VENDOR_ID_SITECOM
#define PCI_VENDOR_ID_SITECOM 0x182D
#endif
#ifndef PCI_DEVICE_ID_SITECOM_3069
#define PCI_DEVICE_ID_SITECOM_3069 0x3069
#endif
#define hfc_RESET_DELAY 20
#define hfc_CLKDEL_TE 0x0f /* CLKDEL in TE mode */
#define hfc_CLKDEL_NT 0x6c /* CLKDEL in NT mode */
/* PCI memory mapped I/O */
#define hfc_PCI_MEM_SIZE 0x0100
#define hfc_PCI_MWBA 0x80
/* GCI/IOM bus monitor registers */
#define hfc_C_I 0x08
#define hfc_TRxR 0x0C
#define hfc_MON1_D 0x28
#define hfc_MON2_D 0x2C
/* GCI/IOM bus timeslot registers */
#define hfc_B1_SSL 0x80
#define hfc_B2_SSL 0x84
#define hfc_AUX1_SSL 0x88
#define hfc_AUX2_SSL 0x8C
#define hfc_B1_RSL 0x90
#define hfc_B2_RSL 0x94
#define hfc_AUX1_RSL 0x98
#define hfc_AUX2_RSL 0x9C
/* GCI/IOM bus data registers */
#define hfc_B1_D 0xA0
#define hfc_B2_D 0xA4
#define hfc_AUX1_D 0xA8
#define hfc_AUX2_D 0xAC
/* GCI/IOM bus configuration registers */
#define hfc_MST_EMOD 0xB4
#define hfc_MST_MODE 0xB8
#define hfc_CONNECT 0xBC
/* Interrupt and status registers */
#define hfc_FIFO_EN 0x44
#define hfc_TRM 0x48
#define hfc_B_MODE 0x4C
#define hfc_CHIP_ID 0x58
#define hfc_CIRM 0x60
#define hfc_CTMT 0x64
#define hfc_INT_M1 0x68
#define hfc_INT_M2 0x6C
#define hfc_INT_S1 0x78
#define hfc_INT_S2 0x7C
#define hfc_STATUS 0x70
/* S/T section registers */
#define hfc_STATES 0xC0
#define hfc_SCTRL 0xC4
#define hfc_SCTRL_E 0xC8
#define hfc_SCTRL_R 0xCC
#define hfc_SQ 0xD0
#define hfc_CLKDEL 0xDC
#define hfc_B1_REC 0xF0
#define hfc_B1_SEND 0xF0
#define hfc_B2_REC 0xF4
#define hfc_B2_SEND 0xF4
#define hfc_D_REC 0xF8
#define hfc_D_SEND 0xF8
#define hfc_E_REC 0xFC
/* Bits and values in various HFC PCI registers */
/* bits in status register (READ) */
#define hfc_STATUS_PCI_PROC 0x02
#define hfc_STATUS_NBUSY 0x04
#define hfc_STATUS_TIMER_ELAP 0x10
#define hfc_STATUS_STATINT 0x20
#define hfc_STATUS_FRAMEINT 0x40
#define hfc_STATUS_ANYINT 0x80
/* bits in CTMT (Write) */
#define hfc_CTMT_TRANSB1 0x01
#define hfc_CTMT_TRANSB2 0x02
#define hfc_CTMT_TIMER_CLEAR 0x80
#define hfc_CTMT_TIMER_MASK 0x1C
#define hfc_CTMT_TIMER_3_125 (0x01 << 2)
#define hfc_CTMT_TIMER_6_25 (0x02 << 2)
#define hfc_CTMT_TIMER_12_5 (0x03 << 2)
#define hfc_CTMT_TIMER_25 (0x04 << 2)
#define hfc_CTMT_TIMER_50 (0x05 << 2)
#define hfc_CTMT_TIMER_400 (0x06 << 2)
#define hfc_CTMT_TIMER_800 (0x07 << 2)
#define hfc_CTMT_AUTO_TIMER 0x20
/* bits in CIRM (Write) */
#define hfc_CIRM_AUX_MSK 0x07
#define hfc_CIRM_RESET 0x08
#define hfc_CIRM_B1_REV 0x40
#define hfc_CIRM_B2_REV 0x80
/* bits in INT_M1 and INT_S1 */
#define hfc_INTS_B1TRANS 0x01
#define hfc_INTS_B2TRANS 0x02
#define hfc_INTS_DTRANS 0x04
#define hfc_INTS_B1REC 0x08
#define hfc_INTS_B2REC 0x10
#define hfc_INTS_DREC 0x20
#define hfc_INTS_L1STATE 0x40
#define hfc_INTS_TIMER 0x80
/* bits in INT_M2 */
#define hfc_M2_PROC_TRANS 0x01
#define hfc_M2_GCI_I_CHG 0x02
#define hfc_M2_GCI_MON_REC 0x04
#define hfc_M2_IRQ_ENABLE 0x08
#define hfc_M2_PMESEL 0x80
/* bits in STATES */
#define hfc_STATES_STATE_MASK 0x0F
#define hfc_STATES_LOAD_STATE 0x10
#define hfc_STATES_ACTIVATE 0x20
#define hfc_STATES_DO_ACTION 0x40
#define hfc_STATES_NT_G2_G3 0x80
/* bits in HFCD_MST_MODE */
#define hfc_MST_MODE_MASTER 0x01
#define hfc_MST_MODE_SLAVE 0x00