Commit 3bcbfef3 authored by Kai Germaschewski's avatar Kai Germaschewski

ISDN: maintain outstanding CAPI messages in the drivers

It's up to the drivers to maintain their list of buffered messages
themselves. As most drivers can share common code, provide it
in capilib.o, inside of the module kernelcapi.o
parent 86315789
......@@ -6,11 +6,11 @@ O_TARGET := vmlinux-obj.o
# Objects that export symbols.
export-objs := kcapi.o capiutil.o capifs.o
export-objs := kcapi.o capiutil.o capilib.o capifs.o
# Multipart objects.
kernelcapi-objs := kcapi.o capiutil.o
kernelcapi-objs := kcapi.o capiutil.o capilib.o
# Ordering constraints: kernelcapi.o first
......
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/isdn/capilli.h>
#define DBG(format, arg...) do { \
printk(KERN_DEBUG __FUNCTION__ ": " format "\n" , ## arg); \
} while (0)
struct capilib_msgidqueue {
struct capilib_msgidqueue *next;
u16 msgid;
};
struct capilib_ncci {
struct list_head list;
u16 applid;
u32 ncci;
u32 winsize;
int nmsg;
struct capilib_msgidqueue *msgidqueue;
struct capilib_msgidqueue *msgidlast;
struct capilib_msgidqueue *msgidfree;
struct capilib_msgidqueue msgidpool[CAPI_MAXDATAWINDOW];
};
// ---------------------------------------------------------------------------
// NCCI Handling
static inline void mq_init(struct capilib_ncci * np)
{
int i;
np->msgidqueue = 0;
np->msgidlast = 0;
np->nmsg = 0;
memset(np->msgidpool, 0, sizeof(np->msgidpool));
np->msgidfree = &np->msgidpool[0];
for (i = 1; i < np->winsize; i++) {
np->msgidpool[i].next = np->msgidfree;
np->msgidfree = &np->msgidpool[i];
}
}
static inline int mq_enqueue(struct capilib_ncci * np, u16 msgid)
{
struct capilib_msgidqueue *mq;
if ((mq = np->msgidfree) == 0)
return 0;
np->msgidfree = mq->next;
mq->msgid = msgid;
mq->next = 0;
if (np->msgidlast)
np->msgidlast->next = mq;
np->msgidlast = mq;
if (!np->msgidqueue)
np->msgidqueue = mq;
np->nmsg++;
return 1;
}
static inline int mq_dequeue(struct capilib_ncci * np, u16 msgid)
{
struct capilib_msgidqueue **pp;
for (pp = &np->msgidqueue; *pp; pp = &(*pp)->next) {
if ((*pp)->msgid == msgid) {
struct capilib_msgidqueue *mq = *pp;
*pp = mq->next;
if (mq == np->msgidlast)
np->msgidlast = 0;
mq->next = np->msgidfree;
np->msgidfree = mq;
np->nmsg--;
return 1;
}
}
return 0;
}
void capilib_new_ncci(struct list_head *head, u16 applid, u32 ncci, u32 winsize)
{
struct capilib_ncci *np;
np = kmalloc(sizeof(*np), GFP_ATOMIC);
if (!np) {
printk(KERN_WARNING "capilib_new_ncci: no memory.\n");
return;
}
if (winsize > CAPI_MAXDATAWINDOW) {
printk(KERN_ERR "capi_new_ncci: winsize %d too big\n",
winsize);
winsize = CAPI_MAXDATAWINDOW;
}
np->applid = applid;
np->ncci = ncci;
np->winsize = winsize;
mq_init(np);
list_add_tail(&np->list, head);
DBG("kcapi: appl %d ncci 0x%x up", applid, ncci);
}
EXPORT_SYMBOL(capilib_new_ncci);
void capilib_free_ncci(struct list_head *head, u16 applid, u32 ncci)
{
struct list_head *l;
struct capilib_ncci *np;
list_for_each(l, head) {
np = list_entry(l, struct capilib_ncci, list);
if (np->applid != applid)
continue;
if (np->ncci != ncci)
continue;
printk(KERN_INFO "kcapi: appl %d ncci 0x%x down\n", applid, ncci);
list_del(&np->list);
kfree(np);
return;
}
printk(KERN_ERR "capilib_free_ncci: ncci 0x%x not found\n", ncci);
}
EXPORT_SYMBOL(capilib_free_ncci);
void capilib_release_appl(struct list_head *head, u16 applid)
{
struct list_head *l, *n;
struct capilib_ncci *np;
list_for_each_safe(l, n, head) {
np = list_entry(l, struct capilib_ncci, list);
if (np->applid != applid)
continue;
printk(KERN_INFO "kcapi: appl %d ncci 0x%x forced down\n", applid, np->ncci);
list_del(&np->list);
kfree(np);
}
}
EXPORT_SYMBOL(capilib_release_appl);
void capilib_release(struct list_head *head)
{
struct list_head *l, *n;
struct capilib_ncci *np;
list_for_each_safe(l, n, head) {
np = list_entry(l, struct capilib_ncci, list);
printk(KERN_INFO "kcapi: appl %d ncci 0x%x forced down\n", np->applid, np->ncci);
list_del(&np->list);
kfree(np);
}
}
EXPORT_SYMBOL(capilib_release);
u16 capilib_data_b3_req(struct list_head *head, u16 applid, u32 ncci, u16 msgid)
{
struct list_head *l;
struct capilib_ncci *np;
list_for_each(l, head) {
np = list_entry(l, struct capilib_ncci, list);
if (np->applid != applid)
continue;
if (np->ncci != ncci)
continue;
if (mq_enqueue(np, msgid) == 0)
return CAPI_SENDQUEUEFULL;
return CAPI_NOERROR;
}
printk(KERN_ERR "capilib_data_b3_req: ncci 0x%x not found\n", ncci);
return CAPI_NOERROR;
}
EXPORT_SYMBOL(capilib_data_b3_req);
void capilib_data_b3_conf(struct list_head *head, u16 applid, u32 ncci, u16 msgid)
{
struct list_head *l;
struct capilib_ncci *np;
list_for_each(l, head) {
np = list_entry(l, struct capilib_ncci, list);
if (np->applid != applid)
continue;
if (np->ncci != ncci)
continue;
if (mq_dequeue(np, msgid) == 0) {
printk(KERN_ERR "kcapi: msgid %hu ncci 0x%x not on queue\n",
msgid, ncci);
}
return;
}
printk(KERN_ERR "capilib_data_b3_conf: ncci 0x%x not found\n", ncci);
}
EXPORT_SYMBOL(capilib_data_b3_conf);
......@@ -55,23 +55,6 @@ MODULE_PARM(showcapimsgs, "i");
/* ------------------------------------------------------------- */
struct msgidqueue {
struct msgidqueue *next;
u16 msgid;
};
struct capi_ncci {
struct capi_ncci *next;
u16 applid;
u32 ncci;
u32 winsize;
int nmsg;
struct msgidqueue *msgidqueue;
struct msgidqueue *msgidlast;
struct msgidqueue *msgidfree;
struct msgidqueue msgidpool[CAPI_MAXDATAWINDOW];
};
struct capi_appl {
u16 applid;
capi_register_params rparam;
......@@ -245,45 +228,6 @@ static int proc_applications_read_proc(char *page, char **start, off_t off,
return len;
}
/*
* /proc/capi/ncci:
* applid ncci winsize nblk
*/
static int proc_ncci_read_proc(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
struct capi_appl *ap;
struct capi_ncci *np;
int i;
int len = 0;
for (i=1; i <= CAPI_MAXAPPL; i++) {
ap = get_capi_appl_by_nr(i);
if (!ap) continue;
for (np = ap->nccilist; np; np = np->next) {
len += sprintf(page+len, "%d 0x%x %d %d\n",
np->applid,
np->ncci,
np->winsize,
np->nmsg);
if (len <= off) {
off -= len;
len = 0;
} else {
if (len-off > count)
goto endloop;
}
}
}
endloop:
*start = page+off;
if (len < count)
*eof = 1;
if (len>count) len = count;
if (len<0) len = 0;
return len;
}
/*
* /proc/capi/driver:
* driver ncontroller
......@@ -477,7 +421,6 @@ static struct procfsentries {
} procfsentries[] = {
{ "capi", S_IFDIR, 0 },
{ "capi/applications", 0 , proc_applications_read_proc },
{ "capi/ncci", 0 , proc_ncci_read_proc },
{ "capi/driver", 0 , proc_driver_read_proc },
{ "capi/users", 0 , proc_users_read_proc },
{ "capi/controller", 0 , proc_controller_read_proc },
......@@ -525,26 +468,9 @@ static void register_appl(struct capi_ctr *card, u16 applid, capi_register_param
static void release_appl(struct capi_ctr *card, u16 applid)
{
struct capi_appl *ap = get_capi_appl_by_nr(applid);
struct capi_ncci **pp, **nextpp;
DBG("");
DBG("applid %#x", applid);
for (pp = &ap->nccilist; *pp; pp = nextpp) {
if (NCCI2CTRL((*pp)->ncci) == card->cnr) {
struct capi_ncci *np = *pp;
*pp = np->next;
printk(KERN_INFO "kcapi: appl %d ncci 0x%x down!\n", applid, np->ncci);
kfree(np);
ap->nncci--;
nextpp = pp;
} else {
nextpp = &(*pp)->next;
}
}
card->driver->release_appl(card, applid);
capi_ctr_put(card);
}
......@@ -679,130 +605,12 @@ static void notify_handler(void *dummy)
MOD_DEC_USE_COUNT;
}
/* -------- NCCI Handling ------------------------------------- */
static inline void mq_init(struct capi_ncci * np)
{
int i;
np->msgidqueue = 0;
np->msgidlast = 0;
np->nmsg = 0;
memset(np->msgidpool, 0, sizeof(np->msgidpool));
np->msgidfree = &np->msgidpool[0];
for (i = 1; i < np->winsize; i++) {
np->msgidpool[i].next = np->msgidfree;
np->msgidfree = &np->msgidpool[i];
}
}
static inline int mq_enqueue(struct capi_ncci * np, u16 msgid)
{
struct msgidqueue *mq;
if ((mq = np->msgidfree) == 0)
return 0;
np->msgidfree = mq->next;
mq->msgid = msgid;
mq->next = 0;
if (np->msgidlast)
np->msgidlast->next = mq;
np->msgidlast = mq;
if (!np->msgidqueue)
np->msgidqueue = mq;
np->nmsg++;
return 1;
}
static inline int mq_dequeue(struct capi_ncci * np, u16 msgid)
{
struct msgidqueue **pp;
for (pp = &np->msgidqueue; *pp; pp = &(*pp)->next) {
if ((*pp)->msgid == msgid) {
struct msgidqueue *mq = *pp;
*pp = mq->next;
if (mq == np->msgidlast)
np->msgidlast = 0;
mq->next = np->msgidfree;
np->msgidfree = mq;
np->nmsg--;
return 1;
}
}
return 0;
}
/*
* ncci management
*/
static void controllercb_new_ncci(struct capi_ctr * card,
u16 appl, u32 ncci, u32 winsize)
{
struct capi_ncci *np;
struct capi_appl *ap = get_capi_appl_by_nr(appl);
if (!ap) {
printk(KERN_ERR "avmb1_handle_new_ncci: illegal appl %d\n", appl);
return;
}
if ((np = (struct capi_ncci *) kmalloc(sizeof(struct capi_ncci), GFP_ATOMIC)) == 0) {
printk(KERN_ERR "capi_new_ncci: alloc failed ncci 0x%x\n", ncci);
return;
}
if (winsize > CAPI_MAXDATAWINDOW) {
printk(KERN_ERR "capi_new_ncci: winsize %d too big, set to %d\n",
winsize, CAPI_MAXDATAWINDOW);
winsize = CAPI_MAXDATAWINDOW;
}
np->applid = appl;
np->ncci = ncci;
np->winsize = winsize;
mq_init(np);
np->next = ap->nccilist;
ap->nccilist = np;
ap->nncci++;
printk(KERN_INFO "kcapi: appl %d ncci 0x%x up\n", appl, ncci);
}
static void controllercb_free_ncci(struct capi_ctr * card,
u16 appl, u32 ncci)
{
struct capi_ncci **pp;
struct capi_appl *ap = get_capi_appl_by_nr(appl);
if (!ap) {
printk(KERN_ERR "free_ncci: illegal appl %d\n", appl);
return;
}
for (pp = &ap->nccilist; *pp; pp = &(*pp)->next) {
if ((*pp)->ncci == ncci) {
struct capi_ncci *np = *pp;
*pp = np->next;
kfree(np);
ap->nncci--;
printk(KERN_INFO "kcapi: appl %d ncci 0x%x down\n", appl, ncci);
return;
}
}
printk(KERN_ERR "free_ncci: ncci 0x%x not found\n", ncci);
}
static struct capi_ncci *find_ncci(struct capi_appl * app, u32 ncci)
{
struct capi_ncci *np;
for (np = app->nccilist; np; np = np->next) {
if (np->ncci == ncci)
return np;
}
return 0;
}
/* -------- Receiver ------------------------------------------ */
static void recv_handler(void *dummy)
{
struct sk_buff *skb;
struct capi_appl *ap;
struct capi_ncci *np;
while ((skb = skb_dequeue(&recv_queue)) != 0) {
ap = get_capi_appl_by_nr(CAPIMSG_APPID(skb->data));
......@@ -818,13 +626,6 @@ static void recv_handler(void *dummy)
kfree_skb(skb);
continue;
}
if ( CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3
&& CAPIMSG_SUBCOMMAND(skb->data) == CAPI_CONF
&& (np = find_ncci(ap, CAPIMSG_NCCI(skb->data))) != 0
&& mq_dequeue(np, CAPIMSG_MSGID(skb->data)) == 0) {
printk(KERN_ERR "kcapi: msgid %hu ncci 0x%x not on queue\n",
CAPIMSG_MSGID(skb->data), np->ncci);
}
if ( CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3
&& CAPIMSG_SUBCOMMAND(skb->data) == CAPI_IND) {
ap->nrecvdatapkt++;
......@@ -917,22 +718,9 @@ static void controllercb_reseted(struct capi_ctr * card)
for (appl = 1; appl <= CAPI_MAXAPPL; appl++) {
struct capi_appl *ap = get_capi_appl_by_nr(appl);
struct capi_ncci **pp, **nextpp;
if (!ap)
continue;
for (pp = &ap->nccilist; *pp; pp = nextpp) {
if (NCCI2CTRL((*pp)->ncci) == card->cnr) {
struct capi_ncci *np = *pp;
*pp = np->next;
printk(KERN_INFO "kcapi: appl %d ncci 0x%x forced down!\n", appl, np->ncci);
kfree(np);
nextpp = pp;
} else {
nextpp = &(*pp)->next;
}
}
capi_ctr_put(card);
}
......@@ -993,8 +781,6 @@ attach_capi_ctr(struct capi_driver *driver, char *name, void *driverdata)
card->suspend_output = controllercb_suspend_output;
card->resume_output = controllercb_resume_output;
card->handle_capimsg = controllercb_handle_capimsg;
card->new_ncci = controllercb_new_ncci;
card->free_ncci = controllercb_free_ncci;
list_add_tail(&card->driver_list, &driver->contr_head);
driver->ncontroller++;
......@@ -1185,7 +971,6 @@ static u16 capi_put_message(u16 applid, struct sk_buff *skb)
{
struct capi_ctr *card;
struct capi_appl *ap;
struct capi_ncci *np;
int showctl = 0;
u8 cmd, subcmd;
......@@ -1213,9 +998,6 @@ static u16 capi_put_message(u16 applid, struct sk_buff *skb)
subcmd = CAPIMSG_SUBCOMMAND(skb->data);
if (cmd == CAPI_DATA_B3 && subcmd== CAPI_REQ) {
if ((np = find_ncci(ap, CAPIMSG_NCCI(skb->data))) != 0
&& mq_enqueue(np, CAPIMSG_MSGID(skb->data)) == 0)
return CAPI_SENDQUEUEFULL;
card->nsentdatapkt++;
ap->nsentdatapkt++;
if (card->traceflag > 2) showctl |= 2;
......@@ -1239,8 +1021,7 @@ static u16 capi_put_message(u16 applid, struct sk_buff *skb)
}
}
card->driver->send_message(card, skb);
return CAPI_NOERROR;
return card->driver->send_message(card, skb);
}
static u16 capi_get_message(u16 applid, struct sk_buff **msgp)
......
......@@ -69,6 +69,7 @@ typedef struct avmctrl_info {
struct avmcard *card;
struct capi_ctr *capi_ctrl;
struct list_head ncci_head;
} avmctrl_info;
typedef struct avmcard {
......@@ -549,7 +550,7 @@ void b1_reset_ctr(struct capi_ctr *ctrl);
void b1_register_appl(struct capi_ctr *ctrl, u16 appl,
capi_register_params *rp);
void b1_release_appl(struct capi_ctr *ctrl, u16 appl);
void b1_send_message(struct capi_ctr *ctrl, struct sk_buff *skb);
u16 b1_send_message(struct capi_ctr *ctrl, struct sk_buff *skb);
void b1_parse_version(avmctrl_info *card);
void b1_interrupt(int interrupt, void *devptr, struct pt_regs *regs);
......@@ -574,7 +575,7 @@ void b1dma_register_appl(struct capi_ctr *ctrl,
u16 appl,
capi_register_params *rp);
void b1dma_release_appl(struct capi_ctr *ctrl, u16 appl);
void b1dma_send_message(struct capi_ctr *ctrl, struct sk_buff *skb);
u16 b1dma_send_message(struct capi_ctr *ctrl, struct sk_buff *skb);
int b1dmactl_read_proc(char *page, char **start, off_t off,
int count, int *eof, struct capi_ctr *ctrl);
......
......@@ -80,6 +80,7 @@ avmcard *b1_alloc_card(int nr_controllers)
card->ctrlinfo = cinfo;
for (i = 0; i < nr_controllers; i++) {
INIT_LIST_HEAD(&cinfo[i].ncci_head);
cinfo[i].card = card;
}
spin_lock_init(&card->lock);
......@@ -331,6 +332,7 @@ void b1_reset_ctr(struct capi_ctr *ctrl)
b1_reset(port);
memset(cinfo->version, 0, sizeof(cinfo->version));
capilib_release(&cinfo->ncci_head);
ctrl->reseted(ctrl);
}
......@@ -366,6 +368,8 @@ void b1_release_appl(struct capi_ctr *ctrl, u16 appl)
unsigned int port = card->port;
unsigned long flags;
capilib_release_appl(&cinfo->ncci_head, appl);
save_flags(flags);
cli();
b1_put_byte(port, SEND_RELEASE);
......@@ -373,7 +377,7 @@ void b1_release_appl(struct capi_ctr *ctrl, u16 appl)
restore_flags(flags);
}
void b1_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
u16 b1_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
......@@ -382,20 +386,36 @@ void b1_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
u16 len = CAPIMSG_LEN(skb->data);
u8 cmd = CAPIMSG_COMMAND(skb->data);
u8 subcmd = CAPIMSG_SUBCOMMAND(skb->data);
u16 dlen, retval;
save_flags(flags);
cli();
if (CAPICMD(cmd, subcmd) == CAPI_DATA_B3_REQ) {
u16 dlen = CAPIMSG_DATALEN(skb->data);
retval = capilib_data_b3_req(&cinfo->ncci_head,
CAPIMSG_APPID(skb->data),
CAPIMSG_NCCI(skb->data),
CAPIMSG_MSGID(skb->data));
if (retval != CAPI_NOERROR)
goto out;
dlen = CAPIMSG_DATALEN(skb->data);
save_flags(flags);
cli();
b1_put_byte(port, SEND_DATA_B3_REQ);
b1_put_slice(port, skb->data, len);
b1_put_slice(port, skb->data + len, dlen);
restore_flags(flags);
} else {
retval = CAPI_NOERROR;
save_flags(flags);
cli();
b1_put_byte(port, SEND_MESSAGE);
b1_put_slice(port, skb->data, len);
restore_flags(flags);
}
restore_flags(flags);
out:
dev_kfree_skb_any(skb);
return retval;
}
/* ------------------------------------------------------------- */
......@@ -525,6 +545,11 @@ void b1_interrupt(int interrupt, void *devptr, struct pt_regs *regs)
card->name);
} else {
memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen);
if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_CONF)
capilib_data_b3_conf(&cinfo->ncci_head, ApplId,
CAPIMSG_NCCI(skb->data),
CAPIMSG_MSGID(skb->data));
ctrl->handle_capimsg(ctrl, ApplId, skb);
}
break;
......@@ -535,7 +560,7 @@ void b1_interrupt(int interrupt, void *devptr, struct pt_regs *regs)
NCCI = b1_get_word(card->port);
WindowSize = b1_get_word(card->port);
ctrl->new_ncci(ctrl, ApplId, NCCI, WindowSize);
capilib_new_ncci(&cinfo->ncci_head, ApplId, NCCI, WindowSize);
break;
......@@ -545,8 +570,8 @@ void b1_interrupt(int interrupt, void *devptr, struct pt_regs *regs)
NCCI = b1_get_word(card->port);
if (NCCI != 0xffffffff)
ctrl->free_ncci(ctrl, ApplId, NCCI);
capilib_free_ncci(&cinfo->ncci_head, ApplId, NCCI);
break;
case RECEIVE_START:
......
......@@ -488,6 +488,11 @@ static void b1dma_handle_rx(avmcard *card)
card->name);
} else {
memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen);
if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_CONF)
capilib_data_b3_conf(&cinfo->ncci_head, ApplId,
CAPIMSG_NCCI(skb->data),
CAPIMSG_MSGID(skb->data));
ctrl->handle_capimsg(ctrl, ApplId, skb);
}
break;
......@@ -498,7 +503,7 @@ static void b1dma_handle_rx(avmcard *card)
NCCI = _get_word(&p);
WindowSize = _get_word(&p);
ctrl->new_ncci(ctrl, ApplId, NCCI, WindowSize);
capilib_new_ncci(&cinfo->ncci_head, ApplId, NCCI, WindowSize);
break;
......@@ -508,7 +513,7 @@ static void b1dma_handle_rx(avmcard *card)
NCCI = _get_word(&p);
if (NCCI != 0xffffffff)
ctrl->free_ncci(ctrl, ApplId, NCCI);
capilib_free_ncci(&cinfo->ncci_head, ApplId, NCCI);
break;
......@@ -734,6 +739,7 @@ void b1dma_reset_ctr(struct capi_ctr *ctrl)
b1dma_reset(card);
memset(cinfo->version, 0, sizeof(cinfo->version));
capilib_release(&cinfo->ncci_head);
ctrl->reseted(ctrl);
}
......@@ -785,6 +791,8 @@ void b1dma_release_appl(struct capi_ctr *ctrl, u16 appl)
struct sk_buff *skb;
void *p;
capilib_release_appl(&cinfo->ncci_head, appl);
skb = alloc_skb(7, GFP_ATOMIC);
if (!skb) {
printk(KERN_CRIT "%s: no memory, lost release appl.\n",
......@@ -804,12 +812,24 @@ void b1dma_release_appl(struct capi_ctr *ctrl, u16 appl)
/* ------------------------------------------------------------- */
void b1dma_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
u16 b1dma_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
u16 retval = CAPI_NOERROR;
b1dma_queue_tx(card, skb);
if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_REQ) {
retval = capilib_data_b3_req(&cinfo->ncci_head,
CAPIMSG_APPID(skb->data),
CAPIMSG_NCCI(skb->data),
CAPIMSG_MSGID(skb->data));
}
if (retval == CAPI_NOERROR)
b1dma_queue_tx(card, skb);
else
dev_kfree_skb_any(skb);
return retval;
}
/* ------------------------------------------------------------- */
......
......@@ -548,6 +548,7 @@ static void c4_handle_rx(avmcard *card)
MsgLen = _get_slice(&p, card->msgbuf);
cidx = CAPIMSG_CONTROLLER(card->msgbuf)-card->cardnr;
if (cidx >= card->nlogcontr) cidx = 0;
cinfo = &card->ctrlinfo[cidx];
ctrl = card->ctrlinfo[cidx].capi_ctrl;
if (!(skb = alloc_skb(MsgLen, GFP_ATOMIC))) {
......@@ -555,6 +556,11 @@ static void c4_handle_rx(avmcard *card)
card->name);
} else {
memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen);
if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_CONF)
capilib_data_b3_conf(&cinfo->ncci_head, ApplId,
CAPIMSG_NCCI(skb->data),
CAPIMSG_MSGID(skb->data));
ctrl->handle_capimsg(ctrl, ApplId, skb);
}
break;
......@@ -566,9 +572,8 @@ static void c4_handle_rx(avmcard *card)
WindowSize = _get_word(&p);
cidx = (NCCI&0x7f) - card->cardnr;
if (cidx >= card->nlogcontr) cidx = 0;
ctrl = card->ctrlinfo[cidx].capi_ctrl;
ctrl->new_ncci(ctrl, ApplId, NCCI, WindowSize);
capilib_new_ncci(&card->ctrlinfo[cidx].ncci_head, ApplId, NCCI, WindowSize);
break;
......@@ -580,9 +585,7 @@ static void c4_handle_rx(avmcard *card)
if (NCCI != 0xffffffff) {
cidx = (NCCI&0x7f) - card->cardnr;
if (cidx >= card->nlogcontr) cidx = 0;
ctrl = card->ctrlinfo[cidx].capi_ctrl;
if (ctrl)
ctrl->free_ncci(ctrl, ApplId, NCCI);
capilib_free_ncci(&card->ctrlinfo[cidx].ncci_head, ApplId, NCCI);
}
break;
......@@ -675,6 +678,7 @@ static void c4_handle_interrupt(avmcard *card)
for (i=0; i < 4; i++) {
avmctrl_info *cinfo = &card->ctrlinfo[i];
memset(cinfo->version, 0, sizeof(cinfo->version));
capilib_release(&cinfo->ncci_head);
if (cinfo->capi_ctrl)
cinfo->capi_ctrl->reseted(cinfo->capi_ctrl);
}
......@@ -974,6 +978,8 @@ void c4_release_appl(struct capi_ctr *ctrl, u16 appl)
struct sk_buff *skb;
void *p;
capilib_release_appl(&cinfo->ncci_head, appl);
if (ctrl->cnr == card->cardnr) {
skb = alloc_skb(7, GFP_ATOMIC);
if (!skb) {
......@@ -996,12 +1002,25 @@ void c4_release_appl(struct capi_ctr *ctrl, u16 appl)
/* ------------------------------------------------------------- */
static void c4_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
static u16 c4_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
skb_queue_tail(&card->dma->send_queue, skb);
c4_dispatch_tx(card);
u16 retval = CAPI_NOERROR;
if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_REQ) {
retval = capilib_data_b3_req(&cinfo->ncci_head,
CAPIMSG_APPID(skb->data),
CAPIMSG_NCCI(skb->data),
CAPIMSG_MSGID(skb->data));
}
if (retval == CAPI_NOERROR) {
skb_queue_tail(&card->dma->send_queue, skb);
c4_dispatch_tx(card);
} else {
dev_kfree_skb_any(skb);
}
return retval;
}
/* ------------------------------------------------------------- */
......
......@@ -17,6 +17,7 @@
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/capi.h>
#include <linux/netdevice.h>
#include <linux/kernelcapi.h>
#include <linux/init.h>
#include <asm/io.h>
......@@ -174,6 +175,11 @@ static void t1isa_interrupt(int interrupt, void *devptr, struct pt_regs *regs)
card->name);
} else {
memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen);
if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3)
capilib_data_b3_conf(&cinfo->ncci_head, ApplId,
CAPIMSG_NCCI(skb->data),
CAPIMSG_MSGID(skb->data));
ctrl->handle_capimsg(ctrl, ApplId, skb);
}
break;
......@@ -184,7 +190,7 @@ static void t1isa_interrupt(int interrupt, void *devptr, struct pt_regs *regs)
NCCI = b1_get_word(card->port);
WindowSize = b1_get_word(card->port);
ctrl->new_ncci(ctrl, ApplId, NCCI, WindowSize);
capilib_new_ncci(&cinfo->ncci_head, ApplId, NCCI, WindowSize);
break;
......@@ -194,7 +200,7 @@ static void t1isa_interrupt(int interrupt, void *devptr, struct pt_regs *regs)
NCCI = b1_get_word(card->port);
if (NCCI != 0xffffffff)
ctrl->free_ncci(ctrl, ApplId, NCCI);
capilib_free_ncci(&cinfo->ncci_head, ApplId, NCCI);
break;
......@@ -313,6 +319,7 @@ void t1isa_reset_ctr(struct capi_ctr *ctrl)
b1_reset(port);
memset(cinfo->version, 0, sizeof(cinfo->version));
capilib_release(&cinfo->ncci_head);
ctrl->reseted(ctrl);
}
......@@ -433,7 +440,7 @@ static int t1isa_add_card(struct capi_driver *driver, struct capicardparams *p)
return retval;
}
static void t1isa_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
static u16 t1isa_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
......@@ -442,20 +449,36 @@ static void t1isa_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
u16 len = CAPIMSG_LEN(skb->data);
u8 cmd = CAPIMSG_COMMAND(skb->data);
u8 subcmd = CAPIMSG_SUBCOMMAND(skb->data);
u16 dlen, retval;
save_flags(flags);
cli();
if (CAPICMD(cmd, subcmd) == CAPI_DATA_B3_REQ) {
u16 dlen = CAPIMSG_DATALEN(skb->data);
retval = capilib_data_b3_req(&cinfo->ncci_head,
CAPIMSG_APPID(skb->data),
CAPIMSG_NCCI(skb->data),
CAPIMSG_MSGID(skb->data));
if (retval != CAPI_NOERROR)
goto out;
dlen = CAPIMSG_DATALEN(skb->data);
save_flags(flags);
cli();
b1_put_byte(port, SEND_DATA_B3_REQ);
t1_put_slice(port, skb->data, len);
t1_put_slice(port, skb->data + len, dlen);
restore_flags(flags);
} else {
retval = CAPI_NOERROR;
save_flags(flags);
cli();
b1_put_byte(port, SEND_MESSAGE);
t1_put_slice(port, skb->data, len);
restore_flags(flags);
}
restore_flags(flags);
dev_kfree_skb(skb);
out:
dev_kfree_skb_any(skb);
return retval;
}
/* ------------------------------------------------------------- */
......
......@@ -15,7 +15,7 @@
#include <linux/signal.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#define VER_DRIVER 0
#define VER_CARDTYPE 1
......@@ -62,9 +62,12 @@ Kernel-Capi callback reset_ctr
void
hycapi_reset_ctr(struct capi_ctr *ctrl)
{
hycapictrl_info *cinfo = ctrl->driverdata;
#ifdef HYCAPI_PRINTFNAMES
printk(KERN_NOTICE "HYCAPI hycapi_reset_ctr\n");
#endif
capilib_release(&cinfo->ncci_head);
ctrl->reseted(ctrl);
}
......@@ -269,6 +272,9 @@ static void hycapi_release_internal(struct capi_ctr *ctrl, __u16 appl)
__u16 len;
__u8 _command = 0xa1, _subcommand = 0x80;
__u16 MessageNumber = 0x0000;
capilib_release_appl(&cinfo->ncci_head, appl);
#ifdef HYCAPI_PRINTFNAMES
printk(KERN_NOTICE "hycapi_release_appl\n");
#endif
......@@ -373,12 +379,14 @@ firmware-releases that do not check the MsgLen-Indication!
***************************************************************/
void hycapi_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
u16 hycapi_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
{
__u16 appl_id;
int _len, _len2;
__u8 msghead[64];
hycapictrl_info *cinfo = ctrl->driverdata;
u16 retval = CAPI_NOERROR;
appl_id = CAPIMSG_APPID(skb->data);
switch(_hycapi_appCheck(appl_id, ctrl->cnr))
{
......@@ -392,12 +400,13 @@ void hycapi_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
break;
default:
printk(KERN_ERR "HYCAPI: Controller mixup!\n");
return;
retval = CAPI_ILLAPPNR;
goto out;
}
switch(CAPIMSG_CMD(skb->data)) {
case CAPI_DISCONNECT_B3_RESP:
ctrl->free_ncci(ctrl, appl_id,
CAPIMSG_NCCI(skb->data));
capilib_free_ncci(&cinfo->ncci_head, appl_id,
CAPIMSG_NCCI(skb->data));
break;
case CAPI_DATA_B3_REQ:
_len = CAPIMSG_LEN(skb->data);
......@@ -407,6 +416,10 @@ void hycapi_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
memcpy(skb->data + _len2, msghead, 22);
skb_pull(skb, _len2);
CAPIMSG_SETLEN(skb->data, 22);
retval = capilib_data_b3_req(&cinfo->ncci_head,
CAPIMSG_APPID(skb->data),
CAPIMSG_NCCI(skb->data),
CAPIMSG_MSGID(skb->data));
}
break;
case CAPI_LISTEN_REQ:
......@@ -423,7 +436,13 @@ void hycapi_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
default:
break;
}
hycapi_sendmsg_internal(ctrl, skb);
out:
if (retval == CAPI_NOERROR)
hycapi_sendmsg_internal(ctrl, skb);
else
dev_kfree_skb_any(skb);
return retval;
}
/*********************************************************************
......@@ -575,8 +594,8 @@ hycapi_rx_capipkt(hysdn_card * card, uchar * buf, word len)
switch(info)
{
case 0:
ctrl->new_ncci(ctrl, ApplId, CAPIMSG_NCCI(skb->data),
hycapi_applications[ApplId-1].rp.datablkcnt);
capilib_new_ncci(&cinfo->ncci_head, ApplId, CAPIMSG_NCCI(skb->data),
hycapi_applications[ApplId-1].rp.datablkcnt);
break;
case 0x0001:
......@@ -604,9 +623,14 @@ hycapi_rx_capipkt(hysdn_card * card, uchar * buf, word len)
}
break;
case CAPI_CONNECT_B3_IND:
ctrl->new_ncci(ctrl, ApplId,
CAPIMSG_NCCI(skb->data),
hycapi_applications[ApplId-1].rp.datablkcnt);
capilib_new_ncci(&cinfo->ncci_head, ApplId,
CAPIMSG_NCCI(skb->data),
hycapi_applications[ApplId-1].rp.datablkcnt);
break;
case CAPI_DATA_B3_CONF:
capilib_data_b3_conf(&cinfo->ncci_head, ApplId,
CAPIMSG_NCCI(skb->data),
CAPIMSG_MSGID(skb->data));
break;
default:
break;
......@@ -786,6 +810,7 @@ hycapi_capi_create(hysdn_card *card)
card->hyctrlinfo = cinfo;
cinfo->card = card;
spin_lock_init(&cinfo->lock);
INIT_LIST_HEAD(&cinfo->ncci_head);
switch (card->brdtype) {
case BD_PCCARD: strcpy(cinfo->cardname,"HYSDN Hycard"); break;
......
......@@ -213,6 +213,8 @@ typedef struct HYSDN_CARD {
int in_idx, out_idx; /* indexes to buffer ring */
int sk_count; /* number of buffers currently in ring */
struct sk_buff *tx_skb; /* buffer for tx operation */
struct list_head ncci_head;
} *hyctrlinfo;
#endif /* CONFIG_HYSDN_CAPI */
} hysdn_card;
......@@ -284,7 +286,7 @@ extern void hycapi_remove_ctr(struct capi_ctr *);
extern void hycapi_register_appl(struct capi_ctr *, __u16 appl,
capi_register_params *);
extern void hycapi_release_appl(struct capi_ctr *, __u16 appl);
extern void hycapi_send_message(struct capi_ctr *, struct sk_buff *skb);
extern u16 hycapi_send_message(struct capi_ctr *, struct sk_buff *skb);
extern char *hycapi_procinfo(struct capi_ctr *);
extern int hycapi_read_proc(char *page, char **start, off_t off,
int count, int *eof, struct capi_ctr *card);
......
......@@ -12,7 +12,10 @@
#ifndef __CAPILLI_H__
#define __CAPILLI_H__
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/capi.h>
#include <linux/kernelcapi.h>
typedef struct capiloaddatapart {
int user; /* data in userspace ? */
......@@ -60,10 +63,6 @@ struct capi_ctr {
void (*handle_capimsg)(struct capi_ctr * card,
__u16 appl, struct sk_buff *skb);
void (*new_ncci)(struct capi_ctr * card,
__u16 appl, __u32 ncci, __u32 winsize);
void (*free_ncci)(struct capi_ctr * card, __u16 appl, __u32 ncci);
/* management information for kcapi */
unsigned long nrecvctlpkt;
......@@ -85,7 +84,7 @@ struct capi_driver {
void (*register_appl)(struct capi_ctr *, __u16 appl,
capi_register_params *);
void (*release_appl)(struct capi_ctr *, __u16 appl);
void (*send_message)(struct capi_ctr *, struct sk_buff *skb);
u16 (*send_message)(struct capi_ctr *, struct sk_buff *skb);
char *(*procinfo)(struct capi_ctr *);
int (*ctr_read_proc)(char *page, char **start, off_t off,
......@@ -109,4 +108,16 @@ void detach_capi_driver(struct capi_driver *driver);
struct capi_ctr *attach_capi_ctr(struct capi_driver *driver, char *name, void *data);
int detach_capi_ctr(struct capi_ctr *);
// ---------------------------------------------------------------------------
// library functions for use by hardware controller drivers
void capilib_new_ncci(struct list_head *head, u16 applid, u32 ncci, u32 winsize);
void capilib_free_ncci(struct list_head *head, u16 applid, u32 ncci);
void capilib_release_appl(struct list_head *head, u16 applid);
void capilib_release(struct list_head *head);
void capilib_data_b3_conf(struct list_head *head, u16 applid, u32 ncci, u16 msgid);
u16 capilib_data_b3_req(struct list_head *head, u16 applid, u32 ncci, u16 msgid);
#endif /* __CAPILLI_H__ */
......@@ -47,6 +47,8 @@ typedef struct kcapi_carddef {
#ifdef __KERNEL__
#include <linux/skbuff.h>
struct capi_interface {
__u16 (*capi_isinstalled) (void);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment