diff options
author | James Morris <jmorris@macbook.(none)> | 2009-12-03 12:03:40 +0530 |
---|---|---|
committer | James Morris <jmorris@macbook.(none)> | 2009-12-03 12:03:40 +0530 |
commit | c84d6efd363a3948eb32ec40d46bab6338580454 (patch) | |
tree | 3ba7ac46e6626fe8ac843834588609eb6ccee5c6 /drivers/isdn | |
parent | 7539cf4b92be4aecc573ea962135f246a7a33401 (diff) | |
parent | 22763c5cf3690a681551162c15d34d935308c8d7 (diff) |
Merge branch 'master' into next
Diffstat (limited to 'drivers/isdn')
34 files changed, 475 insertions, 328 deletions
diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c index 2d8352419c0..65bf91e16a4 100644 --- a/drivers/isdn/capi/capi.c +++ b/drivers/isdn/capi/capi.c @@ -603,7 +603,7 @@ static void capi_recv_message(struct capi20_appl *ap, struct sk_buff *skb) if (CAPIMSG_CMD(skb->data) == CAPI_CONNECT_B3_CONF) { u16 info = CAPIMSG_U16(skb->data, 12); // Info field - if (info == 0) { + if ((info & 0xff00) == 0) { mutex_lock(&cdev->ncci_list_mtx); capincci_alloc(cdev, CAPIMSG_NCCI(skb->data)); mutex_unlock(&cdev->ncci_list_mtx); diff --git a/drivers/isdn/capi/capidrv.c b/drivers/isdn/capi/capidrv.c index 650120261ab..3e6d17f42a9 100644 --- a/drivers/isdn/capi/capidrv.c +++ b/drivers/isdn/capi/capidrv.c @@ -40,7 +40,7 @@ static int debugmode = 0; MODULE_DESCRIPTION("CAPI4Linux: Interface to ISDN4Linux"); MODULE_AUTHOR("Carsten Paeth"); MODULE_LICENSE("GPL"); -module_param(debugmode, uint, 0); +module_param(debugmode, uint, S_IRUGO|S_IWUSR); /* -------- type definitions ----------------------------------------- */ @@ -671,8 +671,8 @@ static void n0(capidrv_contr * card, capidrv_ncci * ncci) NULL, /* Useruserdata */ /* $$$$ */ NULL /* Facilitydataarray */ ); - send_message(card, &cmsg); plci_change_state(card, ncci->plcip, EV_PLCI_DISCONNECT_REQ); + send_message(card, &cmsg); cmd.command = ISDN_STAT_BHUP; cmd.driver = card->myid; @@ -924,8 +924,8 @@ static void handle_incoming_call(capidrv_contr * card, _cmsg * cmsg) */ capi_cmsg_answer(cmsg); cmsg->Reject = 1; /* ignore */ - send_message(card, cmsg); plci_change_state(card, plcip, EV_PLCI_CONNECT_REJECT); + send_message(card, cmsg); printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s ignored\n", card->contrnr, cmd.parm.setup.phone, @@ -974,8 +974,8 @@ static void handle_incoming_call(capidrv_contr * card, _cmsg * cmsg) case 2: /* Call will be rejected. */ capi_cmsg_answer(cmsg); cmsg->Reject = 2; /* reject call, normal call clearing */ - send_message(card, cmsg); plci_change_state(card, plcip, EV_PLCI_CONNECT_REJECT); + send_message(card, cmsg); break; default: @@ -983,8 +983,8 @@ static void handle_incoming_call(capidrv_contr * card, _cmsg * cmsg) capi_cmsg_answer(cmsg); cmsg->Reject = 8; /* reject call, destination out of order */ - send_message(card, cmsg); plci_change_state(card, plcip, EV_PLCI_CONNECT_REJECT); + send_message(card, cmsg); break; } return; @@ -1020,8 +1020,8 @@ static void handle_plci(_cmsg * cmsg) card->bchans[plcip->chan].disconnecting = 1; plci_change_state(card, plcip, EV_PLCI_DISCONNECT_IND); capi_cmsg_answer(cmsg); - send_message(card, cmsg); plci_change_state(card, plcip, EV_PLCI_DISCONNECT_RESP); + send_message(card, cmsg); break; case CAPI_DISCONNECT_CONF: /* plci */ @@ -1078,8 +1078,8 @@ static void handle_plci(_cmsg * cmsg) if (card->bchans[plcip->chan].incoming) { capi_cmsg_answer(cmsg); - send_message(card, cmsg); plci_change_state(card, plcip, EV_PLCI_CONNECT_ACTIVE_IND); + send_message(card, cmsg); } else { capidrv_ncci *nccip; capi_cmsg_answer(cmsg); @@ -1098,13 +1098,14 @@ static void handle_plci(_cmsg * cmsg) NULL /* NCPI */ ); nccip->msgid = cmsg->Messagenumber; + plci_change_state(card, plcip, + EV_PLCI_CONNECT_ACTIVE_IND); + ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_REQ); send_message(card, cmsg); cmd.command = ISDN_STAT_DCONN; cmd.driver = card->myid; cmd.arg = plcip->chan; card->interface.statcallb(&cmd); - plci_change_state(card, plcip, EV_PLCI_CONNECT_ACTIVE_IND); - ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_REQ); } break; @@ -1193,8 +1194,8 @@ static void handle_ncci(_cmsg * cmsg) goto notfound; capi_cmsg_answer(cmsg); - send_message(card, cmsg); ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_ACTIVE_IND); + send_message(card, cmsg); cmd.command = ISDN_STAT_BCONN; cmd.driver = card->myid; @@ -1222,8 +1223,8 @@ static void handle_ncci(_cmsg * cmsg) 0, /* Reject */ NULL /* NCPI */ ); - send_message(card, cmsg); ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_RESP); + send_message(card, cmsg); break; } printk(KERN_ERR "capidrv-%d: no mem for ncci, sorry\n", card->contrnr); @@ -1299,8 +1300,8 @@ static void handle_ncci(_cmsg * cmsg) card->bchans[nccip->chan].disconnecting = 1; ncci_change_state(card, nccip, EV_NCCI_DISCONNECT_B3_IND); capi_cmsg_answer(cmsg); - send_message(card, cmsg); ncci_change_state(card, nccip, EV_NCCI_DISCONNECT_B3_RESP); + send_message(card, cmsg); break; case CAPI_DISCONNECT_B3_CONF: /* ncci */ @@ -2014,8 +2015,8 @@ static void send_listen(capidrv_contr *card) card->cipmask, card->cipmask2, NULL, NULL); - send_message(card, &cmdcmsg); listen_change_state(card, EV_LISTEN_REQ); + send_message(card, &cmdcmsg); } static void listentimerfunc(unsigned long x) diff --git a/drivers/isdn/capi/kcapi.c b/drivers/isdn/capi/kcapi.c index 57d26360f64..dc506ab99ca 100644 --- a/drivers/isdn/capi/kcapi.c +++ b/drivers/isdn/capi/kcapi.c @@ -18,6 +18,7 @@ #include <linux/interrupt.h> #include <linux/ioport.h> #include <linux/proc_fs.h> +#include <linux/sched.h> #include <linux/seq_file.h> #include <linux/skbuff.h> #include <linux/workqueue.h> diff --git a/drivers/isdn/divert/divert_procfs.c b/drivers/isdn/divert/divert_procfs.c index 8b256a617c8..3697c409bec 100644 --- a/drivers/isdn/divert/divert_procfs.c +++ b/drivers/isdn/divert/divert_procfs.c @@ -16,6 +16,7 @@ #else #include <linux/fs.h> #endif +#include <linux/sched.h> #include <linux/isdnif.h> #include <net/net_namespace.h> #include "isdn_divert.h" diff --git a/drivers/isdn/gigaset/asyncdata.c b/drivers/isdn/gigaset/asyncdata.c index 234cc5d5331..44a58e6f8f6 100644 --- a/drivers/isdn/gigaset/asyncdata.c +++ b/drivers/isdn/gigaset/asyncdata.c @@ -334,7 +334,14 @@ static inline int iraw_loop(unsigned char c, unsigned char *src, int numbytes, return startbytes - numbytes; } -/* process a block of data received from the device +/** + * gigaset_m10x_input() - process a block of data received from the device + * @inbuf: received data and device descriptor structure. + * + * Called by hardware module {ser,usb}_gigaset with a block of received + * bytes. Separates the bytes received over the serial data channel into + * user data and command replies (locked/unlocked) according to the + * current state of the interface. */ void gigaset_m10x_input(struct inbuf_t *inbuf) { @@ -543,16 +550,17 @@ static struct sk_buff *iraw_encode(struct sk_buff *skb, int head, int tail) return iraw_skb; } -/* gigaset_send_skb - * called by common.c to queue an skb for sending - * and start transmission if necessary - * parameters: - * B Channel control structure - * skb +/** + * gigaset_m10x_send_skb() - queue an skb for sending + * @bcs: B channel descriptor structure. + * @skb: data to send. + * + * Called by i4l.c to encode and queue an skb for sending, and start + * transmission if necessary. + * * Return value: - * number of bytes accepted for sending - * (skb->len if ok, 0 if out of buffer space) - * or error code (< 0, eg. -EINVAL) + * number of bytes accepted for sending (skb->len) if ok, + * error code < 0 (eg. -ENOMEM) on error */ int gigaset_m10x_send_skb(struct bc_state *bcs, struct sk_buff *skb) { diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c index 781c4041f7b..5ed1d99eb9f 100644 --- a/drivers/isdn/gigaset/bas-gigaset.c +++ b/drivers/isdn/gigaset/bas-gigaset.c @@ -134,6 +134,7 @@ struct bas_cardstate { #define BS_ATRDPEND 0x040 /* urb_cmd_in in use */ #define BS_ATWRPEND 0x080 /* urb_cmd_out in use */ #define BS_SUSPEND 0x100 /* USB port suspended */ +#define BS_RESETTING 0x200 /* waiting for HD_RESET_INTERRUPT_PIPE_ACK */ static struct gigaset_driver *driver = NULL; @@ -319,6 +320,21 @@ static int gigaset_set_line_ctrl(struct cardstate *cs, unsigned cflag) return -EINVAL; } +/* set/clear bits in base connection state, return previous state + */ +static inline int update_basstate(struct bas_cardstate *ucs, + int set, int clear) +{ + unsigned long flags; + int state; + + spin_lock_irqsave(&ucs->lock, flags); + state = ucs->basstate; + ucs->basstate = (state & ~clear) | set; + spin_unlock_irqrestore(&ucs->lock, flags); + return state; +} + /* error_hangup * hang up any existing connection because of an unrecoverable error * This function may be called from any context and takes care of scheduling @@ -350,12 +366,9 @@ static inline void error_hangup(struct bc_state *bcs) */ static inline void error_reset(struct cardstate *cs) { - /* close AT command channel to recover (ignore errors) */ - req_submit(cs->bcs, HD_CLOSE_ATCHANNEL, 0, BAS_TIMEOUT); - - //FIXME try to recover without bothering the user - dev_err(cs->dev, - "unrecoverable error - please disconnect Gigaset base to reset\n"); + /* reset interrupt pipe to recover (ignore errors) */ + update_basstate(cs->hw.bas, BS_RESETTING, 0); + req_submit(cs->bcs, HD_RESET_INTERRUPT_PIPE, 0, BAS_TIMEOUT); } /* check_pending @@ -398,8 +411,13 @@ static void check_pending(struct bas_cardstate *ucs) case HD_DEVICE_INIT_ACK: /* no reply expected */ ucs->pending = 0; break; - /* HD_READ_ATMESSAGE, HD_WRITE_ATMESSAGE, HD_RESET_INTERRUPTPIPE - * are handled separately and should never end up here + case HD_RESET_INTERRUPT_PIPE: + 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 */ default: dev_warn(&ucs->interface->dev, @@ -449,21 +467,6 @@ static void cmd_in_timeout(unsigned long data) error_reset(cs); } -/* set/clear bits in base connection state, return previous state - */ -inline static int update_basstate(struct bas_cardstate *ucs, - int set, int clear) -{ - unsigned long flags; - int state; - - spin_lock_irqsave(&ucs->lock, flags); - state = ucs->basstate; - ucs->basstate = (state & ~clear) | set; - spin_unlock_irqrestore(&ucs->lock, flags); - return state; -} - /* read_ctrl_callback * USB completion handler for control pipe input * called by the USB subsystem in interrupt context @@ -762,7 +765,8 @@ static void read_int_callback(struct urb *urb) break; case HD_RESET_INTERRUPT_PIPE_ACK: - gig_dbg(DEBUG_USBREQ, "HD_RESET_INTERRUPT_PIPE_ACK"); + update_basstate(ucs, 0, BS_RESETTING); + dev_notice(cs->dev, "interrupt pipe reset\n"); break; case HD_SUSPEND_END: @@ -1331,28 +1335,24 @@ static void read_iso_tasklet(unsigned long data) rcvbuf = urb->transfer_buffer; totleft = urb->actual_length; for (frame = 0; totleft > 0 && frame < BAS_NUMFRAMES; frame++) { - if (unlikely(urb->iso_frame_desc[frame].status)) { + numbytes = urb->iso_frame_desc[frame].actual_length; + if (unlikely(urb->iso_frame_desc[frame].status)) dev_warn(cs->dev, - "isochronous read: frame %d: %s\n", - frame, + "isochronous read: frame %d[%d]: %s\n", + frame, numbytes, get_usb_statmsg( urb->iso_frame_desc[frame].status)); - break; - } - numbytes = urb->iso_frame_desc[frame].actual_length; - if (unlikely(numbytes > BAS_MAXFRAME)) { + if (unlikely(numbytes > BAS_MAXFRAME)) dev_warn(cs->dev, "isochronous read: frame %d: " "numbytes (%d) > BAS_MAXFRAME\n", frame, numbytes); - break; - } if (unlikely(numbytes > totleft)) { dev_warn(cs->dev, "isochronous read: frame %d: " "numbytes (%d) > totleft (%d)\n", frame, numbytes, totleft); - break; + numbytes = totleft; } offset = urb->iso_frame_desc[frame].offset; if (unlikely(offset + numbytes > BAS_INBUFSIZE)) { @@ -1361,7 +1361,7 @@ static void read_iso_tasklet(unsigned long data) "offset (%d) + numbytes (%d) " "> BAS_INBUFSIZE\n", frame, offset, numbytes); - break; + numbytes = BAS_INBUFSIZE - offset; } gigaset_isoc_receive(rcvbuf + offset, numbytes, bcs); totleft -= numbytes; @@ -1433,6 +1433,7 @@ static void req_timeout(unsigned long data) case HD_CLOSE_ATCHANNEL: dev_err(bcs->cs->dev, "timeout closing AT channel\n"); + error_reset(bcs->cs); break; case HD_CLOSE_B2CHANNEL: @@ -1442,6 +1443,13 @@ static void req_timeout(unsigned long data) error_reset(bcs->cs); break; + case HD_RESET_INTERRUPT_PIPE: + /* error recovery escalation */ + dev_err(bcs->cs->dev, + "reset interrupt pipe timeout, attempting USB reset\n"); + usb_queue_reset_device(bcs->cs->hw.bas->interface); + break; + default: dev_warn(bcs->cs->dev, "request 0x%02x timed out, clearing\n", pending); @@ -1934,6 +1942,15 @@ static int gigaset_write_cmd(struct cardstate *cs, goto notqueued; } + /* translate "+++" escape sequence sent as a single separate command + * into "close AT channel" command for error recovery + * The next command will reopen the AT channel automatically. + */ + if (len == 3 && !memcmp(buf, "+++", 3)) { + rc = req_submit(cs->bcs, HD_CLOSE_ATCHANNEL, 0, BAS_TIMEOUT); + goto notqueued; + } + if (len > IF_WRITEBUF) len = IF_WRITEBUF; if (!(cb = kmalloc(sizeof(struct cmdbuf_t) + len, GFP_ATOMIC))) { diff --git a/drivers/isdn/gigaset/common.c b/drivers/isdn/gigaset/common.c index e4141bf8b2f..33dcd8d72b7 100644 --- a/drivers/isdn/gigaset/common.c +++ b/drivers/isdn/gigaset/common.c @@ -22,6 +22,12 @@ #define DRIVER_AUTHOR "Hansjoerg Lipp <hjlipp@web.de>, Tilman Schmidt <tilman@imap.cc>, Stefan Eilers" #define DRIVER_DESC "Driver for Gigaset 307x" +#ifdef CONFIG_GIGASET_DEBUG +#define DRIVER_DESC_DEBUG " (debug build)" +#else +#define DRIVER_DESC_DEBUG "" +#endif + /* Module parameters */ int gigaset_debuglevel = DEBUG_DEFAULT; EXPORT_SYMBOL_GPL(gigaset_debuglevel); @@ -32,6 +38,17 @@ MODULE_PARM_DESC(debug, "debug level"); #define VALID_MINOR 0x01 #define VALID_ID 0x02 +/** + * gigaset_dbg_buffer() - dump data in ASCII and hex for debugging + * @level: debugging level. + * @msg: message prefix. + * @len: number of bytes to dump. + * @buf: data to dump. + * + * If the current debugging level includes one of the bits set in @level, + * @len bytes starting at @buf are logged to dmesg at KERN_DEBUG prio, + * prefixed by the text @msg. + */ void gigaset_dbg_buffer(enum debuglevel level, const unsigned char *msg, size_t len, const unsigned char *buf) { @@ -274,6 +291,20 @@ static void clear_events(struct cardstate *cs) spin_unlock_irqrestore(&cs->ev_lock, flags); } +/** + * gigaset_add_event() - add event to device event queue + * @cs: device descriptor structure. + * @at_state: connection state structure. + * @type: event type. + * @ptr: pointer parameter for event. + * @parameter: integer parameter for event. + * @arg: pointer parameter for event. + * + * Allocate an event queue entry from the device's event queue, and set it up + * with the parameters given. + * + * Return value: added event + */ struct event_t *gigaset_add_event(struct cardstate *cs, struct at_state_t *at_state, int type, void *ptr, int parameter, void *arg) @@ -398,6 +429,15 @@ static void make_invalid(struct cardstate *cs, unsigned mask) spin_unlock_irqrestore(&drv->lock, flags); } +/** + * gigaset_freecs() - free all associated ressources of a device + * @cs: device descriptor structure. + * + * Stops all tasklets and timers, unregisters the device from all + * subsystems it was registered to, deallocates the device structure + * @cs and all structures referenced from it. + * Operations on the device should be stopped before calling this. + */ void gigaset_freecs(struct cardstate *cs) { int i; @@ -506,7 +546,12 @@ static void gigaset_inbuf_init(struct inbuf_t *inbuf, struct bc_state *bcs, inbuf->inputstate = inputstate; } -/* append received bytes to inbuf */ +/** + * gigaset_fill_inbuf() - append received data to input buffer + * @inbuf: buffer structure. + * @src: received data. + * @numbytes: number of bytes received. + */ int gigaset_fill_inbuf(struct inbuf_t *inbuf, const unsigned char *src, unsigned numbytes) { @@ -606,20 +651,22 @@ static struct bc_state *gigaset_initbcs(struct bc_state *bcs, return NULL; } -/* gigaset_initcs +/** + * gigaset_initcs() - initialize device structure + * @drv: hardware driver the device belongs to + * @channels: number of B channels supported by device + * @onechannel: !=0 if B channel data and AT commands share one + * communication channel (M10x), + * ==0 if B channels have separate communication channels (base) + * @ignoreframes: number of frames to ignore after setting up B channel + * @cidmode: !=0: start in CallID mode + * @modulename: name of driver module for LL registration + * * Allocate and initialize cardstate structure for Gigaset driver * Calls hardware dependent gigaset_initcshw() function * Calls B channel initialization function gigaset_initbcs() for each B channel - * parameters: - * drv hardware driver the device belongs to - * channels number of B channels supported by device - * onechannel !=0: B channel data and AT commands share one - * communication channel - * ==0: B channels have separate communication channels - * ignoreframes number of frames to ignore after setting up B channel - * cidmode !=0: start in CallID mode - * modulename name of driver module (used for I4L registration) - * return value: + * + * Return value: * pointer to cardstate structure */ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels, @@ -837,6 +884,17 @@ static void cleanup_cs(struct cardstate *cs) } +/** + * gigaset_start() - start device operations + * @cs: device descriptor structure. + * + * Prepares the device for use by setting up communication parameters, + * scheduling an EV_START event to initiate device initialization, and + * waiting for completion of the initialization. + * + * Return value: + * 1 - success, 0 - error + */ int gigaset_start(struct cardstate *cs) { unsigned long flags; @@ -879,9 +937,15 @@ error: } EXPORT_SYMBOL_GPL(gigaset_start); -/* gigaset_shutdown - * check if a device is associated to the cardstate structure and stop it - * return value: 0 if ok, -1 if no device was associated +/** + * gigaset_shutdown() - shut down device operations + * @cs: device descriptor structure. + * + * Deactivates the device by scheduling an EV_SHUTDOWN event and + * waiting for completion of the shutdown. + * + * Return value: + * 0 - success, -1 - error (no device associated) */ int gigaset_shutdown(struct cardstate *cs) { @@ -912,6 +976,13 @@ exit: } EXPORT_SYMBOL_GPL(gigaset_shutdown); +/** + * gigaset_stop() - stop device operations + * @cs: device descriptor structure. + * + * Stops operations on the device by scheduling an EV_STOP event and + * waiting for completion of the shutdown. + */ void gigaset_stop(struct cardstate *cs) { mutex_lock(&cs->mutex); @@ -1020,6 +1091,14 @@ struct cardstate *gigaset_get_cs_by_tty(struct tty_struct *tty) return gigaset_get_cs_by_minor(tty->index + tty->driver->minor_start); } +/** + * gigaset_freedriver() - free all associated ressources of a driver + * @drv: driver descriptor structure. + * + * Unregisters the driver from the system and deallocates the driver + * structure @drv and all structures referenced from it. + * All devices should be shut down before calling this. + */ void gigaset_freedriver(struct gigaset_driver *drv) { unsigned long flags; @@ -1035,14 +1114,16 @@ void gigaset_freedriver(struct gigaset_driver *drv) } EXPORT_SYMBOL_GPL(gigaset_freedriver); -/* gigaset_initdriver +/** + * gigaset_initdriver() - initialize driver structure + * @minor: First minor number + * @minors: Number of minors this driver can handle + * @procname: Name of the driver + * @devname: Name of the device files (prefix without minor number) + * * Allocate and initialize gigaset_driver structure. Initialize interface. - * parameters: - * minor First minor number - * minors Number of minors this driver can handle - * procname Name of the driver - * devname Name of the device files (prefix without minor number) - * return value: + * + * Return value: * Pointer to the gigaset_driver structure on success, NULL on failure. */ struct gigaset_driver *gigaset_initdriver(unsigned minor, unsigned minors, @@ -1095,6 +1176,13 @@ error: } EXPORT_SYMBOL_GPL(gigaset_initdriver); +/** + * gigaset_blockdriver() - block driver + * @drv: driver descriptor structure. + * + * Prevents the driver from attaching new devices, in preparation for + * deregistration. + */ void gigaset_blockdriver(struct gigaset_driver *drv) { drv->blocked = 1; @@ -1110,7 +1198,7 @@ static int __init gigaset_init_module(void) if (gigaset_debuglevel == 1) gigaset_debuglevel = DEBUG_DEFAULT; - pr_info(DRIVER_DESC "\n"); + pr_info(DRIVER_DESC DRIVER_DESC_DEBUG "\n"); return 0; } diff --git a/drivers/isdn/gigaset/ev-layer.c b/drivers/isdn/gigaset/ev-layer.c index 2d91049571a..cc768caa38f 100644 --- a/drivers/isdn/gigaset/ev-layer.c +++ b/drivers/isdn/gigaset/ev-layer.c @@ -207,7 +207,6 @@ struct reply_t gigaset_tab_nocid[] = /* 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, 202, 0, {ACT_ERROR}},//DELETE {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}}, @@ -265,6 +264,7 @@ struct reply_t gigaset_tab_nocid[] = {EV_SHUTDOWN, -1, -1, -1, -1,-1, {ACT_SHUTDOWN}}, //FIXME /* misc. */ + {RSP_ERROR, -1, -1, -1, -1, -1, {ACT_ERROR} }, {RSP_EMPTY, -1, -1, -1, -1,-1, {ACT_DEBUG}}, //FIXME {RSP_ZCFGT, -1, -1, -1, -1,-1, {ACT_DEBUG}}, //FIXME {RSP_ZCFG, -1, -1, -1, -1,-1, {ACT_DEBUG}}, //FIXME @@ -328,10 +328,9 @@ struct reply_t gigaset_tab_cid[] = {RSP_INIT, -1, -1,SEQ_HUP, 401, 5, {0}, "+VLS=0\r"}, /* hang up */ //-1,-1? {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}}, /* if not remote hup */ - //{RSP_ZSAU, 403,403,ZSAU_NULL, 401, 0, {ACT_ERROR}}, //DELETE//FIXME -> DLE0 // should we do this _before_ hanging up for base driver? - {RSP_ZSAU, 403,403,ZSAU_NULL, 0, 0, {ACT_DISCONNECT}}, //FIXME -> DLE0 // should we do this _before_ hanging up for base driver? - {RSP_NODEV, 401,403, -1, 0, 0, {ACT_FAKEHUP}}, //FIXME -> DLE0 // should we do this _before_ hanging up for base driver? + {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}}, @@ -474,8 +473,13 @@ static int cid_of_response(char *s) //FIXME is ;<digit>+ at end of non-CID response really impossible? } -/* This function will be called via task queue from the callback handler. - * We received a modem response and have to handle it.. +/** + * gigaset_handle_modem_response() - process received modem response + * @cs: device descriptor structure. + * + * Called by asyncdata/isocdata if a block of data received from the + * device must be processed as a modem command response. The data is + * already in the cs structure. */ void gigaset_handle_modem_response(struct cardstate *cs) { @@ -707,6 +711,11 @@ static void disconnect(struct at_state_t **at_state_p) if (bcs) { /* B channel assigned: invoke hardware specific handler */ cs->ops->close_bchannel(bcs); + /* notify LL */ + if (bcs->chstate & (CHS_D_UP | CHS_NOTIFY_LL)) { + bcs->chstate &= ~(CHS_D_UP | CHS_NOTIFY_LL); + gigaset_i4l_channel_cmd(bcs, ISDN_STAT_DHUP); + } } else { /* no B channel assigned: just deallocate */ spin_lock_irqsave(&cs->lock, flags); @@ -1429,11 +1438,12 @@ static void do_action(int action, struct cardstate *cs, cs->gotfwver = -1; dev_err(cs->dev, "could not read firmware version.\n"); break; -#ifdef CONFIG_GIGASET_DEBUG case ACT_ERROR: - *p_genresp = 1; - *p_resp_code = RSP_ERROR; + gig_dbg(DEBUG_ANY, "%s: ERROR response in ConState %d", + __func__, at_state->ConState); + cs->cur_at_seq = SEQ_NONE; break; +#ifdef CONFIG_GIGASET_DEBUG case ACT_TEST: { static int count = 3; //2; //1; diff --git a/drivers/isdn/gigaset/i4l.c b/drivers/isdn/gigaset/i4l.c index 9b22f9cf2f3..654489d836c 100644 --- a/drivers/isdn/gigaset/i4l.c +++ b/drivers/isdn/gigaset/i4l.c @@ -51,6 +51,12 @@ static int writebuf_from_LL(int driverID, int channel, int ack, return -ENODEV; } bcs = &cs->bcs[channel]; + + /* can only handle linear sk_buffs */ + if (skb_linearize(skb) < 0) { + dev_err(cs->dev, "%s: skb_linearize failed\n", __func__); + return -ENOMEM; + } len = skb->len; gig_dbg(DEBUG_LLDATA, @@ -79,6 +85,14 @@ static int writebuf_from_LL(int driverID, int channel, int ack, return cs->ops->send_skb(bcs, skb); } +/** + * gigaset_skb_sent() - acknowledge sending an skb + * @bcs: B channel descriptor structure. + * @skb: sent data. + * + * Called by hardware module {bas,ser,usb}_gigaset when the data in a + * skb has been successfully sent, for signalling completion to the LL. + */ void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb) { unsigned len; @@ -455,6 +469,15 @@ int gigaset_isdn_setup_accept(struct at_state_t *at_state) return 0; } +/** + * gigaset_isdn_icall() - signal incoming call + * @at_state: connection state structure. + * + * Called by main module to notify the LL that an incoming call has been + * received. @at_state contains the parameters of the call. + * + * Return value: call disposition (ICALL_*) + */ int gigaset_isdn_icall(struct at_state_t *at_state) { struct cardstate *cs = at_state->cs; diff --git a/drivers/isdn/gigaset/interface.c b/drivers/isdn/gigaset/interface.c index f33ac27de64..6a8e1384e7b 100644 --- a/drivers/isdn/gigaset/interface.c +++ b/drivers/isdn/gigaset/interface.c @@ -616,6 +616,15 @@ void gigaset_if_free(struct cardstate *cs) tty_unregister_device(drv->tty, cs->minor_index); } +/** + * gigaset_if_receive() - pass a received block of data to the tty device + * @cs: device descriptor structure. + * @buffer: received data. + * @len: number of bytes received. + * + * Called by asyncdata/isocdata if a block of data received from the + * device must be sent to userspace through the ttyG* device. + */ void gigaset_if_receive(struct cardstate *cs, unsigned char *buffer, size_t len) { diff --git a/drivers/isdn/gigaset/isocdata.c b/drivers/isdn/gigaset/isocdata.c index bed38fcc432..9f3ef7b4248 100644 --- a/drivers/isdn/gigaset/isocdata.c +++ b/drivers/isdn/gigaset/isocdata.c @@ -429,7 +429,7 @@ static inline int hdlc_buildframe(struct isowbuf_t *iwb, return -EAGAIN; } - dump_bytes(DEBUG_STREAM, "snd data", in, count); + dump_bytes(DEBUG_STREAM_DUMP, "snd data", in, count); /* bitstuff and checksum input data */ fcs = PPP_INITFCS; @@ -448,7 +448,6 @@ static inline int hdlc_buildframe(struct isowbuf_t *iwb, /* put closing flag and repeat byte for flag idle */ isowbuf_putflag(iwb); end = isowbuf_donewrite(iwb); - dump_bytes(DEBUG_STREAM_DUMP, "isowbuf", iwb->data, end + 1); return end; } @@ -482,6 +481,8 @@ static inline int trans_buildframe(struct isowbuf_t *iwb, } gig_dbg(DEBUG_STREAM, "put %d bytes", count); + dump_bytes(DEBUG_STREAM_DUMP, "snd data", in, count); + write = iwb->write; do { c = bitrev8(*in++); @@ -583,7 +584,7 @@ static inline void hdlc_done(struct bc_state *bcs) procskb->tail -= 2; gig_dbg(DEBUG_ISO, "%s: good frame (%d octets)", __func__, procskb->len); - dump_bytes(DEBUG_STREAM, + dump_bytes(DEBUG_STREAM_DUMP, "rcv data", procskb->data, procskb->len); bcs->hw.bas->goodbytes += procskb->len; gigaset_rcv_skb(procskb, bcs->cs, bcs); @@ -878,6 +879,8 @@ static inline void trans_receive(unsigned char *src, unsigned count, dobytes--; } if (dobytes == 0) { + dump_bytes(DEBUG_STREAM_DUMP, + "rcv data", skb->data, skb->len); gigaset_rcv_skb(skb, bcs->cs, bcs); bcs->skb = skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN); if (!skb) { @@ -973,16 +976,17 @@ void gigaset_isoc_input(struct inbuf_t *inbuf) /* == data output ========================================================== */ -/* gigaset_send_skb - * called by common.c to queue an skb for sending - * and start transmission if necessary - * parameters: - * B Channel control structure - * skb - * return value: - * number of bytes accepted for sending - * (skb->len if ok, 0 if out of buffer space) - * or error code (< 0, eg. -EINVAL) +/** + * gigaset_isoc_send_skb() - queue an skb for sending + * @bcs: B channel descriptor structure. + * @skb: data to send. + * + * Called by i4l.c to queue an skb for sending, and start transmission if + * necessary. + * + * Return value: + * number of bytes accepted for sending (skb->len) if ok, + * error code < 0 (eg. -ENODEV) on error */ int gigaset_isoc_send_skb(struct bc_state *bcs, struct sk_buff *skb) { diff --git a/drivers/isdn/hardware/eicon/maintidi.c b/drivers/isdn/hardware/eicon/maintidi.c index 23960cb6eaa..41c26e75645 100644 --- a/drivers/isdn/hardware/eicon/maintidi.c +++ b/drivers/isdn/hardware/eicon/maintidi.c @@ -959,8 +959,9 @@ static int process_idi_event (diva_strace_context_t* pLib, } if (!strncmp("State\\Layer2 No1", path, pVar->path_length)) { char* tmp = &pLib->lines[0].pInterface->Layer2[0]; - dword l2_state; - diva_strace_read_uint (pVar, &l2_state); + dword l2_state; + if (diva_strace_read_uint(pVar, &l2_state)) + return -1; switch (l2_state) { case 0: diff --git a/drivers/isdn/hardware/eicon/message.c b/drivers/isdn/hardware/eicon/message.c index 27d5dd68f4f..ae89fb89da6 100644 --- a/drivers/isdn/hardware/eicon/message.c +++ b/drivers/isdn/hardware/eicon/message.c @@ -2692,7 +2692,7 @@ static byte connect_b3_req(dword Id, word Number, DIVA_CAPI_ADAPTER *a, if (!(fax_control_bits & T30_CONTROL_BIT_MORE_DOCUMENTS) || (fax_feature_bits & T30_FEATURE_BIT_MORE_DOCUMENTS)) { - len = (byte)(&(((T30_INFO *) 0)->universal_6)); + len = offsetof(T30_INFO, universal_6); fax_info_change = false; if (ncpi->length >= 4) { @@ -2754,7 +2754,7 @@ static byte connect_b3_req(dword Id, word Number, DIVA_CAPI_ADAPTER *a, for (i = 0; i < w; i++) ((T30_INFO *)(plci->fax_connect_info_buffer))->station_id[i] = fax_parms[4].info[1+i]; ((T30_INFO *)(plci->fax_connect_info_buffer))->head_line_len = 0; - len = (byte)(((T30_INFO *) 0)->station_id + 20); + len = offsetof(T30_INFO, station_id) + 20; w = fax_parms[5].length; if (w > 20) w = 20; @@ -2788,7 +2788,7 @@ static byte connect_b3_req(dword Id, word Number, DIVA_CAPI_ADAPTER *a, } else { - len = (byte)(&(((T30_INFO *) 0)->universal_6)); + len = offsetof(T30_INFO, universal_6); } fax_info_change = true; @@ -2892,7 +2892,7 @@ static byte connect_b3_res(dword Id, word Number, DIVA_CAPI_ADAPTER *a, && (plci->nsf_control_bits & T30_NSF_CONTROL_BIT_ENABLE_NSF) && (plci->nsf_control_bits & T30_NSF_CONTROL_BIT_NEGOTIATE_RESP)) { - len = ((byte)(((T30_INFO *) 0)->station_id + 20)); + len = offsetof(T30_INFO, station_id) + 20; if (plci->fax_connect_info_length < len) { ((T30_INFO *)(plci->fax_connect_info_buffer))->station_id_len = 0; @@ -3802,7 +3802,7 @@ static byte manufacturer_res(dword Id, word Number, DIVA_CAPI_ADAPTER *a, break; } ncpi = &m_parms[1]; - len = ((byte)(((T30_INFO *) 0)->station_id + 20)); + len = offsetof(T30_INFO, station_id) + 20; if (plci->fax_connect_info_length < len) { ((T30_INFO *)(plci->fax_connect_info_buffer))->station_id_len = 0; @@ -6844,7 +6844,7 @@ static void nl_ind(PLCI *plci) if ((plci->requested_options_conn | plci->requested_options | a->requested_options_table[plci->appl->Id-1]) & ((1L << PRIVATE_FAX_SUB_SEP_PWD) | (1L << PRIVATE_FAX_NONSTANDARD))) { - i = ((word)(((T30_INFO *) 0)->station_id + 20)) + ((T30_INFO *)plci->NL.RBuffer->P)->head_line_len; + i = offsetof(T30_INFO, station_id) + 20 + ((T30_INFO *)plci->NL.RBuffer->P)->head_line_len; while (i < plci->NL.RBuffer->length) plci->ncpi_buffer[++len] = plci->NL.RBuffer->P[i++]; } @@ -7236,7 +7236,7 @@ static void nl_ind(PLCI *plci) { plci->RData[1].P = plci->RData[0].P; plci->RData[1].PLength = plci->RData[0].PLength; - plci->RData[0].P = v120_header_buffer + (-((int) v120_header_buffer) & 3); + plci->RData[0].P = v120_header_buffer + (-((unsigned long)v120_header_buffer) & 3); if ((plci->NL.RBuffer->P[0] & V120_HEADER_EXTEND_BIT) || (plci->NL.RLength == 1)) plci->RData[0].PLength = 1; else @@ -8473,7 +8473,7 @@ static word add_b23(PLCI *plci, API_PARSE *bp) fax_control_bits |= T30_CONTROL_BIT_ACCEPT_SEL_POLLING; } len = nlc[0]; - pos = ((byte)(((T30_INFO *) 0)->station_id + 20)); + pos = offsetof(T30_INFO, station_id) + 20; if (pos < plci->fax_connect_info_length) { for (i = 1 + plci->fax_connect_info_buffer[pos]; i != 0; i--) @@ -8525,7 +8525,7 @@ static word add_b23(PLCI *plci, API_PARSE *bp) } PUT_WORD(&(((T30_INFO *)&nlc[1])->control_bits_low), fax_control_bits); - len = ((byte)(((T30_INFO *) 0)->station_id + 20)); + len = offsetof(T30_INFO, station_id) + 20; for (i = 0; i < len; i++) plci->fax_connect_info_buffer[i] = nlc[1+i]; ((T30_INFO *) plci->fax_connect_info_buffer)->head_line_len = 0; diff --git a/drivers/isdn/hardware/mISDN/Kconfig b/drivers/isdn/hardware/mISDN/Kconfig index bde55d7287f..eadc1cd34a2 100644 --- a/drivers/isdn/hardware/mISDN/Kconfig +++ b/drivers/isdn/hardware/mISDN/Kconfig @@ -78,6 +78,7 @@ config MISDN_NETJET depends on PCI select MISDN_IPAC select ISDN_HDLC + select ISDN_I4L help Enable support for Traverse Technologies NETJet PCI cards. diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c index faed794cf75..a6624ad252c 100644 --- a/drivers/isdn/hardware/mISDN/hfcmulti.c +++ b/drivers/isdn/hardware/mISDN/hfcmulti.c @@ -5481,7 +5481,7 @@ HFCmulti_init(void) if (err) { printk(KERN_ERR "error registering embedded driver: " "%x\n", err); - return -err; + return err; } HFC_cnt++; printk(KERN_INFO "%d devices registered\n", HFC_cnt); diff --git a/drivers/isdn/hisax/amd7930_fn.c b/drivers/isdn/hisax/amd7930_fn.c index bf526a7a63a..d6fdf1f6675 100644 --- a/drivers/isdn/hisax/amd7930_fn.c +++ b/drivers/isdn/hisax/amd7930_fn.c @@ -594,6 +594,7 @@ Amd7930_l1hw(struct PStack *st, int pr, void *arg) if (cs->debug & L1_DEB_WARN) debugl1(cs, "Amd7930: l1hw: l2l1 tx_skb exist this shouldn't happen"); skb_queue_tail(&cs->sq, skb); + spin_unlock_irqrestore(&cs->lock, flags); break; } if (cs->debug & DEB_DLOG_HEX) diff --git a/drivers/isdn/hisax/arcofi.c b/drivers/isdn/hisax/arcofi.c index d30ce5b978c..85a8fd8dd0b 100644 --- a/drivers/isdn/hisax/arcofi.c +++ b/drivers/isdn/hisax/arcofi.c @@ -10,6 +10,7 @@ * */ +#include <linux/sched.h> #include "hisax.h" #include "isdnl1.h" #include "isac.h" diff --git a/drivers/isdn/hisax/diva.c b/drivers/isdn/hisax/diva.c index 018bd293e58..0b0c2e5d806 100644 --- a/drivers/isdn/hisax/diva.c +++ b/drivers/isdn/hisax/diva.c @@ -382,7 +382,7 @@ MemwaitforXFW(struct IsdnCardState *cs, int hscx) { int to = 50; - while ((!(MemReadHSCX(cs, hscx, HSCX_STAR) & 0x44) == 0x40) && to) { + while (((MemReadHSCX(cs, hscx, HSCX_STAR) & 0x44) != 0x40) && to) { udelay(1); to--; } diff --git a/drivers/isdn/hisax/elsa_ser.c b/drivers/isdn/hisax/elsa_ser.c index f181db46439..1657bba7879 100644 --- a/drivers/isdn/hisax/elsa_ser.c +++ b/drivers/isdn/hisax/elsa_ser.c @@ -477,62 +477,62 @@ static void modem_set_init(struct IsdnCardState *cs) { int timeout; -#define RCV_DELAY 20000 +#define RCV_DELAY 20 modem_write_cmd(cs, MInit_1, strlen(MInit_1)); timeout = 1000; while(timeout-- && cs->hw.elsa.transcnt) udelay(1000); debugl1(cs, "msi tout=%d", timeout); - udelay(RCV_DELAY); + mdelay(RCV_DELAY); modem_write_cmd(cs, MInit_2, strlen(MInit_2)); timeout = 1000; while(timeout-- && cs->hw.elsa.transcnt) udelay(1000); debugl1(cs, "msi tout=%d", timeout); - udelay(RCV_DELAY); + mdelay(RCV_DELAY); modem_write_cmd(cs, MInit_3, strlen(MInit_3)); timeout = 1000; while(timeout-- && cs->hw.elsa.transcnt) udelay(1000); debugl1(cs, "msi tout=%d", timeout); - udelay(RCV_DELAY); + mdelay(RCV_DELAY); modem_write_cmd(cs, MInit_4, strlen(MInit_4)); timeout = 1000; while(timeout-- && cs->hw.elsa.transcnt) udelay(1000); debugl1(cs, "msi tout=%d", timeout); - udelay(RCV_DELAY ); + mdelay(RCV_DELAY); modem_write_cmd(cs, MInit_5, strlen(MInit_5)); timeout = 1000; while(timeout-- && cs->hw.elsa.transcnt) udelay(1000); debugl1(cs, "msi tout=%d", timeout); - udelay(RCV_DELAY); + mdelay(RCV_DELAY); modem_write_cmd(cs, MInit_6, strlen(MInit_6)); timeout = 1000; while(timeout-- && cs->hw.elsa.transcnt) udelay(1000); debugl1(cs, "msi tout=%d", timeout); - udelay(RCV_DELAY); + mdelay(RCV_DELAY); modem_write_cmd(cs, MInit_7, strlen(MInit_7)); timeout = 1000; while(timeout-- && cs->hw.elsa.transcnt) udelay(1000); debugl1(cs, "msi tout=%d", timeout); - udelay(RCV_DELAY); + mdelay(RCV_DELAY); } static void modem_set_dial(struct IsdnCardState *cs, int outgoing) { int timeout; -#define RCV_DELAY 20000 +#define RCV_DELAY 20 modem_write_cmd(cs, MInit_speed28800, strlen(MInit_speed28800)); timeout = 1000; while(timeout-- && cs->hw.elsa.transcnt) udelay(1000); debugl1(cs, "msi tout=%d", timeout); - udelay(RCV_DELAY); + mdelay(RCV_DELAY); if (outgoing) modem_write_cmd(cs, MInit_dialout, strlen(MInit_dialout)); else @@ -541,7 +541,7 @@ modem_set_dial(struct IsdnCardState *cs, int outgoing) { while(timeout-- && cs->hw.elsa.transcnt) udelay(1000); debugl1(cs, "msi tout=%d", timeout); - udelay(RCV_DELAY); + mdelay(RCV_DELAY); } static void diff --git a/drivers/isdn/hisax/hfc_2bds0.c b/drivers/isdn/hisax/hfc_2bds0.c index 5c46a7130e0..8d22f50760e 100644 --- a/drivers/isdn/hisax/hfc_2bds0.c +++ b/drivers/isdn/hisax/hfc_2bds0.c @@ -11,6 +11,7 @@ */ #include <linux/init.h> +#include <linux/sched.h> #include "hisax.h" #include "hfc_2bds0.h" #include "isdnl1.h" diff --git a/drivers/isdn/hisax/hfc_pci.c b/drivers/isdn/hisax/hfc_pci.c index d110a77940a..10914731b30 100644 --- a/drivers/isdn/hisax/hfc_pci.c +++ b/drivers/isdn/hisax/hfc_pci.c @@ -20,6 +20,7 @@ #include "hfc_pci.h" #include "isdnl1.h" #include <linux/pci.h> +#include <linux/sched.h> #include <linux/interrupt.h> static const char *hfcpci_revision = "$Revision: 1.48.2.4 $"; diff --git a/drivers/isdn/hisax/hfc_usb.c b/drivers/isdn/hisax/hfc_usb.c index 9de54202c90..a420b64472e 100644 --- a/drivers/isdn/hisax/hfc_usb.c +++ b/drivers/isdn/hisax/hfc_usb.c @@ -817,8 +817,8 @@ collect_rx_frame(usb_fifo * fifo, __u8 * data, int len, int finish) } /* we have a complete hdlc packet */ if (finish) { - if ((!fifo->skbuff->data[fifo->skbuff->len - 1]) - && (fifo->skbuff->len > 3)) { + if (fifo->skbuff->len > 3 && + !fifo->skbuff->data[fifo->skbuff->len - 1]) { if (fifon == HFCUSB_D_RX) { DBG(HFCUSB_DBG_DCHANNEL, diff --git a/drivers/isdn/hisax/hscx_irq.c b/drivers/isdn/hisax/hscx_irq.c index 7b1ad5e4ecd..2387d76c721 100644 --- a/drivers/isdn/hisax/hscx_irq.c +++ b/drivers/isdn/hisax/hscx_irq.c @@ -32,7 +32,7 @@ waitforXFW(struct IsdnCardState *cs, int hscx) { int to = 50; - while ((!(READHSCX(cs, hscx, HSCX_STAR) & 0x44) == 0x40) && to) { + while (((READHSCX(cs, hscx, HSCX_STAR) & 0x44) != 0x40) && to) { udelay(1); to--; } diff --git a/drivers/isdn/hisax/icc.c b/drivers/isdn/hisax/icc.c index 9aba646ba22..c80cbb8a2ef 100644 --- a/drivers/isdn/hisax/icc.c +++ b/drivers/isdn/hisax/icc.c @@ -468,6 +468,7 @@ ICC_l1hw(struct PStack *st, int pr, void *arg) if (cs->debug & L1_DEB_WARN) debugl1(cs, " l2l1 tx_skb exist this shouldn't happen"); skb_queue_tail(&cs->sq, skb); + spin_unlock_irqrestore(&cs->lock, flags); break; } if (cs->debug & DEB_DLOG_HEX) diff --git a/drivers/isdn/hysdn/hysdn_procconf.c b/drivers/isdn/hysdn/hysdn_procconf.c index 8f9f4912de3..90b35e1a4b7 100644 --- a/drivers/isdn/hysdn/hysdn_procconf.c +++ b/drivers/isdn/hysdn/hysdn_procconf.c @@ -11,6 +11,7 @@ * */ +#include <linux/cred.h> #include <linux/module.h> #include <linux/poll.h> #include <linux/proc_fs.h> diff --git a/drivers/isdn/hysdn/hysdn_proclog.c b/drivers/isdn/hysdn/hysdn_proclog.c index 8991d2c8ee4..8bcae28c440 100644 --- a/drivers/isdn/hysdn/hysdn_proclog.c +++ b/drivers/isdn/hysdn/hysdn_proclog.c @@ -13,6 +13,7 @@ #include <linux/module.h> #include <linux/poll.h> #include <linux/proc_fs.h> +#include <linux/sched.h> #include <linux/smp_lock.h> #include "hysdn_defs.h" diff --git a/drivers/isdn/i4l/Kconfig b/drivers/isdn/i4l/Kconfig index dd744ffd240..07c4e49f9e7 100644 --- a/drivers/isdn/i4l/Kconfig +++ b/drivers/isdn/i4l/Kconfig @@ -141,8 +141,7 @@ endmenu endif config ISDN_HDLC - tristate - depends on HISAX_ST5481 + tristate select CRC_CCITT select BITREVERSE diff --git a/drivers/isdn/i4l/isdn_net.h b/drivers/isdn/i4l/isdn_net.h index 74032d0881e..7511f08effa 100644 --- a/drivers/isdn/i4l/isdn_net.h +++ b/drivers/isdn/i4l/isdn_net.h @@ -83,19 +83,19 @@ static __inline__ isdn_net_local * isdn_net_get_locked_lp(isdn_net_dev *nd) spin_lock_irqsave(&nd->queue_lock, flags); lp = nd->queue; /* get lp on top of queue */ - spin_lock(&nd->queue->xmit_lock); while (isdn_net_lp_busy(nd->queue)) { - spin_unlock(&nd->queue->xmit_lock); nd->queue = nd->queue->next; if (nd->queue == lp) { /* not found -- should never happen */ lp = NULL; goto errout; } - spin_lock(&nd->queue->xmit_lock); } lp = nd->queue; nd->queue = nd->queue->next; + spin_unlock_irqrestore(&nd->queue_lock, flags); + spin_lock(&lp->xmit_lock); local_bh_disable(); + return lp; errout: spin_unlock_irqrestore(&nd->queue_lock, flags); return lp; diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c index 2d14b64202a..642d5aaf53c 100644 --- a/drivers/isdn/i4l/isdn_ppp.c +++ b/drivers/isdn/i4l/isdn_ppp.c @@ -1535,10 +1535,8 @@ static int isdn_ppp_mp_bundle_array_init(void) int sz = ISDN_MAX_CHANNELS*sizeof(ippp_bundle); if( (isdn_ppp_bundle_arr = kzalloc(sz, GFP_KERNEL)) == NULL ) return -ENOMEM; - for (i = 0; i < ISDN_MAX_CHANNELS; i++) { + for( i = 0; i < ISDN_MAX_CHANNELS; i++ ) spin_lock_init(&isdn_ppp_bundle_arr[i].lock); - skb_queue_head_init(&isdn_ppp_bundle_arr[i].frags); - } return 0; } @@ -1571,7 +1569,7 @@ static int isdn_ppp_mp_init( isdn_net_local * lp, ippp_bundle * add_to ) if ((lp->netdev->pb = isdn_ppp_mp_bundle_alloc()) == NULL) return -ENOMEM; lp->next = lp->last = lp; /* nobody else in a queue */ - skb_queue_head_init(&lp->netdev->pb->frags); + lp->netdev->pb->frags = NULL; lp->netdev->pb->frames = 0; lp->netdev->pb->seq = UINT_MAX; } @@ -1583,29 +1581,28 @@ static int isdn_ppp_mp_init( isdn_net_local * lp, ippp_bundle * add_to ) static u32 isdn_ppp_mp_get_seq( int short_seq, struct sk_buff * skb, u32 last_seq ); -static void isdn_ppp_mp_discard(ippp_bundle *mp, struct sk_buff *from, - struct sk_buff *to); -static void isdn_ppp_mp_reassembly(isdn_net_dev *net_dev, isdn_net_local *lp, - struct sk_buff *from, struct sk_buff *to, - u32 lastseq); -static void isdn_ppp_mp_free_skb(ippp_bundle *mp, struct sk_buff *skb); +static struct sk_buff * isdn_ppp_mp_discard( ippp_bundle * mp, + struct sk_buff * from, struct sk_buff * to ); +static void isdn_ppp_mp_reassembly( isdn_net_dev * net_dev, isdn_net_local * lp, + struct sk_buff * from, struct sk_buff * to ); +static void isdn_ppp_mp_free_skb( ippp_bundle * mp, struct sk_buff * skb ); static void isdn_ppp_mp_print_recv_pkt( int slot, struct sk_buff * skb ); static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, - struct sk_buff *skb) + struct sk_buff *skb) { - struct sk_buff *newfrag, *frag, *start, *nextf; - u32 newseq, minseq, thisseq; - isdn_mppp_stats *stats; struct ippp_struct *is; + isdn_net_local * lpq; + ippp_bundle * mp; + isdn_mppp_stats * stats; + struct sk_buff * newfrag, * frag, * start, *nextf; + u32 newseq, minseq, thisseq; unsigned long flags; - isdn_net_local *lpq; - ippp_bundle *mp; int slot; spin_lock_irqsave(&net_dev->pb->lock, flags); - mp = net_dev->pb; - stats = &mp->stats; + mp = net_dev->pb; + stats = &mp->stats; slot = lp->ppp_slot; if (slot < 0 || slot >= ISDN_MAX_CHANNELS) { printk(KERN_ERR "%s: lp->ppp_slot(%d)\n", @@ -1616,19 +1613,20 @@ static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, return; } is = ippp_table[slot]; - if (++mp->frames > stats->max_queue_len) + if( ++mp->frames > stats->max_queue_len ) stats->max_queue_len = mp->frames; - + if (is->debug & 0x8) isdn_ppp_mp_print_recv_pkt(lp->ppp_slot, skb); - newseq = isdn_ppp_mp_get_seq(is->mpppcfg & SC_IN_SHORT_SEQ, - skb, is->last_link_seqno); + newseq = isdn_ppp_mp_get_seq(is->mpppcfg & SC_IN_SHORT_SEQ, + skb, is->last_link_seqno); + /* if this packet seq # is less than last already processed one, * toss it right away, but check for sequence start case first */ - if (mp->seq > MP_LONGSEQ_MAX && (newseq & MP_LONGSEQ_MAXBIT)) { + if( mp->seq > MP_LONGSEQ_MAX && (newseq & MP_LONGSEQ_MAXBIT) ) { mp->seq = newseq; /* the first packet: required for * rfc1990 non-compliant clients -- * prevents constant packet toss */ @@ -1638,7 +1636,7 @@ static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, spin_unlock_irqrestore(&mp->lock, flags); return; } - + /* find the minimum received sequence number over all links */ is->last_link_seqno = minseq = newseq; for (lpq = net_dev->queue;;) { @@ -1659,31 +1657,22 @@ static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, * packets */ newfrag = skb; - /* Insert new fragment into the proper sequence slot. */ - skb_queue_walk(&mp->frags, frag) { - if (MP_SEQ(frag) == newseq) { - isdn_ppp_mp_free_skb(mp, newfrag); - newfrag = NULL; - break; - } - if (MP_LT(newseq, MP_SEQ(frag))) { - __skb_queue_before(&mp->frags, frag, newfrag); - newfrag = NULL; - break; - } - } - if (newfrag) - __skb_queue_tail(&mp->frags, newfrag); + /* if this new fragment is before the first one, then enqueue it now. */ + if ((frag = mp->frags) == NULL || MP_LT(newseq, MP_SEQ(frag))) { + newfrag->next = frag; + mp->frags = frag = newfrag; + newfrag = NULL; + } - frag = skb_peek(&mp->frags); - start = ((MP_FLAGS(frag) & MP_BEGIN_FRAG) && - (MP_SEQ(frag) == mp->seq)) ? frag : NULL; - if (!start) - goto check_overflow; + start = MP_FLAGS(frag) & MP_BEGIN_FRAG && + MP_SEQ(frag) == mp->seq ? frag : NULL; - /* main fragment traversing loop + /* + * main fragment traversing loop * * try to accomplish several tasks: + * - insert new fragment into the proper sequence slot (once that's done + * newfrag will be set to NULL) * - reassemble any complete fragment sequence (non-null 'start' * indicates there is a continguous sequence present) * - discard any incomplete sequences that are below minseq -- due @@ -1692,46 +1681,71 @@ static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, * come to complete such sequence and it should be discarded * * loop completes when we accomplished the following tasks: + * - new fragment is inserted in the proper sequence ('newfrag' is + * set to NULL) * - we hit a gap in the sequence, so no reassembly/processing is * possible ('start' would be set to NULL) * * algorithm for this code is derived from code in the book * 'PPP Design And Debugging' by James Carlson (Addison-Wesley) */ - skb_queue_walk_safe(&mp->frags, frag, nextf) { - thisseq = MP_SEQ(frag); - - /* check for misplaced start */ - if (start != frag && (MP_FLAGS(frag) & MP_BEGIN_FRAG)) { - printk(KERN_WARNING"isdn_mppp(seq %d): new " - "BEGIN flag with no prior END", thisseq); - stats->seqerrs++; - stats->frame_drops++; - isdn_ppp_mp_discard(mp, start, frag); - start = frag; - } else if (MP_LE(thisseq, minseq)) { - if (MP_FLAGS(frag) & MP_BEGIN_FRAG) + while (start != NULL || newfrag != NULL) { + + thisseq = MP_SEQ(frag); + nextf = frag->next; + + /* drop any duplicate fragments */ + if (newfrag != NULL && thisseq == newseq) { + isdn_ppp_mp_free_skb(mp, newfrag); + newfrag = NULL; + } + + /* insert new fragment before next element if possible. */ + if (newfrag != NULL && (nextf == NULL || + MP_LT(newseq, MP_SEQ(nextf)))) { + newfrag->next = nextf; + frag->next = nextf = newfrag; + newfrag = NULL; + } + + if (start != NULL) { + /* check for misplaced start */ + if (start != frag && (MP_FLAGS(frag) & MP_BEGIN_FRAG)) { + printk(KERN_WARNING"isdn_mppp(seq %d): new " + "BEGIN flag with no prior END", thisseq); + stats->seqerrs++; + stats->frame_drops++; + start = isdn_ppp_mp_discard(mp, start,frag); + nextf = frag->next; + } + } else if (MP_LE(thisseq, minseq)) { + if (MP_FLAGS(frag) & MP_BEGIN_FRAG) start = frag; - else { + else { if (MP_FLAGS(frag) & MP_END_FRAG) - stats->frame_drops++; - __skb_unlink(skb, &mp->frags); + stats->frame_drops++; + if( mp->frags == frag ) + mp->frags = nextf; isdn_ppp_mp_free_skb(mp, frag); + frag = nextf; continue; - } + } } - - /* if we have end fragment, then we have full reassembly - * sequence -- reassemble and process packet now + + /* if start is non-null and we have end fragment, then + * we have full reassembly sequence -- reassemble + * and process packet now */ - if (MP_FLAGS(frag) & MP_END_FRAG) { - minseq = mp->seq = (thisseq+1) & MP_LONGSEQ_MASK; - /* Reassemble the packet then dispatch it */ - isdn_ppp_mp_reassembly(net_dev, lp, start, frag, thisseq); + if (start != NULL && (MP_FLAGS(frag) & MP_END_FRAG)) { + minseq = mp->seq = (thisseq+1) & MP_LONGSEQ_MASK; + /* Reassemble the packet then dispatch it */ + isdn_ppp_mp_reassembly(net_dev, lp, start, nextf); + + start = NULL; + frag = NULL; - start = NULL; - frag = NULL; - } + mp->frags = nextf; + } /* check if need to update start pointer: if we just * reassembled the packet and sequence is contiguous @@ -1742,25 +1756,26 @@ static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, * below low watermark and set start to the next frag or * clear start ptr. */ - if (nextf != (struct sk_buff *)&mp->frags && + if (nextf != NULL && ((thisseq+1) & MP_LONGSEQ_MASK) == MP_SEQ(nextf)) { - /* if we just reassembled and the next one is here, - * then start another reassembly. - */ - if (frag == NULL) { + /* if we just reassembled and the next one is here, + * then start another reassembly. */ + + if (frag == NULL) { if (MP_FLAGS(nextf) & MP_BEGIN_FRAG) - start = nextf; - else { - printk(KERN_WARNING"isdn_mppp(seq %d):" - " END flag with no following " - "BEGIN", thisseq); + start = nextf; + else + { + printk(KERN_WARNING"isdn_mppp(seq %d):" + " END flag with no following " + "BEGIN", thisseq); stats->seqerrs++; } } - } else { - if (nextf != (struct sk_buff *)&mp->frags && - frag != NULL && - MP_LT(thisseq, minseq)) { + + } else { + if ( nextf != NULL && frag != NULL && + MP_LT(thisseq, minseq)) { /* we've got a break in the sequence * and we not at the end yet * and we did not just reassembled @@ -1769,39 +1784,41 @@ static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, * discard all the frames below low watermark * and start over */ stats->frame_drops++; - isdn_ppp_mp_discard(mp, start, nextf); + mp->frags = isdn_ppp_mp_discard(mp,start,nextf); } /* break in the sequence, no reassembly */ - start = NULL; - } - if (!start) - break; - } - -check_overflow: + start = NULL; + } + + frag = nextf; + } /* while -- main loop */ + + if (mp->frags == NULL) + mp->frags = frag; + /* rather straighforward way to deal with (not very) possible - * queue overflow - */ + * queue overflow */ if (mp->frames > MP_MAX_QUEUE_LEN) { stats->overflows++; - skb_queue_walk_safe(&mp->frags, frag, nextf) { - if (mp->frames <= MP_MAX_QUEUE_LEN) - break; - __skb_unlink(frag, &mp->frags); - isdn_ppp_mp_free_skb(mp, frag); + while (mp->frames > MP_MAX_QUEUE_LEN) { + frag = mp->frags->next; + isdn_ppp_mp_free_skb(mp, mp->frags); + mp->frags = frag; } } spin_unlock_irqrestore(&mp->lock, flags); } -static void isdn_ppp_mp_cleanup(isdn_net_local *lp) +static void isdn_ppp_mp_cleanup( isdn_net_local * lp ) { - struct sk_buff *skb, *tmp; - - skb_queue_walk_safe(&lp->netdev->pb->frags, skb, tmp) { - __skb_unlink(skb, &lp->netdev->pb->frags); - isdn_ppp_mp_free_skb(lp->netdev->pb, skb); - } + struct sk_buff * frag = lp->netdev->pb->frags; + struct sk_buff * nextfrag; + while( frag ) { + nextfrag = frag->next; + isdn_ppp_mp_free_skb(lp->netdev->pb, frag); + frag = nextfrag; + } + lp->netdev->pb->frags = NULL; } static u32 isdn_ppp_mp_get_seq( int short_seq, @@ -1838,115 +1855,72 @@ static u32 isdn_ppp_mp_get_seq( int short_seq, return seq; } -static void isdn_ppp_mp_discard(ippp_bundle *mp, struct sk_buff *from, - struct sk_buff *to) +struct sk_buff * isdn_ppp_mp_discard( ippp_bundle * mp, + struct sk_buff * from, struct sk_buff * to ) { - if (from) { - struct sk_buff *skb, *tmp; - int freeing = 0; - - skb_queue_walk_safe(&mp->frags, skb, tmp) { - if (skb == to) - break; - if (skb == from) - freeing = 1; - if (!freeing) - continue; - __skb_unlink(skb, &mp->frags); - isdn_ppp_mp_free_skb(mp, skb); + if( from ) + while (from != to) { + struct sk_buff * next = from->next; + isdn_ppp_mp_free_skb(mp, from); + from = next; } - } -} - -static unsigned int calc_tot_len(struct sk_buff_head *queue, - struct sk_buff *from, struct sk_buff *to) -{ - unsigned int tot_len = 0; - struct sk_buff *skb; - int found_start = 0; - - skb_queue_walk(queue, skb) { - if (skb == from) - found_start = 1; - if (!found_start) - continue; - tot_len += skb->len - MP_HEADER_LEN; - if (skb == to) - break; - } - return tot_len; + return from; } -/* Reassemble packet using fragments in the reassembly queue from - * 'from' until 'to', inclusive. - */ -static void isdn_ppp_mp_reassembly(isdn_net_dev *net_dev, isdn_net_local *lp, - struct sk_buff *from, struct sk_buff *to, - u32 lastseq) +void isdn_ppp_mp_reassembly( isdn_net_dev * net_dev, isdn_net_local * lp, + struct sk_buff * from, struct sk_buff * to ) { - ippp_bundle *mp = net_dev->pb; - unsigned int tot_len; - struct sk_buff *skb; + ippp_bundle * mp = net_dev->pb; int proto; + struct sk_buff * skb; + unsigned int tot_len; if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) { printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n", __func__, lp->ppp_slot); return; } - - tot_len = calc_tot_len(&mp->frags, from, to); - - if (MP_FLAGS(from) == (MP_BEGIN_FRAG | MP_END_FRAG)) { - if (ippp_table[lp->ppp_slot]->debug & 0x40) + if( MP_FLAGS(from) == (MP_BEGIN_FRAG | MP_END_FRAG) ) { + if( ippp_table[lp->ppp_slot]->debug & 0x40 ) printk(KERN_DEBUG "isdn_mppp: reassembly: frame %d, " - "len %d\n", MP_SEQ(from), from->len); + "len %d\n", MP_SEQ(from), from->len ); skb = from; skb_pull(skb, MP_HEADER_LEN); - __skb_unlink(skb, &mp->frags); mp->frames--; } else { - struct sk_buff *walk, *tmp; - int found_start = 0; + struct sk_buff * frag; + int n; - if (ippp_table[lp->ppp_slot]->debug & 0x40) - printk(KERN_DEBUG"isdn_mppp: reassembling frames %d " - "to %d, len %d\n", MP_SEQ(from), lastseq, - tot_len); + for(tot_len=n=0, frag=from; frag != to; frag=frag->next, n++) + tot_len += frag->len - MP_HEADER_LEN; - skb = dev_alloc_skb(tot_len); - if (!skb) + if( ippp_table[lp->ppp_slot]->debug & 0x40 ) + printk(KERN_DEBUG"isdn_mppp: reassembling frames %d " + "to %d, len %d\n", MP_SEQ(from), + (MP_SEQ(from)+n-1) & MP_LONGSEQ_MASK, tot_len ); + if( (skb = dev_alloc_skb(tot_len)) == NULL ) { printk(KERN_ERR "isdn_mppp: cannot allocate sk buff " - "of size %d\n", tot_len); - - found_start = 0; - skb_queue_walk_safe(&mp->frags, walk, tmp) { - if (walk == from) - found_start = 1; - if (!found_start) - continue; + "of size %d\n", tot_len); + isdn_ppp_mp_discard(mp, from, to); + return; + } - if (skb) { - unsigned int len = walk->len - MP_HEADER_LEN; - skb_copy_from_linear_data_offset(walk, MP_HEADER_LEN, - skb_put(skb, len), - len); - } - __skb_unlink(walk, &mp->frags); - isdn_ppp_mp_free_skb(mp, walk); + while( from != to ) { + unsigned int len = from->len - MP_HEADER_LEN; - if (walk == to) - break; + skb_copy_from_linear_data_offset(from, MP_HEADER_LEN, + skb_put(skb,len), + len); + frag = from->next; + isdn_ppp_mp_free_skb(mp, from); + from = frag; } } - if (!skb) - return; - proto = isdn_ppp_strip_proto(skb); isdn_ppp_push_higher(net_dev, lp, skb, proto); } -static void isdn_ppp_mp_free_skb(ippp_bundle *mp, struct sk_buff *skb) +static void isdn_ppp_mp_free_skb(ippp_bundle * mp, struct sk_buff * skb) { dev_kfree_skb(skb); mp->frames--; diff --git a/drivers/isdn/mISDN/socket.c b/drivers/isdn/mISDN/socket.c index c36f5213745..feb0fa45b66 100644 --- a/drivers/isdn/mISDN/socket.c +++ b/drivers/isdn/mISDN/socket.c @@ -415,7 +415,7 @@ data_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) } static int data_sock_setsockopt(struct socket *sock, int level, int optname, - char __user *optval, int len) + char __user *optval, unsigned int len) { struct sock *sk = sock->sk; int err = 0, opt = 0; diff --git a/drivers/isdn/mISDN/stack.c b/drivers/isdn/mISDN/stack.c index 3e1532a180f..0d05ec43012 100644 --- a/drivers/isdn/mISDN/stack.c +++ b/drivers/isdn/mISDN/stack.c @@ -364,7 +364,7 @@ add_layer2(struct mISDNchannel *ch, struct mISDNstack *st) static int st_own_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg) { - if (!ch->st || ch->st->layer1) + if (!ch->st || !ch->st->layer1) return -EINVAL; return ch->st->layer1->ctrl(ch->st->layer1, cmd, arg); } diff --git a/drivers/isdn/pcbit/drv.c b/drivers/isdn/pcbit/drv.c index 8c66bcb953a..123c1d6c43b 100644 --- a/drivers/isdn/pcbit/drv.c +++ b/drivers/isdn/pcbit/drv.c @@ -23,6 +23,7 @@ #include <linux/kernel.h> #include <linux/types.h> +#include <linux/sched.h> #include <linux/slab.h> #include <linux/mm.h> #include <linux/interrupt.h> diff --git a/drivers/isdn/pcbit/layer2.c b/drivers/isdn/pcbit/layer2.c index e075e8d2fce..30f0f45e313 100644 --- a/drivers/isdn/pcbit/layer2.c +++ b/drivers/isdn/pcbit/layer2.c @@ -27,6 +27,7 @@ #include <linux/string.h> #include <linux/kernel.h> #include <linux/types.h> +#include <linux/sched.h> #include <linux/slab.h> #include <linux/interrupt.h> #include <linux/workqueue.h> diff --git a/drivers/isdn/sc/init.c b/drivers/isdn/sc/init.c index dd0acd06750..5a0774880d5 100644 --- a/drivers/isdn/sc/init.c +++ b/drivers/isdn/sc/init.c @@ -8,6 +8,7 @@ #include <linux/init.h> #include <linux/interrupt.h> #include <linux/delay.h> +#include <linux/sched.h> #include "includes.h" #include "hardware.h" #include "card.h" |