diff options
Diffstat (limited to 'drivers/isdn')
47 files changed, 1666 insertions, 1393 deletions
diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c index b902794bbf07..38c4bd87b2c9 100644 --- a/drivers/isdn/capi/capi.c +++ b/drivers/isdn/capi/capi.c @@ -336,11 +336,6 @@ static inline void capincci_alloc_minor(struct capidev *cdev, struct capincci *np) { } static inline void capincci_free_minor(struct capincci *np) { } -static inline unsigned int capincci_minor_opencount(struct capincci *np) -{ - return 0; -} - #endif /* !CONFIG_ISDN_CAPI_MIDDLEWARE */ static struct capincci *capincci_alloc(struct capidev *cdev, u32 ncci) @@ -372,6 +367,7 @@ static void capincci_free(struct capidev *cdev, u32 ncci) } } +#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE static struct capincci *capincci_find(struct capidev *cdev, u32 ncci) { struct capincci *np; @@ -382,7 +378,6 @@ static struct capincci *capincci_find(struct capidev *cdev, u32 ncci) return NULL; } -#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE /* -------- handle data queue --------------------------------------- */ static struct sk_buff * @@ -578,8 +573,8 @@ static void capi_recv_message(struct capi20_appl *ap, struct sk_buff *skb) struct tty_struct *tty; struct capiminor *mp; u16 datahandle; -#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ struct capincci *np; +#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ mutex_lock(&cdev->lock); @@ -597,6 +592,12 @@ static void capi_recv_message(struct capi20_appl *ap, struct sk_buff *skb) goto unlock_out; } +#ifndef CONFIG_ISDN_CAPI_MIDDLEWARE + skb_queue_tail(&cdev->recvqueue, skb); + wake_up_interruptible(&cdev->recvwait); + +#else /* CONFIG_ISDN_CAPI_MIDDLEWARE */ + np = capincci_find(cdev, CAPIMSG_CONTROL(skb->data)); if (!np) { printk(KERN_ERR "BUG: capi_signal: ncci not found\n"); @@ -605,12 +606,6 @@ static void capi_recv_message(struct capi20_appl *ap, struct sk_buff *skb) goto unlock_out; } -#ifndef CONFIG_ISDN_CAPI_MIDDLEWARE - skb_queue_tail(&cdev->recvqueue, skb); - wake_up_interruptible(&cdev->recvwait); - -#else /* CONFIG_ISDN_CAPI_MIDDLEWARE */ - mp = np->minorp; if (!mp) { skb_queue_tail(&cdev->recvqueue, skb); @@ -786,7 +781,6 @@ register_out: return retval; case CAPI_GET_VERSION: - { if (copy_from_user(&data.contr, argp, sizeof(data.contr))) return -EFAULT; @@ -796,11 +790,9 @@ register_out: if (copy_to_user(argp, &data.version, sizeof(data.version))) return -EFAULT; - } - return 0; + return 0; case CAPI_GET_SERIAL: - { if (copy_from_user(&data.contr, argp, sizeof(data.contr))) return -EFAULT; @@ -810,10 +802,9 @@ register_out: if (copy_to_user(argp, data.serial, sizeof(data.serial))) return -EFAULT; - } - return 0; + return 0; + case CAPI_GET_PROFILE: - { if (copy_from_user(&data.contr, argp, sizeof(data.contr))) return -EFAULT; @@ -837,11 +828,9 @@ register_out: } if (retval) return -EFAULT; - } - return 0; + return 0; case CAPI_GET_MANUFACTURER: - { if (copy_from_user(&data.contr, argp, sizeof(data.contr))) return -EFAULT; @@ -853,8 +842,8 @@ register_out: sizeof(data.manufacturer))) return -EFAULT; - } - return 0; + return 0; + case CAPI_GET_ERRCODE: data.errcode = cdev->errcode; cdev->errcode = CAPI_NOERROR; @@ -870,8 +859,7 @@ register_out: return 0; return -ENXIO; - case CAPI_MANUFACTURER_CMD: - { + case CAPI_MANUFACTURER_CMD: { struct capi_manufacturer_cmd mcmd; if (!capable(CAP_SYS_ADMIN)) return -EPERM; @@ -879,8 +867,6 @@ register_out: return -EFAULT; return capi20_manufacturer(mcmd.cmd, mcmd.data); } - return 0; - case CAPI_SET_FLAGS: case CAPI_CLR_FLAGS: { unsigned userflags; @@ -902,6 +888,11 @@ register_out: return -EFAULT; return 0; +#ifndef CONFIG_ISDN_CAPI_MIDDLEWARE + case CAPI_NCCI_OPENCOUNT: + return 0; + +#else /* CONFIG_ISDN_CAPI_MIDDLEWARE */ case CAPI_NCCI_OPENCOUNT: { struct capincci *nccip; unsigned ncci; @@ -918,7 +909,6 @@ register_out: return count; } -#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE case CAPI_NCCI_GETUNIT: { struct capincci *nccip; struct capiminor *mp; diff --git a/drivers/isdn/capi/capidrv.c b/drivers/isdn/capi/capidrv.c index 6f5016b479f8..832bc807ed20 100644 --- a/drivers/isdn/capi/capidrv.c +++ b/drivers/isdn/capi/capidrv.c @@ -1593,7 +1593,7 @@ static int capidrv_command(isdn_ctrl *c, capidrv_contr *card) return capidrv_ioctl(c, card); switch (c->command) { - case ISDN_CMD_DIAL:{ + case ISDN_CMD_DIAL: { u8 calling[ISDN_MSNLEN + 3]; u8 called[ISDN_MSNLEN + 2]; @@ -2072,7 +2072,8 @@ static int capidrv_addcontr(u16 contr, struct capi_profile *profp) card->interface.writebuf_skb = if_sendbuf; card->interface.writecmd = NULL; card->interface.readstat = if_readstat; - card->interface.features = ISDN_FEATURE_L2_HDLC | + card->interface.features = + ISDN_FEATURE_L2_HDLC | ISDN_FEATURE_L2_TRANS | ISDN_FEATURE_L3_TRANS | ISDN_FEATURE_P_UNKNOWN | @@ -2080,7 +2081,8 @@ static int capidrv_addcontr(u16 contr, struct capi_profile *profp) ISDN_FEATURE_L2_X75UI | ISDN_FEATURE_L2_X75BUI; if (profp->support1 & (1 << 2)) - card->interface.features |= ISDN_FEATURE_L2_V11096 | + card->interface.features |= + ISDN_FEATURE_L2_V11096 | ISDN_FEATURE_L2_V11019 | ISDN_FEATURE_L2_V11038; if (profp->support1 & (1 << 8)) diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c index afa080258bfa..527588708948 100644 --- a/drivers/isdn/gigaset/bas-gigaset.c +++ b/drivers/isdn/gigaset/bas-gigaset.c @@ -148,6 +148,7 @@ static struct usb_driver gigaset_usb_driver = { .reset_resume = gigaset_post_reset, .pre_reset = gigaset_pre_reset, .post_reset = gigaset_post_reset, + .disable_hub_initiated_lpm = 1, }; /* get message text for usb_submit_urb return code @@ -410,10 +411,10 @@ static void check_pending(struct bas_cardstate *ucs) if (!(ucs->basstate & BS_RESETTING)) ucs->pending = 0; break; - /* - * HD_READ_ATMESSAGE and HD_WRITE_ATMESSAGE are handled separately - * and should never end up here - */ + /* + * HD_READ_ATMESSAGE and HD_WRITE_ATMESSAGE are handled separately + * and should never end up here + */ default: dev_warn(&ucs->interface->dev, "unknown pending request 0x%02x cleared\n", @@ -877,8 +878,7 @@ static void read_iso_callback(struct urb *urb) for (i = 0; i < BAS_NUMFRAMES; i++) { ubc->isoinlost += urb->iso_frame_desc[i].actual_length; if (unlikely(urb->iso_frame_desc[i].status != 0 && - urb->iso_frame_desc[i].status != - -EINPROGRESS)) + urb->iso_frame_desc[i].status != -EINPROGRESS)) ubc->loststatus = urb->iso_frame_desc[i].status; urb->iso_frame_desc[i].status = 0; urb->iso_frame_desc[i].actual_length = 0; @@ -2078,16 +2078,14 @@ static int gigaset_brkchars(struct cardstate *cs, const unsigned char buf[6]) /* Free hardware dependent part of the B channel structure * parameter: * bcs B channel structure - * return value: - * !=0 on success */ -static int gigaset_freebcshw(struct bc_state *bcs) +static void gigaset_freebcshw(struct bc_state *bcs) { struct bas_bc_state *ubc = bcs->hw.bas; int i; if (!ubc) - return 0; + return; /* kill URBs and tasklets before freeing - better safe than sorry */ ubc->running = 0; @@ -2105,14 +2103,13 @@ static int gigaset_freebcshw(struct bc_state *bcs) kfree(ubc->isooutbuf); kfree(ubc); bcs->hw.bas = NULL; - return 1; } /* Initialize hardware dependent part of the B channel structure * parameter: * bcs B channel structure * return value: - * !=0 on success + * 0 on success, error code < 0 on failure */ static int gigaset_initbcshw(struct bc_state *bcs) { @@ -2122,7 +2119,7 @@ static int gigaset_initbcshw(struct bc_state *bcs) bcs->hw.bas = ubc = kmalloc(sizeof(struct bas_bc_state), GFP_KERNEL); if (!ubc) { pr_err("out of memory\n"); - return 0; + return -ENOMEM; } ubc->running = 0; @@ -2139,7 +2136,7 @@ static int gigaset_initbcshw(struct bc_state *bcs) pr_err("out of memory\n"); kfree(ubc); bcs->hw.bas = NULL; - return 0; + return -ENOMEM; } tasklet_init(&ubc->sent_tasklet, write_iso_tasklet, (unsigned long) bcs); @@ -2164,7 +2161,7 @@ static int gigaset_initbcshw(struct bc_state *bcs) ubc->stolen0s = 0; tasklet_init(&ubc->rcvd_tasklet, read_iso_tasklet, (unsigned long) bcs); - return 1; + return 0; } static void gigaset_reinitbcshw(struct bc_state *bcs) @@ -2187,6 +2184,12 @@ static void gigaset_freecshw(struct cardstate *cs) cs->hw.bas = NULL; } +/* Initialize hardware dependent part of the cardstate structure + * parameter: + * cs cardstate structure + * return value: + * 0 on success, error code < 0 on failure + */ static int gigaset_initcshw(struct cardstate *cs) { struct bas_cardstate *ucs; @@ -2194,13 +2197,13 @@ static int gigaset_initcshw(struct cardstate *cs) cs->hw.bas = ucs = kmalloc(sizeof *ucs, GFP_KERNEL); if (!ucs) { pr_err("out of memory\n"); - return 0; + return -ENOMEM; } ucs->int_in_buf = kmalloc(IP_MSGSIZE, GFP_KERNEL); if (!ucs->int_in_buf) { kfree(ucs); pr_err("out of memory\n"); - return 0; + return -ENOMEM; } ucs->urb_cmd_in = NULL; @@ -2219,7 +2222,7 @@ static int gigaset_initcshw(struct cardstate *cs) init_waitqueue_head(&ucs->waitqueue); INIT_WORK(&ucs->int_in_wq, int_in_work); - return 1; + return 0; } /* freeurbs @@ -2379,18 +2382,20 @@ static int gigaset_probe(struct usb_interface *interface, /* save address of controller structure */ usb_set_intfdata(interface, cs); - if (!gigaset_start(cs)) + rc = gigaset_start(cs); + if (rc < 0) goto error; return 0; allocerr: dev_err(cs->dev, "could not allocate URBs\n"); + rc = -ENOMEM; error: freeurbs(cs); usb_set_intfdata(interface, NULL); gigaset_freecs(cs); - return -ENODEV; + return rc; } /* gigaset_disconnect diff --git a/drivers/isdn/gigaset/capi.c b/drivers/isdn/gigaset/capi.c index 343b5c80cb7b..27e4a3e21d64 100644 --- a/drivers/isdn/gigaset/capi.c +++ b/drivers/isdn/gigaset/capi.c @@ -14,6 +14,7 @@ #include "gigaset.h" #include <linux/proc_fs.h> #include <linux/seq_file.h> +#include <linux/ratelimit.h> #include <linux/isdn/capilli.h> #include <linux/isdn/capicmd.h> #include <linux/isdn/capiutil.h> @@ -108,51 +109,35 @@ static struct { u8 *bc; u8 *hlc; } cip2bchlc[] = { - [1] = { "8090A3", NULL }, - /* Speech (A-law) */ - [2] = { "8890", NULL }, - /* Unrestricted digital information */ - [3] = { "8990", NULL }, - /* Restricted digital information */ - [4] = { "9090A3", NULL }, - /* 3,1 kHz audio (A-law) */ - [5] = { "9190", NULL }, - /* 7 kHz audio */ - [6] = { "9890", NULL }, - /* Video */ - [7] = { "88C0C6E6", NULL }, - /* Packet mode */ - [8] = { "8890218F", NULL }, - /* 56 kbit/s rate adaptation */ - [9] = { "9190A5", NULL }, - /* Unrestricted digital information with tones/announcements */ - [16] = { "8090A3", "9181" }, - /* Telephony */ - [17] = { "9090A3", "9184" }, - /* Group 2/3 facsimile */ - [18] = { "8890", "91A1" }, - /* Group 4 facsimile Class 1 */ - [19] = { "8890", "91A4" }, - /* Teletex service basic and mixed mode - and Group 4 facsimile service Classes II and III */ - [20] = { "8890", "91A8" }, - /* Teletex service basic and processable mode */ - [21] = { "8890", "91B1" }, - /* Teletex service basic mode */ - [22] = { "8890", "91B2" }, - /* International interworking for Videotex */ - [23] = { "8890", "91B5" }, - /* Telex */ - [24] = { "8890", "91B8" }, - /* Message Handling Systems in accordance with X.400 */ - [25] = { "8890", "91C1" }, - /* OSI application in accordance with X.200 */ - [26] = { "9190A5", "9181" }, - /* 7 kHz telephony */ - [27] = { "9190A5", "916001" }, - /* Video telephony, first connection */ - [28] = { "8890", "916002" }, - /* Video telephony, second connection */ + [1] = { "8090A3", NULL }, /* Speech (A-law) */ + [2] = { "8890", NULL }, /* Unrestricted digital information */ + [3] = { "8990", NULL }, /* Restricted digital information */ + [4] = { "9090A3", NULL }, /* 3,1 kHz audio (A-law) */ + [5] = { "9190", NULL }, /* 7 kHz audio */ + [6] = { "9890", NULL }, /* Video */ + [7] = { "88C0C6E6", NULL }, /* Packet mode */ + [8] = { "8890218F", NULL }, /* 56 kbit/s rate adaptation */ + [9] = { "9190A5", NULL }, /* Unrestricted digital information + * with tones/announcements */ + [16] = { "8090A3", "9181" }, /* Telephony */ + [17] = { "9090A3", "9184" }, /* Group 2/3 facsimile */ + [18] = { "8890", "91A1" }, /* Group 4 facsimile Class 1 */ + [19] = { "8890", "91A4" }, /* Teletex service basic and mixed mode + * and Group 4 facsimile service + * Classes II and III */ + [20] = { "8890", "91A8" }, /* Teletex service basic and + * processable mode */ + [21] = { "8890", "91B1" }, /* Teletex service basic mode */ + [22] = { "8890", "91B2" }, /* International interworking for + * Videotex */ + [23] = { "8890", "91B5" }, /* Telex */ + [24] = { "8890", "91B8" }, /* Message Handling Systems + * in accordance with X.400 */ + [25] = { "8890", "91C1" }, /* OSI application + * in accordance with X.200 */ + [26] = { "9190A5", "9181" }, /* 7 kHz telephony */ + [27] = { "9190A5", "916001" }, /* Video telephony, first connection */ + [28] = { "8890", "916002" }, /* Video telephony, second connection */ }; /* @@ -223,10 +208,14 @@ get_appl(struct gigaset_capi_ctr *iif, u16 appl) static inline void dump_cmsg(enum debuglevel level, const char *tag, _cmsg *p) { #ifdef CONFIG_GIGASET_DEBUG + /* dump at most 20 messages in 20 secs */ + static DEFINE_RATELIMIT_STATE(msg_dump_ratelimit, 20 * HZ, 20); _cdebbuf *cdb; if (!(gigaset_debuglevel & level)) return; + if (!___ratelimit(&msg_dump_ratelimit, tag)) + return; cdb = capi_cmsg2str(p); if (cdb) { @@ -1192,7 +1181,9 @@ static void do_facility_req(struct gigaset_capi_ctr *iif, confparam[3] = 2; /* length */ capimsg_setu16(confparam, 4, CapiSuccess); break; - /* ToDo: add supported services */ + + /* ToDo: add supported services */ + default: dev_notice(cs->dev, "%s: unsupported supplementary service function 0x%04x\n", @@ -1766,7 +1757,8 @@ static void do_connect_b3_req(struct gigaset_capi_ctr *iif, /* NCPI parameter: not applicable for B3 Transparent */ ignore_cstruct_param(cs, cmsg->NCPI, "CONNECT_B3_REQ", "NCPI"); - send_conf(iif, ap, skb, (cmsg->NCPI && cmsg->NCPI[0]) ? + send_conf(iif, ap, skb, + (cmsg->NCPI && cmsg->NCPI[0]) ? CapiNcpiNotSupportedByProtocol : CapiSuccess); } @@ -1882,6 +1874,9 @@ static void do_disconnect_req(struct gigaset_capi_ctr *iif, /* check for active logical connection */ if (bcs->apconnstate >= APCONN_ACTIVE) { + /* clear it */ + bcs->apconnstate = APCONN_SETUP; + /* * emit DISCONNECT_B3_IND with cause 0x3301 * use separate cmsg structure, as the content of iif->acmsg @@ -1906,6 +1901,7 @@ static void do_disconnect_req(struct gigaset_capi_ctr *iif, } capi_cmsg2message(b3cmsg, __skb_put(b3skb, CAPI_DISCONNECT_B3_IND_BASELEN)); + dump_cmsg(DEBUG_CMD, __func__, b3cmsg); kfree(b3cmsg); capi_ctr_handle_message(&iif->ctr, ap->id, b3skb); } @@ -1966,7 +1962,8 @@ static void do_disconnect_b3_req(struct gigaset_capi_ctr *iif, /* NCPI parameter: not applicable for B3 Transparent */ ignore_cstruct_param(cs, cmsg->NCPI, "DISCONNECT_B3_REQ", "NCPI"); - send_conf(iif, ap, skb, (cmsg->NCPI && cmsg->NCPI[0]) ? + send_conf(iif, ap, skb, + (cmsg->NCPI && cmsg->NCPI[0]) ? CapiNcpiNotSupportedByProtocol : CapiSuccess); } @@ -2059,12 +2056,6 @@ static void do_reset_b3_req(struct gigaset_capi_ctr *iif, } /* - * dump unsupported/ignored messages at most twice per minute, - * some apps send those very frequently - */ -static unsigned long ignored_msg_dump_time; - -/* * unsupported CAPI message handler */ static void do_unsupported(struct gigaset_capi_ctr *iif, @@ -2073,8 +2064,7 @@ static void do_unsupported(struct gigaset_capi_ctr *iif, { /* decode message */ capi_message2cmsg(&iif->acmsg, skb->data); - if (printk_timed_ratelimit(&ignored_msg_dump_time, 30 * 1000)) - dump_cmsg(DEBUG_CMD, __func__, &iif->acmsg); + dump_cmsg(DEBUG_CMD, __func__, &iif->acmsg); send_conf(iif, ap, skb, CapiMessageNotSupportedInCurrentState); } @@ -2085,11 +2075,9 @@ static void do_nothing(struct gigaset_capi_ctr *iif, struct gigaset_capi_appl *ap, struct sk_buff *skb) { - if (printk_timed_ratelimit(&ignored_msg_dump_time, 30 * 1000)) { - /* decode message */ - capi_message2cmsg(&iif->acmsg, skb->data); - dump_cmsg(DEBUG_CMD, __func__, &iif->acmsg); - } + /* decode message */ + capi_message2cmsg(&iif->acmsg, skb->data); + dump_cmsg(DEBUG_CMD, __func__, &iif->acmsg); dev_kfree_skb_any(skb); } @@ -2358,7 +2346,7 @@ static const struct file_operations gigaset_proc_fops = { * @cs: device descriptor structure. * @isdnid: device name. * - * Return value: 1 for success, 0 for failure + * Return value: 0 on success, error code < 0 on failure */ int gigaset_isdn_regdev(struct cardstate *cs, const char *isdnid) { @@ -2368,7 +2356,7 @@ int gigaset_isdn_regdev(struct cardstate *cs, const char *isdnid) iif = kmalloc(sizeof(*iif), GFP_KERNEL); if (!iif) { pr_err("%s: out of memory\n", __func__); - return 0; + return -ENOMEM; } /* prepare controller structure */ @@ -2392,12 +2380,12 @@ int gigaset_isdn_regdev(struct cardstate *cs, const char *isdnid) if (rc) { pr_err("attach_capi_ctr failed (%d)\n", rc); kfree(iif); - return 0; + return rc; } cs->iif = iif; cs->hw_hdr_len = CAPI_DATA_B3_REQ_LEN; - return 1; + return 0; } /** diff --git a/drivers/isdn/gigaset/common.c b/drivers/isdn/gigaset/common.c index 76792707f995..aa41485bc594 100644 --- a/drivers/isdn/gigaset/common.c +++ b/drivers/isdn/gigaset/common.c @@ -194,13 +194,13 @@ int gigaset_get_channel(struct bc_state *bcs) gig_dbg(DEBUG_CHANNEL, "could not allocate channel %d", bcs->channel); spin_unlock_irqrestore(&bcs->cs->lock, flags); - return 0; + return -EBUSY; } ++bcs->use_count; bcs->busy = 1; gig_dbg(DEBUG_CHANNEL, "allocated channel %d", bcs->channel); spin_unlock_irqrestore(&bcs->cs->lock, flags); - return 1; + return 0; } struct bc_state *gigaset_get_free_channel(struct cardstate *cs) @@ -258,7 +258,7 @@ int gigaset_get_channels(struct cardstate *cs) spin_unlock_irqrestore(&cs->lock, flags); gig_dbg(DEBUG_CHANNEL, "could not allocate all channels"); - return 0; + return -EBUSY; } for (i = 0; i < cs->channels; ++i) ++cs->bcs[i].use_count; @@ -266,7 +266,7 @@ int gigaset_get_channels(struct cardstate *cs) gig_dbg(DEBUG_CHANNEL, "allocated all channels"); - return 1; + return 0; } void gigaset_free_channels(struct cardstate *cs) @@ -362,7 +362,7 @@ struct event_t *gigaset_add_event(struct cardstate *cs, } EXPORT_SYMBOL_GPL(gigaset_add_event); -static void free_strings(struct at_state_t *at_state) +static void clear_at_state(struct at_state_t *at_state) { int i; @@ -372,18 +372,13 @@ static void free_strings(struct at_state_t *at_state) } } -static void clear_at_state(struct at_state_t *at_state) -{ - free_strings(at_state); -} - -static void dealloc_at_states(struct cardstate *cs) +static void dealloc_temp_at_states(struct cardstate *cs) { struct at_state_t *cur, *next; list_for_each_entry_safe(cur, next, &cs->temp_at_states, list) { list_del(&cur->list); - free_strings(cur); + clear_at_state(cur); kfree(cur); } } @@ -393,8 +388,7 @@ static void gigaset_freebcs(struct bc_state *bcs) int i; gig_dbg(DEBUG_INIT, "freeing bcs[%d]->hw", bcs->channel); - if (!bcs->cs->ops->freebcshw(bcs)) - gig_dbg(DEBUG_INIT, "failed"); + bcs->cs->ops->freebcshw(bcs); gig_dbg(DEBUG_INIT, "clearing bcs[%d]->at_state", bcs->channel); clear_at_state(&bcs->at_state); @@ -512,7 +506,7 @@ void gigaset_freecs(struct cardstate *cs) case 1: /* error when registering to LL */ gig_dbg(DEBUG_INIT, "clearing at_state"); clear_at_state(&cs->at_state); - dealloc_at_states(cs); + dealloc_temp_at_states(cs); /* fall through */ case 0: /* error in basic setup */ @@ -571,6 +565,8 @@ static void gigaset_inbuf_init(struct inbuf_t *inbuf, struct cardstate *cs) * @inbuf: buffer structure. * @src: received data. * @numbytes: number of bytes received. + * + * Return value: !=0 if some data was appended */ int gigaset_fill_inbuf(struct inbuf_t *inbuf, const unsigned char *src, unsigned numbytes) @@ -614,8 +610,8 @@ int gigaset_fill_inbuf(struct inbuf_t *inbuf, const unsigned char *src, EXPORT_SYMBOL_GPL(gigaset_fill_inbuf); /* Initialize the b-channel structure */ -static struct bc_state *gigaset_initbcs(struct bc_state *bcs, - struct cardstate *cs, int channel) +static int gigaset_initbcs(struct bc_state *bcs, struct cardstate *cs, + int channel) { int i; @@ -654,11 +650,7 @@ static struct bc_state *gigaset_initbcs(struct bc_state *bcs, bcs->apconnstate = 0; gig_dbg(DEBUG_INIT, " setting up bcs[%d]->hw", channel); - if (cs->ops->initbcshw(bcs)) - return bcs; - - gig_dbg(DEBUG_INIT, " failed"); - return NULL; + return cs->ops->initbcshw(bcs); } /** @@ -757,7 +749,7 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels, cs->cmdbytes = 0; gig_dbg(DEBUG_INIT, "setting up iif"); - if (!gigaset_isdn_regdev(cs, modulename)) { + if (gigaset_isdn_regdev(cs, modulename) < 0) { pr_err("error registering ISDN device\n"); goto error; } @@ -765,7 +757,7 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels, make_valid(cs, VALID_ID); ++cs->cs_init; gig_dbg(DEBUG_INIT, "setting up hw"); - if (!cs->ops->initcshw(cs)) + if (cs->ops->initcshw(cs) < 0) goto error; ++cs->cs_init; @@ -779,7 +771,7 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels, /* set up channel data structures */ for (i = 0; i < channels; ++i) { gig_dbg(DEBUG_INIT, "setting up bcs[%d]", i); - if (!gigaset_initbcs(cs->bcs + i, cs, i)) { + if (gigaset_initbcs(cs->bcs + i, cs, i) < 0) { pr_err("could not allocate channel %d data\n", i); goto error; } @@ -848,8 +840,7 @@ static void cleanup_cs(struct cardstate *cs) cs->mstate = MS_UNINITIALIZED; clear_at_state(&cs->at_state); - dealloc_at_states(cs); - free_strings(&cs->at_state); + dealloc_temp_at_states(cs); gigaset_at_init(&cs->at_state, NULL, cs, 0); cs->inbuf->inputstate = INS_command; @@ -875,7 +866,7 @@ static void cleanup_cs(struct cardstate *cs) for (i = 0; i < cs->channels; ++i) { gigaset_freebcs(cs->bcs + i); - if (!gigaset_initbcs(cs->bcs + i, cs, i)) + if (gigaset_initbcs(cs->bcs + i, cs, i) < 0) pr_err("could not allocate channel %d data\n", i); } @@ -896,14 +887,14 @@ static void cleanup_cs(struct cardstate *cs) * waiting for completion of the initialization. * * Return value: - * 1 - success, 0 - error + * 0 on success, error code < 0 on failure */ int gigaset_start(struct cardstate *cs) { unsigned long flags; if (mutex_lock_interruptible(&cs->mutex)) - return 0; + return -EBUSY; spin_lock_irqsave(&cs->lock, flags); cs->connected = 1; @@ -927,11 +918,11 @@ int gigaset_start(struct cardstate *cs) wait_event(cs->waitqueue, !cs->waiting); mutex_unlock(&cs->mutex); - return 1; + return 0; error: mutex_unlock(&cs->mutex); - return 0; + return -ENOMEM; } EXPORT_SYMBOL_GPL(gigaset_start); @@ -943,7 +934,7 @@ EXPORT_SYMBOL_GPL(gigaset_start); * waiting for completion of the shutdown. * * Return value: - * 0 - success, -1 - error (no device associated) + * 0 - success, -ENODEV - error (no device associated) */ int gigaset_shutdown(struct cardstate *cs) { @@ -951,7 +942,7 @@ int gigaset_shutdown(struct cardstate *cs) if (!(cs->flags & VALID_MINOR)) { mutex_unlock(&cs->mutex); - return -1; + return -ENODEV; } cs->waiting = 1; diff --git a/drivers/isdn/gigaset/dummyll.c b/drivers/isdn/gigaset/dummyll.c index 19b1c779d50f..570c2d53b84e 100644 --- a/drivers/isdn/gigaset/dummyll.c +++ b/drivers/isdn/gigaset/dummyll.c @@ -60,7 +60,7 @@ void gigaset_isdn_stop(struct cardstate *cs) int gigaset_isdn_regdev(struct cardstate *cs, const char *isdnid) { - return 1; + return 0; } void gigaset_isdn_unregdev(struct cardstate *cs) diff --git a/drivers/isdn/gigaset/ev-layer.c b/drivers/isdn/gigaset/ev-layer.c index 624a8256a77f..2e6963dc740e 100644 --- a/drivers/isdn/gigaset/ev-layer.c +++ b/drivers/isdn/gigaset/ev-layer.c @@ -153,103 +153,104 @@ struct reply_t gigaset_tab_nocid[] = * action, command */ /* initialize device, set cid mode if possible */ - {RSP_INIT, -1, -1, SEQ_INIT, 100, 1, {ACT_TIMEOUT} }, + {RSP_INIT, -1, -1, SEQ_INIT, 100, 1, {ACT_TIMEOUT} }, - {EV_TIMEOUT, 100, 100, -1, 101, 3, {0}, "Z\r"}, - {RSP_OK, 101, 103, -1, 120, 5, {ACT_GETSTRING}, - "+GMR\r"}, + {EV_TIMEOUT, 100, 100, -1, 101, 3, {0}, "Z\r"}, + {RSP_OK, 101, 103, -1, 120, 5, {ACT_GETSTRING}, + "+GMR\r"}, - {EV_TIMEOUT, 101, 101, -1, 102, 5, {0}, "Z\r"}, - {RSP_ERROR, 101, 101, -1, 102, 5, {0}, "Z\r"}, + {EV_TIMEOUT, 101, 101, -1, 102, 5, {0}, "Z\r"}, + {RSP_ERROR, 101, 101, -1, 102, 5, {0}, "Z\r"}, - {EV_TIMEOUT, 102, 102, -1, 108, 5, {ACT_SETDLE1}, - "^SDLE=0\r"}, - {RSP_OK, 108, 108, -1, 104, -1}, - {RSP_ZDLE, 104, 104, 0, 103, 5, {0}, "Z\r"}, - {EV_TIMEOUT, 104, 104, -1, 0, 0, {ACT_FAILINIT} }, - {RSP_ERROR, 108, 108, -1, 0, 0, {ACT_FAILINIT} }, + {EV_TIMEOUT, 102, 102, -1, 108, 5, {ACT_SETDLE1}, + "^SDLE=0\r"}, + {RSP_OK, 108, 108, -1, 104, -1}, + {RSP_ZDLE, 104, 104, 0, 103, 5, {0}, "Z\r"}, + {EV_TIMEOUT, 104, 104, -1, 0, 0, {ACT_FAILINIT} }, + {RSP_ERROR, 108, 108, -1, 0, 0, {ACT_FAILINIT} }, - {EV_TIMEOUT, 108, 108, -1, 105, 2, {ACT_SETDLE0, - ACT_HUPMODEM, - ACT_TIMEOUT} }, - {EV_TIMEOUT, 105, 105, -1, 103, 5, {0}, "Z\r"}, + {EV_TIMEOUT, 108, 108, -1, 105, 2, {ACT_SETDLE0, + ACT_HUPMODEM, + ACT_TIMEOUT} }, + {EV_TIMEOUT, 105, 105, -1, 103, 5, {0}, "Z\r"}, - {RSP_ERROR, 102, 102, -1, 107, 5, {0}, "^GETPRE\r"}, - {RSP_OK, 107, 107, -1, 0, 0, {ACT_CONFIGMODE} }, - {RSP_ERROR, 107, 107, -1, 0, 0, {ACT_FAILINIT} }, - {EV_TIMEOUT, 107, 107, -1, 0, 0, {ACT_FAILINIT} }, + {RSP_ERROR, 102, 102, -1, 107, 5, {0}, "^GETPRE\r"}, + {RSP_OK, 107, 107, -1, 0, 0, {ACT_CONFIGMODE} }, + {RSP_ERROR, 107, 107, -1, 0, 0, {ACT_FAILINIT} }, + {EV_TIMEOUT, 107, 107, -1, 0, 0, {ACT_FAILINIT} }, - {RSP_ERROR, 103, 103, -1, 0, 0, {ACT_FAILINIT} }, - {EV_TIMEOUT, 103, 103, -1, 0, 0, {ACT_FAILINIT} }, + {RSP_ERROR, 103, 103, -1, 0, 0, {ACT_FAILINIT} }, + {EV_TIMEOUT, 103, 103, -1, 0, 0, {ACT_FAILINIT} }, - {RSP_STRING, 120, 120, -1, 121, -1, {ACT_SETVER} }, + {RSP_STRING, 120, 120, -1, 121, -1, {ACT_SETVER} }, - {EV_TIMEOUT, 120, 121, -1, 0, 0, {ACT_FAILVER, - ACT_INIT} }, - {RSP_ERROR, 120, 121, -1, 0, 0, {ACT_FAILVER, - ACT_INIT} }, - {RSP_OK, 121, 121, -1, 0, 0, {ACT_GOTVER, - ACT_INIT} }, + {EV_TIMEOUT, 120, 121, -1, 0, 0, {ACT_FAILVER, + ACT_INIT} }, + {RSP_ERROR, 120, 121, -1, 0, 0, {ACT_FAILVER, + ACT_INIT} }, + {RSP_OK, 121, 121, -1, 0, 0, {ACT_GOTVER, + ACT_INIT} }, + {RSP_NONE, 121, 121, -1, 120, 0, {ACT_GETSTRING} }, /* leave dle mode */ - {RSP_INIT, 0, 0, SEQ_DLE0, 201, 5, {0}, "^SDLE=0\r"}, - {RSP_OK, 201, 201, -1, 202, -1}, - {RSP_ZDLE, 202, 202, 0, 0, 0, {ACT_DLE0} }, - {RSP_NODEV, 200, 249, -1, 0, 0, {ACT_FAKEDLE0} }, - {RSP_ERROR, 200, 249, -1, 0, 0, {ACT_FAILDLE0} }, - {EV_TIMEOUT, 200, 249, -1, 0, 0, {ACT_FAILDLE0} }, + {RSP_INIT, 0, 0, SEQ_DLE0, 201, 5, {0}, "^SDLE=0\r"}, + {RSP_OK, 201, 201, -1, 202, -1}, + {RSP_ZDLE, 202, 202, 0, 0, 0, {ACT_DLE0} }, + {RSP_NODEV, 200, 249, -1, 0, 0, {ACT_FAKEDLE0} }, + {RSP_ERROR, 200, 249, -1, 0, 0, {ACT_FAILDLE0} }, + {EV_TIMEOUT, 200, 249, -1, 0, 0, {ACT_FAILDLE0} }, /* enter dle mode */ - {RSP_INIT, 0, 0, SEQ_DLE1, 251, 5, {0}, "^SDLE=1\r"}, - {RSP_OK, 251, 251, -1, 252, -1}, - {RSP_ZDLE, 252, 252, 1, 0, 0, {ACT_DLE1} }, - {RSP_ERROR, 250, 299, -1, 0, 0, {ACT_FAILDLE1} }, - {EV_TIMEOUT, 250, 299, -1, 0, 0, {ACT_FAILDLE1} }, + {RSP_INIT, 0, 0, SEQ_DLE1, 251, 5, {0}, "^SDLE=1\r"}, + {RSP_OK, 251, 251, -1, 252, -1}, + {RSP_ZDLE, 252, 252, 1, 0, 0, {ACT_DLE1} }, + {RSP_ERROR, 250, 299, -1, 0, 0, {ACT_FAILDLE1} }, + {EV_TIMEOUT, 250, 299, -1, 0, 0, {ACT_FAILDLE1} }, /* incoming call */ - {RSP_RING, -1, -1, -1, -1, -1, {ACT_RING} }, + {RSP_RING, -1, -1, -1, -1, -1, {ACT_RING} }, /* get cid */ - {RSP_INIT, 0, 0, SEQ_CID, 301, 5, {0}, "^SGCI?\r"}, - {RSP_OK, 301, 301, -1, 302, -1}, - {RSP_ZGCI, 302, 302, -1, 0, 0, {ACT_CID} }, - {RSP_ERROR, 301, 349, -1, 0, 0, {ACT_FAILCID} }, - {EV_TIMEOUT, 301, 349, -1, 0, 0, {ACT_FAILCID} }, + {RSP_INIT, 0, 0, SEQ_CID, 301, 5, {0}, "^SGCI?\r"}, + {RSP_OK, 301, 301, -1, 302, -1}, + {RSP_ZGCI, 302, 302, -1, 0, 0, {ACT_CID} }, + {RSP_ERROR, 301, 349, -1, 0, 0, {ACT_FAILCID} }, + {EV_TIMEOUT, 301, 349, -1, 0, 0, {ACT_FAILCID} }, /* enter cid mode */ - {RSP_INIT, 0, 0, SEQ_CIDMODE, 150, 5, {0}, "^SGCI=1\r"}, - {RSP_OK, 150, 150, -1, 0, 0, {ACT_CMODESET} }, - {RSP_ERROR, 150, 150, -1, 0, 0, {ACT_FAILCMODE} }, - {EV_TIMEOUT, 150, 150, -1, 0, 0, {ACT_FAILCMODE} }, + {RSP_INIT, 0, 0, SEQ_CIDMODE, 150, 5, {0}, "^SGCI=1\r"}, + {RSP_OK, 150, 150, -1, 0, 0, {ACT_CMODESET} }, + {RSP_ERROR, 150, 150, -1, 0, 0, {ACT_FAILCMODE} }, + {EV_TIMEOUT, 150, 150, -1, 0, 0, {ACT_FAILCMODE} }, /* leave cid mode */ - {RSP_INIT, 0, 0, SEQ_UMMODE, 160, 5, {0}, "Z\r"}, - {RSP_OK, 160, 160, -1, 0, 0, {ACT_UMODESET} }, - {RSP_ERROR, 160, 160, -1, 0, 0, {ACT_FAILUMODE} }, - {EV_TIMEOUT, 160, 160, -1, 0, 0, {ACT_FAILUMODE} }, + {RSP_INIT, 0, 0, SEQ_UMMODE, 160, 5, {0}, "Z\r"}, + {RSP_OK, 160, 160, -1, 0, 0, {ACT_UMODESET} }, + {RSP_ERROR, 160, 160, -1, 0, 0, {ACT_FAILUMODE} }, + {EV_TIMEOUT, 160, 160, -1, 0, 0, {ACT_FAILUMODE} }, /* abort getting cid */ - {RSP_INIT, 0, 0, SEQ_NOCID, 0, 0, {ACT_ABORTCID} }, + {RSP_INIT, 0, 0, SEQ_NOCID, 0, 0, {ACT_ABORTCID} }, /* reset */ - {RSP_INIT, 0, 0, SEQ_SHUTDOWN, 504, 5, {0}, "Z\r"}, - {RSP_OK, 504, 504, -1, 0, 0, {ACT_SDOWN} }, - {RSP_ERROR, 501, 599, -1, 0, 0, {ACT_FAILSDOWN} }, - {EV_TIMEOUT, 501, 599, -1, 0, 0, {ACT_FAILSDOWN} }, - {RSP_NODEV, 501, 599, -1, 0, 0, {ACT_FAKESDOWN} }, - - {EV_PROC_CIDMODE, -1, -1, -1, -1, -1, {ACT_PROC_CIDMODE} }, - {EV_IF_LOCK, -1, -1, -1, -1, -1, {ACT_IF_LOCK} }, - {EV_IF_VER, -1, -1, -1, -1, -1, {ACT_IF_VER} }, - {EV_START, -1, -1, -1, -1, -1, {ACT_START} }, - {EV_STOP, -1, -1, -1, -1, -1, {ACT_STOP} }, - {EV_SHUTDOWN, -1, -1, -1, -1, -1, {ACT_SHUTDOWN} }, + {RSP_INIT, 0, 0, SEQ_SHUTDOWN, 504, 5, {0}, "Z\r"}, + {RSP_OK, 504, 504, -1, 0, 0, {ACT_SDOWN} }, + {RSP_ERROR, 501, 599, -1, 0, 0, {ACT_FAILSDOWN} }, + {EV_TIMEOUT, 501, 599, -1, 0, 0, {ACT_FAILSDOWN} }, + {RSP_NODEV, 501, 599, -1, 0, 0, {ACT_FAKESDOWN} }, + + {EV_PROC_CIDMODE, -1, -1, -1, -1, -1, {ACT_PROC_CIDMODE} }, + {EV_IF_LOCK, -1, -1, -1, -1, -1, {ACT_IF_LOCK} }, + {EV_IF_VER, -1, -1, -1, -1, -1, {ACT_IF_VER} }, + {EV_START, -1, -1, -1, -1, -1, {ACT_START} }, + {EV_STOP, -1, -1, -1, -1, -1, {ACT_STOP} }, + {EV_SHUTDOWN, -1, -1, -1, -1, -1, {ACT_SHUTDOWN} }, /* misc. */ - {RSP_ERROR, -1, -1, -1, -1, -1, {ACT_ERROR} }, - {RSP_ZCAU, -1, -1, -1, -1, -1, {ACT_ZCAU} }, - {RSP_NONE, -1, -1, -1, -1, -1, {ACT_DEBUG} }, - {RSP_ANY, -1, -1, -1, -1, -1, {ACT_WARN} }, + {RSP_ERROR, -1, -1, -1, -1, -1, {ACT_ERROR} }, + {RSP_ZCAU, -1, -1, -1, -1, -1, {ACT_ZCAU} }, + {RSP_NONE, -1, -1, -1, -1, -1, {ACT_DEBUG} }, + {RSP_ANY, -1, -1, -1, -1, -1, {ACT_WARN} }, {RSP_LAST} }; @@ -261,90 +262,90 @@ struct reply_t gigaset_tab_cid[] = * action, command */ /* dial */ - {EV_DIAL, -1, -1, -1, -1, -1, {ACT_DIAL} }, - {RSP_INIT, 0, 0, SEQ_DIAL, 601, 5, {ACT_CMD + AT_BC} }, - {RSP_OK, 601, 601, -1, 603, 5, {ACT_CMD + AT_PROTO} }, - {RSP_OK, 603, 603, -1, 604, 5, {ACT_CMD + AT_TYPE} }, - {RSP_OK, 604, 604, -1, 605, 5, {ACT_CMD + AT_MSN} }, - {RSP_NULL, 605, 605, -1, 606, 5, {ACT_CMD + AT_CLIP} }, - {RSP_OK, 605, 605, -1, 606, 5, {ACT_CMD + AT_CLIP} }, - {RSP_NULL, 606, 606, -1, 607, 5, {ACT_CMD + AT_ISO} }, - {RSP_OK, 606, 606, -1, 607, 5, {ACT_CMD + AT_ISO} }, - {RSP_OK, 607, 607, -1, 608, 5, {0}, "+VLS=17\r"}, - {RSP_OK, 608, 608, -1, 609, -1}, - {RSP_ZSAU, 609, 609, ZSAU_PROCEEDING, 610, 5, {ACT_CMD + AT_DIAL} }, - {RSP_OK, 610, 610, -1, 650, 0, {ACT_DIALING} }, - - {RSP_ERROR, 601, 610, -1, 0, 0, {ACT_ABORTDIAL} }, - {EV_TIMEOUT, 601, 610, -1, 0, 0, {ACT_ABORTDIAL} }, + {EV_DIAL, -1, -1, -1, -1, -1, {ACT_DIAL} }, + {RSP_INIT, 0, 0, SEQ_DIAL, 601, 5, {ACT_CMD + AT_BC} }, + {RSP_OK, 601, 601, -1, 603, 5, {ACT_CMD + AT_PROTO} }, + {RSP_OK, 603, 603, -1, 604, 5, {ACT_CMD + AT_TYPE} }, + {RSP_OK, 604, 604, -1, 605, 5, {ACT_CMD + AT_MSN} }, + {RSP_NULL, 605, 605, -1, 606, 5, {ACT_CMD + AT_CLIP} }, + {RSP_OK, 605, 605, -1, 606, 5, {ACT_CMD + AT_CLIP} }, + {RSP_NULL, 606, 606, -1, 607, 5, {ACT_CMD + AT_ISO} }, + {RSP_OK, 606, 606, -1, 607, 5, {ACT_CMD + AT_ISO} }, + {RSP_OK, 607, 607, -1, 608, 5, {0}, "+VLS=17\r"}, + {RSP_OK, 608, 608, -1, 609, -1}, + {RSP_ZSAU, 609, 609, ZSAU_PROCEEDING, 610, 5, {ACT_CMD + AT_DIAL} }, + {RSP_OK, 610, 610, -1, 650, 0, {ACT_DIALING} }, + + {RSP_ERROR, 601, 610, -1, 0, 0, {ACT_ABORTDIAL} }, + {EV_TIMEOUT, 601, 610, -1, 0, 0, {ACT_ABORTDIAL} }, /* optional dialing responses */ - {EV_BC_OPEN, 650, 650, -1, 651, -1}, - {RSP_ZVLS, 609, 651, 17, -1, -1, {ACT_DEBUG} }, - {RSP_ZCTP, 610, 651, -1, -1, -1, {ACT_DEBUG} }, - {RSP_ZCPN, 610, 651, -1, -1, -1, {ACT_DEBUG} }, - {RSP_ZSAU, 650, 651, ZSAU_CALL_DELIVERED, -1, -1, {ACT_DEBUG} }, + {EV_BC_OPEN, 650, 650, -1, 651, -1}, + {RSP_ZVLS, 609, 651, 17, -1, -1, {ACT_DEBUG} }, + {RSP_ZCTP, 610, 651, -1, -1, -1, {ACT_DEBUG} }, + {RSP_ZCPN, 610, 651, -1, -1, -1, {ACT_DEBUG} }, + {RSP_ZSAU, 650, 651, ZSAU_CALL_DELIVERED, -1, -1, {ACT_DEBUG} }, /* connect */ - {RSP_ZSAU, 650, 650, ZSAU_ACTIVE, 800, -1, {ACT_CONNECT} }, - {RSP_ZSAU, 651, 651, ZSAU_ACTIVE, 800, -1, {ACT_CONNECT, - ACT_NOTIFY_BC_UP} }, - {RSP_ZSAU, 750, 750, ZSAU_ACTIVE, 800, -1, {ACT_CONNECT} }, - {RSP_ZSAU, 751, 751, ZSAU_ACTIVE, 800, -1, {ACT_CONNECT, - ACT_NOTIFY_BC_UP} }, - {EV_BC_OPEN, 800, 800, -1, 800, -1, {ACT_NOTIFY_BC_UP} }, + {RSP_ZSAU, 650, 650, ZSAU_ACTIVE, 800, -1, {ACT_CONNECT} }, + {RSP_ZSAU, 651, 651, ZSAU_ACTIVE, 800, -1, {ACT_CONNECT, + ACT_NOTIFY_BC_UP} }, + {RSP_ZSAU, 750, 750, ZSAU_ACTIVE, 800, -1, {ACT_CONNECT} }, + {RSP_ZSAU, 751, 751, ZSAU_ACTIVE, 800, -1, {ACT_CONNECT, + ACT_NOTIFY_BC_UP} }, + {EV_BC_OPEN, 800, 800, -1, 800, -1, {ACT_NOTIFY_BC_UP} }, /* remote hangup */ - {RSP_ZSAU, 650, 651, ZSAU_DISCONNECT_IND, 0, 0, {ACT_REMOTEREJECT} }, - {RSP_ZSAU, 750, 751, ZSAU_DISCONNECT_IND, 0, 0, {ACT_REMOTEHUP} }, - {RSP_ZSAU, 800, 800, ZSAU_DISCONNECT_IND, 0, 0, {ACT_REMOTEHUP} }, + {RSP_ZSAU, 650, 651, ZSAU_DISCONNECT_IND, 0, 0, {ACT_REMOTEREJECT} }, + {RSP_ZSAU, 750, 751, ZSAU_DISCONNECT_IND, 0, 0, {ACT_REMOTEHUP} }, + {RSP_ZSAU, 800, 800, ZSAU_DISCONNECT_IND, 0, 0, {ACT_REMOTEHUP} }, /* hangup */ - {EV_HUP, -1, -1, -1, -1, -1, {ACT_HUP} }, - {RSP_INIT, -1, -1, SEQ_HUP, 401, 5, {0}, "+VLS=0\r"}, - {RSP_OK, 401, 401, -1, 402, 5}, - {RSP_ZVLS, 402, 402, 0, 403, 5}, - {RSP_ZSAU, 403, 403, ZSAU_DISCONNECT_REQ, -1, -1, {ACT_DEBUG} }, - {RSP_ZSAU, 403, 403, ZSAU_NULL, 0, 0, {ACT_DISCONNECT} }, - {RSP_NODEV, 401, 403, -1, 0, 0, {ACT_FAKEHUP} }, - {RSP_ERROR, 401, 401, -1, 0, 0, {ACT_ABORTHUP} }, - {EV_TIMEOUT, 401, 403, -1, 0, 0, {ACT_ABORTHUP} }, - - {EV_BC_CLOSED, 0, 0, -1, 0, -1, {ACT_NOTIFY_BC_DOWN} }, + {EV_HUP, -1, -1, -1, -1, -1, {ACT_HUP} }, + {RSP_INIT, -1, -1, SEQ_HUP, 401, 5, {0}, "+VLS=0\r"}, + {RSP_OK, 401, 401, -1, 402, 5}, + {RSP_ZVLS, 402, 402, 0, 403, 5}, + {RSP_ZSAU, 403, 403, ZSAU_DISCONNECT_REQ, -1, -1, {ACT_DEBUG} }, + {RSP_ZSAU, 403, 403, ZSAU_NULL, 0, 0, {ACT_DISCONNECT} }, + {RSP_NODEV, 401, 403, -1, 0, 0, {ACT_FAKEHUP} }, + {RSP_ERROR, 401, 401, -1, 0, 0, {ACT_ABORTHUP} }, + {EV_TIMEOUT, 401, 403, -1, 0, 0, {ACT_ABORTHUP} }, + + {EV_BC_CLOSED, 0, 0, -1, 0, -1, {ACT_NOTIFY_BC_DOWN} }, /* ring */ - {RSP_ZBC, 700, 700, -1, -1, -1, {0} }, - {RSP_ZHLC, 700, 700, -1, -1, -1, {0} }, - {RSP_NMBR, 700, 700, -1, -1, -1, {0} }, - {RSP_ZCPN, 700, 700, -1, -1, -1, {0} }, - {RSP_ZCTP, 700, 700, -1, -1, -1, {0} }, - {EV_TIMEOUT, 700, 700, -1, 720, 720, {ACT_ICALL} }, - {EV_BC_CLOSED, 720, 720, -1, 0, -1, {ACT_NOTIFY_BC_DOWN} }, + {RSP_ZBC, 700, 700, -1, -1, -1, {0} }, + {RSP_ZHLC, 700, 700, -1, -1, -1, {0} }, + {RSP_NMBR, 700, 700, -1, -1, -1, {0} }, + {RSP_ZCPN, 700, 700, -1, -1, -1, {0} }, + {RSP_ZCTP, 700, 700, -1, -1, -1, {0} }, + {EV_TIMEOUT, 700, 700, -1, 720, 720, {ACT_ICALL} }, + {EV_BC_CLOSED, 720, 720, -1, 0, -1, {ACT_NOTIFY_BC_DOWN} }, /*accept icall*/ - {EV_ACCEPT, -1, -1, -1, -1, -1, {ACT_ACCEPT} }, - {RSP_INIT, 720, 720, SEQ_ACCEPT, 721, 5, {ACT_CMD + AT_PROTO} }, - {RSP_OK, 721, 721, -1, 722, 5, {ACT_CMD + AT_ISO} }, - {RSP_OK, 722, 722, -1, 723, 5, {0}, "+VLS=17\r"}, - {RSP_OK, 723, 723, -1, 724, 5, {0} }, - {RSP_ZVLS, 724, 724, 17, 750, 50, {ACT_ACCEPTED} }, - {RSP_ERROR, 721, 729, -1, 0, 0, {ACT_ABORTACCEPT} }, - {EV_TIMEOUT, 721, 729, -1, 0, 0, {ACT_ABORTACCEPT} }, - {RSP_ZSAU, 700, 729, ZSAU_NULL, 0, 0, {ACT_ABORTACCEPT} }, - {RSP_ZSAU, 700, 729, ZSAU_ACTIVE, 0, 0, {ACT_ABORTACCEPT} }, - {RSP_ZSAU, 700, 729, ZSAU_DISCONNECT_IND, 0, 0, {ACT_ABORTACCEPT} }, - - {EV_BC_OPEN, 750, 750, -1, 751, -1}, - {EV_TIMEOUT, 750, 751, -1, 0, 0, {ACT_CONNTIMEOUT} }, + {EV_ACCEPT, -1, -1, -1, -1, -1, {ACT_ACCEPT} }, + {RSP_INIT, 720, 720, SEQ_ACCEPT, 721, 5, {ACT_CMD + AT_PROTO} }, + {RSP_OK, 721, 721, -1, 722, 5, {ACT_CMD + AT_ISO} }, + {RSP_OK, 722, 722, -1, 723, 5, {0}, "+VLS=17\r"}, + {RSP_OK, 723, 723, -1, 724, 5, {0} }, + {RSP_ZVLS, 724, 724, 17, 750, 50, {ACT_ACCEPTED} }, + {RSP_ERROR, 721, 729, -1, 0, 0, {ACT_ABORTACCEPT} }, + {EV_TIMEOUT, 721, 729, -1, 0, 0, {ACT_ABORTACCEPT} }, + {RSP_ZSAU, 700, 729, ZSAU_NULL, 0, 0, {ACT_ABORTACCEPT} }, + {RSP_ZSAU, 700, 729, ZSAU_ACTIVE, 0, 0, {ACT_ABORTACCEPT} }, + {RSP_ZSAU, 700, 729, ZSAU_DISCONNECT_IND, 0, 0, {ACT_ABORTACCEPT} }, + + {EV_BC_OPEN, 750, 750, -1, 751, -1}, + {EV_TIMEOUT, 750, 751, -1, 0, 0, {ACT_CONNTIMEOUT} }, /* B channel closed (general case) */ - {EV_BC_CLOSED, -1, -1, -1, -1, -1, {ACT_NOTIFY_BC_DOWN} }, + {EV_BC_CLOSED, -1, -1, -1, -1, -1, {ACT_NOTIFY_BC_DOWN} }, /* misc. */ - {RSP_ZCON, -1, -1, -1, -1, -1, {ACT_DEBUG} }, - {RSP_ZCAU, -1, -1, -1, -1, -1, {ACT_ZCAU} }, - {RSP_NONE, -1, -1, -1, -1, -1, {ACT_DEBUG} }, - {RSP_ANY, -1, -1, -1, -1, -1, {ACT_WARN} }, + {RSP_ZCON, -1, -1, -1, -1, -1, {ACT_DEBUG} }, + {RSP_ZCAU, -1, -1, -1, -1, -1, {ACT_ZCAU} }, + {RSP_NONE, -1, -1, -1, -1, -1, {ACT_DEBUG} }, + {RSP_ANY, -1, -1, -1, -1, -1, {ACT_WARN} }, {RSP_LAST} }; @@ -648,16 +649,16 @@ static void disconnect(struct at_state_t **at_state_p) static inline struct at_state_t *get_free_channel(struct cardstate *cs, int cid) /* cids: >0: siemens-cid - 0: without cid - -1: no cid assigned yet -*/ + * 0: without cid + * -1: no cid assigned yet + */ { unsigned long flags; int i; struct at_state_t *ret; for (i = 0; i < cs->channels; ++i) - if (gigaset_get_channel(cs->bcs + i)) { + if (gigaset_get_channel(cs->bcs + i) >= 0) { ret = &cs->bcs[i].at_state; ret->cid = cid; return ret; @@ -922,18 +923,18 @@ static void do_stop(struct cardstate *cs) * channel >= 0: getting cid for the channel failed * channel < 0: entering cid mode failed * - * returns 0 on failure + * returns 0 on success, <0 on failure */ static int reinit_and_retry(struct cardstate *cs, int channel) { int i; if (--cs->retry_count <= 0) - return 0; + return -EFAULT; for (i = 0; i < cs->channels; ++i) if (cs->bcs[i].at_state.cid > 0) - return 0; + return -EBUSY; if (channel < 0) dev_warn(cs->dev, @@ -944,7 +945,7 @@ static int reinit_and_retry(struct cardstate *cs, int channel) cs->bcs[channel].at_state.pending_commands |= PC_CID; } schedule_init(cs, MS_INIT); - return 1; + return 0; } static int at_state_invalid(struct cardstate *cs, @@ -1015,7 +1016,7 @@ static int do_lock(struct cardstate *cs) if (cs->bcs[i].at_state.pending_commands) return -EBUSY; - if (!gigaset_get_channels(cs)) + if (gigaset_get_channels(cs) < 0) return -EBUSY; break; @@ -1124,7 +1125,7 @@ static void do_action(int action, struct cardstate *cs, init_failed(cs, M_UNKNOWN); break; } - if (!reinit_and_retry(cs, -1)) + if (reinit_and_retry(cs, -1) < 0) schedule_init(cs, MS_RECOVER); break; case ACT_FAILUMODE: @@ -1267,7 +1268,7 @@ static void do_action(int action, struct cardstate *cs, case ACT_FAILCID: cs->cur_at_seq = SEQ_NONE; channel = cs->curchannel; - if (!reinit_and_retry(cs, channel)) { + if (reinit_and_retry(cs, channel) < 0) { dev_warn(cs->dev, "Could not get a call ID. Cannot dial.\n"); at_state2 = &cs->bcs[channel].at_state; @@ -1314,8 +1315,9 @@ static void do_action(int action, struct cardstate *cs, s = ev->ptr; if (!strcmp(s, "OK")) { + /* OK without version string: assume old response */ *p_genresp = 1; - *p_resp_code = RSP_ERROR; + *p_resp_code = RSP_NONE; break; } @@ -1372,7 +1374,8 @@ static void do_action(int action, struct cardstate *cs, ev->parameter, at_state->ConState); break; - /* events from the LL */ + /* events from the LL */ + case ACT_DIAL: start_dial(at_state, ev->ptr, ev->parameter); break; @@ -1385,7 +1388,8 @@ static void do_action(int action, struct cardstate *cs, cs->commands_pending = 1; break; - /* hotplug events */ + /* hotplug events */ + case ACT_STOP: do_stop(cs); break; @@ -1393,7 +1397,8 @@ static void do_action(int action, struct cardstate *cs, do_start(cs); break; - /* events from the interface */ + /* events from the interface */ + case ACT_IF_LOCK: cs->cmd_result = ev->parameter ? do_lock(cs) : do_unlock(cs); cs->waiting = 0; @@ -1412,7 +1417,8 @@ static void do_action(int action, struct cardstate *cs, wake_up(&cs->waitqueue); break; - /* events from the proc file system */ + /* events from the proc file system */ + case ACT_PROC_CIDMODE: spin_lock_irqsave(&cs->lock, flags); if (ev->parameter != cs->cidmode) { @@ -1431,7 +1437,8 @@ static void do_action(int action, struct cardstate *cs, wake_up(&cs->waitqueue); break; - /* events from the hardware drivers */ + /* events from the hardware drivers */ + case ACT_NOTIFY_BC_DOWN: bchannel_down(bcs); break; diff --git a/drivers/isdn/gigaset/gigaset.h b/drivers/isdn/gigaset/gigaset.h index 1dc25131e670..8e2fc8f31d16 100644 --- a/drivers/isdn/gigaset/gigaset.h +++ b/drivers/isdn/gigaset/gigaset.h @@ -163,8 +163,8 @@ void gigaset_dbg_buffer(enum debuglevel level, const unsigned char *msg, #define BAS_LOWFRAME 5 /* " " with negative flow control */ #define BAS_CORRFRAMES 4 /* flow control multiplicator */ -#define BAS_INBUFSIZE (BAS_MAXFRAME * BAS_NUMFRAMES) -/* size of isoc in buf per URB */ +#define BAS_INBUFSIZE (BAS_MAXFRAME * BAS_NUMFRAMES) /* size of isoc in buf + * per URB */ #define BAS_OUTBUFSIZE 4096 /* size of common isoc out buffer */ #define BAS_OUTBUFPAD BAS_MAXFRAME /* size of pad area for isoc out buf */ @@ -471,18 +471,18 @@ struct cardstate { for */ int commands_pending; /* flag(s) in xxx.commands_pending have been set */ - struct tasklet_struct event_tasklet; - /* tasklet for serializing AT commands. - * Scheduled - * -> for modem reponses (and - * incoming data for M10x) - * -> on timeout - * -> after setting bits in - * xxx.at_state.pending_command - * (e.g. command from LL) */ - struct tasklet_struct write_tasklet; - /* tasklet for serial output - * (not used in base driver) */ + struct tasklet_struct + event_tasklet; /* tasklet for serializing AT commands. + * Scheduled + * -> for modem reponses (and + * incoming data for M10x) + * -> on timeout + * -> after setting bits in + * xxx.at_state.pending_command + * (e.g. command from LL) */ + struct tasklet_struct + write_tasklet; /* tasklet for serial output + * (not used in base driver) */ /* event queue */ struct event_t events[MAX_EVENTS]; @@ -583,7 +583,7 @@ struct gigaset_ops { int (*initbcshw)(struct bc_state *bcs); /* Called by gigaset_freecs() for freeing bcs->hw.xxx */ - int (*freebcshw)(struct bc_state *bcs); + void (*freebcshw)(struct bc_state *bcs); /* Called by gigaset_bchannel_down() for resetting bcs->hw.xxx */ void (*reinitbcshw)(struct bc_state *bcs); diff --git a/drivers/isdn/gigaset/i4l.c b/drivers/isdn/gigaset/i4l.c index 0f13eb1de657..2d75329007f1 100644 --- a/drivers/isdn/gigaset/i4l.c +++ b/drivers/isdn/gigaset/i4l.c @@ -229,7 +229,7 @@ static int command_from_LL(isdn_ctrl *cntrl) return -EINVAL; } bcs = cs->bcs + ch; - if (!gigaset_get_channel(bcs)) { + if (gigaset_get_channel(bcs) < 0) { dev_err(cs->dev, "ISDN_CMD_DIAL: channel not free\n"); return -EBUSY; } @@ -618,7 +618,7 @@ void gigaset_isdn_stop(struct cardstate *cs) * @cs: device descriptor structure. * @isdnid: device name. * - * Return value: 1 for success, 0 for failure + * Return value: 0 on success, error code < 0 on failure */ int gigaset_isdn_regdev(struct cardstate *cs, const char *isdnid) { @@ -627,14 +627,14 @@ int gigaset_isdn_regdev(struct cardstate *cs, const char *isdnid) iif = kmalloc(sizeof *iif, GFP_KERNEL); if (!iif) { pr_err("out of memory\n"); - return 0; + return -ENOMEM; } if (snprintf(iif->id, sizeof iif->id, "%s_%u", isdnid, cs->minor_index) >= sizeof iif->id) { pr_err("ID too long: %s\n", isdnid); kfree(iif); - return 0; + return -EINVAL; } iif->owner = THIS_MODULE; @@ -656,13 +656,13 @@ int gigaset_isdn_regdev(struct cardstate *cs, const char *isdnid) if (!register_isdn(iif)) { pr_err("register_isdn failed\n"); kfree(iif); - return 0; + return -EINVAL; } cs->iif = iif; cs->myid = iif->channels; /* Set my device id */ cs->hw_hdr_len = HW_HDR_LEN; - return 1; + return 0; } /** diff --git a/drivers/isdn/gigaset/isocdata.c b/drivers/isdn/gigaset/isocdata.c index a351c16705bd..bc29f1d52a2f 100644 --- a/drivers/isdn/gigaset/isocdata.c +++ b/drivers/isdn/gigaset/isocdata.c @@ -56,7 +56,7 @@ static inline int isowbuf_freebytes(struct isowbuf_t *iwb) /* start writing * acquire the write semaphore - * return true if acquired, false if busy + * return 0 if acquired, <0 if busy */ static inline int isowbuf_startwrite(struct isowbuf_t *iwb) { @@ -64,12 +64,12 @@ static inline int isowbuf_startwrite(struct isowbuf_t *iwb) atomic_inc(&iwb->writesem); gig_dbg(DEBUG_ISO, "%s: couldn't acquire iso write semaphore", __func__); - return 0; + return -EBUSY; } gig_dbg(DEBUG_ISO, "%s: acquired iso write semaphore, data[write]=%02x, nbits=%d", __func__, iwb->data[iwb->write], iwb->wbits); - return 1; + return 0; } /* finish writing @@ -158,7 +158,7 @@ int gigaset_isowbuf_getbytes(struct isowbuf_t *iwb, int size) /* no wraparound in valid data */ if (limit >= write) { /* append idle frame */ - if (!isowbuf_startwrite(iwb)) + if (isowbuf_startwrite(iwb) < 0) return -EBUSY; /* write position could have changed */ write = iwb->write; @@ -403,7 +403,7 @@ static inline int hdlc_buildframe(struct isowbuf_t *iwb, unsigned char c; if (isowbuf_freebytes(iwb) < count + count / 5 + 6 || - !isowbuf_startwrite(iwb)) { + isowbuf_startwrite(iwb) < 0) { gig_dbg(DEBUG_ISO, "%s: %d bytes free -> -EAGAIN", __func__, isowbuf_freebytes(iwb)); return -EAGAIN; @@ -457,7 +457,7 @@ static inline int trans_buildframe(struct isowbuf_t *iwb, return iwb->write; if (isowbuf_freebytes(iwb) < count || - !isowbuf_startwrite(iwb)) { + isowbuf_startwrite(iwb) < 0) { gig_dbg(DEBUG_ISO, "can't put %d bytes", count); return -EAGAIN; } diff --git a/drivers/isdn/gigaset/ser-gigaset.c b/drivers/isdn/gigaset/ser-gigaset.c index 6f3fd4cf4378..8c91fd5eb6fd 100644 --- a/drivers/isdn/gigaset/ser-gigaset.c +++ b/drivers/isdn/gigaset/ser-gigaset.c @@ -340,17 +340,16 @@ static int gigaset_initbcshw(struct bc_state *bcs) { /* unused */ bcs->hw.ser = NULL; - return 1; + return 0; } /* * Free B channel structure * Called by "gigaset_freebcs" in common.c */ -static int gigaset_freebcshw(struct bc_state *bcs) +static void gigaset_freebcshw(struct bc_state *bcs) { /* unused */ - return 1; } /* @@ -398,7 +397,7 @@ static int gigaset_initcshw(struct cardstate *cs) scs = kzalloc(sizeof(struct ser_cardstate), GFP_KERNEL); if (!scs) { pr_err("out of memory\n"); - return 0; + return -ENOMEM; } cs->hw.ser = scs; @@ -410,13 +409,13 @@ static int gigaset_initcshw(struct cardstate *cs) pr_err("error %d registering platform device\n", rc); kfree(cs->hw.ser); cs->hw.ser = NULL; - return 0; + return rc; } dev_set_drvdata(&cs->hw.ser->dev.dev, cs); tasklet_init(&cs->write_tasklet, gigaset_modem_fill, (unsigned long) cs); - return 1; + return 0; } /* @@ -503,6 +502,7 @@ static int gigaset_tty_open(struct tty_struct *tty) { struct cardstate *cs; + int rc; gig_dbg(DEBUG_INIT, "Starting HLL for Gigaset M101"); @@ -515,8 +515,10 @@ gigaset_tty_open(struct tty_struct *tty) /* allocate memory for our device state and initialize it */ cs = gigaset_initcs(driver, 1, 1, 0, cidmode, GIGASET_MODULENAME); - if (!cs) + if (!cs) { + rc = -ENODEV; goto error; + } cs->dev = &cs->hw.ser->dev.dev; cs->hw.ser->tty = tty; @@ -530,7 +532,8 @@ gigaset_tty_open(struct tty_struct *tty) */ if (startmode == SM_LOCKED) cs->mstate = MS_LOCKED; - if (!gigaset_start(cs)) { + rc = gigaset_start(cs); + if (rc < 0) { tasklet_kill(&cs->write_tasklet); goto error; } @@ -542,7 +545,7 @@ error: gig_dbg(DEBUG_INIT, "Startup of HLL failed"); tty->disc_data = NULL; gigaset_freecs(cs); - return -ENODEV; + return rc; } /* diff --git a/drivers/isdn/gigaset/usb-gigaset.c b/drivers/isdn/gigaset/usb-gigaset.c index 049da67f6392..d0a41cb0cf62 100644 --- a/drivers/isdn/gigaset/usb-gigaset.c +++ b/drivers/isdn/gigaset/usb-gigaset.c @@ -124,6 +124,7 @@ static struct usb_driver gigaset_usb_driver = { .reset_resume = gigaset_resume, .pre_reset = gigaset_pre_reset, .post_reset = gigaset_resume, + .disable_hub_initiated_lpm = 1, }; struct usb_cardstate { @@ -549,10 +550,9 @@ static int gigaset_brkchars(struct cardstate *cs, const unsigned char buf[6]) 0, 0, &buf, 6, 2000); } -static int gigaset_freebcshw(struct bc_state *bcs) +static void gigaset_freebcshw(struct bc_state *bcs) { /* unused */ - return 1; } /* Initialize the b-channel structure */ @@ -560,7 +560,7 @@ static int gigaset_initbcshw(struct bc_state *bcs) { /* unused */ bcs->hw.usb = NULL; - return 1; + return 0; } static void gigaset_reinitbcshw(struct bc_state *bcs) @@ -582,7 +582,7 @@ static int gigaset_initcshw(struct cardstate *cs) kmalloc(sizeof(struct usb_cardstate), GFP_KERNEL); if (!ucs) { pr_err("out of memory\n"); - return 0; + return -ENOMEM; } ucs->bchars[0] = 0; @@ -597,7 +597,7 @@ static int gigaset_initcshw(struct cardstate *cs) tasklet_init(&cs->write_tasklet, gigaset_modem_fill, (unsigned long) cs); - return 1; + return 0; } /* Send data from current skb to the device. */ @@ -766,9 +766,9 @@ static int gigaset_probe(struct usb_interface *interface, if (startmode == SM_LOCKED) cs->mstate = MS_LOCKED; - if (!gigaset_start(cs)) { + retval = gigaset_start(cs); + if (retval < 0) { tasklet_kill(&cs->write_tasklet); - retval = -ENODEV; goto error; } return 0; @@ -898,8 +898,10 @@ static int __init usb_gigaset_init(void) driver = gigaset_initdriver(GIGASET_MINOR, GIGASET_MINORS, GIGASET_MODULENAME, GIGASET_DEVNAME, &ops, THIS_MODULE); - if (driver == NULL) + if (driver == NULL) { + result = -ENOMEM; goto error; + } /* register this driver with the USB subsystem */ result = usb_register(&gigaset_usb_driver); @@ -915,7 +917,7 @@ error: if (driver) gigaset_freedriver(driver); driver = NULL; - return -1; + return result; } /* diff --git a/drivers/isdn/hardware/eicon/capifunc.c b/drivers/isdn/hardware/eicon/capifunc.c index a576f32e6635..7a0bdbdd87ea 100644 --- a/drivers/isdn/hardware/eicon/capifunc.c +++ b/drivers/isdn/hardware/eicon/capifunc.c @@ -1120,7 +1120,7 @@ int fax_head_line_time(char *buffer) /* * init (alloc) main structures */ -static int DIVA_INIT_FUNCTION init_main_structs(void) +static int __init init_main_structs(void) { if (!(mapped_msg = (CAPI_MSG *) diva_os_malloc(0, MAX_MSG_SIZE))) { DBG_ERR(("init: failed alloc mapped_msg.")) @@ -1181,7 +1181,7 @@ static void do_api_remove_start(void) /* * init */ -int DIVA_INIT_FUNCTION init_capifunc(void) +int __init init_capifunc(void) { diva_os_initialize_spin_lock(&api_lock, "capifunc"); memset(ControllerMap, 0, MAX_DESCRIPTORS + 1); @@ -1209,7 +1209,7 @@ int DIVA_INIT_FUNCTION init_capifunc(void) /* * finit */ -void DIVA_EXIT_FUNCTION finit_capifunc(void) +void __exit finit_capifunc(void) { do_api_remove_start(); divacapi_disconnect_didd(); diff --git a/drivers/isdn/hardware/eicon/capimain.c b/drivers/isdn/hardware/eicon/capimain.c index eabe0fa1b627..997d46abf5b2 100644 --- a/drivers/isdn/hardware/eicon/capimain.c +++ b/drivers/isdn/hardware/eicon/capimain.c @@ -118,7 +118,7 @@ void diva_os_set_controller_struct(struct capi_ctr *ctrl) /* * module init */ -static int DIVA_INIT_FUNCTION divacapi_init(void) +static int __init divacapi_init(void) { char tmprev[32]; int ret = 0; @@ -144,7 +144,7 @@ static int DIVA_INIT_FUNCTION divacapi_init(void) /* * module exit */ -static void DIVA_EXIT_FUNCTION divacapi_exit(void) +static void __exit divacapi_exit(void) { finit_capifunc(); printk(KERN_INFO "%s: module unloaded.\n", DRIVERLNAME); diff --git a/drivers/isdn/hardware/eicon/diddfunc.c b/drivers/isdn/hardware/eicon/diddfunc.c index c4c8220c9d72..b0b23ed8b374 100644 --- a/drivers/isdn/hardware/eicon/diddfunc.c +++ b/drivers/isdn/hardware/eicon/diddfunc.c @@ -47,7 +47,7 @@ static void *didd_callback(void *context, DESCRIPTOR *adapter, /* * connect to didd */ -static int DIVA_INIT_FUNCTION connect_didd(void) +static int __init connect_didd(void) { int x = 0; int dadapter = 0; @@ -79,7 +79,7 @@ static int DIVA_INIT_FUNCTION connect_didd(void) /* * disconnect from didd */ -static void DIVA_EXIT_FUNCTION disconnect_didd(void) +static void __exit disconnect_didd(void) { IDI_SYNC_REQ req; @@ -92,7 +92,7 @@ static void DIVA_EXIT_FUNCTION disconnect_didd(void) /* * init */ -int DIVA_INIT_FUNCTION diddfunc_init(void) +int __init diddfunc_init(void) { diva_didd_load_time_init(); @@ -107,7 +107,7 @@ int DIVA_INIT_FUNCTION diddfunc_init(void) /* * finit */ -void DIVA_EXIT_FUNCTION diddfunc_finit(void) +void __exit diddfunc_finit(void) { DbgDeregister(); disconnect_didd(); diff --git a/drivers/isdn/hardware/eicon/diva_didd.c b/drivers/isdn/hardware/eicon/diva_didd.c index d1d3de03cced..fab6ccfb00d5 100644 --- a/drivers/isdn/hardware/eicon/diva_didd.c +++ b/drivers/isdn/hardware/eicon/diva_didd.c @@ -91,7 +91,7 @@ static const struct file_operations divadidd_proc_fops = { .release = single_release, }; -static int DIVA_INIT_FUNCTION create_proc(void) +static int __init create_proc(void) { proc_net_eicon = proc_mkdir("eicon", init_net.proc_net); @@ -109,7 +109,7 @@ static void remove_proc(void) remove_proc_entry("eicon", init_net.proc_net); } -static int DIVA_INIT_FUNCTION divadidd_init(void) +static int __init divadidd_init(void) { char tmprev[32]; int ret = 0; @@ -141,7 +141,7 @@ out: return (ret); } -static void DIVA_EXIT_FUNCTION divadidd_exit(void) +static void __exit divadidd_exit(void) { diddfunc_finit(); remove_proc(); diff --git a/drivers/isdn/hardware/eicon/divamnt.c b/drivers/isdn/hardware/eicon/divamnt.c index ffa0c31be745..48db08d0bb3d 100644 --- a/drivers/isdn/hardware/eicon/divamnt.c +++ b/drivers/isdn/hardware/eicon/divamnt.c @@ -184,7 +184,7 @@ static void divas_maint_unregister_chrdev(void) unregister_chrdev(major, DEVNAME); } -static int DIVA_INIT_FUNCTION divas_maint_register_chrdev(void) +static int __init divas_maint_register_chrdev(void) { if ((major = register_chrdev(0, DEVNAME, &divas_maint_fops)) < 0) { @@ -207,7 +207,7 @@ void diva_maint_wakeup_read(void) /* * Driver Load */ -static int DIVA_INIT_FUNCTION maint_init(void) +static int __init maint_init(void) { char tmprev[50]; int ret = 0; @@ -245,7 +245,7 @@ out: /* ** Driver Unload */ -static void DIVA_EXIT_FUNCTION maint_exit(void) +static void __exit maint_exit(void) { divas_maint_unregister_chrdev(); mntfunc_finit(); diff --git a/drivers/isdn/hardware/eicon/divasfunc.c b/drivers/isdn/hardware/eicon/divasfunc.c index 60aaf9580956..4be5f8814777 100644 --- a/drivers/isdn/hardware/eicon/divasfunc.c +++ b/drivers/isdn/hardware/eicon/divasfunc.c @@ -153,7 +153,7 @@ static void *didd_callback(void *context, DESCRIPTOR *adapter, /* * connect to didd */ -static int DIVA_INIT_FUNCTION connect_didd(void) +static int __init connect_didd(void) { int x = 0; int dadapter = 0; @@ -209,7 +209,7 @@ static void disconnect_didd(void) /* * init */ -int DIVA_INIT_FUNCTION divasfunc_init(int dbgmask) +int __init divasfunc_init(int dbgmask) { char *version; diff --git a/drivers/isdn/hardware/eicon/divasi.c b/drivers/isdn/hardware/eicon/divasi.c index a5c8f90b3b37..4103a8c178d7 100644 --- a/drivers/isdn/hardware/eicon/divasi.c +++ b/drivers/isdn/hardware/eicon/divasi.c @@ -114,7 +114,7 @@ static const struct file_operations um_idi_proc_fops = { .release = single_release, }; -static int DIVA_INIT_FUNCTION create_um_idi_proc(void) +static int __init create_um_idi_proc(void) { um_idi_proc_entry = proc_create(DRIVERLNAME, S_IRUGO, proc_net_eicon, &um_idi_proc_fops); @@ -146,7 +146,7 @@ static void divas_idi_unregister_chrdev(void) unregister_chrdev(major, DEVNAME); } -static int DIVA_INIT_FUNCTION divas_idi_register_chrdev(void) +static int __init divas_idi_register_chrdev(void) { if ((major = register_chrdev(0, DEVNAME, &divas_idi_fops)) < 0) { @@ -161,7 +161,7 @@ static int DIVA_INIT_FUNCTION divas_idi_register_chrdev(void) /* ** Driver Load */ -static int DIVA_INIT_FUNCTION divasi_init(void) +static int __init divasi_init(void) { char tmprev[50]; int ret = 0; @@ -202,7 +202,7 @@ out: /* ** Driver Unload */ -static void DIVA_EXIT_FUNCTION divasi_exit(void) +static void __exit divasi_exit(void) { idifunc_finit(); remove_um_idi_proc(); diff --git a/drivers/isdn/hardware/eicon/divasmain.c b/drivers/isdn/hardware/eicon/divasmain.c index 7eaab06276f9..ca6d276bb256 100644 --- a/drivers/isdn/hardware/eicon/divasmain.c +++ b/drivers/isdn/hardware/eicon/divasmain.c @@ -673,7 +673,7 @@ static void divas_unregister_chrdev(void) unregister_chrdev(major, DEVNAME); } -static int DIVA_INIT_FUNCTION divas_register_chrdev(void) +static int __init divas_register_chrdev(void) { if ((major = register_chrdev(0, DEVNAME, &divas_fops)) < 0) { @@ -767,7 +767,7 @@ static void __devexit divas_remove_one(struct pci_dev *pdev) /* -------------------------------------------------------------------------- Driver Load / Startup -------------------------------------------------------------------------- */ -static int DIVA_INIT_FUNCTION divas_init(void) +static int __init divas_init(void) { char tmprev[50]; int ret = 0; @@ -831,7 +831,7 @@ out: /* -------------------------------------------------------------------------- Driver Unload -------------------------------------------------------------------------- */ -static void DIVA_EXIT_FUNCTION divas_exit(void) +static void __exit divas_exit(void) { pci_unregister_driver(&diva_pci_driver); remove_divas_proc(); diff --git a/drivers/isdn/hardware/eicon/idifunc.c b/drivers/isdn/hardware/eicon/idifunc.c index d153e3cdecf7..fef6586fe5ac 100644 --- a/drivers/isdn/hardware/eicon/idifunc.c +++ b/drivers/isdn/hardware/eicon/idifunc.c @@ -133,7 +133,7 @@ static void um_remove_card(DESCRIPTOR *d) /* * remove all adapter */ -static void DIVA_EXIT_FUNCTION remove_all_idi_proc(void) +static void __exit remove_all_idi_proc(void) { udiva_card *card; diva_os_spin_lock_magic_t old_irql; @@ -181,7 +181,7 @@ static void *didd_callback(void *context, DESCRIPTOR *adapter, /* * connect DIDD */ -static int DIVA_INIT_FUNCTION connect_didd(void) +static int __init connect_didd(void) { int x = 0; int dadapter = 0; @@ -225,7 +225,7 @@ static int DIVA_INIT_FUNCTION connect_didd(void) /* * Disconnect from DIDD */ -static void DIVA_EXIT_FUNCTION disconnect_didd(void) +static void __exit disconnect_didd(void) { IDI_SYNC_REQ req; @@ -240,7 +240,7 @@ static void DIVA_EXIT_FUNCTION disconnect_didd(void) /* * init */ -int DIVA_INIT_FUNCTION idifunc_init(void) +int __init idifunc_init(void) { diva_os_initialize_spin_lock(&ll_lock, "idifunc"); @@ -260,7 +260,7 @@ int DIVA_INIT_FUNCTION idifunc_init(void) /* * finit */ -void DIVA_EXIT_FUNCTION idifunc_finit(void) +void __exit idifunc_finit(void) { diva_user_mode_idi_finit(); disconnect_didd(); diff --git a/drivers/isdn/hardware/eicon/mntfunc.c b/drivers/isdn/hardware/eicon/mntfunc.c index d6072607305c..1cd9affb6058 100644 --- a/drivers/isdn/hardware/eicon/mntfunc.c +++ b/drivers/isdn/hardware/eicon/mntfunc.c @@ -72,7 +72,7 @@ static void *didd_callback(void *context, DESCRIPTOR *adapter, /* * connect to didd */ -static int DIVA_INIT_FUNCTION connect_didd(void) +static int __init connect_didd(void) { int x = 0; int dadapter = 0; @@ -114,7 +114,7 @@ static int DIVA_INIT_FUNCTION connect_didd(void) /* * disconnect from didd */ -static void DIVA_EXIT_FUNCTION disconnect_didd(void) +static void __exit disconnect_didd(void) { IDI_SYNC_REQ req; @@ -300,7 +300,7 @@ int maint_read_write(void __user *buf, int count) /* * init */ -int DIVA_INIT_FUNCTION mntfunc_init(int *buffer_length, void **buffer, +int __init mntfunc_init(int *buffer_length, void **buffer, unsigned long diva_dbg_mem) { if (*buffer_length < 64) { @@ -348,7 +348,7 @@ int DIVA_INIT_FUNCTION mntfunc_init(int *buffer_length, void **buffer, /* * exit */ -void DIVA_EXIT_FUNCTION mntfunc_finit(void) +void __exit mntfunc_finit(void) { void *buffer; int i = 100; diff --git a/drivers/isdn/hardware/eicon/platform.h b/drivers/isdn/hardware/eicon/platform.h index 7331c3b14a5f..b2edb7590dda 100644 --- a/drivers/isdn/hardware/eicon/platform.h +++ b/drivers/isdn/hardware/eicon/platform.h @@ -38,9 +38,6 @@ #define DIVA_NO_DEBUGLIB #endif -#define DIVA_INIT_FUNCTION __init -#define DIVA_EXIT_FUNCTION __exit - #define DIVA_USER_MODE_CARD_CONFIG 1 #define USE_EXTENDED_DEBUGS 1 diff --git a/drivers/isdn/hardware/mISDN/avmfritz.c b/drivers/isdn/hardware/mISDN/avmfritz.c index c0b8c960ee3f..c08fc605e56b 100644 --- a/drivers/isdn/hardware/mISDN/avmfritz.c +++ b/drivers/isdn/hardware/mISDN/avmfritz.c @@ -30,7 +30,7 @@ #include "ipac.h" -#define AVMFRITZ_REV "2.1" +#define AVMFRITZ_REV "2.3" static int AVM_cnt; static int debug; @@ -69,6 +69,7 @@ enum { #define HDLC_MODE_TRANS 0x02 #define HDLC_MODE_CCR_7 0x04 #define HDLC_MODE_CCR_16 0x08 +#define HDLC_FIFO_SIZE_128 0x20 #define HDLC_MODE_TESTLOOP 0x80 #define HDLC_INT_XPR 0x80 @@ -80,13 +81,16 @@ enum { #define HDLC_STAT_RDO 0x10 #define HDLC_STAT_CRCVFRRAB 0x0E #define HDLC_STAT_CRCVFR 0x06 -#define HDLC_STAT_RML_MASK 0x3f00 +#define HDLC_STAT_RML_MASK_V1 0x3f00 +#define HDLC_STAT_RML_MASK_V2 0x7f00 #define HDLC_CMD_XRS 0x80 #define HDLC_CMD_XME 0x01 #define HDLC_CMD_RRS 0x20 #define HDLC_CMD_XML_MASK 0x3f00 -#define HDLC_FIFO_SIZE 32 + +#define HDLC_FIFO_SIZE_V1 32 +#define HDLC_FIFO_SIZE_V2 128 /* Fritz PCI v2.0 */ @@ -346,11 +350,14 @@ modehdlc(struct bchannel *bch, int protocol) { struct fritzcard *fc = bch->hw; struct hdlc_hw *hdlc; + u8 mode; hdlc = &fc->hdlc[(bch->nr - 1) & 1]; pr_debug("%s: hdlc %c protocol %x-->%x ch %d\n", fc->name, '@' + bch->nr, bch->state, protocol, bch->nr); hdlc->ctrl.ctrl = 0; + mode = (fc->type == AVM_FRITZ_PCIV2) ? HDLC_FIFO_SIZE_128 : 0; + switch (protocol) { case -1: /* used for init */ bch->state = -1; @@ -358,7 +365,7 @@ modehdlc(struct bchannel *bch, int protocol) if (bch->state == ISDN_P_NONE) break; hdlc->ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS; - hdlc->ctrl.sr.mode = HDLC_MODE_TRANS; + hdlc->ctrl.sr.mode = mode | HDLC_MODE_TRANS; write_ctrl(bch, 5); bch->state = ISDN_P_NONE; test_and_clear_bit(FLG_HDLC, &bch->Flags); @@ -367,7 +374,7 @@ modehdlc(struct bchannel *bch, int protocol) case ISDN_P_B_RAW: bch->state = protocol; hdlc->ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS; - hdlc->ctrl.sr.mode = HDLC_MODE_TRANS; + hdlc->ctrl.sr.mode = mode | HDLC_MODE_TRANS; write_ctrl(bch, 5); hdlc->ctrl.sr.cmd = HDLC_CMD_XRS; write_ctrl(bch, 1); @@ -377,7 +384,7 @@ modehdlc(struct bchannel *bch, int protocol) case ISDN_P_B_HDLC: bch->state = protocol; hdlc->ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS; - hdlc->ctrl.sr.mode = HDLC_MODE_ITF_FLG; + hdlc->ctrl.sr.mode = mode | HDLC_MODE_ITF_FLG; write_ctrl(bch, 5); hdlc->ctrl.sr.cmd = HDLC_CMD_XRS; write_ctrl(bch, 1); @@ -397,39 +404,40 @@ hdlc_empty_fifo(struct bchannel *bch, int count) u32 *ptr; u8 *p; u32 val, addr; - int cnt = 0; + int cnt; struct fritzcard *fc = bch->hw; pr_debug("%s: %s %d\n", fc->name, __func__, count); - if (!bch->rx_skb) { - bch->rx_skb = mI_alloc_skb(bch->maxlen, GFP_ATOMIC); - if (!bch->rx_skb) { - pr_info("%s: B receive out of memory\n", - fc->name); + if (test_bit(FLG_RX_OFF, &bch->Flags)) { + p = NULL; + bch->dropcnt += count; + } else { + cnt = bchannel_get_rxbuf(bch, count); + if (cnt < 0) { + pr_warning("%s.B%d: No bufferspace for %d bytes\n", + fc->name, bch->nr, count); return; } + p = skb_put(bch->rx_skb, count); } - if ((bch->rx_skb->len + count) > bch->maxlen) { - pr_debug("%s: overrun %d\n", fc->name, - bch->rx_skb->len + count); - return; - } - p = skb_put(bch->rx_skb, count); ptr = (u32 *)p; - if (AVM_FRITZ_PCIV2 == fc->type) + if (fc->type == AVM_FRITZ_PCIV2) addr = fc->addr + (bch->nr == 2 ? AVM_HDLC_FIFO_2 : AVM_HDLC_FIFO_1); else { addr = fc->addr + CHIP_WINDOW; outl(bch->nr == 2 ? AVM_HDLC_2 : AVM_HDLC_1, fc->addr); } + cnt = 0; while (cnt < count) { val = le32_to_cpu(inl(addr)); - put_unaligned(val, ptr); - ptr++; + if (p) { + put_unaligned(val, ptr); + ptr++; + } cnt += 4; } - if (debug & DEBUG_HW_BFIFO) { + if (p && (debug & DEBUG_HW_BFIFO)) { snprintf(fc->log, LOG_SIZE, "B%1d-recv %s %d ", bch->nr, fc->name, count); print_hex_dump_bytes(fc->log, DUMP_PREFIX_OFFSET, p, count); @@ -441,30 +449,43 @@ hdlc_fill_fifo(struct bchannel *bch) { struct fritzcard *fc = bch->hw; struct hdlc_hw *hdlc; - int count, cnt = 0; + int count, fs, cnt = 0, idx, fillempty = 0; u8 *p; u32 *ptr, val, addr; - hdlc = &fc->hdlc[(bch->nr - 1) & 1]; - if (!bch->tx_skb) - return; - count = bch->tx_skb->len - bch->tx_idx; - if (count <= 0) - return; - p = bch->tx_skb->data + bch->tx_idx; + idx = (bch->nr - 1) & 1; + hdlc = &fc->hdlc[idx]; + fs = (fc->type == AVM_FRITZ_PCIV2) ? + HDLC_FIFO_SIZE_V2 : HDLC_FIFO_SIZE_V1; + if (!bch->tx_skb) { + if (!test_bit(FLG_TX_EMPTY, &bch->Flags)) + return; + count = fs; + p = bch->fill; + fillempty = 1; + } else { + count = bch->tx_skb->len - bch->tx_idx; + if (count <= 0) + return; + p = bch->tx_skb->data + bch->tx_idx; + } hdlc->ctrl.sr.cmd &= ~HDLC_CMD_XME; - if (count > HDLC_FIFO_SIZE) { - count = HDLC_FIFO_SIZE; + if (count > fs) { + count = fs; } else { if (test_bit(FLG_HDLC, &bch->Flags)) hdlc->ctrl.sr.cmd |= HDLC_CMD_XME; } - pr_debug("%s: %s %d/%d/%d", fc->name, __func__, count, - bch->tx_idx, bch->tx_skb->len); ptr = (u32 *)p; - bch->tx_idx += count; - hdlc->ctrl.sr.xml = ((count == HDLC_FIFO_SIZE) ? 0 : count); - if (AVM_FRITZ_PCIV2 == fc->type) { + if (fillempty) { + pr_debug("%s.B%d: %d/%d/%d", fc->name, bch->nr, count, + bch->tx_idx, bch->tx_skb->len); + bch->tx_idx += count; + } else { + pr_debug("%s.B%d: fillempty %d\n", fc->name, bch->nr, count); + } + hdlc->ctrl.sr.xml = ((count == fs) ? 0 : count); + if (fc->type == AVM_FRITZ_PCIV2) { __write_ctrl_pciv2(fc, hdlc, bch->nr); addr = fc->addr + (bch->nr == 2 ? AVM_HDLC_FIFO_2 : AVM_HDLC_FIFO_1); @@ -472,13 +493,21 @@ hdlc_fill_fifo(struct bchannel *bch) __write_ctrl_pci(fc, hdlc, bch->nr); addr = fc->addr + CHIP_WINDOW; } - while (cnt < count) { - val = get_unaligned(ptr); - outl(cpu_to_le32(val), addr); - ptr++; - cnt += 4; + if (fillempty) { + while (cnt < count) { + /* all bytes the same - no worry about endian */ + outl(*ptr, addr); + cnt += 4; + } + } else { + while (cnt < count) { + val = get_unaligned(ptr); + outl(cpu_to_le32(val), addr); + ptr++; + cnt += 4; + } } - if (debug & DEBUG_HW_BFIFO) { + if ((debug & DEBUG_HW_BFIFO) && !fillempty) { snprintf(fc->log, LOG_SIZE, "B%1d-send %s %d ", bch->nr, fc->name, count); print_hex_dump_bytes(fc->log, DUMP_PREFIX_OFFSET, p, count); @@ -488,17 +517,17 @@ hdlc_fill_fifo(struct bchannel *bch) static void HDLC_irq_xpr(struct bchannel *bch) { - if (bch->tx_skb && bch->tx_idx < bch->tx_skb->len) + if (bch->tx_skb && bch->tx_idx < bch->tx_skb->len) { hdlc_fill_fifo(bch); - else { - if (bch->tx_skb) { - /* send confirm, on trans, free on hdlc. */ - if (test_bit(FLG_TRANSPARENT, &bch->Flags)) - confirm_Bsend(bch); + } else { + if (bch->tx_skb) dev_kfree_skb(bch->tx_skb); - } - if (get_next_bframe(bch)) + if (get_next_bframe(bch)) { hdlc_fill_fifo(bch); + test_and_clear_bit(FLG_TX_EMPTY, &bch->Flags); + } else if (test_bit(FLG_TX_EMPTY, &bch->Flags)) { + hdlc_fill_fifo(bch); + } } } @@ -506,13 +535,23 @@ static void HDLC_irq(struct bchannel *bch, u32 stat) { struct fritzcard *fc = bch->hw; - int len; + int len, fs; + u32 rmlMask; struct hdlc_hw *hdlc; hdlc = &fc->hdlc[(bch->nr - 1) & 1]; pr_debug("%s: ch%d stat %#x\n", fc->name, bch->nr, stat); + if (fc->type == AVM_FRITZ_PCIV2) { + rmlMask = HDLC_STAT_RML_MASK_V2; + fs = HDLC_FIFO_SIZE_V2; + } else { + rmlMask = HDLC_STAT_RML_MASK_V1; + fs = HDLC_FIFO_SIZE_V1; + } if (stat & HDLC_INT_RPR) { if (stat & HDLC_STAT_RDO) { + pr_warning("%s: ch%d stat %x RDO\n", + fc->name, bch->nr, stat); hdlc->ctrl.sr.xml = 0; hdlc->ctrl.sr.cmd |= HDLC_CMD_RRS; write_ctrl(bch, 1); @@ -521,21 +560,21 @@ HDLC_irq(struct bchannel *bch, u32 stat) if (bch->rx_skb) skb_trim(bch->rx_skb, 0); } else { - len = (stat & HDLC_STAT_RML_MASK) >> 8; + len = (stat & rmlMask) >> 8; if (!len) - len = 32; + len = fs; hdlc_empty_fifo(bch, len); if (!bch->rx_skb) goto handle_tx; - if ((stat & HDLC_STAT_RME) || test_bit(FLG_TRANSPARENT, - &bch->Flags)) { - if (((stat & HDLC_STAT_CRCVFRRAB) == - HDLC_STAT_CRCVFR) || - test_bit(FLG_TRANSPARENT, &bch->Flags)) { - recv_Bchannel(bch, 0); + if (test_bit(FLG_TRANSPARENT, &bch->Flags)) { + recv_Bchannel(bch, 0, false); + } else if (stat & HDLC_STAT_RME) { + if ((stat & HDLC_STAT_CRCVFRRAB) == + HDLC_STAT_CRCVFR) { + recv_Bchannel(bch, 0, false); } else { - pr_debug("%s: got invalid frame\n", - fc->name); + pr_warning("%s: got invalid frame\n", + fc->name); skb_trim(bch->rx_skb, 0); } } @@ -547,16 +586,13 @@ handle_tx: * restart transmitting the whole frame on HDLC * in transparent mode we send the next data */ - if (bch->tx_skb) - pr_debug("%s: ch%d XDU len(%d) idx(%d) Flags(%lx)\n", - fc->name, bch->nr, bch->tx_skb->len, - bch->tx_idx, bch->Flags); - else - pr_debug("%s: ch%d XDU no tx_skb Flags(%lx)\n", - fc->name, bch->nr, bch->Flags); + pr_warning("%s: ch%d stat %x XDU %s\n", fc->name, bch->nr, + stat, bch->tx_skb ? "tx_skb" : "no tx_skb"); if (bch->tx_skb && bch->tx_skb->len) { if (!test_bit(FLG_TRANSPARENT, &bch->Flags)) bch->tx_idx = 0; + } else if (test_bit(FLG_FILLEMPTY, &bch->Flags)) { + test_and_set_bit(FLG_TX_EMPTY, &bch->Flags); } hdlc->ctrl.sr.xml = 0; hdlc->ctrl.sr.cmd |= HDLC_CMD_XRS; @@ -659,22 +695,17 @@ avm_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb) struct fritzcard *fc = bch->hw; int ret = -EINVAL; struct mISDNhead *hh = mISDN_HEAD_P(skb); - u32 id; - u_long flags; + unsigned long flags; switch (hh->prim) { case PH_DATA_REQ: spin_lock_irqsave(&fc->lock, flags); ret = bchannel_senddata(bch, skb); if (ret > 0) { /* direct TX */ - id = hh->id; /* skb can be freed */ hdlc_fill_fifo(bch); ret = 0; - spin_unlock_irqrestore(&fc->lock, flags); - if (!test_bit(FLG_TRANSPARENT, &bch->Flags)) - queue_ch_frame(ch, PH_DATA_CNF, id, NULL); - } else - spin_unlock_irqrestore(&fc->lock, flags); + } + spin_unlock_irqrestore(&fc->lock, flags); return ret; case PH_ACTIVATE_REQ: spin_lock_irqsave(&fc->lock, flags); @@ -783,7 +814,7 @@ init_card(struct fritzcard *fc) inithdlc(fc); enable_hwirq(fc); /* RESET Receiver and Transmitter */ - if (AVM_FRITZ_PCIV2 == fc->type) { + if (fc->type == AVM_FRITZ_PCIV2) { WriteISAC_V2(fc, ISACX_MASK, 0); WriteISAC_V2(fc, ISACX_CMDRD, 0x41); } else { @@ -810,21 +841,7 @@ init_card(struct fritzcard *fc) static int channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) { - int ret = 0; - struct fritzcard *fc = bch->hw; - - switch (cq->op) { - case MISDN_CTRL_GETOP: - cq->op = 0; - break; - /* Nothing implemented yet */ - case MISDN_CTRL_FILL_EMPTY: - default: - pr_info("%s: %s unknown Op %x\n", fc->name, __func__, cq->op); - ret = -EINVAL; - break; - } - return ret; + return mISDN_ctrl_bchannel(bch, cq); } static int @@ -839,14 +856,10 @@ avm_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg) switch (cmd) { case CLOSE_CHANNEL: test_and_clear_bit(FLG_OPEN, &bch->Flags); - if (test_bit(FLG_ACTIVE, &bch->Flags)) { - spin_lock_irqsave(&fc->lock, flags); - mISDN_freebchannel(bch); - test_and_clear_bit(FLG_TX_BUSY, &bch->Flags); - test_and_clear_bit(FLG_ACTIVE, &bch->Flags); - modehdlc(bch, ISDN_P_NONE); - spin_unlock_irqrestore(&fc->lock, flags); - } + spin_lock_irqsave(&fc->lock, flags); + mISDN_freebchannel(bch); + modehdlc(bch, ISDN_P_NONE); + spin_unlock_irqrestore(&fc->lock, flags); ch->protocol = ISDN_P_NONE; ch->peer = NULL; module_put(THIS_MODULE); @@ -868,7 +881,7 @@ channel_ctrl(struct fritzcard *fc, struct mISDN_ctrl_req *cq) switch (cq->op) { case MISDN_CTRL_GETOP: - cq->op = MISDN_CTRL_LOOP; + cq->op = MISDN_CTRL_LOOP | MISDN_CTRL_L1_TIMER3; break; case MISDN_CTRL_LOOP: /* cq->channel: 0 disable, 1 B1 loop 2 B2 loop, 3 both */ @@ -878,6 +891,9 @@ channel_ctrl(struct fritzcard *fc, struct mISDN_ctrl_req *cq) } ret = fc->isac.ctrl(&fc->isac, HW_TESTLOOP, cq->channel); break; + case MISDN_CTRL_L1_TIMER3: + ret = fc->isac.ctrl(&fc->isac, HW_TIMER3_VALUE, cq->p1); + break; default: pr_info("%s: %s unknown Op %x\n", fc->name, __func__, cq->op); ret = -EINVAL; @@ -898,7 +914,6 @@ open_bchannel(struct fritzcard *fc, struct channel_req *rq) bch = &fc->bch[rq->adr.channel - 1]; if (test_and_set_bit(FLG_OPEN, &bch->Flags)) return -EBUSY; /* b-channel can be only open once */ - test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags); bch->ch.protocol = rq->protocol; rq->ch = &bch->ch; return 0; @@ -1021,6 +1036,7 @@ static int __devinit setup_instance(struct fritzcard *card) { int i, err; + unsigned short minsize; u_long flags; snprintf(card->name, MISDN_MAX_IDLEN - 1, "AVM.%d", AVM_cnt + 1); @@ -1040,7 +1056,11 @@ setup_instance(struct fritzcard *card) for (i = 0; i < 2; i++) { card->bch[i].nr = i + 1; set_channelmap(i + 1, card->isac.dch.dev.channelmap); - mISDN_initbchannel(&card->bch[i], MAX_DATA_MEM); + if (AVM_FRITZ_PCIV2 == card->type) + minsize = HDLC_FIFO_SIZE_V2; + else + minsize = HDLC_FIFO_SIZE_V1; + mISDN_initbchannel(&card->bch[i], MAX_DATA_MEM, minsize); card->bch[i].hw = card; card->bch[i].ch.send = avm_l2l1B; card->bch[i].ch.ctrl = avm_bctrl; diff --git a/drivers/isdn/hardware/mISDN/hfc_multi.h b/drivers/isdn/hardware/mISDN/hfc_multi.h index b0588acbb47d..c601f880141e 100644 --- a/drivers/isdn/hardware/mISDN/hfc_multi.h +++ b/drivers/isdn/hardware/mISDN/hfc_multi.h @@ -205,18 +205,22 @@ struct hfc_multi { u_int slots; /* number of PCM slots */ u_int leds; /* type of leds */ - u_int ledcount; /* used to animate leds */ u_long ledstate; /* save last state of leds */ int opticalsupport; /* has the e1 board */ /* an optical Interface */ - int dslot; /* channel # of d-channel (E1) default 16 */ + + u_int bmask[32]; /* bitmask of bchannels for port */ + u_char dnum[32]; /* array of used dchannel numbers for port */ + u_char created[32]; /* what port is created */ + u_int activity_tx; /* if there is data TX / RX */ + u_int activity_rx; /* bitmask according to port number */ + /* (will be cleared after */ + /* showing led-states) */ + u_int flash[8]; /* counter for flashing 8 leds on activity */ u_long wdcount; /* every 500 ms we need to */ /* send the watchdog a signal */ u_char wdbyte; /* watchdog toggle byte */ - u_int activity[8]; /* if there is any action on this */ - /* port (will be cleared after */ - /* showing led-states) */ int e1_state; /* keep track of last state */ int e1_getclock; /* if sync is retrieved from interface */ int syncronized; /* keep track of existing sync interface */ @@ -233,7 +237,6 @@ struct hfc_multi { * the bch->channel is equvalent to the hfc-channel */ struct hfc_chan chan[32]; - u_char created[8]; /* what port is created */ signed char slot_owner[256]; /* owner channel of slot */ }; diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c index 033223180b55..5e402cf2e795 100644 --- a/drivers/isdn/hardware/mISDN/hfcmulti.c +++ b/drivers/isdn/hardware/mISDN/hfcmulti.c @@ -103,14 +103,26 @@ * Omit this value, if all cards are interconnected or none is connected. * If unsure, don't give this parameter. * - * dslot: - * NOTE: only one dslot value must be given for every card. - * Also this value must be given for non-E1 cards. If omitted, the E1 - * card has D-channel on time slot 16, which is default. - * If 1..15 or 17..31, an alternate time slot is used for D-channel. - * In this case, the application must be able to handle this. - * If -1 is given, the D-channel is disabled and all 31 slots can be used - * for B-channel. (only for specific applications) + * dmask and bmask: + * NOTE: One dmask value must be given for every HFC-E1 card. + * If omitted, the E1 card has D-channel on time slot 16, which is default. + * dmask is a 32 bit mask. The bit must be set for an alternate time slot. + * If multiple bits are set, multiple virtual card fragments are created. + * For each bit set, a bmask value must be given. Each bit on the bmask + * value stands for a B-channel. The bmask may not overlap with dmask or + * with other bmask values for that card. + * Example: dmask=0x00020002 bmask=0x0000fffc,0xfffc0000 + * This will create one fragment with D-channel on slot 1 with + * B-channels on slots 2..15, and a second fragment with D-channel + * on slot 17 with B-channels on slot 18..31. Slot 16 is unused. + * If bit 0 is set (dmask=0x00000001) the D-channel is on slot 0 and will + * not function. + * Example: dmask=0x00000001 bmask=0xfffffffe + * This will create a port with all 31 usable timeslots as + * B-channels. + * If no bits are set on bmask, no B-channel is created for that fragment. + * Example: dmask=0xfffffffe bmask=0,0,0,0.... (31 0-values for bmask) + * This will create 31 ports with one D-channel only. * If you don't know how to use it, you don't need it! * * iomode: @@ -172,6 +184,7 @@ #define MAX_CARDS 8 #define MAX_PORTS (8 * MAX_CARDS) +#define MAX_FRAGS (32 * MAX_CARDS) static LIST_HEAD(HFClist); static spinlock_t HFClock; /* global hfc list lock */ @@ -203,7 +216,8 @@ static int nt_t1_count[] = { 3840, 1920, 960, 480, 240, 120, 60, 30 }; static uint type[MAX_CARDS]; static int pcm[MAX_CARDS]; -static int dslot[MAX_CARDS]; +static uint dmask[MAX_CARDS]; +static uint bmask[MAX_FRAGS]; static uint iomode[MAX_CARDS]; static uint port[MAX_PORTS]; static uint debug; @@ -218,7 +232,7 @@ static uint clockdelay_nt = CLKDEL_NT; #define HWID_MINIP16 3 static uint hwid = HWID_NONE; -static int HFC_cnt, Port_cnt, PCM_cnt = 99; +static int HFC_cnt, E1_cnt, bmask_cnt, Port_cnt, PCM_cnt = 99; MODULE_AUTHOR("Andreas Eversberg"); MODULE_LICENSE("GPL"); @@ -231,7 +245,8 @@ module_param(clockdelay_te, uint, S_IRUGO | S_IWUSR); module_param(clockdelay_nt, uint, S_IRUGO | S_IWUSR); module_param_array(type, uint, NULL, S_IRUGO | S_IWUSR); module_param_array(pcm, int, NULL, S_IRUGO | S_IWUSR); -module_param_array(dslot, int, NULL, S_IRUGO | S_IWUSR); +module_param_array(dmask, uint, NULL, S_IRUGO | S_IWUSR); +module_param_array(bmask, uint, NULL, S_IRUGO | S_IWUSR); module_param_array(iomode, uint, NULL, S_IRUGO | S_IWUSR); module_param_array(port, uint, NULL, S_IRUGO | S_IWUSR); module_param(hwid, uint, S_IRUGO | S_IWUSR); /* The hardware ID */ @@ -1156,7 +1171,7 @@ init_chip(struct hfc_multi *hc) hc->DTMFbase = 0x1000; if (test_bit(HFC_CHIP_EXRAM_128, &hc->chip)) { if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: changing to 128K extenal RAM\n", + printk(KERN_DEBUG "%s: changing to 128K external RAM\n", __func__); hc->hw.r_ctrl |= V_EXT_RAM; hc->hw.r_ram_sz = 1; @@ -1167,7 +1182,7 @@ init_chip(struct hfc_multi *hc) } if (test_bit(HFC_CHIP_EXRAM_512, &hc->chip)) { if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: changing to 512K extenal RAM\n", + printk(KERN_DEBUG "%s: changing to 512K external RAM\n", __func__); hc->hw.r_ctrl |= V_EXT_RAM; hc->hw.r_ram_sz = 2; @@ -1607,40 +1622,46 @@ hfcmulti_leds(struct hfc_multi *hc) struct dchannel *dch; int led[4]; - hc->ledcount += poll; - if (hc->ledcount > 4096) { - hc->ledcount -= 4096; - hc->ledstate = 0xAFFEAFFE; - } - switch (hc->leds) { case 1: /* HFC-E1 OEM */ - /* 2 red blinking: NT mode deactivate - * 2 red steady: TE mode deactivate - * left green: L1 active - * left red: frame sync, but no L1 - * right green: L2 active + /* 2 red steady: LOS + * 1 red steady: L1 not active + * 2 green steady: L1 active + * 1st green flashing: activity on TX + * 2nd green flashing: activity on RX */ - if (hc->chan[hc->dslot].sync != 2) { /* no frame sync */ - if (hc->chan[hc->dslot].dch->dev.D.protocol - != ISDN_P_NT_E1) { - led[0] = 1; + led[0] = 0; + led[1] = 0; + led[2] = 0; + led[3] = 0; + dch = hc->chan[hc->dnum[0]].dch; + if (dch) { + if (hc->chan[hc->dnum[0]].los) led[1] = 1; - } else if (hc->ledcount >> 11) { + if (hc->e1_state != 1) { led[0] = 1; - led[1] = 1; + hc->flash[2] = 0; + hc->flash[3] = 0; } else { - led[0] = 0; - led[1] = 0; + led[2] = 1; + led[3] = 1; + if (!hc->flash[2] && hc->activity_tx) + hc->flash[2] = poll; + if (!hc->flash[3] && hc->activity_rx) + hc->flash[3] = poll; + if (hc->flash[2] && hc->flash[2] < 1024) + led[2] = 0; + if (hc->flash[3] && hc->flash[3] < 1024) + led[3] = 0; + if (hc->flash[2] >= 2048) + hc->flash[2] = 0; + if (hc->flash[3] >= 2048) + hc->flash[3] = 0; + if (hc->flash[2]) + hc->flash[2] += poll; + if (hc->flash[3]) + hc->flash[3] += poll; } - led[2] = 0; - led[3] = 0; - } else { /* with frame sync */ - /* TODO make it work */ - led[0] = 0; - led[1] = 0; - led[2] = 0; - led[3] = 1; } leds = (led[0] | (led[1]<<2) | (led[2]<<1) | (led[3]<<3))^0xF; /* leds are inverted */ @@ -1651,9 +1672,9 @@ hfcmulti_leds(struct hfc_multi *hc) break; case 2: /* HFC-4S OEM */ - /* red blinking = PH_DEACTIVATE NT Mode - * red steady = PH_DEACTIVATE TE Mode - * green steady = PH_ACTIVATE + /* red steady: PH_DEACTIVATE + * green steady: PH_ACTIVATE + * green flashing: activity on TX */ for (i = 0; i < 4; i++) { state = 0; @@ -1669,17 +1690,20 @@ hfcmulti_leds(struct hfc_multi *hc) if (state) { if (state == active) { led[i] = 1; /* led green */ - } else - if (dch->dev.D.protocol == ISDN_P_TE_S0) - /* TE mode: led red */ - led[i] = 2; - else - if (hc->ledcount >> 11) - /* led red */ - led[i] = 2; - else - /* led off */ - led[i] = 0; + hc->activity_tx |= hc->activity_rx; + if (!hc->flash[i] && + (hc->activity_tx & (1 << i))) + hc->flash[i] = poll; + if (hc->flash[i] && hc->flash[i] < 1024) + led[i] = 0; /* led off */ + if (hc->flash[i] >= 2048) + hc->flash[i] = 0; + if (hc->flash[i]) + hc->flash[i] += poll; + } else { + led[i] = 2; /* led red */ + hc->flash[i] = 0; + } } else led[i] = 0; /* led off */ } @@ -1712,9 +1736,9 @@ hfcmulti_leds(struct hfc_multi *hc) break; case 3: /* HFC 1S/2S Beronet */ - /* red blinking = PH_DEACTIVATE NT Mode - * red steady = PH_DEACTIVATE TE Mode - * green steady = PH_ACTIVATE + /* red steady: PH_DEACTIVATE + * green steady: PH_ACTIVATE + * green flashing: activity on TX */ for (i = 0; i < 2; i++) { state = 0; @@ -1730,22 +1754,23 @@ hfcmulti_leds(struct hfc_multi *hc) if (state) { if (state == active) { led[i] = 1; /* led green */ - } else - if (dch->dev.D.protocol == ISDN_P_TE_S0) - /* TE mode: led red */ - led[i] = 2; - else - if (hc->ledcount >> 11) - /* led red */ - led[i] = 2; - else - /* led off */ - led[i] = 0; + hc->activity_tx |= hc->activity_rx; + if (!hc->flash[i] && + (hc->activity_tx & (1 << i))) + hc->flash[i] = poll; + if (hc->flash[i] < 1024) + led[i] = 0; /* led off */ + if (hc->flash[i] >= 2048) + hc->flash[i] = 0; + if (hc->flash[i]) + hc->flash[i] += poll; + } else { + led[i] = 2; /* led red */ + hc->flash[i] = 0; + } } else led[i] = 0; /* led off */ } - - leds = (led[0] > 0) | ((led[1] > 0) << 1) | ((led[0]&1) << 2) | ((led[1]&1) << 3); if (leds != (int)hc->ledstate) { @@ -1757,8 +1782,11 @@ hfcmulti_leds(struct hfc_multi *hc) } break; case 8: /* HFC 8S+ Beronet */ - lled = 0; - + /* off: PH_DEACTIVATE + * steady: PH_ACTIVATE + * flashing: activity on TX + */ + lled = 0xff; /* leds off */ for (i = 0; i < 8; i++) { state = 0; active = -1; @@ -1772,14 +1800,20 @@ hfcmulti_leds(struct hfc_multi *hc) } if (state) { if (state == active) { - lled |= 0 << i; + lled &= ~(1 << i); /* led on */ + hc->activity_tx |= hc->activity_rx; + if (!hc->flash[i] && + (hc->activity_tx & (1 << i))) + hc->flash[i] = poll; + if (hc->flash[i] < 1024) + lled |= 1 << i; /* led off */ + if (hc->flash[i] >= 2048) + hc->flash[i] = 0; + if (hc->flash[i]) + hc->flash[i] += poll; } else - if (hc->ledcount >> 11) - lled |= 0 << i; - else - lled |= 1 << i; - } else - lled |= 1 << i; + hc->flash[i] = 0; + } } leddw = lled << 24 | lled << 16 | lled << 8 | lled; if (leddw != hc->ledstate) { @@ -1794,6 +1828,8 @@ hfcmulti_leds(struct hfc_multi *hc) } break; } + hc->activity_tx = 0; + hc->activity_rx = 0; } /* * read dtmf coefficients @@ -2093,7 +2129,8 @@ next_frame: *txpending = 1; /* show activity */ - hc->activity[hc->chan[ch].port] = 1; + if (dch) + hc->activity_tx |= 1 << hc->chan[ch].port; /* fill fifo to what we have left */ ii = len; @@ -2129,13 +2166,9 @@ next_frame: HFC_wait_nodebug(hc); } - /* send confirm, since get_net_bframe will not do it with trans */ - if (bch && test_bit(FLG_TRANSPARENT, &bch->Flags)) - confirm_Bsend(bch); - - /* check for next frame */ dev_kfree_skb(*sp); - if (bch && get_next_bframe(bch)) { /* hdlc is confirmed here */ + /* check for next frame */ + if (bch && get_next_bframe(bch)) { len = (*sp)->len; goto next_frame; } @@ -2163,24 +2196,20 @@ hfcmulti_rx(struct hfc_multi *hc, int ch) int f1 = 0, f2 = 0; /* = 0, to make GCC happy */ int again = 0; struct bchannel *bch; - struct dchannel *dch; + struct dchannel *dch = NULL; struct sk_buff *skb, **sp = NULL; int maxlen; bch = hc->chan[ch].bch; - dch = hc->chan[ch].dch; - if ((!dch) && (!bch)) - return; - if (dch) { + if (bch) { + if (!test_bit(FLG_ACTIVE, &bch->Flags)) + return; + } else if (hc->chan[ch].dch) { + dch = hc->chan[ch].dch; if (!test_bit(FLG_ACTIVE, &dch->Flags)) return; - sp = &dch->rx_skb; - maxlen = dch->maxlen; } else { - if (!test_bit(FLG_ACTIVE, &bch->Flags)) - return; - sp = &bch->rx_skb; - maxlen = bch->maxlen; + return; } next_frame: /* on first AND before getting next valid frame, R_FIFO must be written @@ -2195,8 +2224,11 @@ next_frame: HFC_wait_nodebug(hc); /* ignore if rx is off BUT change fifo (above) to start pending TX */ - if (hc->chan[ch].rx_off) + if (hc->chan[ch].rx_off) { + if (bch) + bch->dropcnt += poll; /* not exact but fair enough */ return; + } if (dch || test_bit(FLG_HDLC, &bch->Flags)) { f1 = HFC_inb_nodebug(hc, A_F1); @@ -2227,16 +2259,30 @@ next_frame: if (Zsize <= 0) return; - if (*sp == NULL) { - *sp = mI_alloc_skb(maxlen + 3, GFP_ATOMIC); - if (*sp == NULL) { - printk(KERN_DEBUG "%s: No mem for rx_skb\n", - __func__); + if (bch) { + maxlen = bchannel_get_rxbuf(bch, Zsize); + if (maxlen < 0) { + pr_warning("card%d.B%d: No bufferspace for %d bytes\n", + hc->id + 1, bch->nr, Zsize); return; } + sp = &bch->rx_skb; + maxlen = bch->maxlen; + } else { /* Dchannel */ + sp = &dch->rx_skb; + maxlen = dch->maxlen + 3; + if (*sp == NULL) { + *sp = mI_alloc_skb(maxlen, GFP_ATOMIC); + if (*sp == NULL) { + pr_warning("card%d: No mem for dch rx_skb\n", + hc->id + 1); + return; + } + } } /* show activity */ - hc->activity[hc->chan[ch].port] = 1; + if (dch) + hc->activity_rx |= 1 << hc->chan[ch].port; /* empty fifo with what we have */ if (dch || test_bit(FLG_HDLC, &bch->Flags)) { @@ -2247,7 +2293,7 @@ next_frame: Zsize, z1, z2, (f1 == f2) ? "fragment" : "COMPLETE", f1, f2, Zsize + (*sp)->len, again); /* HDLC */ - if ((Zsize + (*sp)->len) > (maxlen + 3)) { + if ((Zsize + (*sp)->len) > maxlen) { if (debug & DEBUG_HFCMULTI_FIFO) printk(KERN_DEBUG "%s(card %d): hdlc-frame too large.\n", @@ -2309,7 +2355,7 @@ next_frame: if (dch) recv_Dchannel(dch); else - recv_Bchannel(bch, MISDN_ID_ANY); + recv_Bchannel(bch, MISDN_ID_ANY, false); *sp = skb; again++; goto next_frame; @@ -2317,32 +2363,14 @@ next_frame: /* there is an incomplete frame */ } else { /* transparent */ - if (Zsize > skb_tailroom(*sp)) - Zsize = skb_tailroom(*sp); hc->read_fifo(hc, skb_put(*sp, Zsize), Zsize); - if (((*sp)->len) < MISDN_COPY_SIZE) { - skb = *sp; - *sp = mI_alloc_skb(skb->len, GFP_ATOMIC); - if (*sp) { - memcpy(skb_put(*sp, skb->len), - skb->data, skb->len); - skb_trim(skb, 0); - } else { - printk(KERN_DEBUG "%s: No mem\n", __func__); - *sp = skb; - skb = NULL; - } - } else { - skb = NULL; - } if (debug & DEBUG_HFCMULTI_FIFO) printk(KERN_DEBUG "%s(card %d): fifo(%d) reading %d bytes " "(z1=%04x, z2=%04x) TRANS\n", __func__, hc->id + 1, ch, Zsize, z1, z2); /* only bch is transparent */ - recv_Bchannel(bch, hc->chan[ch].Zfill); - *sp = skb; + recv_Bchannel(bch, hc->chan[ch].Zfill, false); } } @@ -2430,55 +2458,55 @@ handle_timer_irq(struct hfc_multi *hc) } } if (hc->ctype == HFC_TYPE_E1 && hc->created[0]) { - dch = hc->chan[hc->dslot].dch; - if (test_bit(HFC_CFG_REPORT_LOS, &hc->chan[hc->dslot].cfg)) { - /* LOS */ - temp = HFC_inb_nodebug(hc, R_SYNC_STA) & V_SIG_LOS; - if (!temp && hc->chan[hc->dslot].los) + dch = hc->chan[hc->dnum[0]].dch; + /* LOS */ + temp = HFC_inb_nodebug(hc, R_SYNC_STA) & V_SIG_LOS; + hc->chan[hc->dnum[0]].los = temp; + if (test_bit(HFC_CFG_REPORT_LOS, &hc->chan[hc->dnum[0]].cfg)) { + if (!temp && hc->chan[hc->dnum[0]].los) signal_state_up(dch, L1_SIGNAL_LOS_ON, "LOS detected"); - if (temp && !hc->chan[hc->dslot].los) + if (temp && !hc->chan[hc->dnum[0]].los) signal_state_up(dch, L1_SIGNAL_LOS_OFF, "LOS gone"); - hc->chan[hc->dslot].los = temp; } - if (test_bit(HFC_CFG_REPORT_AIS, &hc->chan[hc->dslot].cfg)) { + if (test_bit(HFC_CFG_REPORT_AIS, &hc->chan[hc->dnum[0]].cfg)) { /* AIS */ temp = HFC_inb_nodebug(hc, R_SYNC_STA) & V_AIS; - if (!temp && hc->chan[hc->dslot].ais) + if (!temp && hc->chan[hc->dnum[0]].ais) signal_state_up(dch, L1_SIGNAL_AIS_ON, "AIS detected"); - if (temp && !hc->chan[hc->dslot].ais) + if (temp && !hc->chan[hc->dnum[0]].ais) signal_state_up(dch, L1_SIGNAL_AIS_OFF, "AIS gone"); - hc->chan[hc->dslot].ais = temp; + hc->chan[hc->dnum[0]].ais = temp; } - if (test_bit(HFC_CFG_REPORT_SLIP, &hc->chan[hc->dslot].cfg)) { + if (test_bit(HFC_CFG_REPORT_SLIP, &hc->chan[hc->dnum[0]].cfg)) { /* SLIP */ temp = HFC_inb_nodebug(hc, R_SLIP) & V_FOSLIP_RX; - if (!temp && hc->chan[hc->dslot].slip_rx) + if (!temp && hc->chan[hc->dnum[0]].slip_rx) signal_state_up(dch, L1_SIGNAL_SLIP_RX, " bit SLIP detected RX"); - hc->chan[hc->dslot].slip_rx = temp; + hc->chan[hc->dnum[0]].slip_rx = temp; temp = HFC_inb_nodebug(hc, R_SLIP) & V_FOSLIP_TX; - if (!temp && hc->chan[hc->dslot].slip_tx) + if (!temp && hc->chan[hc->dnum[0]].slip_tx) signal_state_up(dch, L1_SIGNAL_SLIP_TX, " bit SLIP detected TX"); - hc->chan[hc->dslot].slip_tx = temp; + hc->chan[hc->dnum[0]].slip_tx = temp; } - if (test_bit(HFC_CFG_REPORT_RDI, &hc->chan[hc->dslot].cfg)) { + if (test_bit(HFC_CFG_REPORT_RDI, &hc->chan[hc->dnum[0]].cfg)) { /* RDI */ temp = HFC_inb_nodebug(hc, R_RX_SL0_0) & V_A; - if (!temp && hc->chan[hc->dslot].rdi) + if (!temp && hc->chan[hc->dnum[0]].rdi) signal_state_up(dch, L1_SIGNAL_RDI_ON, "RDI detected"); - if (temp && !hc->chan[hc->dslot].rdi) + if (temp && !hc->chan[hc->dnum[0]].rdi) signal_state_up(dch, L1_SIGNAL_RDI_OFF, "RDI gone"); - hc->chan[hc->dslot].rdi = temp; + hc->chan[hc->dnum[0]].rdi = temp; } temp = HFC_inb_nodebug(hc, R_JATT_DIR); - switch (hc->chan[hc->dslot].sync) { + switch (hc->chan[hc->dnum[0]].sync) { case 0: if ((temp & 0x60) == 0x60) { if (debug & DEBUG_HFCMULTI_SYNC) @@ -2487,10 +2515,10 @@ handle_timer_irq(struct hfc_multi *hc) "in clock sync\n", __func__, hc->id); HFC_outb(hc, R_RX_OFF, - hc->chan[hc->dslot].jitter | V_RX_INIT); + hc->chan[hc->dnum[0]].jitter | V_RX_INIT); HFC_outb(hc, R_TX_OFF, - hc->chan[hc->dslot].jitter | V_RX_INIT); - hc->chan[hc->dslot].sync = 1; + hc->chan[hc->dnum[0]].jitter | V_RX_INIT); + hc->chan[hc->dnum[0]].sync = 1; goto check_framesync; } break; @@ -2501,7 +2529,7 @@ handle_timer_irq(struct hfc_multi *hc) "%s: (id=%d) E1 " "lost clock sync\n", __func__, hc->id); - hc->chan[hc->dslot].sync = 0; + hc->chan[hc->dnum[0]].sync = 0; break; } check_framesync: @@ -2512,7 +2540,7 @@ handle_timer_irq(struct hfc_multi *hc) "%s: (id=%d) E1 " "now in frame sync\n", __func__, hc->id); - hc->chan[hc->dslot].sync = 2; + hc->chan[hc->dnum[0]].sync = 2; } break; case 2: @@ -2522,7 +2550,7 @@ handle_timer_irq(struct hfc_multi *hc) "%s: (id=%d) E1 lost " "clock & frame sync\n", __func__, hc->id); - hc->chan[hc->dslot].sync = 0; + hc->chan[hc->dnum[0]].sync = 0; break; } temp = HFC_inb_nodebug(hc, R_SYNC_STA); @@ -2532,7 +2560,7 @@ handle_timer_irq(struct hfc_multi *hc) "%s: (id=%d) E1 " "lost frame sync\n", __func__, hc->id); - hc->chan[hc->dslot].sync = 1; + hc->chan[hc->dnum[0]].sync = 1; } break; } @@ -2673,7 +2701,7 @@ hfcmulti_interrupt(int intno, void *dev_id) int i; void __iomem *plx_acc; u_short wval; - u_char e1_syncsta, temp; + u_char e1_syncsta, temp, temp2; u_long flags; if (!hc) { @@ -2748,7 +2776,7 @@ hfcmulti_interrupt(int intno, void *dev_id) if (r_irq_misc & V_STA_IRQ) { if (hc->ctype == HFC_TYPE_E1) { /* state machine */ - dch = hc->chan[hc->dslot].dch; + dch = hc->chan[hc->dnum[0]].dch; e1_syncsta = HFC_inb_nodebug(hc, R_SYNC_STA); if (test_bit(HFC_CHIP_PLXSD, &hc->chip) && hc->e1_getclock) { @@ -2758,23 +2786,26 @@ hfcmulti_interrupt(int intno, void *dev_id) hc->syncronized = 0; } /* undocumented: status changes during read */ - dch->state = HFC_inb_nodebug(hc, R_E1_RD_STA); - while (dch->state != (temp = + temp = HFC_inb_nodebug(hc, R_E1_RD_STA); + while (temp != (temp2 = HFC_inb_nodebug(hc, R_E1_RD_STA))) { if (debug & DEBUG_HFCMULTI_STATE) printk(KERN_DEBUG "%s: reread " "STATE because %d!=%d\n", - __func__, temp, - dch->state); - dch->state = temp; /* repeat */ + __func__, temp, temp2); + temp = temp2; /* repeat */ } - dch->state = HFC_inb_nodebug(hc, R_E1_RD_STA) - & 0x7; - schedule_event(dch, FLG_PHCHANGE); + /* broadcast state change to all fragments */ if (debug & DEBUG_HFCMULTI_STATE) printk(KERN_DEBUG "%s: E1 (id=%d) newstate %x\n", - __func__, hc->id, dch->state); + __func__, hc->id, temp & 0x7); + for (i = 0; i < hc->ports; i++) { + dch = hc->chan[hc->dnum[i]].dch; + dch->state = temp & 0x7; + schedule_event(dch, FLG_PHCHANGE); + } + if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) plxsd_checksync(hc, 0); } @@ -3018,8 +3049,10 @@ mode_hfcmulti(struct hfc_multi *hc, int ch, int protocol, int slot_tx, HFC_outb(hc, A_CON_HDLC, 0x20 | V_HDLC_TRP | V_IFF); HFC_outb(hc, A_SUBCH_CFG, 0); HFC_outb(hc, A_IRQ_MSK, 0); - HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); - HFC_wait(hc); + if (hc->chan[ch].protocol != protocol) { + HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); + HFC_wait(hc); + } HFC_outb(hc, R_SLOT, ((((ch / 4) * 8) + ((ch % 4) * 4) + 1) << 1) | 1); HFC_outb(hc, A_SL_CFG, 0x80 | 0x20 | (ch << 1) | 1); @@ -3039,8 +3072,10 @@ mode_hfcmulti(struct hfc_multi *hc, int ch, int protocol, int slot_tx, HFC_outb(hc, A_CON_HDLC, 0x20 | V_HDLC_TRP | V_IFF); HFC_outb(hc, A_SUBCH_CFG, 0); HFC_outb(hc, A_IRQ_MSK, 0); - HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); - HFC_wait(hc); + if (hc->chan[ch].protocol != protocol) { + HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); + HFC_wait(hc); + } /* tx silence */ HFC_outb_nodebug(hc, A_FIFO_DATA0_NOINC, hc->silence); HFC_outb(hc, R_SLOT, (((ch / 4) * 8) + @@ -3059,8 +3094,10 @@ mode_hfcmulti(struct hfc_multi *hc, int ch, int protocol, int slot_tx, V_HDLC_TRP | V_IFF); HFC_outb(hc, A_SUBCH_CFG, 0); HFC_outb(hc, A_IRQ_MSK, 0); - HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); - HFC_wait(hc); + if (hc->chan[ch].protocol != protocol) { + HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); + HFC_wait(hc); + } /* tx silence */ HFC_outb_nodebug(hc, A_FIFO_DATA0_NOINC, hc->silence); /* enable RX fifo */ @@ -3075,8 +3112,10 @@ mode_hfcmulti(struct hfc_multi *hc, int ch, int protocol, int slot_tx, V_HDLC_TRP); HFC_outb(hc, A_SUBCH_CFG, 0); HFC_outb(hc, A_IRQ_MSK, 0); - HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); - HFC_wait(hc); + if (hc->chan[ch].protocol != protocol) { + HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); + HFC_wait(hc); + } } if (hc->ctype != HFC_TYPE_E1) { hc->hw.a_st_ctrl0[hc->chan[ch].port] |= @@ -3433,8 +3472,7 @@ handle_bmsg(struct mISDNchannel *ch, struct sk_buff *skb) struct hfc_multi *hc = bch->hw; int ret = -EINVAL; struct mISDNhead *hh = mISDN_HEAD_P(skb); - unsigned int id; - u_long flags; + unsigned long flags; switch (hh->prim) { case PH_DATA_REQ: @@ -3443,19 +3481,13 @@ handle_bmsg(struct mISDNchannel *ch, struct sk_buff *skb) spin_lock_irqsave(&hc->lock, flags); ret = bchannel_senddata(bch, skb); if (ret > 0) { /* direct TX */ - id = hh->id; /* skb can be freed */ hfcmulti_tx(hc, bch->slot); ret = 0; /* start fifo */ HFC_outb_nodebug(hc, R_FIFO, 0); HFC_wait_nodebug(hc); - if (!test_bit(FLG_TRANSPARENT, &bch->Flags)) { - spin_unlock_irqrestore(&hc->lock, flags); - queue_ch_frame(ch, PH_DATA_CNF, id, NULL); - } else - spin_unlock_irqrestore(&hc->lock, flags); - } else - spin_unlock_irqrestore(&hc->lock, flags); + } + spin_unlock_irqrestore(&hc->lock, flags); return ret; case PH_ACTIVATE_REQ: if (debug & DEBUG_HFCMULTI_MSG) @@ -3545,10 +3577,11 @@ channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) switch (cq->op) { case MISDN_CTRL_GETOP: - cq->op = MISDN_CTRL_HFC_OP | MISDN_CTRL_HW_FEATURES_OP - | MISDN_CTRL_RX_OFF | MISDN_CTRL_FILL_EMPTY; + ret = mISDN_ctrl_bchannel(bch, cq); + cq->op |= MISDN_CTRL_HFC_OP | MISDN_CTRL_HW_FEATURES_OP; break; case MISDN_CTRL_RX_OFF: /* turn off / on rx stream */ + ret = mISDN_ctrl_bchannel(bch, cq); hc->chan[bch->slot].rx_off = !!cq->p1; if (!hc->chan[bch->slot].rx_off) { /* reset fifo on rx on */ @@ -3561,11 +3594,10 @@ channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) printk(KERN_DEBUG "%s: RX_OFF request (nr=%d off=%d)\n", __func__, bch->nr, hc->chan[bch->slot].rx_off); break; - case MISDN_CTRL_FILL_EMPTY: /* fill fifo, if empty */ - test_and_set_bit(FLG_FILLEMPTY, &bch->Flags); - if (debug & DEBUG_HFCMULTI_MSG) - printk(KERN_DEBUG "%s: FILL_EMPTY request (nr=%d " - "off=%d)\n", __func__, bch->nr, !!cq->p1); + case MISDN_CTRL_FILL_EMPTY: + ret = mISDN_ctrl_bchannel(bch, cq); + hc->silence = bch->fill[0]; + memset(hc->silence_data, hc->silence, sizeof(hc->silence_data)); break; case MISDN_CTRL_HW_FEATURES: /* fill features structure */ if (debug & DEBUG_HFCMULTI_MSG) @@ -3654,9 +3686,7 @@ channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) ret = -EINVAL; break; default: - printk(KERN_WARNING "%s: unknown Op %x\n", - __func__, cq->op); - ret = -EINVAL; + ret = mISDN_ctrl_bchannel(bch, cq); break; } return ret; @@ -3676,8 +3706,7 @@ hfcm_bctrl(struct mISDNchannel *ch, u_int cmd, void *arg) switch (cmd) { case CLOSE_CHANNEL: test_and_clear_bit(FLG_OPEN, &bch->Flags); - if (test_bit(FLG_ACTIVE, &bch->Flags)) - deactivate_bchannel(bch); /* locked there */ + deactivate_bchannel(bch); /* locked there */ ch->protocol = ISDN_P_NONE; ch->peer = NULL; module_put(THIS_MODULE); @@ -3839,31 +3868,37 @@ hfcmulti_initmode(struct dchannel *dch) if (debug & DEBUG_HFCMULTI_INIT) printk(KERN_DEBUG "%s: entered\n", __func__); + i = dch->slot; + pt = hc->chan[i].port; if (hc->ctype == HFC_TYPE_E1) { - hc->chan[hc->dslot].slot_tx = -1; - hc->chan[hc->dslot].slot_rx = -1; - hc->chan[hc->dslot].conf = -1; - if (hc->dslot) { - mode_hfcmulti(hc, hc->dslot, dch->dev.D.protocol, + /* E1 */ + hc->chan[hc->dnum[pt]].slot_tx = -1; + hc->chan[hc->dnum[pt]].slot_rx = -1; + hc->chan[hc->dnum[pt]].conf = -1; + if (hc->dnum[pt]) { + mode_hfcmulti(hc, dch->slot, dch->dev.D.protocol, -1, 0, -1, 0); dch->timer.function = (void *) hfcmulti_dbusy_timer; dch->timer.data = (long) dch; init_timer(&dch->timer); } for (i = 1; i <= 31; i++) { - if (i == hc->dslot) + if (!((1 << i) & hc->bmask[pt])) /* skip unused chan */ continue; hc->chan[i].slot_tx = -1; hc->chan[i].slot_rx = -1; hc->chan[i].conf = -1; mode_hfcmulti(hc, i, ISDN_P_NONE, -1, 0, -1, 0); } - /* E1 */ - if (test_bit(HFC_CFG_REPORT_LOS, &hc->chan[hc->dslot].cfg)) { + } + if (hc->ctype == HFC_TYPE_E1 && pt == 0) { + /* E1, port 0 */ + dch = hc->chan[hc->dnum[0]].dch; + if (test_bit(HFC_CFG_REPORT_LOS, &hc->chan[hc->dnum[0]].cfg)) { HFC_outb(hc, R_LOS0, 255); /* 2 ms */ HFC_outb(hc, R_LOS1, 255); /* 512 ms */ } - if (test_bit(HFC_CFG_OPTICAL, &hc->chan[hc->dslot].cfg)) { + if (test_bit(HFC_CFG_OPTICAL, &hc->chan[hc->dnum[0]].cfg)) { HFC_outb(hc, R_RX0, 0); hc->hw.r_tx0 = 0 | V_OUT_EN; } else { @@ -3876,12 +3911,12 @@ hfcmulti_initmode(struct dchannel *dch) HFC_outb(hc, R_TX_FR0, 0x00); HFC_outb(hc, R_TX_FR1, 0xf8); - if (test_bit(HFC_CFG_CRC4, &hc->chan[hc->dslot].cfg)) + if (test_bit(HFC_CFG_CRC4, &hc->chan[hc->dnum[0]].cfg)) HFC_outb(hc, R_TX_FR2, V_TX_MF | V_TX_E | V_NEG_E); HFC_outb(hc, R_RX_FR0, V_AUTO_RESYNC | V_AUTO_RECO | 0); - if (test_bit(HFC_CFG_CRC4, &hc->chan[hc->dslot].cfg)) + if (test_bit(HFC_CFG_CRC4, &hc->chan[hc->dnum[0]].cfg)) HFC_outb(hc, R_RX_FR1, V_RX_MF | V_RX_MF_SYNC); if (dch->dev.D.protocol == ISDN_P_NT_E1) { @@ -3944,13 +3979,14 @@ hfcmulti_initmode(struct dchannel *dch) hc->syncronized = 0; plxsd_checksync(hc, 0); } - } else { - i = dch->slot; + } + if (hc->ctype != HFC_TYPE_E1) { + /* ST */ hc->chan[i].slot_tx = -1; hc->chan[i].slot_rx = -1; hc->chan[i].conf = -1; mode_hfcmulti(hc, i, dch->dev.D.protocol, -1, 0, -1, 0); - dch->timer.function = (void *)hfcmulti_dbusy_timer; + dch->timer.function = (void *) hfcmulti_dbusy_timer; dch->timer.data = (long) dch; init_timer(&dch->timer); hc->chan[i - 2].slot_tx = -1; @@ -3961,8 +3997,6 @@ hfcmulti_initmode(struct dchannel *dch) hc->chan[i - 1].slot_rx = -1; hc->chan[i - 1].conf = -1; mode_hfcmulti(hc, i - 1, ISDN_P_NONE, -1, 0, -1, 0); - /* ST */ - pt = hc->chan[i].port; /* select interface */ HFC_outb(hc, R_ST_SEL, pt); /* undocumented: delay after R_ST_SEL */ @@ -4054,14 +4088,9 @@ open_dchannel(struct hfc_multi *hc, struct dchannel *dch, hfcmulti_initmode(dch); spin_unlock_irqrestore(&hc->lock, flags); } - - if (((rq->protocol == ISDN_P_NT_S0) && (dch->state == 3)) || - ((rq->protocol == ISDN_P_TE_S0) && (dch->state == 7)) || - ((rq->protocol == ISDN_P_NT_E1) && (dch->state == 1)) || - ((rq->protocol == ISDN_P_TE_E1) && (dch->state == 1))) { + if (test_bit(FLG_ACTIVE, &dch->Flags)) _queue_data(&dch->dev.D, PH_ACTIVATE_IND, MISDN_ID_ANY, 0, NULL, GFP_KERNEL); - } rq->ch = &dch->dev.D; if (!try_module_get(THIS_MODULE)) printk(KERN_WARNING "%s:cannot get module\n", __func__); @@ -4091,7 +4120,6 @@ open_bchannel(struct hfc_multi *hc, struct dchannel *dch, } if (test_and_set_bit(FLG_OPEN, &bch->Flags)) return -EBUSY; /* b-channel can be only open once */ - test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags); bch->ch.protocol = rq->protocol; hc->chan[ch].rx_off = 0; rq->ch = &bch->ch; @@ -4112,7 +4140,7 @@ channel_dctrl(struct dchannel *dch, struct mISDN_ctrl_req *cq) switch (cq->op) { case MISDN_CTRL_GETOP: - cq->op = MISDN_CTRL_HFC_OP; + cq->op = MISDN_CTRL_HFC_OP | MISDN_CTRL_L1_TIMER3; break; case MISDN_CTRL_HFC_WD_INIT: /* init the watchdog */ wd_cnt = cq->p1 & 0xf; @@ -4142,6 +4170,9 @@ channel_dctrl(struct dchannel *dch, struct mISDN_ctrl_req *cq) __func__); HFC_outb(hc, R_BERT_WD_MD, hc->hw.r_bert_wd_md | V_WD_RES); break; + case MISDN_CTRL_L1_TIMER3: + ret = l1_event(dch->l1, HW_TIMER3_VALUE | (cq->p1 & 0xff)); + break; default: printk(KERN_WARNING "%s: unknown Op %x\n", __func__, cq->op); @@ -4545,6 +4576,8 @@ release_port(struct hfc_multi *hc, struct dchannel *dch) } /* free channels */ for (i = 0; i <= 31; i++) { + if (!((1 << i) & hc->bmask[pt])) /* skip unused chan */ + continue; if (hc->chan[i].bch) { if (debug & DEBUG_HFCMULTI_INIT) printk(KERN_DEBUG @@ -4600,7 +4633,8 @@ release_port(struct hfc_multi *hc, struct dchannel *dch) spin_unlock_irqrestore(&hc->lock, flags); if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: free port %d channel D\n", __func__, pt); + printk(KERN_DEBUG "%s: free port %d channel D(%d)\n", __func__, + pt+1, ci); mISDN_freedchannel(dch); kfree(dch); @@ -4622,15 +4656,19 @@ release_card(struct hfc_multi *hc) if (hc->iclock) mISDN_unregister_clock(hc->iclock); - /* disable irq */ + /* disable and free irq */ spin_lock_irqsave(&hc->lock, flags); disable_hwirq(hc); spin_unlock_irqrestore(&hc->lock, flags); udelay(1000); + if (hc->irq) { + if (debug & DEBUG_HFCMULTI_INIT) + printk(KERN_DEBUG "%s: free irq %d (hc=%p)\n", + __func__, hc->irq, hc); + free_irq(hc->irq, hc); + hc->irq = 0; - /* dimm leds */ - if (hc->leds) - hfcmulti_leds(hc); + } /* disable D-channels & B-channels */ if (debug & DEBUG_HFCMULTI_INIT) @@ -4641,15 +4679,11 @@ release_card(struct hfc_multi *hc) release_port(hc, hc->chan[ch].dch); } - /* release hardware & irq */ - if (hc->irq) { - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: free irq %d\n", - __func__, hc->irq); - free_irq(hc->irq, hc); - hc->irq = 0; + /* dimm leds */ + if (hc->leds) + hfcmulti_leds(hc); - } + /* release hardware */ release_io_hfcmulti(hc); if (debug & DEBUG_HFCMULTI_INIT) @@ -4667,61 +4701,9 @@ release_card(struct hfc_multi *hc) __func__); } -static int -init_e1_port(struct hfc_multi *hc, struct hm_map *m) +static void +init_e1_port_hw(struct hfc_multi *hc, struct hm_map *m) { - struct dchannel *dch; - struct bchannel *bch; - int ch, ret = 0; - char name[MISDN_MAX_IDLEN]; - - dch = kzalloc(sizeof(struct dchannel), GFP_KERNEL); - if (!dch) - return -ENOMEM; - dch->debug = debug; - mISDN_initdchannel(dch, MAX_DFRAME_LEN_L1, ph_state_change); - dch->hw = hc; - dch->dev.Dprotocols = (1 << ISDN_P_TE_E1) | (1 << ISDN_P_NT_E1); - dch->dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) | - (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK)); - dch->dev.D.send = handle_dmsg; - dch->dev.D.ctrl = hfcm_dctrl; - dch->dev.nrbchan = (hc->dslot) ? 30 : 31; - dch->slot = hc->dslot; - hc->chan[hc->dslot].dch = dch; - hc->chan[hc->dslot].port = 0; - hc->chan[hc->dslot].nt_timer = -1; - for (ch = 1; ch <= 31; ch++) { - if (ch == hc->dslot) /* skip dchannel */ - continue; - bch = kzalloc(sizeof(struct bchannel), GFP_KERNEL); - if (!bch) { - printk(KERN_ERR "%s: no memory for bchannel\n", - __func__); - ret = -ENOMEM; - goto free_chan; - } - hc->chan[ch].coeff = kzalloc(512, GFP_KERNEL); - if (!hc->chan[ch].coeff) { - printk(KERN_ERR "%s: no memory for coeffs\n", - __func__); - ret = -ENOMEM; - kfree(bch); - goto free_chan; - } - bch->nr = ch; - bch->slot = ch; - bch->debug = debug; - mISDN_initbchannel(bch, MAX_DATA_MEM); - bch->hw = hc; - bch->ch.send = handle_bmsg; - bch->ch.ctrl = hfcm_bctrl; - bch->ch.nr = ch; - list_add(&bch->ch.list, &dch->dev.bchannels); - hc->chan[ch].bch = bch; - hc->chan[ch].port = 0; - set_channelmap(bch->nr, dch->dev.channelmap); - } /* set optical line type */ if (port[Port_cnt] & 0x001) { if (!m->opticalsupport) { @@ -4737,7 +4719,7 @@ init_e1_port(struct hfc_multi *hc, struct hm_map *m) __func__, HFC_cnt + 1, 1); test_and_set_bit(HFC_CFG_OPTICAL, - &hc->chan[hc->dslot].cfg); + &hc->chan[hc->dnum[0]].cfg); } } /* set LOS report */ @@ -4747,7 +4729,7 @@ init_e1_port(struct hfc_multi *hc, struct hm_map *m) "LOS report: card(%d) port(%d)\n", __func__, HFC_cnt + 1, 1); test_and_set_bit(HFC_CFG_REPORT_LOS, - &hc->chan[hc->dslot].cfg); + &hc->chan[hc->dnum[0]].cfg); } /* set AIS report */ if (port[Port_cnt] & 0x008) { @@ -4756,7 +4738,7 @@ init_e1_port(struct hfc_multi *hc, struct hm_map *m) "AIS report: card(%d) port(%d)\n", __func__, HFC_cnt + 1, 1); test_and_set_bit(HFC_CFG_REPORT_AIS, - &hc->chan[hc->dslot].cfg); + &hc->chan[hc->dnum[0]].cfg); } /* set SLIP report */ if (port[Port_cnt] & 0x010) { @@ -4766,7 +4748,7 @@ init_e1_port(struct hfc_multi *hc, struct hm_map *m) "card(%d) port(%d)\n", __func__, HFC_cnt + 1, 1); test_and_set_bit(HFC_CFG_REPORT_SLIP, - &hc->chan[hc->dslot].cfg); + &hc->chan[hc->dnum[0]].cfg); } /* set RDI report */ if (port[Port_cnt] & 0x020) { @@ -4776,7 +4758,7 @@ init_e1_port(struct hfc_multi *hc, struct hm_map *m) "card(%d) port(%d)\n", __func__, HFC_cnt + 1, 1); test_and_set_bit(HFC_CFG_REPORT_RDI, - &hc->chan[hc->dslot].cfg); + &hc->chan[hc->dnum[0]].cfg); } /* set CRC-4 Mode */ if (!(port[Port_cnt] & 0x100)) { @@ -4785,7 +4767,7 @@ init_e1_port(struct hfc_multi *hc, struct hm_map *m) " card(%d) port(%d)\n", __func__, HFC_cnt + 1, 1); test_and_set_bit(HFC_CFG_CRC4, - &hc->chan[hc->dslot].cfg); + &hc->chan[hc->dnum[0]].cfg); } else { if (debug & DEBUG_HFCMULTI_INIT) printk(KERN_DEBUG "%s: PORT turn off CRC4" @@ -4817,20 +4799,85 @@ init_e1_port(struct hfc_multi *hc, struct hm_map *m) } /* set elastic jitter buffer */ if (port[Port_cnt] & 0x3000) { - hc->chan[hc->dslot].jitter = (port[Port_cnt]>>12) & 0x3; + hc->chan[hc->dnum[0]].jitter = (port[Port_cnt]>>12) & 0x3; if (debug & DEBUG_HFCMULTI_INIT) printk(KERN_DEBUG "%s: PORT set elastic " "buffer to %d: card(%d) port(%d)\n", - __func__, hc->chan[hc->dslot].jitter, + __func__, hc->chan[hc->dnum[0]].jitter, HFC_cnt + 1, 1); } else - hc->chan[hc->dslot].jitter = 2; /* default */ - snprintf(name, MISDN_MAX_IDLEN - 1, "hfc-e1.%d", HFC_cnt + 1); + hc->chan[hc->dnum[0]].jitter = 2; /* default */ +} + +static int +init_e1_port(struct hfc_multi *hc, struct hm_map *m, int pt) +{ + struct dchannel *dch; + struct bchannel *bch; + int ch, ret = 0; + char name[MISDN_MAX_IDLEN]; + int bcount = 0; + + dch = kzalloc(sizeof(struct dchannel), GFP_KERNEL); + if (!dch) + return -ENOMEM; + dch->debug = debug; + mISDN_initdchannel(dch, MAX_DFRAME_LEN_L1, ph_state_change); + dch->hw = hc; + dch->dev.Dprotocols = (1 << ISDN_P_TE_E1) | (1 << ISDN_P_NT_E1); + dch->dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) | + (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK)); + dch->dev.D.send = handle_dmsg; + dch->dev.D.ctrl = hfcm_dctrl; + dch->slot = hc->dnum[pt]; + hc->chan[hc->dnum[pt]].dch = dch; + hc->chan[hc->dnum[pt]].port = pt; + hc->chan[hc->dnum[pt]].nt_timer = -1; + for (ch = 1; ch <= 31; ch++) { + if (!((1 << ch) & hc->bmask[pt])) /* skip unused channel */ + continue; + bch = kzalloc(sizeof(struct bchannel), GFP_KERNEL); + if (!bch) { + printk(KERN_ERR "%s: no memory for bchannel\n", + __func__); + ret = -ENOMEM; + goto free_chan; + } + hc->chan[ch].coeff = kzalloc(512, GFP_KERNEL); + if (!hc->chan[ch].coeff) { + printk(KERN_ERR "%s: no memory for coeffs\n", + __func__); + ret = -ENOMEM; + kfree(bch); + goto free_chan; + } + bch->nr = ch; + bch->slot = ch; + bch->debug = debug; + mISDN_initbchannel(bch, MAX_DATA_MEM, poll >> 1); + bch->hw = hc; + bch->ch.send = handle_bmsg; + bch->ch.ctrl = hfcm_bctrl; + bch->ch.nr = ch; + list_add(&bch->ch.list, &dch->dev.bchannels); + hc->chan[ch].bch = bch; + hc->chan[ch].port = pt; + set_channelmap(bch->nr, dch->dev.channelmap); + bcount++; + } + dch->dev.nrbchan = bcount; + if (pt == 0) + init_e1_port_hw(hc, m); + if (hc->ports > 1) + snprintf(name, MISDN_MAX_IDLEN - 1, "hfc-e1.%d-%d", + HFC_cnt + 1, pt+1); + else + snprintf(name, MISDN_MAX_IDLEN - 1, "hfc-e1.%d", HFC_cnt + 1); ret = mISDN_register_device(&dch->dev, &hc->pci_dev->dev, name); if (ret) goto free_chan; - hc->created[0] = 1; + hc->created[pt] = 1; return ret; free_chan: release_port(hc, dch); @@ -4881,7 +4928,7 @@ init_multi_port(struct hfc_multi *hc, int pt) bch->nr = ch + 1; bch->slot = i + ch; bch->debug = debug; - mISDN_initbchannel(bch, MAX_DATA_MEM); + mISDN_initbchannel(bch, MAX_DATA_MEM, poll >> 1); bch->hw = hc; bch->ch.send = handle_bmsg; bch->ch.ctrl = hfcm_bctrl; @@ -4963,7 +5010,8 @@ hfcmulti_init(struct hm_map *m, struct pci_dev *pdev, struct hfc_multi *hc; u_long flags; u_char dips = 0, pmj = 0; /* dip settings, port mode Jumpers */ - int i; + int i, ch; + u_int maskcheck; if (HFC_cnt >= MAX_CARDS) { printk(KERN_ERR "too many cards (max=%d).\n", @@ -4997,18 +5045,36 @@ hfcmulti_init(struct hm_map *m, struct pci_dev *pdev, hc->id = HFC_cnt; hc->pcm = pcm[HFC_cnt]; hc->io_mode = iomode[HFC_cnt]; - if (dslot[HFC_cnt] < 0 && hc->ctype == HFC_TYPE_E1) { - hc->dslot = 0; - printk(KERN_INFO "HFC-E1 card has disabled D-channel, but " - "31 B-channels\n"); - } - if (dslot[HFC_cnt] > 0 && dslot[HFC_cnt] < 32 - && hc->ctype == HFC_TYPE_E1) { - hc->dslot = dslot[HFC_cnt]; - printk(KERN_INFO "HFC-E1 card has alternating D-channel on " - "time slot %d\n", dslot[HFC_cnt]); - } else - hc->dslot = 16; + if (hc->ctype == HFC_TYPE_E1 && dmask[E1_cnt]) { + /* fragment card */ + pt = 0; + maskcheck = 0; + for (ch = 0; ch <= 31; ch++) { + if (!((1 << ch) & dmask[E1_cnt])) + continue; + hc->dnum[pt] = ch; + hc->bmask[pt] = bmask[bmask_cnt++]; + if ((maskcheck & hc->bmask[pt]) + || (dmask[E1_cnt] & hc->bmask[pt])) { + printk(KERN_INFO + "HFC-E1 #%d has overlapping B-channels on fragment #%d\n", + E1_cnt + 1, pt); + return -EINVAL; + } + maskcheck |= hc->bmask[pt]; + printk(KERN_INFO + "HFC-E1 #%d uses D-channel on slot %d and a B-channel map of 0x%08x\n", + E1_cnt + 1, ch, hc->bmask[pt]); + pt++; + } + hc->ports = pt; + } + if (hc->ctype == HFC_TYPE_E1 && !dmask[E1_cnt]) { + /* default card layout */ + hc->dnum[0] = 16; + hc->bmask[0] = 0xfffefffe; + hc->ports = 1; + } /* set chip specific features */ hc->masterclk = -1; @@ -5091,23 +5157,33 @@ hfcmulti_init(struct hm_map *m, struct pci_dev *pdev, goto free_card; } if (hc->ctype == HFC_TYPE_E1) - ret_err = init_e1_port(hc, m); + ret_err = init_e1_port(hc, m, pt); else ret_err = init_multi_port(hc, pt); if (debug & DEBUG_HFCMULTI_INIT) printk(KERN_DEBUG - "%s: Registering D-channel, card(%d) port(%d)" + "%s: Registering D-channel, card(%d) port(%d) " "result %d\n", - __func__, HFC_cnt + 1, pt, ret_err); + __func__, HFC_cnt + 1, pt + 1, ret_err); if (ret_err) { while (pt) { /* release already registered ports */ pt--; - release_port(hc, hc->chan[(pt << 2) + 2].dch); + if (hc->ctype == HFC_TYPE_E1) + release_port(hc, + hc->chan[hc->dnum[pt]].dch); + else + release_port(hc, + hc->chan[(pt << 2) + 2].dch); } goto free_card; } - Port_cnt++; + if (hc->ctype != HFC_TYPE_E1) + Port_cnt++; /* for each S0 port */ + } + if (hc->ctype == HFC_TYPE_E1) { + Port_cnt++; /* for each E1 port */ + E1_cnt++; } /* disp switches */ diff --git a/drivers/isdn/hardware/mISDN/hfcpci.c b/drivers/isdn/hardware/mISDN/hfcpci.c index e2c83a2d7691..81363ffa5357 100644 --- a/drivers/isdn/hardware/mISDN/hfcpci.c +++ b/drivers/isdn/hardware/mISDN/hfcpci.c @@ -453,7 +453,7 @@ hfcpci_empty_bfifo(struct bchannel *bch, struct bzfifo *bz, } bz->za[new_f2].z2 = cpu_to_le16(new_z2); bz->f2 = new_f2; /* next buffer */ - recv_Bchannel(bch, MISDN_ID_ANY); + recv_Bchannel(bch, MISDN_ID_ANY, false); } } @@ -565,11 +565,6 @@ hfcpci_empty_fifo_trans(struct bchannel *bch, struct bzfifo *rxbz, if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL)) new_z2 -= B_FIFO_SIZE; /* buffer wrap */ - if (fcnt_rx > MAX_DATA_SIZE) { /* flush, if oversized */ - *z2r = cpu_to_le16(new_z2); /* new position */ - return; - } - fcnt_tx = le16_to_cpu(*z2t) - le16_to_cpu(*z1t); if (fcnt_tx <= 0) fcnt_tx += B_FIFO_SIZE; @@ -577,8 +572,16 @@ hfcpci_empty_fifo_trans(struct bchannel *bch, struct bzfifo *rxbz, fcnt_tx = B_FIFO_SIZE - fcnt_tx; /* remaining bytes to send (bytes in tx-fifo) */ - bch->rx_skb = mI_alloc_skb(fcnt_rx, GFP_ATOMIC); - if (bch->rx_skb) { + if (test_bit(FLG_RX_OFF, &bch->Flags)) { + bch->dropcnt += fcnt_rx; + *z2r = cpu_to_le16(new_z2); + return; + } + maxlen = bchannel_get_rxbuf(bch, fcnt_rx); + if (maxlen < 0) { + pr_warning("B%d: No bufferspace for %d bytes\n", + bch->nr, fcnt_rx); + } else { ptr = skb_put(bch->rx_skb, fcnt_rx); if (le16_to_cpu(*z2r) + fcnt_rx <= B_FIFO_SIZE + B_SUB_VAL) maxlen = fcnt_rx; /* complete transfer */ @@ -596,10 +599,8 @@ hfcpci_empty_fifo_trans(struct bchannel *bch, struct bzfifo *rxbz, ptr1 = bdata; /* start of buffer */ memcpy(ptr, ptr1, fcnt_rx); /* rest */ } - recv_Bchannel(bch, fcnt_tx); /* bch, id */ - } else - printk(KERN_WARNING "HFCPCI: receive out of memory\n"); - + recv_Bchannel(bch, fcnt_tx, false); /* bch, id, !force */ + } *z2r = cpu_to_le16(new_z2); /* new position */ } @@ -760,9 +761,14 @@ hfcpci_fill_fifo(struct bchannel *bch) if ((bch->debug & DEBUG_HW_BCHANNEL) && !(bch->debug & DEBUG_HW_BFIFO)) printk(KERN_DEBUG "%s\n", __func__); - if ((!bch->tx_skb) || bch->tx_skb->len <= 0) - return; - count = bch->tx_skb->len - bch->tx_idx; + if ((!bch->tx_skb) || bch->tx_skb->len == 0) { + if (!test_bit(FLG_FILLEMPTY, &bch->Flags) && + !test_bit(FLG_TRANSPARENT, &bch->Flags)) + return; + count = HFCPCI_FILLEMPTY; + } else { + count = bch->tx_skb->len - bch->tx_idx; + } if ((bch->nr & 2) && (!hc->hw.bswapped)) { bz = &((union fifo_area *)(hc->hw.fifos))->b_chans.txbz_b2; bdata = ((union fifo_area *)(hc->hw.fifos))->b_chans.txdat_b2; @@ -781,16 +787,10 @@ hfcpci_fill_fifo(struct bchannel *bch) fcnt = le16_to_cpu(*z2t) - le16_to_cpu(*z1t); if (fcnt <= 0) fcnt += B_FIFO_SIZE; - /* fcnt contains available bytes in fifo */ - fcnt = B_FIFO_SIZE - fcnt; - /* remaining bytes to send (bytes in fifo) */ - - /* "fill fifo if empty" feature */ - if (test_bit(FLG_FILLEMPTY, &bch->Flags) && !fcnt) { - /* printk(KERN_DEBUG "%s: buffer empty, so we have " - "underrun\n", __func__); */ - /* fill buffer, to prevent future underrun */ - count = HFCPCI_FILLEMPTY; + if (test_bit(FLG_FILLEMPTY, &bch->Flags)) { + /* fcnt contains available bytes in fifo */ + if (count > fcnt) + count = fcnt; new_z1 = le16_to_cpu(*z1t) + count; /* new buffer Position */ if (new_z1 >= (B_FIFO_SIZE + B_SUB_VAL)) @@ -802,17 +802,20 @@ hfcpci_fill_fifo(struct bchannel *bch) printk(KERN_DEBUG "hfcpci_FFt fillempty " "fcnt(%d) maxl(%d) nz1(%x) dst(%p)\n", fcnt, maxlen, new_z1, dst); - fcnt += count; if (maxlen > count) maxlen = count; /* limit size */ - memset(dst, 0x2a, maxlen); /* first copy */ + memset(dst, bch->fill[0], maxlen); /* first copy */ count -= maxlen; /* remaining bytes */ if (count) { dst = bdata; /* start of buffer */ - memset(dst, 0x2a, count); + memset(dst, bch->fill[0], count); } *z1t = cpu_to_le16(new_z1); /* now send data */ + return; } + /* fcnt contains available bytes in fifo */ + fcnt = B_FIFO_SIZE - fcnt; + /* remaining bytes to send (bytes in fifo) */ next_t_frame: count = bch->tx_skb->len - bch->tx_idx; @@ -849,9 +852,6 @@ hfcpci_fill_fifo(struct bchannel *bch) *z1t = cpu_to_le16(new_z1); /* now send data */ if (bch->tx_idx < bch->tx_skb->len) return; - /* send confirm, on trans, free on hdlc. */ - if (test_bit(FLG_TRANSPARENT, &bch->Flags)) - confirm_Bsend(bch); dev_kfree_skb(bch->tx_skb); if (get_next_bframe(bch)) goto next_t_frame; @@ -1533,24 +1533,7 @@ deactivate_bchannel(struct bchannel *bch) static int channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) { - int ret = 0; - - switch (cq->op) { - case MISDN_CTRL_GETOP: - cq->op = MISDN_CTRL_FILL_EMPTY; - break; - case MISDN_CTRL_FILL_EMPTY: /* fill fifo, if empty */ - test_and_set_bit(FLG_FILLEMPTY, &bch->Flags); - if (debug & DEBUG_HW_OPEN) - printk(KERN_DEBUG "%s: FILL_EMPTY request (nr=%d " - "off=%d)\n", __func__, bch->nr, !!cq->p1); - break; - default: - printk(KERN_WARNING "%s: unknown Op %x\n", __func__, cq->op); - ret = -EINVAL; - break; - } - return ret; + return mISDN_ctrl_bchannel(bch, cq); } static int hfc_bctrl(struct mISDNchannel *ch, u_int cmd, void *arg) @@ -1581,8 +1564,7 @@ hfc_bctrl(struct mISDNchannel *ch, u_int cmd, void *arg) break; case CLOSE_CHANNEL: test_and_clear_bit(FLG_OPEN, &bch->Flags); - if (test_bit(FLG_ACTIVE, &bch->Flags)) - deactivate_bchannel(bch); + deactivate_bchannel(bch); ch->protocol = ISDN_P_NONE; ch->peer = NULL; module_put(THIS_MODULE); @@ -1692,22 +1674,17 @@ hfcpci_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb) struct hfc_pci *hc = bch->hw; int ret = -EINVAL; struct mISDNhead *hh = mISDN_HEAD_P(skb); - unsigned int id; - u_long flags; + unsigned long flags; switch (hh->prim) { case PH_DATA_REQ: spin_lock_irqsave(&hc->lock, flags); ret = bchannel_senddata(bch, skb); if (ret > 0) { /* direct TX */ - id = hh->id; /* skb can be freed */ hfcpci_fill_fifo(bch); ret = 0; - spin_unlock_irqrestore(&hc->lock, flags); - if (!test_bit(FLG_TRANSPARENT, &bch->Flags)) - queue_ch_frame(ch, PH_DATA_CNF, id, NULL); - } else - spin_unlock_irqrestore(&hc->lock, flags); + } + spin_unlock_irqrestore(&hc->lock, flags); return ret; case PH_ACTIVATE_REQ: spin_lock_irqsave(&hc->lock, flags); @@ -1819,7 +1796,7 @@ channel_ctrl(struct hfc_pci *hc, struct mISDN_ctrl_req *cq) switch (cq->op) { case MISDN_CTRL_GETOP: cq->op = MISDN_CTRL_LOOP | MISDN_CTRL_CONNECT | - MISDN_CTRL_DISCONNECT; + MISDN_CTRL_DISCONNECT | MISDN_CTRL_L1_TIMER3; break; case MISDN_CTRL_LOOP: /* channel 0 disabled loop */ @@ -1896,6 +1873,9 @@ channel_ctrl(struct hfc_pci *hc, struct mISDN_ctrl_req *cq) Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn); hc->hw.trm &= 0x7f; /* disable IOM-loop */ break; + case MISDN_CTRL_L1_TIMER3: + ret = l1_event(hc->dch.l1, HW_TIMER3_VALUE | (cq->p1 & 0xff)); + break; default: printk(KERN_WARNING "%s: unknown Op %x\n", __func__, cq->op); @@ -1969,7 +1949,6 @@ open_bchannel(struct hfc_pci *hc, struct channel_req *rq) bch = &hc->bch[rq->adr.channel - 1]; if (test_and_set_bit(FLG_OPEN, &bch->Flags)) return -EBUSY; /* b-channel can be only open once */ - test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags); bch->ch.protocol = rq->protocol; rq->ch = &bch->ch; /* TODO: E-channel */ if (!try_module_get(THIS_MODULE)) @@ -2121,7 +2100,7 @@ setup_card(struct hfc_pci *card) card->bch[i].nr = i + 1; set_channelmap(i + 1, card->dch.dev.channelmap); card->bch[i].debug = debug; - mISDN_initbchannel(&card->bch[i], MAX_DATA_MEM); + mISDN_initbchannel(&card->bch[i], MAX_DATA_MEM, poll >> 1); card->bch[i].hw = card; card->bch[i].ch.send = hfcpci_l2l1B; card->bch[i].ch.ctrl = hfc_bctrl; diff --git a/drivers/isdn/hardware/mISDN/hfcsusb.c b/drivers/isdn/hardware/mISDN/hfcsusb.c index 8cde2a0538ab..c65c3440cd70 100644 --- a/drivers/isdn/hardware/mISDN/hfcsusb.c +++ b/drivers/isdn/hardware/mISDN/hfcsusb.c @@ -226,19 +226,12 @@ hfcusb_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb) if (debug & DBG_HFC_CALL_TRACE) printk(KERN_DEBUG "%s: %s PH_DATA_REQ ret(%i)\n", hw->name, __func__, ret); - if (ret > 0) { - /* - * other l1 drivers don't send early confirms on - * transp data, but hfcsusb does because tx_next - * skb is needed in tx_iso_complete() - */ - queue_ch_frame(ch, PH_DATA_CNF, hh->id, NULL); + if (ret > 0) ret = 0; - } return ret; case PH_ACTIVATE_REQ: if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags)) { - hfcsusb_start_endpoint(hw, bch->nr); + hfcsusb_start_endpoint(hw, bch->nr - 1); ret = hfcsusb_setup_bch(bch, ch->protocol); } else ret = 0; @@ -498,16 +491,9 @@ open_bchannel(struct hfcsusb *hw, struct channel_req *rq) bch = &hw->bch[rq->adr.channel - 1]; if (test_and_set_bit(FLG_OPEN, &bch->Flags)) return -EBUSY; /* b-channel can be only open once */ - test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags); bch->ch.protocol = rq->protocol; rq->ch = &bch->ch; - /* start USB endpoint for bchannel */ - if (rq->adr.channel == 1) - hfcsusb_start_endpoint(hw, HFC_CHAN_B1); - else - hfcsusb_start_endpoint(hw, HFC_CHAN_B2); - if (!try_module_get(THIS_MODULE)) printk(KERN_WARNING "%s: %s:cannot get module\n", hw->name, __func__); @@ -819,24 +805,7 @@ hfcsusb_ph_command(struct hfcsusb *hw, u_char command) static int channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) { - int ret = 0; - - switch (cq->op) { - case MISDN_CTRL_GETOP: - cq->op = MISDN_CTRL_FILL_EMPTY; - break; - case MISDN_CTRL_FILL_EMPTY: /* fill fifo, if empty */ - test_and_set_bit(FLG_FILLEMPTY, &bch->Flags); - if (debug & DEBUG_HW_OPEN) - printk(KERN_DEBUG "%s: FILL_EMPTY request (nr=%d " - "off=%d)\n", __func__, bch->nr, !!cq->p1); - break; - default: - printk(KERN_WARNING "%s: unknown Op %x\n", __func__, cq->op); - ret = -EINVAL; - break; - } - return ret; + return mISDN_ctrl_bchannel(bch, cq); } /* collect data from incoming interrupt or isochron USB data */ @@ -873,7 +842,21 @@ hfcsusb_rx_frame(struct usb_fifo *fifo, __u8 *data, unsigned int len, hdlc = 1; } if (fifo->bch) { + if (test_bit(FLG_RX_OFF, &fifo->bch->Flags)) { + fifo->bch->dropcnt += len; + spin_unlock(&hw->lock); + return; + } + maxlen = bchannel_get_rxbuf(fifo->bch, len); rx_skb = fifo->bch->rx_skb; + if (maxlen < 0) { + if (rx_skb) + skb_trim(rx_skb, 0); + pr_warning("%s.B%d: No bufferspace for %d bytes\n", + hw->name, fifo->bch->nr, len); + spin_unlock(&hw->lock); + return; + } maxlen = fifo->bch->maxlen; hdlc = test_bit(FLG_HDLC, &fifo->bch->Flags); } @@ -883,25 +866,22 @@ hfcsusb_rx_frame(struct usb_fifo *fifo, __u8 *data, unsigned int len, hdlc = 1; } - if (!rx_skb) { - rx_skb = mI_alloc_skb(maxlen, GFP_ATOMIC); - if (rx_skb) { - if (fifo->dch) - fifo->dch->rx_skb = rx_skb; - if (fifo->bch) - fifo->bch->rx_skb = rx_skb; - if (fifo->ech) - fifo->ech->rx_skb = rx_skb; - skb_trim(rx_skb, 0); - } else { - printk(KERN_DEBUG "%s: %s: No mem for rx_skb\n", - hw->name, __func__); - spin_unlock(&hw->lock); - return; - } - } - if (fifo->dch || fifo->ech) { + if (!rx_skb) { + rx_skb = mI_alloc_skb(maxlen, GFP_ATOMIC); + if (rx_skb) { + if (fifo->dch) + fifo->dch->rx_skb = rx_skb; + if (fifo->ech) + fifo->ech->rx_skb = rx_skb; + skb_trim(rx_skb, 0); + } else { + printk(KERN_DEBUG "%s: %s: No mem for rx_skb\n", + hw->name, __func__); + spin_unlock(&hw->lock); + return; + } + } /* D/E-Channel SKB range check */ if ((rx_skb->len + len) >= MAX_DFRAME_LEN_L1) { printk(KERN_DEBUG "%s: %s: sbk mem exceeded " @@ -911,16 +891,6 @@ hfcsusb_rx_frame(struct usb_fifo *fifo, __u8 *data, unsigned int len, spin_unlock(&hw->lock); return; } - } else if (fifo->bch) { - /* B-Channel SKB range check */ - if ((rx_skb->len + len) >= (MAX_BCH_SIZE + 3)) { - printk(KERN_DEBUG "%s: %s: sbk mem exceeded " - "for fifo(%d) HFCUSB_B_RX\n", - hw->name, __func__, fifon); - skb_trim(rx_skb, 0); - spin_unlock(&hw->lock); - return; - } } memcpy(skb_put(rx_skb, len), data, len); @@ -948,7 +918,8 @@ hfcsusb_rx_frame(struct usb_fifo *fifo, __u8 *data, unsigned int len, if (fifo->dch) recv_Dchannel(fifo->dch); if (fifo->bch) - recv_Bchannel(fifo->bch, MISDN_ID_ANY); + recv_Bchannel(fifo->bch, MISDN_ID_ANY, + 0); if (fifo->ech) recv_Echannel(fifo->ech, &hw->dch); @@ -969,8 +940,7 @@ hfcsusb_rx_frame(struct usb_fifo *fifo, __u8 *data, unsigned int len, } } else { /* deliver transparent data to layer2 */ - if (rx_skb->len >= poll) - recv_Bchannel(fifo->bch, MISDN_ID_ANY); + recv_Bchannel(fifo->bch, MISDN_ID_ANY, false); } spin_unlock(&hw->lock); } @@ -1200,8 +1170,8 @@ tx_iso_complete(struct urb *urb) int k, tx_offset, num_isoc_packets, sink, remain, current_len, errcode, hdlc, i; int *tx_idx; - int frame_complete, fifon, status; - __u8 threshbit; + int frame_complete, fifon, status, fillempty = 0; + __u8 threshbit, *p; spin_lock(&hw->lock); if (fifo->stop_gracefull) { @@ -1219,6 +1189,9 @@ tx_iso_complete(struct urb *urb) tx_skb = fifo->bch->tx_skb; tx_idx = &fifo->bch->tx_idx; hdlc = test_bit(FLG_HDLC, &fifo->bch->Flags); + if (!tx_skb && !hdlc && + test_bit(FLG_FILLEMPTY, &fifo->bch->Flags)) + fillempty = 1; } else { printk(KERN_DEBUG "%s: %s: neither BCH nor DCH\n", hw->name, __func__); @@ -1277,6 +1250,8 @@ tx_iso_complete(struct urb *urb) /* Generate next ISO Packets */ if (tx_skb) remain = tx_skb->len - *tx_idx; + else if (fillempty) + remain = 15; /* > not complete */ else remain = 0; @@ -1307,15 +1282,20 @@ tx_iso_complete(struct urb *urb) } /* copy tx data to iso-urb buffer */ - memcpy(context_iso_urb->buffer + tx_offset + 1, - (tx_skb->data + *tx_idx), current_len); - *tx_idx += current_len; - + p = context_iso_urb->buffer + tx_offset + 1; + if (fillempty) { + memset(p, fifo->bch->fill[0], + current_len); + } else { + memcpy(p, (tx_skb->data + *tx_idx), + current_len); + *tx_idx += current_len; + } urb->iso_frame_desc[k].offset = tx_offset; urb->iso_frame_desc[k].length = current_len + 1; /* USB data log for every D ISO out */ - if ((fifon == HFCUSB_D_RX) && + if ((fifon == HFCUSB_D_RX) && !fillempty && (debug & DBG_HFC_USB_VERBOSE)) { printk(KERN_DEBUG "%s: %s (%d/%d) offs(%d) len(%d) ", @@ -1365,12 +1345,8 @@ tx_iso_complete(struct urb *urb) if (fifo->dch && get_next_dframe(fifo->dch)) tx_skb = fifo->dch->tx_skb; else if (fifo->bch && - get_next_bframe(fifo->bch)) { - if (test_bit(FLG_TRANSPARENT, - &fifo->bch->Flags)) - confirm_Bsend(fifo->bch); + get_next_bframe(fifo->bch)) tx_skb = fifo->bch->tx_skb; - } } } errcode = usb_submit_urb(urb, GFP_ATOMIC); @@ -1812,7 +1788,7 @@ deactivate_bchannel(struct bchannel *bch) mISDN_clear_bchannel(bch); spin_unlock_irqrestore(&hw->lock, flags); hfcsusb_setup_bch(bch, ISDN_P_NONE); - hfcsusb_stop_endpoint(hw, bch->nr); + hfcsusb_stop_endpoint(hw, bch->nr - 1); } /* @@ -1836,8 +1812,7 @@ hfc_bctrl(struct mISDNchannel *ch, u_int cmd, void *arg) case CLOSE_CHANNEL: test_and_clear_bit(FLG_OPEN, &bch->Flags); - if (test_bit(FLG_ACTIVE, &bch->Flags)) - deactivate_bchannel(bch); + deactivate_bchannel(bch); ch->protocol = ISDN_P_NONE; ch->peer = NULL; module_put(THIS_MODULE); @@ -1883,7 +1858,7 @@ setup_instance(struct hfcsusb *hw, struct device *parent) hw->bch[i].nr = i + 1; set_channelmap(i + 1, hw->dch.dev.channelmap); hw->bch[i].debug = debug; - mISDN_initbchannel(&hw->bch[i], MAX_DATA_MEM); + mISDN_initbchannel(&hw->bch[i], MAX_DATA_MEM, poll >> 1); hw->bch[i].hw = hw; hw->bch[i].ch.send = hfcusb_l2l1B; hw->bch[i].ch.ctrl = hfc_bctrl; @@ -2151,6 +2126,7 @@ static struct usb_driver hfcsusb_drv = { .id_table = hfcsusb_idtab, .probe = hfcsusb_probe, .disconnect = hfcsusb_disconnect, + .disable_hub_initiated_lpm = 1, }; module_usb_driver(hfcsusb_drv); diff --git a/drivers/isdn/hardware/mISDN/mISDNipac.c b/drivers/isdn/hardware/mISDN/mISDNipac.c index 884369f09cad..752e0825591f 100644 --- a/drivers/isdn/hardware/mISDN/mISDNipac.c +++ b/drivers/isdn/hardware/mISDN/mISDNipac.c @@ -603,10 +603,11 @@ isac_l1hw(struct mISDNchannel *ch, struct sk_buff *skb) } static int -isac_ctrl(struct isac_hw *isac, u32 cmd, u_long para) +isac_ctrl(struct isac_hw *isac, u32 cmd, unsigned long para) { u8 tl = 0; - u_long flags; + unsigned long flags; + int ret = 0; switch (cmd) { case HW_TESTLOOP: @@ -626,12 +627,15 @@ isac_ctrl(struct isac_hw *isac, u32 cmd, u_long para) } spin_unlock_irqrestore(isac->hwlock, flags); break; + case HW_TIMER3_VALUE: + ret = l1_event(isac->dch.l1, HW_TIMER3_VALUE | (para & 0xff)); + break; default: pr_debug("%s: %s unknown command %x %lx\n", isac->name, __func__, cmd, para); - return -1; + ret = -1; } - return 0; + return ret; } static int @@ -929,22 +933,21 @@ static void hscx_empty_fifo(struct hscx_hw *hscx, u8 count) { u8 *p; + int maxlen; pr_debug("%s: B%1d %d\n", hscx->ip->name, hscx->bch.nr, count); - if (!hscx->bch.rx_skb) { - hscx->bch.rx_skb = mI_alloc_skb(hscx->bch.maxlen, GFP_ATOMIC); - if (!hscx->bch.rx_skb) { - pr_info("%s: B receive out of memory\n", - hscx->ip->name); - hscx_cmdr(hscx, 0x80); /* RMC */ - return; - } + if (test_bit(FLG_RX_OFF, &hscx->bch.Flags)) { + hscx->bch.dropcnt += count; + hscx_cmdr(hscx, 0x80); /* RMC */ + return; } - if ((hscx->bch.rx_skb->len + count) > hscx->bch.maxlen) { - pr_debug("%s: overrun %d\n", hscx->ip->name, - hscx->bch.rx_skb->len + count); - skb_trim(hscx->bch.rx_skb, 0); + maxlen = bchannel_get_rxbuf(&hscx->bch, count); + if (maxlen < 0) { hscx_cmdr(hscx, 0x80); /* RMC */ + if (hscx->bch.rx_skb) + skb_trim(hscx->bch.rx_skb, 0); + pr_warning("%s.B%d: No bufferspace for %d bytes\n", + hscx->ip->name, hscx->bch.nr, count); return; } p = skb_put(hscx->bch.rx_skb, count); @@ -971,22 +974,28 @@ hscx_fill_fifo(struct hscx_hw *hscx) int count, more; u8 *p; - if (!hscx->bch.tx_skb) - return; - count = hscx->bch.tx_skb->len - hscx->bch.tx_idx; - if (count <= 0) - return; - p = hscx->bch.tx_skb->data + hscx->bch.tx_idx; - - more = test_bit(FLG_TRANSPARENT, &hscx->bch.Flags) ? 1 : 0; - if (count > hscx->fifo_size) { + if (!hscx->bch.tx_skb) { + if (!test_bit(FLG_TX_EMPTY, &hscx->bch.Flags)) + return; count = hscx->fifo_size; more = 1; - } - pr_debug("%s: B%1d %d/%d/%d\n", hscx->ip->name, hscx->bch.nr, count, - hscx->bch.tx_idx, hscx->bch.tx_skb->len); - hscx->bch.tx_idx += count; + p = hscx->log; + memset(p, hscx->bch.fill[0], count); + } else { + count = hscx->bch.tx_skb->len - hscx->bch.tx_idx; + if (count <= 0) + return; + p = hscx->bch.tx_skb->data + hscx->bch.tx_idx; + more = test_bit(FLG_TRANSPARENT, &hscx->bch.Flags) ? 1 : 0; + if (count > hscx->fifo_size) { + count = hscx->fifo_size; + more = 1; + } + pr_debug("%s: B%1d %d/%d/%d\n", hscx->ip->name, hscx->bch.nr, + count, hscx->bch.tx_idx, hscx->bch.tx_skb->len); + hscx->bch.tx_idx += count; + } if (hscx->ip->type & IPAC_TYPE_IPACX) hscx->ip->write_fifo(hscx->ip->hw, hscx->off + IPACX_XFIFOB, p, count); @@ -997,7 +1006,7 @@ hscx_fill_fifo(struct hscx_hw *hscx) } hscx_cmdr(hscx, more ? 0x08 : 0x0a); - if (hscx->bch.debug & DEBUG_HW_BFIFO) { + if (hscx->bch.tx_skb && (hscx->bch.debug & DEBUG_HW_BFIFO)) { snprintf(hscx->log, 64, "B%1d-send %s %d ", hscx->bch.nr, hscx->ip->name, count); print_hex_dump_bytes(hscx->log, DUMP_PREFIX_OFFSET, p, count); @@ -1007,17 +1016,17 @@ hscx_fill_fifo(struct hscx_hw *hscx) static void hscx_xpr(struct hscx_hw *hx) { - if (hx->bch.tx_skb && hx->bch.tx_idx < hx->bch.tx_skb->len) + if (hx->bch.tx_skb && hx->bch.tx_idx < hx->bch.tx_skb->len) { hscx_fill_fifo(hx); - else { - if (hx->bch.tx_skb) { - /* send confirm, on trans, free on hdlc. */ - if (test_bit(FLG_TRANSPARENT, &hx->bch.Flags)) - confirm_Bsend(&hx->bch); + } else { + if (hx->bch.tx_skb) dev_kfree_skb(hx->bch.tx_skb); - } - if (get_next_bframe(&hx->bch)) + if (get_next_bframe(&hx->bch)) { + hscx_fill_fifo(hx); + test_and_clear_bit(FLG_TX_EMPTY, &hx->bch.Flags); + } else if (test_bit(FLG_TX_EMPTY, &hx->bch.Flags)) { hscx_fill_fifo(hx); + } } } @@ -1069,7 +1078,7 @@ ipac_rme(struct hscx_hw *hx) skb_trim(hx->bch.rx_skb, 0); } else { skb_trim(hx->bch.rx_skb, hx->bch.rx_skb->len - 1); - recv_Bchannel(&hx->bch, 0); + recv_Bchannel(&hx->bch, 0, false); } } @@ -1120,11 +1129,8 @@ ipac_irq(struct hscx_hw *hx, u8 ista) if (istab & IPACX_B_RPF) { hscx_empty_fifo(hx, hx->fifo_size); - if (test_bit(FLG_TRANSPARENT, &hx->bch.Flags)) { - /* receive transparent audio data */ - if (hx->bch.rx_skb) - recv_Bchannel(&hx->bch, 0); - } + if (test_bit(FLG_TRANSPARENT, &hx->bch.Flags)) + recv_Bchannel(&hx->bch, 0, false); } if (istab & IPACX_B_RFO) { @@ -1137,7 +1143,9 @@ ipac_irq(struct hscx_hw *hx, u8 ista) if (istab & IPACX_B_XDU) { if (test_bit(FLG_TRANSPARENT, &hx->bch.Flags)) { - hscx_fill_fifo(hx); + if (test_bit(FLG_FILLEMPTY, &hx->bch.Flags)) + test_and_set_bit(FLG_TX_EMPTY, &hx->bch.Flags); + hscx_xpr(hx); return; } pr_debug("%s: B%1d XDU error at len %d\n", hx->ip->name, @@ -1338,22 +1346,17 @@ hscx_l2l1(struct mISDNchannel *ch, struct sk_buff *skb) struct hscx_hw *hx = container_of(bch, struct hscx_hw, bch); int ret = -EINVAL; struct mISDNhead *hh = mISDN_HEAD_P(skb); - u32 id; - u_long flags; + unsigned long flags; switch (hh->prim) { case PH_DATA_REQ: spin_lock_irqsave(hx->ip->hwlock, flags); ret = bchannel_senddata(bch, skb); if (ret > 0) { /* direct TX */ - id = hh->id; /* skb can be freed */ ret = 0; hscx_fill_fifo(hx); - spin_unlock_irqrestore(hx->ip->hwlock, flags); - if (!test_bit(FLG_TRANSPARENT, &bch->Flags)) - queue_ch_frame(ch, PH_DATA_CNF, id, NULL); - } else - spin_unlock_irqrestore(hx->ip->hwlock, flags); + } + spin_unlock_irqrestore(hx->ip->hwlock, flags); return ret; case PH_ACTIVATE_REQ: spin_lock_irqsave(hx->ip->hwlock, flags); @@ -1388,20 +1391,7 @@ hscx_l2l1(struct mISDNchannel *ch, struct sk_buff *skb) static int channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) { - int ret = 0; - - switch (cq->op) { - case MISDN_CTRL_GETOP: - cq->op = 0; - break; - /* Nothing implemented yet */ - case MISDN_CTRL_FILL_EMPTY: - default: - pr_info("%s: unknown Op %x\n", __func__, cq->op); - ret = -EINVAL; - break; - } - return ret; + return mISDN_ctrl_bchannel(bch, cq); } static int @@ -1416,15 +1406,10 @@ hscx_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg) switch (cmd) { case CLOSE_CHANNEL: test_and_clear_bit(FLG_OPEN, &bch->Flags); - if (test_bit(FLG_ACTIVE, &bch->Flags)) { - spin_lock_irqsave(hx->ip->hwlock, flags); - mISDN_freebchannel(bch); - hscx_mode(hx, ISDN_P_NONE); - spin_unlock_irqrestore(hx->ip->hwlock, flags); - } else { - skb_queue_purge(&bch->rqueue); - bch->rcount = 0; - } + spin_lock_irqsave(hx->ip->hwlock, flags); + mISDN_freebchannel(bch); + hscx_mode(hx, ISDN_P_NONE); + spin_unlock_irqrestore(hx->ip->hwlock, flags); ch->protocol = ISDN_P_NONE; ch->peer = NULL; module_put(hx->ip->owner); @@ -1526,7 +1511,7 @@ channel_ctrl(struct ipac_hw *ipac, struct mISDN_ctrl_req *cq) switch (cq->op) { case MISDN_CTRL_GETOP: - cq->op = MISDN_CTRL_LOOP; + cq->op = MISDN_CTRL_LOOP | MISDN_CTRL_L1_TIMER3; break; case MISDN_CTRL_LOOP: /* cq->channel: 0 disable, 1 B1 loop 2 B2 loop, 3 both */ @@ -1536,6 +1521,9 @@ channel_ctrl(struct ipac_hw *ipac, struct mISDN_ctrl_req *cq) } ret = ipac->ctrl(ipac, HW_TESTLOOP, cq->channel); break; + case MISDN_CTRL_L1_TIMER3: + ret = ipac->isac.ctrl(&ipac->isac, HW_TIMER3_VALUE, cq->p1); + break; default: pr_info("%s: unknown CTRL OP %x\n", ipac->name, cq->op); ret = -EINVAL; @@ -1621,7 +1609,8 @@ mISDNipac_init(struct ipac_hw *ipac, void *hw) set_channelmap(i + 1, ipac->isac.dch.dev.channelmap); list_add(&ipac->hscx[i].bch.ch.list, &ipac->isac.dch.dev.bchannels); - mISDN_initbchannel(&ipac->hscx[i].bch, MAX_DATA_MEM); + mISDN_initbchannel(&ipac->hscx[i].bch, MAX_DATA_MEM, + ipac->hscx[i].fifo_size); ipac->hscx[i].bch.ch.nr = i + 1; ipac->hscx[i].bch.ch.send = &hscx_l2l1; ipac->hscx[i].bch.ch.ctrl = hscx_bctrl; diff --git a/drivers/isdn/hardware/mISDN/mISDNisar.c b/drivers/isdn/hardware/mISDN/mISDNisar.c index 9a6da6edcfa8..be5973ded6d6 100644 --- a/drivers/isdn/hardware/mISDN/mISDNisar.c +++ b/drivers/isdn/hardware/mISDN/mISDNisar.c @@ -421,13 +421,19 @@ deliver_status(struct isar_ch *ch, int status) static inline void isar_rcv_frame(struct isar_ch *ch) { - u8 *ptr; + u8 *ptr; + int maxlen; if (!ch->is->clsb) { pr_debug("%s; ISAR zero len frame\n", ch->is->name); ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); return; } + if (test_bit(FLG_RX_OFF, &ch->bch.Flags)) { + ch->bch.dropcnt += ch->is->clsb; + ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); + return; + } switch (ch->bch.state) { case ISDN_P_NONE: pr_debug("%s: ISAR protocol 0 spurious IIS_RDATA %x/%x/%x\n", @@ -437,36 +443,22 @@ isar_rcv_frame(struct isar_ch *ch) case ISDN_P_B_RAW: case ISDN_P_B_L2DTMF: case ISDN_P_B_MODEM_ASYNC: - if (!ch->bch.rx_skb) { - ch->bch.rx_skb = mI_alloc_skb(ch->bch.maxlen, - GFP_ATOMIC); - if (unlikely(!ch->bch.rx_skb)) { - pr_info("%s: B receive out of memory\n", - ch->is->name); - ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); - break; - } + maxlen = bchannel_get_rxbuf(&ch->bch, ch->is->clsb); + if (maxlen < 0) { + pr_warning("%s.B%d: No bufferspace for %d bytes\n", + ch->is->name, ch->bch.nr, ch->is->clsb); + ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); + break; } rcv_mbox(ch->is, skb_put(ch->bch.rx_skb, ch->is->clsb)); - recv_Bchannel(&ch->bch, 0); + recv_Bchannel(&ch->bch, 0, false); break; case ISDN_P_B_HDLC: - if (!ch->bch.rx_skb) { - ch->bch.rx_skb = mI_alloc_skb(ch->bch.maxlen, - GFP_ATOMIC); - if (unlikely(!ch->bch.rx_skb)) { - pr_info("%s: B receive out of memory\n", - ch->is->name); - ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); - break; - } - } - if ((ch->bch.rx_skb->len + ch->is->clsb) > - (ch->bch.maxlen + 2)) { - pr_debug("%s: incoming packet too large\n", - ch->is->name); + maxlen = bchannel_get_rxbuf(&ch->bch, ch->is->clsb); + if (maxlen < 0) { + pr_warning("%s.B%d: No bufferspace for %d bytes\n", + ch->is->name, ch->bch.nr, ch->is->clsb); ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); - skb_trim(ch->bch.rx_skb, 0); break; } if (ch->is->cmsb & HDLC_ERROR) { @@ -494,7 +486,7 @@ isar_rcv_frame(struct isar_ch *ch) break; } skb_trim(ch->bch.rx_skb, ch->bch.rx_skb->len - 2); - recv_Bchannel(&ch->bch, 0); + recv_Bchannel(&ch->bch, 0, false); } break; case ISDN_P_B_T30_FAX: @@ -530,7 +522,7 @@ isar_rcv_frame(struct isar_ch *ch) ch->state = STFAX_ESCAPE; /* set_skb_flag(skb, DF_NOMOREDATA); */ } - recv_Bchannel(&ch->bch, 0); + recv_Bchannel(&ch->bch, 0, false); if (ch->is->cmsb & SART_NMD) deliver_status(ch, HW_MOD_NOCARR); break; @@ -570,7 +562,7 @@ isar_rcv_frame(struct isar_ch *ch) break; } skb_trim(ch->bch.rx_skb, ch->bch.rx_skb->len - 2); - recv_Bchannel(&ch->bch, 0); + recv_Bchannel(&ch->bch, 0, false); } if (ch->is->cmsb & SART_NMD) { /* ABORT */ pr_debug("%s: isar_rcv_frame: no more data\n", @@ -598,16 +590,25 @@ isar_fill_fifo(struct isar_ch *ch) u8 msb; u8 *ptr; - pr_debug("%s: ch%d tx_skb %p tx_idx %d\n", - ch->is->name, ch->bch.nr, ch->bch.tx_skb, ch->bch.tx_idx); - if (!ch->bch.tx_skb) + pr_debug("%s: ch%d tx_skb %d tx_idx %d\n", ch->is->name, ch->bch.nr, + ch->bch.tx_skb ? ch->bch.tx_skb->len : -1, ch->bch.tx_idx); + if (!(ch->is->bstat & + (ch->dpath == 1 ? BSTAT_RDM1 : BSTAT_RDM2))) + return; + if (!ch->bch.tx_skb) { + if (!test_bit(FLG_TX_EMPTY, &ch->bch.Flags) || + (ch->bch.state != ISDN_P_B_RAW)) + return; + count = ch->mml; + /* use the card buffer */ + memset(ch->is->buf, ch->bch.fill[0], count); + send_mbox(ch->is, SET_DPS(ch->dpath) | ISAR_HIS_SDATA, + 0, count, ch->is->buf); return; + } count = ch->bch.tx_skb->len - ch->bch.tx_idx; if (count <= 0) return; - if (!(ch->is->bstat & - (ch->dpath == 1 ? BSTAT_RDM1 : BSTAT_RDM2))) - return; if (count > ch->mml) { msb = 0; count = ch->mml; @@ -686,9 +687,9 @@ sel_bch_isar(struct isar_hw *isar, u8 dpath) static void send_next(struct isar_ch *ch) { - pr_debug("%s: %s ch%d tx_skb %p tx_idx %d\n", - ch->is->name, __func__, ch->bch.nr, - ch->bch.tx_skb, ch->bch.tx_idx); + pr_debug("%s: %s ch%d tx_skb %d tx_idx %d\n", ch->is->name, __func__, + ch->bch.nr, ch->bch.tx_skb ? ch->bch.tx_skb->len : -1, + ch->bch.tx_idx); if (ch->bch.state == ISDN_P_B_T30_FAX) { if (ch->cmd == PCTRL_CMD_FTH) { if (test_bit(FLG_LASTDATA, &ch->bch.Flags)) { @@ -702,15 +703,14 @@ send_next(struct isar_ch *ch) } } } - if (ch->bch.tx_skb) { - /* send confirm, on trans, free on hdlc. */ - if (test_bit(FLG_TRANSPARENT, &ch->bch.Flags)) - confirm_Bsend(&ch->bch); + if (ch->bch.tx_skb) dev_kfree_skb(ch->bch.tx_skb); - } - if (get_next_bframe(&ch->bch)) + if (get_next_bframe(&ch->bch)) { isar_fill_fifo(ch); - else { + test_and_clear_bit(FLG_TX_EMPTY, &ch->bch.Flags); + } else if (test_bit(FLG_TX_EMPTY, &ch->bch.Flags)) { + isar_fill_fifo(ch); + } else { if (test_and_clear_bit(FLG_DLEETX, &ch->bch.Flags)) { if (test_and_clear_bit(FLG_LASTDATA, &ch->bch.Flags)) { @@ -724,6 +724,8 @@ send_next(struct isar_ch *ch) } else { deliver_status(ch, HW_MOD_CONNECT); } + } else if (test_bit(FLG_FILLEMPTY, &ch->bch.Flags)) { + test_and_set_bit(FLG_TX_EMPTY, &ch->bch.Flags); } } } @@ -1487,14 +1489,10 @@ isar_l2l1(struct mISDNchannel *ch, struct sk_buff *skb) spin_lock_irqsave(ich->is->hwlock, flags); ret = bchannel_senddata(bch, skb); if (ret > 0) { /* direct TX */ - id = hh->id; /* skb can be freed */ ret = 0; isar_fill_fifo(ich); - spin_unlock_irqrestore(ich->is->hwlock, flags); - if (!test_bit(FLG_TRANSPARENT, &bch->Flags)) - queue_ch_frame(ch, PH_DATA_CNF, id, NULL); - } else - spin_unlock_irqrestore(ich->is->hwlock, flags); + } + spin_unlock_irqrestore(ich->is->hwlock, flags); return ret; case PH_ACTIVATE_REQ: spin_lock_irqsave(ich->is->hwlock, flags); @@ -1575,20 +1573,7 @@ isar_l2l1(struct mISDNchannel *ch, struct sk_buff *skb) static int channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) { - int ret = 0; - - switch (cq->op) { - case MISDN_CTRL_GETOP: - cq->op = 0; - break; - /* Nothing implemented yet */ - case MISDN_CTRL_FILL_EMPTY: - default: - pr_info("%s: unknown Op %x\n", __func__, cq->op); - ret = -EINVAL; - break; - } - return ret; + return mISDN_ctrl_bchannel(bch, cq); } static int @@ -1603,15 +1588,10 @@ isar_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg) switch (cmd) { case CLOSE_CHANNEL: test_and_clear_bit(FLG_OPEN, &bch->Flags); - if (test_bit(FLG_ACTIVE, &bch->Flags)) { - spin_lock_irqsave(ich->is->hwlock, flags); - mISDN_freebchannel(bch); - modeisar(ich, ISDN_P_NONE); - spin_unlock_irqrestore(ich->is->hwlock, flags); - } else { - skb_queue_purge(&bch->rqueue); - bch->rcount = 0; - } + spin_lock_irqsave(ich->is->hwlock, flags); + mISDN_freebchannel(bch); + modeisar(ich, ISDN_P_NONE); + spin_unlock_irqrestore(ich->is->hwlock, flags); ch->protocol = ISDN_P_NONE; ch->peer = NULL; module_put(ich->is->owner); @@ -1677,7 +1657,6 @@ isar_open(struct isar_hw *isar, struct channel_req *rq) bch = &isar->ch[rq->adr.channel - 1].bch; if (test_and_set_bit(FLG_OPEN, &bch->Flags)) return -EBUSY; /* b-channel can be only open once */ - test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags); bch->ch.protocol = rq->protocol; rq->ch = &bch->ch; return 0; @@ -1691,7 +1670,7 @@ mISDNisar_init(struct isar_hw *isar, void *hw) isar->hw = hw; for (i = 0; i < 2; i++) { isar->ch[i].bch.nr = i + 1; - mISDN_initbchannel(&isar->ch[i].bch, MAX_DATA_MEM); + mISDN_initbchannel(&isar->ch[i].bch, MAX_DATA_MEM, 32); isar->ch[i].bch.ch.nr = i + 1; isar->ch[i].bch.ch.send = &isar_l2l1; isar->ch[i].bch.ch.ctrl = isar_bctrl; diff --git a/drivers/isdn/hardware/mISDN/netjet.c b/drivers/isdn/hardware/mISDN/netjet.c index c726e09d0981..c3e3e7686273 100644 --- a/drivers/isdn/hardware/mISDN/netjet.c +++ b/drivers/isdn/hardware/mISDN/netjet.c @@ -386,24 +386,20 @@ read_dma(struct tiger_ch *bc, u32 idx, int cnt) bc->bch.nr, idx); } bc->lastrx = idx; - if (!bc->bch.rx_skb) { - bc->bch.rx_skb = mI_alloc_skb(bc->bch.maxlen, GFP_ATOMIC); - if (!bc->bch.rx_skb) { - pr_info("%s: B%1d receive out of memory\n", - card->name, bc->bch.nr); - return; - } + if (test_bit(FLG_RX_OFF, &bc->bch.Flags)) { + bc->bch.dropcnt += cnt; + return; } - - if (test_bit(FLG_TRANSPARENT, &bc->bch.Flags)) { - if ((bc->bch.rx_skb->len + cnt) > bc->bch.maxlen) { - pr_debug("%s: B%1d overrun %d\n", card->name, - bc->bch.nr, bc->bch.rx_skb->len + cnt); - skb_trim(bc->bch.rx_skb, 0); - return; - } + stat = bchannel_get_rxbuf(&bc->bch, cnt); + /* only transparent use the count here, HDLC overun is detected later */ + if (stat == ENOMEM) { + pr_warning("%s.B%d: No memory for %d bytes\n", + card->name, bc->bch.nr, cnt); + return; + } + if (test_bit(FLG_TRANSPARENT, &bc->bch.Flags)) p = skb_put(bc->bch.rx_skb, cnt); - } else + else p = bc->hrbuf; for (i = 0; i < cnt; i++) { @@ -414,48 +410,45 @@ read_dma(struct tiger_ch *bc, u32 idx, int cnt) idx = 0; p[i] = val & 0xff; } + + if (test_bit(FLG_TRANSPARENT, &bc->bch.Flags)) { + recv_Bchannel(&bc->bch, 0, false); + return; + } + pn = bc->hrbuf; -next_frame: - if (test_bit(FLG_HDLC, &bc->bch.Flags)) { + while (cnt > 0) { stat = isdnhdlc_decode(&bc->hrecv, pn, cnt, &i, bc->bch.rx_skb->data, bc->bch.maxlen); - if (stat > 0) /* valid frame received */ + if (stat > 0) { /* valid frame received */ p = skb_put(bc->bch.rx_skb, stat); - else if (stat == -HDLC_CRC_ERROR) + if (debug & DEBUG_HW_BFIFO) { + snprintf(card->log, LOG_SIZE, + "B%1d-recv %s %d ", bc->bch.nr, + card->name, stat); + print_hex_dump_bytes(card->log, + DUMP_PREFIX_OFFSET, p, + stat); + } + recv_Bchannel(&bc->bch, 0, false); + stat = bchannel_get_rxbuf(&bc->bch, bc->bch.maxlen); + if (stat < 0) { + pr_warning("%s.B%d: No memory for %d bytes\n", + card->name, bc->bch.nr, cnt); + return; + } + } else if (stat == -HDLC_CRC_ERROR) { pr_info("%s: B%1d receive frame CRC error\n", card->name, bc->bch.nr); - else if (stat == -HDLC_FRAMING_ERROR) + } else if (stat == -HDLC_FRAMING_ERROR) { pr_info("%s: B%1d receive framing error\n", card->name, bc->bch.nr); - else if (stat == -HDLC_LENGTH_ERROR) + } else if (stat == -HDLC_LENGTH_ERROR) { pr_info("%s: B%1d receive frame too long (> %d)\n", card->name, bc->bch.nr, bc->bch.maxlen); - } else - stat = cnt; - - if (stat > 0) { - if (debug & DEBUG_HW_BFIFO) { - snprintf(card->log, LOG_SIZE, "B%1d-recv %s %d ", - bc->bch.nr, card->name, stat); - print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET, - p, stat); } - recv_Bchannel(&bc->bch, 0); - } - if (test_bit(FLG_HDLC, &bc->bch.Flags)) { pn += i; cnt -= i; - if (!bc->bch.rx_skb) { - bc->bch.rx_skb = mI_alloc_skb(bc->bch.maxlen, - GFP_ATOMIC); - if (!bc->bch.rx_skb) { - pr_info("%s: B%1d receive out of memory\n", - card->name, bc->bch.nr); - return; - } - } - if (cnt > 0) - goto next_frame; } } @@ -544,22 +537,31 @@ static void fill_dma(struct tiger_ch *bc) { struct tiger_hw *card = bc->bch.hw; - int count, i; - u32 m, v; + int count, i, fillempty = 0; + u32 m, v, n = 0; u8 *p; if (bc->free == 0) return; - count = bc->bch.tx_skb->len - bc->bch.tx_idx; - if (count <= 0) - return; - pr_debug("%s: %s B%1d %d/%d/%d/%d state %x idx %d/%d\n", card->name, - __func__, bc->bch.nr, count, bc->free, bc->bch.tx_idx, - bc->bch.tx_skb->len, bc->txstate, bc->idx, card->send.idx); + if (!bc->bch.tx_skb) { + if (!test_bit(FLG_TX_EMPTY, &bc->bch.Flags)) + return; + fillempty = 1; + count = card->send.size >> 1; + p = bc->bch.fill; + } else { + count = bc->bch.tx_skb->len - bc->bch.tx_idx; + if (count <= 0) + return; + pr_debug("%s: %s B%1d %d/%d/%d/%d state %x idx %d/%d\n", + card->name, __func__, bc->bch.nr, count, bc->free, + bc->bch.tx_idx, bc->bch.tx_skb->len, bc->txstate, + bc->idx, card->send.idx); + p = bc->bch.tx_skb->data + bc->bch.tx_idx; + } if (bc->txstate & (TX_IDLE | TX_INIT | TX_UNDERRUN)) resync(bc, card); - p = bc->bch.tx_skb->data + bc->bch.tx_idx; - if (test_bit(FLG_HDLC, &bc->bch.Flags)) { + if (test_bit(FLG_HDLC, &bc->bch.Flags) && !fillempty) { count = isdnhdlc_encode(&bc->hsend, p, count, &i, bc->hsbuf, bc->free); pr_debug("%s: B%1d hdlc encoded %d in %d\n", card->name, @@ -570,17 +572,33 @@ fill_dma(struct tiger_ch *bc) } else { if (count > bc->free) count = bc->free; - bc->bch.tx_idx += count; + if (!fillempty) + bc->bch.tx_idx += count; bc->free -= count; } m = (bc->bch.nr & 1) ? 0xffffff00 : 0xffff00ff; - for (i = 0; i < count; i++) { - if (bc->idx >= card->send.size) - bc->idx = 0; - v = card->send.start[bc->idx]; - v &= m; - v |= (bc->bch.nr & 1) ? (u32)(p[i]) : ((u32)(p[i])) << 8; - card->send.start[bc->idx++] = v; + if (fillempty) { + n = p[0]; + if (!(bc->bch.nr & 1)) + n <<= 8; + for (i = 0; i < count; i++) { + if (bc->idx >= card->send.size) + bc->idx = 0; + v = card->send.start[bc->idx]; + v &= m; + v |= n; + card->send.start[bc->idx++] = v; + } + } else { + for (i = 0; i < count; i++) { + if (bc->idx >= card->send.size) + bc->idx = 0; + v = card->send.start[bc->idx]; + v &= m; + n = p[i]; + v |= (bc->bch.nr & 1) ? n : n << 8; + card->send.start[bc->idx++] = v; + } } if (debug & DEBUG_HW_BFIFO) { snprintf(card->log, LOG_SIZE, "B%1d-send %s %d ", @@ -595,21 +613,26 @@ fill_dma(struct tiger_ch *bc) static int bc_next_frame(struct tiger_ch *bc) { - if (bc->bch.tx_skb && bc->bch.tx_idx < bc->bch.tx_skb->len) + int ret = 1; + + if (bc->bch.tx_skb && bc->bch.tx_idx < bc->bch.tx_skb->len) { fill_dma(bc); - else { - if (bc->bch.tx_skb) { - /* send confirm, on trans, free on hdlc. */ - if (test_bit(FLG_TRANSPARENT, &bc->bch.Flags)) - confirm_Bsend(&bc->bch); + } else { + if (bc->bch.tx_skb) dev_kfree_skb(bc->bch.tx_skb); - } - if (get_next_bframe(&bc->bch)) + if (get_next_bframe(&bc->bch)) { fill_dma(bc); - else - return 0; + test_and_clear_bit(FLG_TX_EMPTY, &bc->bch.Flags); + } else if (test_bit(FLG_TX_EMPTY, &bc->bch.Flags)) { + fill_dma(bc); + } else if (test_bit(FLG_FILLEMPTY, &bc->bch.Flags)) { + test_and_set_bit(FLG_TX_EMPTY, &bc->bch.Flags); + ret = 0; + } else { + ret = 0; + } } - return 1; + return ret; } static void @@ -732,22 +755,17 @@ nj_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb) struct tiger_ch *bc = container_of(bch, struct tiger_ch, bch); struct tiger_hw *card = bch->hw; struct mISDNhead *hh = mISDN_HEAD_P(skb); - u32 id; - u_long flags; + unsigned long flags; switch (hh->prim) { case PH_DATA_REQ: spin_lock_irqsave(&card->lock, flags); ret = bchannel_senddata(bch, skb); if (ret > 0) { /* direct TX */ - id = hh->id; /* skb can be freed */ fill_dma(bc); ret = 0; - spin_unlock_irqrestore(&card->lock, flags); - if (!test_bit(FLG_TRANSPARENT, &bch->Flags)) - queue_ch_frame(ch, PH_DATA_CNF, id, NULL); - } else - spin_unlock_irqrestore(&card->lock, flags); + } + spin_unlock_irqrestore(&card->lock, flags); return ret; case PH_ACTIVATE_REQ: spin_lock_irqsave(&card->lock, flags); @@ -778,21 +796,7 @@ nj_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb) static int channel_bctrl(struct tiger_ch *bc, struct mISDN_ctrl_req *cq) { - int ret = 0; - struct tiger_hw *card = bc->bch.hw; - - switch (cq->op) { - case MISDN_CTRL_GETOP: - cq->op = 0; - break; - /* Nothing implemented yet */ - case MISDN_CTRL_FILL_EMPTY: - default: - pr_info("%s: %s unknown Op %x\n", card->name, __func__, cq->op); - ret = -EINVAL; - break; - } - return ret; + return mISDN_ctrl_bchannel(&bc->bch, cq); } static int @@ -808,14 +812,10 @@ nj_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg) switch (cmd) { case CLOSE_CHANNEL: test_and_clear_bit(FLG_OPEN, &bch->Flags); - if (test_bit(FLG_ACTIVE, &bch->Flags)) { - spin_lock_irqsave(&card->lock, flags); - mISDN_freebchannel(bch); - test_and_clear_bit(FLG_TX_BUSY, &bch->Flags); - test_and_clear_bit(FLG_ACTIVE, &bch->Flags); - mode_tiger(bc, ISDN_P_NONE); - spin_unlock_irqrestore(&card->lock, flags); - } + spin_lock_irqsave(&card->lock, flags); + mISDN_freebchannel(bch); + mode_tiger(bc, ISDN_P_NONE); + spin_unlock_irqrestore(&card->lock, flags); ch->protocol = ISDN_P_NONE; ch->peer = NULL; module_put(THIS_MODULE); @@ -837,7 +837,7 @@ channel_ctrl(struct tiger_hw *card, struct mISDN_ctrl_req *cq) switch (cq->op) { case MISDN_CTRL_GETOP: - cq->op = MISDN_CTRL_LOOP; + cq->op = MISDN_CTRL_LOOP | MISDN_CTRL_L1_TIMER3; break; case MISDN_CTRL_LOOP: /* cq->channel: 0 disable, 1 B1 loop 2 B2 loop, 3 both */ @@ -847,6 +847,9 @@ channel_ctrl(struct tiger_hw *card, struct mISDN_ctrl_req *cq) } ret = card->isac.ctrl(&card->isac, HW_TESTLOOP, cq->channel); break; + case MISDN_CTRL_L1_TIMER3: + ret = card->isac.ctrl(&card->isac, HW_TIMER3_VALUE, cq->p1); + break; default: pr_info("%s: %s unknown Op %x\n", card->name, __func__, cq->op); ret = -EINVAL; @@ -1027,7 +1030,8 @@ setup_instance(struct tiger_hw *card) for (i = 0; i < 2; i++) { card->bc[i].bch.nr = i + 1; set_channelmap(i + 1, card->isac.dch.dev.channelmap); - mISDN_initbchannel(&card->bc[i].bch, MAX_DATA_MEM); + mISDN_initbchannel(&card->bc[i].bch, MAX_DATA_MEM, + NJ_DMA_RXSIZE >> 1); card->bc[i].bch.hw = card; card->bc[i].bch.ch.send = nj_l2l1B; card->bc[i].bch.ch.ctrl = nj_bctrl; diff --git a/drivers/isdn/hardware/mISDN/speedfax.c b/drivers/isdn/hardware/mISDN/speedfax.c index 04689935148b..93f344d74e54 100644 --- a/drivers/isdn/hardware/mISDN/speedfax.c +++ b/drivers/isdn/hardware/mISDN/speedfax.c @@ -224,7 +224,7 @@ channel_ctrl(struct sfax_hw *sf, struct mISDN_ctrl_req *cq) switch (cq->op) { case MISDN_CTRL_GETOP: - cq->op = MISDN_CTRL_LOOP; + cq->op = MISDN_CTRL_LOOP | MISDN_CTRL_L1_TIMER3; break; case MISDN_CTRL_LOOP: /* cq->channel: 0 disable, 1 B1 loop 2 B2 loop, 3 both */ @@ -234,6 +234,9 @@ channel_ctrl(struct sfax_hw *sf, struct mISDN_ctrl_req *cq) } ret = sf->isac.ctrl(&sf->isac, HW_TESTLOOP, cq->channel); break; + case MISDN_CTRL_L1_TIMER3: + ret = sf->isac.ctrl(&sf->isac, HW_TIMER3_VALUE, cq->p1); + break; default: pr_info("%s: unknown Op %x\n", sf->name, cq->op); ret = -EINVAL; diff --git a/drivers/isdn/hardware/mISDN/w6692.c b/drivers/isdn/hardware/mISDN/w6692.c index 2183357f0799..26a86b846099 100644 --- a/drivers/isdn/hardware/mISDN/w6692.c +++ b/drivers/isdn/hardware/mISDN/w6692.c @@ -465,6 +465,7 @@ W6692_empty_Bfifo(struct w6692_ch *wch, int count) { struct w6692_hw *card = wch->bch.hw; u8 *ptr; + int maxlen; pr_debug("%s: empty_Bfifo %d\n", card->name, count); if (unlikely(wch->bch.state == ISDN_P_NONE)) { @@ -474,20 +475,18 @@ W6692_empty_Bfifo(struct w6692_ch *wch, int count) skb_trim(wch->bch.rx_skb, 0); return; } - if (!wch->bch.rx_skb) { - wch->bch.rx_skb = mI_alloc_skb(wch->bch.maxlen, GFP_ATOMIC); - if (unlikely(!wch->bch.rx_skb)) { - pr_info("%s: B receive out of memory\n", card->name); - WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | - W_B_CMDR_RACT); - return; - } + if (test_bit(FLG_RX_OFF, &wch->bch.Flags)) { + wch->bch.dropcnt += count; + WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT); + return; } - if (wch->bch.rx_skb->len + count > wch->bch.maxlen) { - pr_debug("%s: empty_Bfifo incoming packet too large\n", - card->name); + maxlen = bchannel_get_rxbuf(&wch->bch, count); + if (maxlen < 0) { WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT); - skb_trim(wch->bch.rx_skb, 0); + if (wch->bch.rx_skb) + skb_trim(wch->bch.rx_skb, 0); + pr_warning("%s.B%d: No bufferspace for %d bytes\n", + card->name, wch->bch.nr, count); return; } ptr = skb_put(wch->bch.rx_skb, count); @@ -504,16 +503,22 @@ static void W6692_fill_Bfifo(struct w6692_ch *wch) { struct w6692_hw *card = wch->bch.hw; - int count; + int count, fillempty = 0; u8 *ptr, cmd = W_B_CMDR_RACT | W_B_CMDR_XMS; pr_debug("%s: fill Bfifo\n", card->name); - if (!wch->bch.tx_skb) - return; - count = wch->bch.tx_skb->len - wch->bch.tx_idx; - if (count <= 0) - return; - ptr = wch->bch.tx_skb->data + wch->bch.tx_idx; + if (!wch->bch.tx_skb) { + if (!test_bit(FLG_TX_EMPTY, &wch->bch.Flags)) + return; + ptr = wch->bch.fill; + count = W_B_FIFO_THRESH; + fillempty = 1; + } else { + count = wch->bch.tx_skb->len - wch->bch.tx_idx; + if (count <= 0) + return; + ptr = wch->bch.tx_skb->data + wch->bch.tx_idx; + } if (count > W_B_FIFO_THRESH) count = W_B_FIFO_THRESH; else if (test_bit(FLG_HDLC, &wch->bch.Flags)) @@ -522,9 +527,16 @@ W6692_fill_Bfifo(struct w6692_ch *wch) pr_debug("%s: fill Bfifo%d/%d\n", card->name, count, wch->bch.tx_idx); wch->bch.tx_idx += count; - outsb(wch->addr + W_B_XFIFO, ptr, count); + if (fillempty) { + while (count > 0) { + outsb(wch->addr + W_B_XFIFO, ptr, MISDN_BCH_FILL_SIZE); + count -= MISDN_BCH_FILL_SIZE; + } + } else { + outsb(wch->addr + W_B_XFIFO, ptr, count); + } WriteW6692B(wch, W_B_CMDR, cmd); - if (debug & DEBUG_HW_DFIFO) { + if ((debug & DEBUG_HW_BFIFO) && !fillempty) { snprintf(card->log, 63, "B%1d-send %s %d ", wch->bch.nr, card->name, count); print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET, ptr, count); @@ -638,17 +650,17 @@ w6692_mode(struct w6692_ch *wch, u32 pr) static void send_next(struct w6692_ch *wch) { - if (wch->bch.tx_skb && wch->bch.tx_idx < wch->bch.tx_skb->len) + if (wch->bch.tx_skb && wch->bch.tx_idx < wch->bch.tx_skb->len) { W6692_fill_Bfifo(wch); - else { - if (wch->bch.tx_skb) { - /* send confirm, on trans, free on hdlc. */ - if (test_bit(FLG_TRANSPARENT, &wch->bch.Flags)) - confirm_Bsend(&wch->bch); + } else { + if (wch->bch.tx_skb) dev_kfree_skb(wch->bch.tx_skb); - } - if (get_next_bframe(&wch->bch)) + if (get_next_bframe(&wch->bch)) { + W6692_fill_Bfifo(wch); + test_and_clear_bit(FLG_TX_EMPTY, &wch->bch.Flags); + } else if (test_bit(FLG_TX_EMPTY, &wch->bch.Flags)) { W6692_fill_Bfifo(wch); + } } } @@ -698,7 +710,7 @@ W6692B_interrupt(struct w6692_hw *card, int ch) if (count == 0) count = W_B_FIFO_THRESH; W6692_empty_Bfifo(wch, count); - recv_Bchannel(&wch->bch, 0); + recv_Bchannel(&wch->bch, 0, false); } } if (stat & W_B_EXI_RMR) { @@ -714,9 +726,8 @@ W6692B_interrupt(struct w6692_hw *card, int ch) W_B_CMDR_RRST | W_B_CMDR_RACT); } else { W6692_empty_Bfifo(wch, W_B_FIFO_THRESH); - if (test_bit(FLG_TRANSPARENT, &wch->bch.Flags) && - wch->bch.rx_skb && (wch->bch.rx_skb->len > 0)) - recv_Bchannel(&wch->bch, 0); + if (test_bit(FLG_TRANSPARENT, &wch->bch.Flags)) + recv_Bchannel(&wch->bch, 0, false); } } if (stat & W_B_EXI_RDOV) { @@ -738,8 +749,8 @@ W6692B_interrupt(struct w6692_hw *card, int ch) wch->bch.nr, star); } if (star & W_B_STAR_XDOW) { - pr_debug("%s: B%d XDOW proto=%x\n", card->name, - wch->bch.nr, wch->bch.state); + pr_warning("%s: B%d XDOW proto=%x\n", card->name, + wch->bch.nr, wch->bch.state); #ifdef ERROR_STATISTIC wch->bch.err_xdu++; #endif @@ -752,20 +763,21 @@ W6692B_interrupt(struct w6692_hw *card, int ch) } } send_next(wch); - if (stat & W_B_EXI_XDUN) + if (star & W_B_STAR_XDOW) return; /* handle XDOW only once */ } if (stat & W_B_EXI_XDUN) { - pr_debug("%s: B%d XDUN proto=%x\n", card->name, - wch->bch.nr, wch->bch.state); + pr_warning("%s: B%d XDUN proto=%x\n", card->name, + wch->bch.nr, wch->bch.state); #ifdef ERROR_STATISTIC wch->bch.err_xdu++; #endif - WriteW6692B(wch, W_B_CMDR, W_B_CMDR_XRST | W_B_CMDR_RACT); - /* resend */ + /* resend - no XRST needed */ if (wch->bch.tx_skb) { if (!test_bit(FLG_TRANSPARENT, &wch->bch.Flags)) wch->bch.tx_idx = 0; + } else if (test_bit(FLG_FILLEMPTY, &wch->bch.Flags)) { + test_and_set_bit(FLG_TX_EMPTY, &wch->bch.Flags); } send_next(wch); } @@ -944,22 +956,17 @@ w6692_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb) struct w6692_hw *card = bch->hw; int ret = -EINVAL; struct mISDNhead *hh = mISDN_HEAD_P(skb); - u32 id; - u_long flags; + unsigned long flags; switch (hh->prim) { case PH_DATA_REQ: spin_lock_irqsave(&card->lock, flags); ret = bchannel_senddata(bch, skb); if (ret > 0) { /* direct TX */ - id = hh->id; /* skb can be freed */ ret = 0; W6692_fill_Bfifo(bc); - spin_unlock_irqrestore(&card->lock, flags); - if (!test_bit(FLG_TRANSPARENT, &bch->Flags)) - queue_ch_frame(ch, PH_DATA_CNF, id, NULL); - } else - spin_unlock_irqrestore(&card->lock, flags); + } + spin_unlock_irqrestore(&card->lock, flags); return ret; case PH_ACTIVATE_REQ: spin_lock_irqsave(&card->lock, flags); @@ -994,20 +1001,7 @@ w6692_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb) static int channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) { - int ret = 0; - - switch (cq->op) { - case MISDN_CTRL_GETOP: - cq->op = 0; - break; - /* Nothing implemented yet */ - case MISDN_CTRL_FILL_EMPTY: - default: - pr_info("%s: unknown Op %x\n", __func__, cq->op); - ret = -EINVAL; - break; - } - return ret; + return mISDN_ctrl_bchannel(bch, cq); } static int @@ -1022,7 +1016,6 @@ open_bchannel(struct w6692_hw *card, struct channel_req *rq) bch = &card->bc[rq->adr.channel - 1].bch; if (test_and_set_bit(FLG_OPEN, &bch->Flags)) return -EBUSY; /* b-channel can be only open once */ - test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags); bch->ch.protocol = rq->protocol; rq->ch = &bch->ch; return 0; @@ -1035,7 +1028,10 @@ channel_ctrl(struct w6692_hw *card, struct mISDN_ctrl_req *cq) switch (cq->op) { case MISDN_CTRL_GETOP: - cq->op = 0; + cq->op = MISDN_CTRL_L1_TIMER3; + break; + case MISDN_CTRL_L1_TIMER3: + ret = l1_event(card->dch.l1, HW_TIMER3_VALUE | (cq->p1 & 0xff)); break; default: pr_info("%s: unknown CTRL OP %x\n", card->name, cq->op); @@ -1058,15 +1054,10 @@ w6692_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg) switch (cmd) { case CLOSE_CHANNEL: test_and_clear_bit(FLG_OPEN, &bch->Flags); - if (test_bit(FLG_ACTIVE, &bch->Flags)) { - spin_lock_irqsave(&card->lock, flags); - mISDN_freebchannel(bch); - w6692_mode(bc, ISDN_P_NONE); - spin_unlock_irqrestore(&card->lock, flags); - } else { - skb_queue_purge(&bch->rqueue); - bch->rcount = 0; - } + spin_lock_irqsave(&card->lock, flags); + mISDN_freebchannel(bch); + w6692_mode(bc, ISDN_P_NONE); + spin_unlock_irqrestore(&card->lock, flags); ch->protocol = ISDN_P_NONE; ch->peer = NULL; module_put(THIS_MODULE); @@ -1320,7 +1311,8 @@ setup_instance(struct w6692_hw *card) card->dch.hw = card; card->dch.dev.nrbchan = 2; for (i = 0; i < 2; i++) { - mISDN_initbchannel(&card->bc[i].bch, MAX_DATA_MEM); + mISDN_initbchannel(&card->bc[i].bch, MAX_DATA_MEM, + W_B_FIFO_THRESH); card->bc[i].bch.hw = card; card->bc[i].bch.nr = i + 1; card->bc[i].bch.ch.nr = i + 1; diff --git a/drivers/isdn/hisax/hfc_usb.c b/drivers/isdn/hisax/hfc_usb.c index 62c65bdefd8a..84f9c8103078 100644 --- a/drivers/isdn/hisax/hfc_usb.c +++ b/drivers/isdn/hisax/hfc_usb.c @@ -1568,6 +1568,7 @@ static struct usb_driver hfc_drv = { .id_table = hfcusb_idtab, .probe = hfc_usb_probe, .disconnect = hfc_usb_disconnect, + .disable_hub_initiated_lpm = 1, }; static void __exit diff --git a/drivers/isdn/hisax/st5481_init.c b/drivers/isdn/hisax/st5481_init.c index 100296e20dc0..54ef9e4f8cbc 100644 --- a/drivers/isdn/hisax/st5481_init.c +++ b/drivers/isdn/hisax/st5481_init.c @@ -182,6 +182,7 @@ static struct usb_driver st5481_usb_driver = { .probe = probe_st5481, .disconnect = disconnect_st5481, .id_table = st5481_ids, + .disable_hub_initiated_lpm = 1, }; static int __init st5481_usb_init(void) diff --git a/drivers/isdn/hysdn/hysdn_proclog.c b/drivers/isdn/hysdn/hysdn_proclog.c index ba91333e3e41..88e4f0ee073c 100644 --- a/drivers/isdn/hysdn/hysdn_proclog.c +++ b/drivers/isdn/hysdn/hysdn_proclog.c @@ -156,17 +156,9 @@ static ssize_t hysdn_log_write(struct file *file, const char __user *buf, size_t count, loff_t *off) { int rc; - unsigned char valbuf[128]; hysdn_card *card = file->private_data; - if (count > (sizeof(valbuf) - 1)) - count = sizeof(valbuf) - 1; /* limit length */ - if (copy_from_user(valbuf, buf, count)) - return (-EFAULT); /* copy failed */ - - valbuf[count] = 0; /* terminating 0 */ - - rc = kstrtoul(valbuf, 0, &card->debug_flags); + rc = kstrtoul_from_user(buf, count, 0, &card->debug_flags); if (rc < 0) return rc; hysdn_addlog(card, "debug set to 0x%lx", card->debug_flags); diff --git a/drivers/isdn/i4l/isdn_bsdcomp.c b/drivers/isdn/i4l/isdn_bsdcomp.c index c59e8d2c0675..8837ac5a492d 100644 --- a/drivers/isdn/i4l/isdn_bsdcomp.c +++ b/drivers/isdn/i4l/isdn_bsdcomp.c @@ -612,7 +612,7 @@ static int bsd_compress(void *state, struct sk_buff *skb_in, struct sk_buff *skb db->n_bits++; /* If output length is too large then this is an incompressible frame. */ - if (!skb_out || (skb_out && skb_out->len >= skb_in->len)) { + if (!skb_out || skb_out->len >= skb_in->len) { ++db->incomp_count; db->incomp_bytes += isize; return 0; diff --git a/drivers/isdn/mISDN/core.c b/drivers/isdn/mISDN/core.c index a24530f05db0..c401634c00ec 100644 --- a/drivers/isdn/mISDN/core.c +++ b/drivers/isdn/mISDN/core.c @@ -355,6 +355,22 @@ mISDN_unregister_Bprotocol(struct Bprotocol *bp) } EXPORT_SYMBOL(mISDN_unregister_Bprotocol); +static const char *msg_no_channel = "<no channel>"; +static const char *msg_no_stack = "<no stack>"; +static const char *msg_no_stackdev = "<no stack device>"; + +const char *mISDNDevName4ch(struct mISDNchannel *ch) +{ + if (!ch) + return msg_no_channel; + if (!ch->st) + return msg_no_stack; + if (!ch->st->dev) + return msg_no_stackdev; + return dev_name(&ch->st->dev->dev); +}; +EXPORT_SYMBOL(mISDNDevName4ch); + static int mISDNInit(void) { diff --git a/drivers/isdn/mISDN/dsp.h b/drivers/isdn/mISDN/dsp.h index afe4173ae007..fc1733a08845 100644 --- a/drivers/isdn/mISDN/dsp.h +++ b/drivers/isdn/mISDN/dsp.h @@ -76,7 +76,9 @@ extern u8 dsp_silence; #define MAX_SECONDS_JITTER_CHECK 5 extern struct timer_list dsp_spl_tl; -extern u32 dsp_spl_jiffies; + +/* the datatype need to match jiffies datatype */ +extern unsigned long dsp_spl_jiffies; /* the structure of conferences: * diff --git a/drivers/isdn/mISDN/dsp_cmx.c b/drivers/isdn/mISDN/dsp_cmx.c index 334feab060a1..a4f05c54c32b 100644 --- a/drivers/isdn/mISDN/dsp_cmx.c +++ b/drivers/isdn/mISDN/dsp_cmx.c @@ -742,8 +742,8 @@ dsp_cmx_hardware(struct dsp_conf *conf, struct dsp *dsp) member->dsp->pcm_slot_tx, member->dsp->pcm_bank_tx, member->dsp->pcm_bank_rx); - conf->hardware = 0; - conf->software = 1; + conf->hardware = 1; + conf->software = tx_data; return; } /* find a new slot */ @@ -834,8 +834,8 @@ dsp_cmx_hardware(struct dsp_conf *conf, struct dsp *dsp) nextm->dsp->name, member->dsp->pcm_slot_tx, member->dsp->pcm_slot_rx); - conf->hardware = 0; - conf->software = 1; + conf->hardware = 1; + conf->software = tx_data; return; } /* find two new slot */ @@ -939,8 +939,11 @@ dsp_cmx_hardware(struct dsp_conf *conf, struct dsp *dsp) /* for more than two members.. */ /* if all members already have the same conference */ - if (all_conf) + if (all_conf) { + conf->hardware = 1; + conf->software = tx_data; return; + } /* * if there is an existing conference, but not all members have joined @@ -1013,6 +1016,8 @@ dsp_cmx_hardware(struct dsp_conf *conf, struct dsp *dsp) dsp_cmx_hw_message(member->dsp, MISDN_CTRL_HFC_CONF_JOIN, current_conf, 0, 0, 0); } + conf->hardware = 1; + conf->software = tx_data; return; } @@ -1328,7 +1333,7 @@ dsp_cmx_send_member(struct dsp *dsp, int len, s32 *c, int members) } if (dsp->conf && dsp->conf->software && dsp->conf->hardware) tx_data_only = 1; - if (dsp->conf->software && dsp->echo.hardware) + if (dsp->echo.software && dsp->echo.hardware) tx_data_only = 1; } @@ -1619,7 +1624,7 @@ send_packet: static u32 jittercount; /* counter for jitter check */ struct timer_list dsp_spl_tl; -u32 dsp_spl_jiffies; /* calculate the next time to fire */ +unsigned long dsp_spl_jiffies; /* calculate the next time to fire */ static u16 dsp_count; /* last sample count */ static int dsp_count_valid; /* if we have last sample count */ diff --git a/drivers/isdn/mISDN/dsp_core.c b/drivers/isdn/mISDN/dsp_core.c index 2ac2d7a25a9f..28c99c623bcd 100644 --- a/drivers/isdn/mISDN/dsp_core.c +++ b/drivers/isdn/mISDN/dsp_core.c @@ -268,6 +268,7 @@ dsp_fill_empty(struct dsp *dsp) } cq.op = MISDN_CTRL_FILL_EMPTY; cq.p1 = 1; + cq.p2 = dsp_silence; if (dsp->ch.peer->ctrl(dsp->ch.peer, CONTROL_CHANNEL, &cq)) { printk(KERN_DEBUG "%s: CONTROL_CHANNEL failed\n", __func__); diff --git a/drivers/isdn/mISDN/dsp_dtmf.c b/drivers/isdn/mISDN/dsp_dtmf.c index 887860bdc63b..642f30be5ce2 100644 --- a/drivers/isdn/mISDN/dsp_dtmf.c +++ b/drivers/isdn/mISDN/dsp_dtmf.c @@ -222,16 +222,25 @@ coefficients: goto storedigit; } - if (dsp_debug & DEBUG_DSP_DTMFCOEFF) + if (dsp_debug & DEBUG_DSP_DTMFCOEFF) { + s32 tresh_100 = tresh/100; + + if (tresh_100 == 0) { + tresh_100 = 1; + printk(KERN_DEBUG + "tresh(%d) too small set tresh/100 to 1\n", + tresh); + } printk(KERN_DEBUG "a %3d %3d %3d %3d %3d %3d %3d %3d" " tr:%3d r %3d %3d %3d %3d %3d %3d %3d %3d\n", result[0] / 10000, result[1] / 10000, result[2] / 10000, result[3] / 10000, result[4] / 10000, result[5] / 10000, result[6] / 10000, result[7] / 10000, tresh / 10000, - result[0] / (tresh / 100), result[1] / (tresh / 100), - result[2] / (tresh / 100), result[3] / (tresh / 100), - result[4] / (tresh / 100), result[5] / (tresh / 100), - result[6] / (tresh / 100), result[7] / (tresh / 100)); + result[0] / (tresh_100), result[1] / (tresh_100), + result[2] / (tresh_100), result[3] / (tresh_100), + result[4] / (tresh_100), result[5] / (tresh_100), + result[6] / (tresh_100), result[7] / (tresh_100)); + } /* calc digit (lowgroup/highgroup) */ lowgroup = -1; diff --git a/drivers/isdn/mISDN/hwchannel.c b/drivers/isdn/mISDN/hwchannel.c index c74c363554c4..ef34fd40867c 100644 --- a/drivers/isdn/mISDN/hwchannel.c +++ b/drivers/isdn/mISDN/hwchannel.c @@ -81,10 +81,16 @@ mISDN_initdchannel(struct dchannel *ch, int maxlen, void *phf) EXPORT_SYMBOL(mISDN_initdchannel); int -mISDN_initbchannel(struct bchannel *ch, int maxlen) +mISDN_initbchannel(struct bchannel *ch, unsigned short maxlen, + unsigned short minlen) { ch->Flags = 0; + ch->minlen = minlen; + ch->next_minlen = minlen; + ch->init_minlen = minlen; ch->maxlen = maxlen; + ch->next_maxlen = maxlen; + ch->init_maxlen = maxlen; ch->hw = NULL; ch->rx_skb = NULL; ch->tx_skb = NULL; @@ -134,6 +140,14 @@ mISDN_clear_bchannel(struct bchannel *ch) test_and_clear_bit(FLG_TX_BUSY, &ch->Flags); test_and_clear_bit(FLG_TX_NEXT, &ch->Flags); test_and_clear_bit(FLG_ACTIVE, &ch->Flags); + test_and_clear_bit(FLG_FILLEMPTY, &ch->Flags); + test_and_clear_bit(FLG_TX_EMPTY, &ch->Flags); + test_and_clear_bit(FLG_RX_OFF, &ch->Flags); + ch->dropcnt = 0; + ch->minlen = ch->init_minlen; + ch->next_minlen = ch->init_minlen; + ch->maxlen = ch->init_maxlen; + ch->next_maxlen = ch->init_maxlen; } EXPORT_SYMBOL(mISDN_clear_bchannel); @@ -148,6 +162,51 @@ mISDN_freebchannel(struct bchannel *ch) } EXPORT_SYMBOL(mISDN_freebchannel); +int +mISDN_ctrl_bchannel(struct bchannel *bch, struct mISDN_ctrl_req *cq) +{ + int ret = 0; + + switch (cq->op) { + case MISDN_CTRL_GETOP: + cq->op = MISDN_CTRL_RX_BUFFER | MISDN_CTRL_FILL_EMPTY | + MISDN_CTRL_RX_OFF; + break; + case MISDN_CTRL_FILL_EMPTY: + if (cq->p1) { + memset(bch->fill, cq->p2 & 0xff, MISDN_BCH_FILL_SIZE); + test_and_set_bit(FLG_FILLEMPTY, &bch->Flags); + } else { + test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags); + } + break; + case MISDN_CTRL_RX_OFF: + /* read back dropped byte count */ + cq->p2 = bch->dropcnt; + if (cq->p1) + test_and_set_bit(FLG_RX_OFF, &bch->Flags); + else + test_and_clear_bit(FLG_RX_OFF, &bch->Flags); + bch->dropcnt = 0; + break; + case MISDN_CTRL_RX_BUFFER: + if (cq->p2 > MISDN_CTRL_RX_SIZE_IGNORE) + bch->next_maxlen = cq->p2; + if (cq->p1 > MISDN_CTRL_RX_SIZE_IGNORE) + bch->next_minlen = cq->p1; + /* we return the old values */ + cq->p1 = bch->minlen; + cq->p2 = bch->maxlen; + break; + default: + pr_info("mISDN unhandled control %x operation\n", cq->op); + ret = -EINVAL; + break; + } + return ret; +} +EXPORT_SYMBOL(mISDN_ctrl_bchannel); + static inline u_int get_sapi_tei(u_char *p) { @@ -197,24 +256,37 @@ recv_Echannel(struct dchannel *ech, struct dchannel *dch) EXPORT_SYMBOL(recv_Echannel); void -recv_Bchannel(struct bchannel *bch, unsigned int id) +recv_Bchannel(struct bchannel *bch, unsigned int id, bool force) { struct mISDNhead *hh; - hh = mISDN_HEAD_P(bch->rx_skb); - hh->prim = PH_DATA_IND; - hh->id = id; - if (bch->rcount >= 64) { - printk(KERN_WARNING "B-channel %p receive queue overflow, " - "flushing!\n", bch); - skb_queue_purge(&bch->rqueue); - bch->rcount = 0; + /* if allocation did fail upper functions still may call us */ + if (unlikely(!bch->rx_skb)) return; + if (unlikely(!bch->rx_skb->len)) { + /* we have no data to send - this may happen after recovery + * from overflow or too small allocation. + * We need to free the buffer here */ + dev_kfree_skb(bch->rx_skb); + bch->rx_skb = NULL; + } else { + if (test_bit(FLG_TRANSPARENT, &bch->Flags) && + (bch->rx_skb->len < bch->minlen) && !force) + return; + hh = mISDN_HEAD_P(bch->rx_skb); + hh->prim = PH_DATA_IND; + hh->id = id; + if (bch->rcount >= 64) { + printk(KERN_WARNING + "B%d receive queue overflow - flushing!\n", + bch->nr); + skb_queue_purge(&bch->rqueue); + } + bch->rcount++; + skb_queue_tail(&bch->rqueue, bch->rx_skb); + bch->rx_skb = NULL; + schedule_event(bch, FLG_RECVQUEUE); } - bch->rcount++; - skb_queue_tail(&bch->rqueue, bch->rx_skb); - bch->rx_skb = NULL; - schedule_event(bch, FLG_RECVQUEUE); } EXPORT_SYMBOL(recv_Bchannel); @@ -272,7 +344,7 @@ get_next_dframe(struct dchannel *dch) } EXPORT_SYMBOL(get_next_dframe); -void +static void confirm_Bsend(struct bchannel *bch) { struct sk_buff *skb; @@ -294,7 +366,6 @@ confirm_Bsend(struct bchannel *bch) skb_queue_tail(&bch->rqueue, skb); schedule_event(bch, FLG_RECVQUEUE); } -EXPORT_SYMBOL(confirm_Bsend); int get_next_bframe(struct bchannel *bch) @@ -305,8 +376,8 @@ get_next_bframe(struct bchannel *bch) if (bch->tx_skb) { bch->next_skb = NULL; test_and_clear_bit(FLG_TX_NEXT, &bch->Flags); - if (!test_bit(FLG_TRANSPARENT, &bch->Flags)) - confirm_Bsend(bch); /* not for transparent */ + /* confirm imediately to allow next data */ + confirm_Bsend(bch); return 1; } else { test_and_clear_bit(FLG_TX_NEXT, &bch->Flags); @@ -395,7 +466,62 @@ bchannel_senddata(struct bchannel *ch, struct sk_buff *skb) /* write to fifo */ ch->tx_skb = skb; ch->tx_idx = 0; + confirm_Bsend(ch); return 1; } } EXPORT_SYMBOL(bchannel_senddata); + +/* The function allocates a new receive skb on demand with a size for the + * requirements of the current protocol. It returns the tailroom of the + * receive skb or an error. + */ +int +bchannel_get_rxbuf(struct bchannel *bch, int reqlen) +{ + int len; + + if (bch->rx_skb) { + len = skb_tailroom(bch->rx_skb); + if (len < reqlen) { + pr_warning("B%d no space for %d (only %d) bytes\n", + bch->nr, reqlen, len); + if (test_bit(FLG_TRANSPARENT, &bch->Flags)) { + /* send what we have now and try a new buffer */ + recv_Bchannel(bch, 0, true); + } else { + /* on HDLC we have to drop too big frames */ + return -EMSGSIZE; + } + } else { + return len; + } + } + /* update current min/max length first */ + if (unlikely(bch->maxlen != bch->next_maxlen)) + bch->maxlen = bch->next_maxlen; + if (unlikely(bch->minlen != bch->next_minlen)) + bch->minlen = bch->next_minlen; + if (unlikely(reqlen > bch->maxlen)) + return -EMSGSIZE; + if (test_bit(FLG_TRANSPARENT, &bch->Flags)) { + if (reqlen >= bch->minlen) { + len = reqlen; + } else { + len = 2 * bch->minlen; + if (len > bch->maxlen) + len = bch->maxlen; + } + } else { + /* with HDLC we do not know the length yet */ + len = bch->maxlen; + } + bch->rx_skb = mI_alloc_skb(len, GFP_ATOMIC); + if (!bch->rx_skb) { + pr_warning("B%d receive no memory for %d bytes\n", + bch->nr, len); + len = -ENOMEM; + } + return len; +} +EXPORT_SYMBOL(bchannel_get_rxbuf); diff --git a/drivers/isdn/mISDN/l1oip_core.c b/drivers/isdn/mISDN/l1oip_core.c index 0f88acf1185f..db50f788855d 100644 --- a/drivers/isdn/mISDN/l1oip_core.c +++ b/drivers/isdn/mISDN/l1oip_core.c @@ -1420,7 +1420,7 @@ init_card(struct l1oip *hc, int pri, int bundle) bch->nr = i + ch; bch->slot = i + ch; bch->debug = debug; - mISDN_initbchannel(bch, MAX_DATA_MEM); + mISDN_initbchannel(bch, MAX_DATA_MEM, 0); bch->hw = hc; bch->ch.send = handle_bmsg; bch->ch.ctrl = l1oip_bctrl; diff --git a/drivers/isdn/mISDN/layer1.c b/drivers/isdn/mISDN/layer1.c index 0fc49b375514..bebc57b72138 100644 --- a/drivers/isdn/mISDN/layer1.c +++ b/drivers/isdn/mISDN/layer1.c @@ -28,13 +28,15 @@ static u_int *debug; struct layer1 { u_long Flags; struct FsmInst l1m; - struct FsmTimer timer; + struct FsmTimer timer3; + struct FsmTimer timerX; int delay; + int t3_value; struct dchannel *dch; dchannel_l1callback *dcb; }; -#define TIMER3_VALUE 7000 +#define TIMER3_DEFAULT_VALUE 7000 static struct Fsm l1fsm_s = {NULL, 0, 0, NULL, NULL}; @@ -134,7 +136,7 @@ l1_deact_req_s(struct FsmInst *fi, int event, void *arg) struct layer1 *l1 = fi->userdata; mISDN_FsmChangeState(fi, ST_L1_F3); - mISDN_FsmRestartTimer(&l1->timer, 550, EV_TIMER_DEACT, NULL, 2); + mISDN_FsmRestartTimer(&l1->timerX, 550, EV_TIMER_DEACT, NULL, 2); test_and_set_bit(FLG_L1_DEACTTIMER, &l1->Flags); } @@ -179,11 +181,11 @@ l1_info4_ind(struct FsmInst *fi, int event, void *arg) mISDN_FsmChangeState(fi, ST_L1_F7); l1->dcb(l1->dch, INFO3_P8); if (test_and_clear_bit(FLG_L1_DEACTTIMER, &l1->Flags)) - mISDN_FsmDelTimer(&l1->timer, 4); + mISDN_FsmDelTimer(&l1->timerX, 4); if (!test_bit(FLG_L1_ACTIVATED, &l1->Flags)) { if (test_and_clear_bit(FLG_L1_T3RUN, &l1->Flags)) - mISDN_FsmDelTimer(&l1->timer, 3); - mISDN_FsmRestartTimer(&l1->timer, 110, EV_TIMER_ACT, NULL, 2); + mISDN_FsmDelTimer(&l1->timer3, 3); + mISDN_FsmRestartTimer(&l1->timerX, 110, EV_TIMER_ACT, NULL, 2); test_and_set_bit(FLG_L1_ACTTIMER, &l1->Flags); } } @@ -201,7 +203,7 @@ l1_timer3(struct FsmInst *fi, int event, void *arg) } if (l1->l1m.state != ST_L1_F6) { mISDN_FsmChangeState(fi, ST_L1_F3); - l1->dcb(l1->dch, HW_POWERUP_REQ); + /* do not force anything here, we need send INFO 0 */ } } @@ -233,8 +235,9 @@ l1_activate_s(struct FsmInst *fi, int event, void *arg) { struct layer1 *l1 = fi->userdata; - mISDN_FsmRestartTimer(&l1->timer, TIMER3_VALUE, EV_TIMER3, NULL, 2); + mISDN_FsmRestartTimer(&l1->timer3, l1->t3_value, EV_TIMER3, NULL, 2); test_and_set_bit(FLG_L1_T3RUN, &l1->Flags); + /* Tell HW to send INFO 1 */ l1->dcb(l1->dch, HW_RESET_REQ); } @@ -302,7 +305,8 @@ static struct FsmNode L1SFnList[] = static void release_l1(struct layer1 *l1) { - mISDN_FsmDelTimer(&l1->timer, 0); + mISDN_FsmDelTimer(&l1->timerX, 0); + mISDN_FsmDelTimer(&l1->timer3, 0); if (l1->dch) l1->dch->l1 = NULL; module_put(THIS_MODULE); @@ -356,6 +360,16 @@ l1_event(struct layer1 *l1, u_int event) release_l1(l1); break; default: + if ((event & ~HW_TIMER3_VMASK) == HW_TIMER3_VALUE) { + int val = event & HW_TIMER3_VMASK; + + if (val < 5) + val = 5; + if (val > 30) + val = 30; + l1->t3_value = val; + break; + } if (*debug & DEBUG_L1) printk(KERN_DEBUG "%s %x unhandled\n", __func__, event); @@ -377,13 +391,15 @@ create_l1(struct dchannel *dch, dchannel_l1callback *dcb) { nl1->l1m.fsm = &l1fsm_s; nl1->l1m.state = ST_L1_F3; nl1->Flags = 0; + nl1->t3_value = TIMER3_DEFAULT_VALUE; nl1->l1m.debug = *debug & DEBUG_L1_FSM; nl1->l1m.userdata = nl1; nl1->l1m.userint = 0; nl1->l1m.printdebug = l1m_debug; nl1->dch = dch; nl1->dcb = dcb; - mISDN_FsmInitTimer(&nl1->l1m, &nl1->timer); + mISDN_FsmInitTimer(&nl1->l1m, &nl1->timer3); + mISDN_FsmInitTimer(&nl1->l1m, &nl1->timerX); __module_get(THIS_MODULE); dch->l1 = nl1; return 0; diff --git a/drivers/isdn/mISDN/layer2.c b/drivers/isdn/mISDN/layer2.c index 39d7375fa551..0dc8abca1407 100644 --- a/drivers/isdn/mISDN/layer2.c +++ b/drivers/isdn/mISDN/layer2.c @@ -58,6 +58,8 @@ enum { EV_L1_DEACTIVATE, EV_L2_T200, EV_L2_T203, + EV_L2_T200I, + EV_L2_T203I, EV_L2_SET_OWN_BUSY, EV_L2_CLEAR_OWN_BUSY, EV_L2_FRAME_ERROR, @@ -86,6 +88,8 @@ static char *strL2Event[] = "EV_L1_DEACTIVATE", "EV_L2_T200", "EV_L2_T203", + "EV_L2_T200I", + "EV_L2_T203I", "EV_L2_SET_OWN_BUSY", "EV_L2_CLEAR_OWN_BUSY", "EV_L2_FRAME_ERROR", @@ -106,8 +110,8 @@ l2m_debug(struct FsmInst *fi, char *fmt, ...) vaf.fmt = fmt; vaf.va = &va; - printk(KERN_DEBUG "l2 (sapi %d tei %d): %pV\n", - l2->sapi, l2->tei, &vaf); + printk(KERN_DEBUG "%s l2 (sapi %d tei %d): %pV\n", + mISDNDevName4ch(&l2->ch), l2->sapi, l2->tei, &vaf); va_end(va); } @@ -150,7 +154,8 @@ l2up(struct layer2 *l2, u_int prim, struct sk_buff *skb) mISDN_HEAD_ID(skb) = (l2->ch.nr << 16) | l2->ch.addr; err = l2->up->send(l2->up, skb); if (err) { - printk(KERN_WARNING "%s: err=%d\n", __func__, err); + printk(KERN_WARNING "%s: dev %s err=%d\n", __func__, + mISDNDevName4ch(&l2->ch), err); dev_kfree_skb(skb); } } @@ -174,7 +179,8 @@ l2up_create(struct layer2 *l2, u_int prim, int len, void *arg) memcpy(skb_put(skb, len), arg, len); err = l2->up->send(l2->up, skb); if (err) { - printk(KERN_WARNING "%s: err=%d\n", __func__, err); + printk(KERN_WARNING "%s: dev %s err=%d\n", __func__, + mISDNDevName4ch(&l2->ch), err); dev_kfree_skb(skb); } } @@ -185,7 +191,8 @@ l2down_skb(struct layer2 *l2, struct sk_buff *skb) { ret = l2->ch.recv(l2->ch.peer, skb); if (ret && (*debug & DEBUG_L2_RECV)) - printk(KERN_DEBUG "l2down_skb: ret(%d)\n", ret); + printk(KERN_DEBUG "l2down_skb: dev %s ret(%d)\n", + mISDNDevName4ch(&l2->ch), ret); return ret; } @@ -276,12 +283,37 @@ ph_data_confirm(struct layer2 *l2, struct mISDNhead *hh, struct sk_buff *skb) { return ret; } +static void +l2_timeout(struct FsmInst *fi, int event, void *arg) +{ + struct layer2 *l2 = fi->userdata; + struct sk_buff *skb; + struct mISDNhead *hh; + + skb = mI_alloc_skb(0, GFP_ATOMIC); + if (!skb) { + printk(KERN_WARNING "%s: L2(%d,%d) nr:%x timer %s no skb\n", + mISDNDevName4ch(&l2->ch), l2->sapi, l2->tei, + l2->ch.nr, event == EV_L2_T200 ? "T200" : "T203"); + return; + } + hh = mISDN_HEAD_P(skb); + hh->prim = event == EV_L2_T200 ? DL_TIMER200_IND : DL_TIMER203_IND; + hh->id = l2->ch.nr; + if (*debug & DEBUG_TIMER) + printk(KERN_DEBUG "%s: L2(%d,%d) nr:%x timer %s expired\n", + mISDNDevName4ch(&l2->ch), l2->sapi, l2->tei, + l2->ch.nr, event == EV_L2_T200 ? "T200" : "T203"); + if (l2->ch.st) + l2->ch.st->own.recv(&l2->ch.st->own, skb); +} + static int l2mgr(struct layer2 *l2, u_int prim, void *arg) { long c = (long)arg; - printk(KERN_WARNING - "l2mgr: addr:%x prim %x %c\n", l2->id, prim, (char)c); + printk(KERN_WARNING "l2mgr: dev %s addr:%x prim %x %c\n", + mISDNDevName4ch(&l2->ch), l2->id, prim, (char)c); if (test_bit(FLG_LAPD, &l2->flag) && !test_bit(FLG_FIXED_TEI, &l2->flag)) { switch (c) { @@ -603,8 +635,8 @@ send_uframe(struct layer2 *l2, struct sk_buff *skb, u_char cmd, u_char cr) else { skb = mI_alloc_skb(i, GFP_ATOMIC); if (!skb) { - printk(KERN_WARNING "%s: can't alloc skbuff\n", - __func__); + printk(KERN_WARNING "%s: can't alloc skbuff in %s\n", + mISDNDevName4ch(&l2->ch), __func__); return; } } @@ -1089,8 +1121,8 @@ enquiry_cr(struct layer2 *l2, u_char typ, u_char cr, u_char pf) tmp[i++] = (l2->vr << 5) | typ | (pf ? 0x10 : 0); skb = mI_alloc_skb(i, GFP_ATOMIC); if (!skb) { - printk(KERN_WARNING - "isdnl2 can't alloc sbbuff for enquiry_cr\n"); + printk(KERN_WARNING "%s: isdnl2 can't alloc sbbuff in %s\n", + mISDNDevName4ch(&l2->ch), __func__); return; } memcpy(skb_put(skb, i), tmp, i); @@ -1150,7 +1182,7 @@ invoke_retransmission(struct layer2 *l2, unsigned int nr) else printk(KERN_WARNING "%s: windowar[%d] is NULL\n", - __func__, p1); + mISDNDevName4ch(&l2->ch), p1); l2->windowar[p1] = NULL; } mISDN_FsmEvent(&l2->l2m, EV_L2_ACK_PULL, NULL); @@ -1461,8 +1493,8 @@ l2_pull_iqueue(struct FsmInst *fi, int event, void *arg) p1 = (l2->vs - l2->va) % 8; p1 = (p1 + l2->sow) % l2->window; if (l2->windowar[p1]) { - printk(KERN_WARNING "isdnl2 try overwrite ack queue entry %d\n", - p1); + printk(KERN_WARNING "%s: l2 try overwrite ack queue entry %d\n", + mISDNDevName4ch(&l2->ch), p1); dev_kfree_skb(l2->windowar[p1]); } l2->windowar[p1] = skb; @@ -1482,12 +1514,14 @@ l2_pull_iqueue(struct FsmInst *fi, int event, void *arg) memcpy(skb_push(nskb, i), header, i); else { printk(KERN_WARNING - "isdnl2 pull_iqueue skb header(%d/%d) too short\n", i, p1); + "%s: L2 pull_iqueue skb header(%d/%d) too short\n", + mISDNDevName4ch(&l2->ch), i, p1); oskb = nskb; nskb = mI_alloc_skb(oskb->len + i, GFP_ATOMIC); if (!nskb) { dev_kfree_skb(oskb); - printk(KERN_WARNING "%s: no skb mem\n", __func__); + printk(KERN_WARNING "%s: no skb mem in %s\n", + mISDNDevName4ch(&l2->ch), __func__); return; } memcpy(skb_put(nskb, i), header, i); @@ -1814,11 +1848,16 @@ static struct FsmNode L2FnList[] = {ST_L2_8, EV_L2_SUPER, l2_st8_got_super}, {ST_L2_7, EV_L2_I, l2_got_iframe}, {ST_L2_8, EV_L2_I, l2_got_iframe}, - {ST_L2_5, EV_L2_T200, l2_st5_tout_200}, - {ST_L2_6, EV_L2_T200, l2_st6_tout_200}, - {ST_L2_7, EV_L2_T200, l2_st7_tout_200}, - {ST_L2_8, EV_L2_T200, l2_st8_tout_200}, - {ST_L2_7, EV_L2_T203, l2_st7_tout_203}, + {ST_L2_5, EV_L2_T200, l2_timeout}, + {ST_L2_6, EV_L2_T200, l2_timeout}, + {ST_L2_7, EV_L2_T200, l2_timeout}, + {ST_L2_8, EV_L2_T200, l2_timeout}, + {ST_L2_7, EV_L2_T203, l2_timeout}, + {ST_L2_5, EV_L2_T200I, l2_st5_tout_200}, + {ST_L2_6, EV_L2_T200I, l2_st6_tout_200}, + {ST_L2_7, EV_L2_T200I, l2_st7_tout_200}, + {ST_L2_8, EV_L2_T200I, l2_st8_tout_200}, + {ST_L2_7, EV_L2_T203I, l2_st7_tout_203}, {ST_L2_7, EV_L2_ACK_PULL, l2_pull_iqueue}, {ST_L2_7, EV_L2_SET_OWN_BUSY, l2_set_own_busy}, {ST_L2_8, EV_L2_SET_OWN_BUSY, l2_set_own_busy}, @@ -1858,7 +1897,8 @@ ph_data_indication(struct layer2 *l2, struct mISDNhead *hh, struct sk_buff *skb) ptei = *datap++; if ((psapi & 1) || !(ptei & 1)) { printk(KERN_WARNING - "l2 D-channel frame wrong EA0/EA1\n"); + "%s l2 D-channel frame wrong EA0/EA1\n", + mISDNDevName4ch(&l2->ch)); return ret; } psapi >>= 2; @@ -1867,7 +1907,8 @@ ph_data_indication(struct layer2 *l2, struct mISDNhead *hh, struct sk_buff *skb) /* not our business */ if (*debug & DEBUG_L2) printk(KERN_DEBUG "%s: sapi %d/%d mismatch\n", - __func__, psapi, l2->sapi); + mISDNDevName4ch(&l2->ch), psapi, + l2->sapi); dev_kfree_skb(skb); return 0; } @@ -1875,7 +1916,7 @@ ph_data_indication(struct layer2 *l2, struct mISDNhead *hh, struct sk_buff *skb) /* not our business */ if (*debug & DEBUG_L2) printk(KERN_DEBUG "%s: tei %d/%d mismatch\n", - __func__, ptei, l2->tei); + mISDNDevName4ch(&l2->ch), ptei, l2->tei); dev_kfree_skb(skb); return 0; } @@ -1916,7 +1957,8 @@ ph_data_indication(struct layer2 *l2, struct mISDNhead *hh, struct sk_buff *skb) } else c = 'L'; if (c) { - printk(KERN_WARNING "l2 D-channel frame error %c\n", c); + printk(KERN_WARNING "%s:l2 D-channel frame error %c\n", + mISDNDevName4ch(&l2->ch), c); mISDN_FsmEvent(&l2->l2m, EV_L2_FRAME_ERROR, (void *)(long)c); } return ret; @@ -1930,8 +1972,17 @@ l2_send(struct mISDNchannel *ch, struct sk_buff *skb) int ret = -EINVAL; if (*debug & DEBUG_L2_RECV) - printk(KERN_DEBUG "%s: prim(%x) id(%x) sapi(%d) tei(%d)\n", - __func__, hh->prim, hh->id, l2->sapi, l2->tei); + printk(KERN_DEBUG "%s: %s prim(%x) id(%x) sapi(%d) tei(%d)\n", + __func__, mISDNDevName4ch(&l2->ch), hh->prim, hh->id, + l2->sapi, l2->tei); + if (hh->prim == DL_INTERN_MSG) { + struct mISDNhead *chh = hh + 1; /* saved copy */ + + *hh = *chh; + if (*debug & DEBUG_L2_RECV) + printk(KERN_DEBUG "%s: prim(%x) id(%x) internal msg\n", + mISDNDevName4ch(&l2->ch), hh->prim, hh->id); + } switch (hh->prim) { case PH_DATA_IND: ret = ph_data_indication(l2, hh, skb); @@ -1987,6 +2038,12 @@ l2_send(struct mISDNchannel *ch, struct sk_buff *skb) ret = mISDN_FsmEvent(&l2->l2m, EV_L2_DL_RELEASE_REQ, skb); break; + case DL_TIMER200_IND: + mISDN_FsmEvent(&l2->l2m, EV_L2_T200I, NULL); + break; + case DL_TIMER203_IND: + mISDN_FsmEvent(&l2->l2m, EV_L2_T203I, NULL); + break; default: if (*debug & DEBUG_L2) l2m_debug(&l2->l2m, "l2 unknown pr %04x", @@ -2005,7 +2062,8 @@ tei_l2(struct layer2 *l2, u_int cmd, u_long arg) int ret = -EINVAL; if (*debug & DEBUG_L2_TEI) - printk(KERN_DEBUG "%s: cmd(%x)\n", __func__, cmd); + printk(KERN_DEBUG "%s: cmd(%x) in %s\n", + mISDNDevName4ch(&l2->ch), cmd, __func__); switch (cmd) { case (MDL_ASSIGN_REQ): ret = mISDN_FsmEvent(&l2->l2m, EV_L2_MDL_ASSIGN, (void *)arg); @@ -2018,7 +2076,8 @@ tei_l2(struct layer2 *l2, u_int cmd, u_long arg) break; case (MDL_ERROR_RSP): /* ETS 300-125 5.3.2.1 Test: TC13010 */ - printk(KERN_NOTICE "MDL_ERROR|REQ (tei_l2)\n"); + printk(KERN_NOTICE "%s: MDL_ERROR|REQ (tei_l2)\n", + mISDNDevName4ch(&l2->ch)); ret = mISDN_FsmEvent(&l2->l2m, EV_L2_MDL_ERROR, NULL); break; } @@ -2050,7 +2109,8 @@ l2_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg) u_int info; if (*debug & DEBUG_L2_CTRL) - printk(KERN_DEBUG "%s:(%x)\n", __func__, cmd); + printk(KERN_DEBUG "%s: %s cmd(%x)\n", + mISDNDevName4ch(ch), __func__, cmd); switch (cmd) { case OPEN_CHANNEL: diff --git a/drivers/isdn/mISDN/tei.c b/drivers/isdn/mISDN/tei.c index ba2bc0c776e2..be88728f1106 100644 --- a/drivers/isdn/mISDN/tei.c +++ b/drivers/isdn/mISDN/tei.c @@ -790,18 +790,23 @@ tei_ph_data_ind(struct teimgr *tm, u_int mt, u_char *dp, int len) static struct layer2 * create_new_tei(struct manager *mgr, int tei, int sapi) { - u_long opt = 0; - u_long flags; - int id; - struct layer2 *l2; + unsigned long opt = 0; + unsigned long flags; + int id; + struct layer2 *l2; + struct channel_req rq; if (!mgr->up) return NULL; if ((tei >= 0) && (tei < 64)) test_and_set_bit(OPTION_L2_FIXEDTEI, &opt); - if (mgr->ch.st->dev->Dprotocols - & ((1 << ISDN_P_TE_E1) | (1 << ISDN_P_NT_E1))) + if (mgr->ch.st->dev->Dprotocols & ((1 << ISDN_P_TE_E1) | + (1 << ISDN_P_NT_E1))) { test_and_set_bit(OPTION_L2_PMX, &opt); + rq.protocol = ISDN_P_NT_E1; + } else { + rq.protocol = ISDN_P_NT_S0; + } l2 = create_l2(mgr->up, ISDN_P_LAPD_NT, opt, tei, sapi); if (!l2) { printk(KERN_WARNING "%s:no memory for layer2\n", __func__); @@ -836,6 +841,14 @@ create_new_tei(struct manager *mgr, int tei, int sapi) l2->ch.recv = mgr->ch.recv; l2->ch.peer = mgr->ch.peer; l2->ch.ctrl(&l2->ch, OPEN_CHANNEL, NULL); + /* We need open here L1 for the manager as well (refcounting) */ + rq.adr.dev = mgr->ch.st->dev->id; + id = mgr->ch.st->own.ctrl(&mgr->ch.st->own, OPEN_CHANNEL, &rq); + if (id < 0) { + printk(KERN_WARNING "%s: cannot open L1\n", __func__); + l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL); + l2 = NULL; + } } return l2; } @@ -978,10 +991,11 @@ TEIrelease(struct layer2 *l2) static int create_teimgr(struct manager *mgr, struct channel_req *crq) { - struct layer2 *l2; - u_long opt = 0; - u_long flags; - int id; + struct layer2 *l2; + unsigned long opt = 0; + unsigned long flags; + int id; + struct channel_req l1rq; if (*debug & DEBUG_L2_TEI) printk(KERN_DEBUG "%s: %s proto(%x) adr(%d %d %d %d)\n", @@ -1016,6 +1030,7 @@ create_teimgr(struct manager *mgr, struct channel_req *crq) if (crq->protocol == ISDN_P_LAPD_TE) test_and_set_bit(MGR_OPT_USER, &mgr->options); } + l1rq.adr = crq->adr; if (mgr->ch.st->dev->Dprotocols & ((1 << ISDN_P_TE_E1) | (1 << ISDN_P_NT_E1))) test_and_set_bit(OPTION_L2_PMX, &opt); @@ -1023,6 +1038,8 @@ create_teimgr(struct manager *mgr, struct channel_req *crq) mgr->up = crq->ch; id = DL_INFO_L2_CONNECT; teiup_create(mgr, DL_INFORMATION_IND, sizeof(id), &id); + if (test_bit(MGR_PH_ACTIVE, &mgr->options)) + teiup_create(mgr, PH_ACTIVATE_IND, 0, NULL); crq->ch = NULL; if (!list_empty(&mgr->layer2)) { read_lock_irqsave(&mgr->lock, flags); @@ -1053,24 +1070,34 @@ create_teimgr(struct manager *mgr, struct channel_req *crq) l2->tm->tei_m.fsm = &teifsmu; l2->tm->tei_m.state = ST_TEI_NOP; l2->tm->tval = 1000; /* T201 1 sec */ + if (test_bit(OPTION_L2_PMX, &opt)) + l1rq.protocol = ISDN_P_TE_E1; + else + l1rq.protocol = ISDN_P_TE_S0; } else { l2->tm->tei_m.fsm = &teifsmn; l2->tm->tei_m.state = ST_TEI_NOP; l2->tm->tval = 2000; /* T202 2 sec */ + if (test_bit(OPTION_L2_PMX, &opt)) + l1rq.protocol = ISDN_P_NT_E1; + else + l1rq.protocol = ISDN_P_NT_S0; } mISDN_FsmInitTimer(&l2->tm->tei_m, &l2->tm->timer); write_lock_irqsave(&mgr->lock, flags); id = get_free_id(mgr); list_add_tail(&l2->list, &mgr->layer2); write_unlock_irqrestore(&mgr->lock, flags); - if (id < 0) { - l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL); - } else { + if (id >= 0) { l2->ch.nr = id; l2->up->nr = id; crq->ch = &l2->ch; - id = 0; + /* We need open here L1 for the manager as well (refcounting) */ + id = mgr->ch.st->own.ctrl(&mgr->ch.st->own, OPEN_CHANNEL, + &l1rq); } + if (id < 0) + l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL); return id; } @@ -1096,12 +1123,16 @@ mgr_send(struct mISDNchannel *ch, struct sk_buff *skb) break; case PH_ACTIVATE_IND: test_and_set_bit(MGR_PH_ACTIVE, &mgr->options); + if (mgr->up) + teiup_create(mgr, PH_ACTIVATE_IND, 0, NULL); mISDN_FsmEvent(&mgr->deact, EV_ACTIVATE_IND, NULL); do_send(mgr); ret = 0; break; case PH_DEACTIVATE_IND: test_and_clear_bit(MGR_PH_ACTIVE, &mgr->options); + if (mgr->up) + teiup_create(mgr, PH_DEACTIVATE_IND, 0, NULL); mISDN_FsmEvent(&mgr->deact, EV_DEACTIVATE_IND, NULL); ret = 0; break; @@ -1263,7 +1294,7 @@ static int mgr_bcast(struct mISDNchannel *ch, struct sk_buff *skb) { struct manager *mgr = container_of(ch, struct manager, bcast); - struct mISDNhead *hh = mISDN_HEAD_P(skb); + struct mISDNhead *hhc, *hh = mISDN_HEAD_P(skb); struct sk_buff *cskb = NULL; struct layer2 *l2; u_long flags; @@ -1278,10 +1309,17 @@ mgr_bcast(struct mISDNchannel *ch, struct sk_buff *skb) skb = NULL; } else { if (!cskb) - cskb = skb_copy(skb, GFP_KERNEL); + cskb = skb_copy(skb, GFP_ATOMIC); } if (cskb) { - ret = l2->ch.send(&l2->ch, cskb); + hhc = mISDN_HEAD_P(cskb); + /* save original header behind normal header */ + hhc++; + *hhc = *hh; + hhc--; + hhc->prim = DL_INTERN_MSG; + hhc->id = l2->ch.nr; + ret = ch->st->own.recv(&ch->st->own, cskb); if (ret) { if (*debug & DEBUG_SEND_ERR) printk(KERN_DEBUG |