Skip to contentSkip to conversation

Gigaset driver port to CAPI

RFC PATCH In review Tilman Schmidt 2 participants 8 messages Aug 21, 2009 – Aug 24, 2009

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

cover Gigaset driver port to CAPI

Folks,

the following set of six patches adds a configuration option to the Gigaset driver to interface to Kernel CAPI instead of the old ISDN4Linux subsystem. Although my unit test are not quite done yet I would appreciate comments.

The patchset is based on 2.6.31-rc6. The first two patches are bugfixes to the existing driver, the third one adds kerneldoc comments for a few functions. These three are included just so that the following ones will apply cleanly, although you are welcome to comment on them, too.

Patch 4 reorganizes the existing driver's code so that the new interface can be fitted in.

Patch 5 adds the Kconfig mechanism for making the ISDN subsystem interface selectable.

Patch 6 finally adds the actual Kernel CAPI interface, and is of course the one I am most eager to hear opinions about.

Thanks,
Tilman

#1 lore raw

RFC PATCH 1/6 gigaset: fix reject/hangup handling

Signal D channel disconnect in a few cases where it was missed, including when an incoming call is disconnected before it was accepted.

Impact: error handling improvement

---
 drivers/isdn/gigaset/ev-layer.c |   5 +++++
 1 file changed, 5 insertions(+)
drivers/isdn/gigaset/ev-layer.c +5 -0
index 2d91049..31082a6 100644
@@ -707,6 +707,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);
Signature · 1 line
1.6.2.1.214.ge986c
#2 lore raw

RFC PATCH 2/6 gigaset: handle isoc frame errors more gracefully

In reply to Tilman Schmidt

Don't drop the remainder of an URB if an isochronous frame has an error.

Impact: error handling improvement

---
 drivers/isdn/gigaset/bas-gigaset.c |   18 +++++++-----------
 1 files changed, 7 insertions(+), 11 deletions(-)
drivers/isdn/gigaset/bas-gigaset.c +7 -11
index 781c404..9e7108a 100644
@@ -1331,28 +1331,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 +1357,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;
Signature · 1 line
1.6.2.1.214.ge986c
#3 lore raw

RFC PATCH 3/6 gigaset: add kerneldoc comments

In reply to Tilman Schmidt

Add kerneldoc comments to some functions in the Gigaset driver.

Impact: documentation

---
 drivers/isdn/gigaset/asyncdata.c |   23 +++++--
 drivers/isdn/gigaset/common.c    |  126 +++++++++++++++++++++++++++++++-------
 drivers/isdn/gigaset/ev-layer.c  |    9 ++-
 drivers/isdn/gigaset/i4l.c       |   17 +++++
 drivers/isdn/gigaset/interface.c |    9 +++
 5 files changed, 153 insertions(+), 31 deletions(-)
drivers/isdn/gigaset/asyncdata.c +16 -7
index 234cc5d..30f1951 100644
@@ -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,12 +550,14 @@ 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_send_skb() - queue an skb for sending
+ * @bcs:	B channel descriptor structure.
+ * @skb:	data to send.
+ *
+ * Called by common.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)
drivers/isdn/gigaset/common.c +104 -22

196 lines not on this page · raw message

drivers/isdn/gigaset/ev-layer.c +7 -2
index 31082a6..7258b25 100644
@@ -474,8 +474,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)
 {
drivers/isdn/gigaset/i4l.c +17 -0
index 7b88130..8c99578 100644
@@ -79,6 +79,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 +463,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;
drivers/isdn/gigaset/interface.c +9 -0
index f33ac27..6a8e138 100644
@@ -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)
 {
Signature · 1 line
1.6.2.1.214.ge986c
#4 lore raw

RFC PATCH 4/6 gigaset: prepare for CAPI implementation

In reply to Tilman Schmidt

Move all isdn4linux dependencies to i4l.c so that we can develop a replacement file capi.c interfacing to Kernel CAPI instead.

Impact: refactoring, no functional change

---
 drivers/isdn/gigaset/asyncdata.c   |  116 ++++-----
 drivers/isdn/gigaset/bas-gigaset.c |    4 +-
 drivers/isdn/gigaset/common.c      |   50 ++--
 drivers/isdn/gigaset/ev-layer.c    |   63 +++--
 drivers/isdn/gigaset/gigaset.h     |   90 ++-----
 drivers/isdn/gigaset/i4l.c         |  499 +++++++++++++++++++++---------------
 drivers/isdn/gigaset/isocdata.c    |   99 ++++----
 7 files changed, 489 insertions(+), 432 deletions(-)
drivers/isdn/gigaset/asyncdata.c +52 -64
index 30f1951..5cadbd2 100644
@@ -119,8 +119,6 @@ static inline int hdlc_loop(unsigned char c, unsigned char *src, int numbytes,
 	int inputstate = bcs->inputstate;
 	__u16 fcs = bcs->fcs;
 	struct sk_buff *skb = bcs->skb;
-	unsigned char error;
-	struct sk_buff *compskb;
 	int startbytes = numbytes;
 	int l;
 
@@ -158,8 +156,8 @@ byte_stuff:
 #endif
 
 				/* end of frame */
-				error = 1;
-				gigaset_rcv_error(NULL, cs, bcs);
+				gigaset_isdn_rcv_err(bcs);
+				dev_kfree_skb(skb);
 			} else if (!(inputstate & INS_have_data)) { /* 7E 7E */
 #ifdef CONFIG_GIGASET_DEBUG
 				++bcs->emptycount;
@@ -170,50 +168,34 @@ byte_stuff:
 					"7e----------------------------");
 
 				/* end of frame */
-				error = 0;
-
 				if (unlikely(fcs != PPP_GOODFCS)) {
 					dev_err(cs->dev,
 				"Checksum failed, %u bytes corrupted!\n",
 						skb->len);
-					compskb = NULL;
-					gigaset_rcv_error(compskb, cs, bcs);
-					error = 1;
+					gigaset_isdn_rcv_err(bcs);
+					dev_kfree_skb(skb);
+				} else if (likely((l = skb->len) > 2)) {
+					__skb_trim(skb, l-2);
+					gigaset_skb_rcvd(bcs, skb);
 				} else {
-					if (likely((l = skb->len) > 2)) {
-						skb->tail -= 2;
-						skb->len -= 2;
-					} else {
-						dev_kfree_skb(skb);
-						skb = NULL;
-						inputstate |= INS_skip_frame;
-						if (l == 1) {
-							dev_err(cs->dev,
-						  "invalid packet size (1)!\n");
-							error = 1;
-							gigaset_rcv_error(NULL,
-								cs, bcs);
-						}
-					}
-					if (likely(!(error ||
-						     (inputstate &
-						      INS_skip_frame)))) {
-						gigaset_rcv_skb(skb, cs, bcs);
+					if (l) {
+						dev_err(cs->dev,
+					"invalid packet size (%d)\n", l);
+						gigaset_isdn_rcv_err(bcs);
 					}
+					dev_kfree_skb(skb);
 				}
 			}
 
-			if (unlikely(error))
-				if (skb)
-					dev_kfree_skb(skb);
-
 			fcs = PPP_INITFCS;
 			inputstate &= ~(INS_have_data | INS_skip_frame);
 			if (unlikely(bcs->ignore)) {
 				inputstate |= INS_skip_frame;
 				skb = NULL;
-			} else if (likely((skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN)) != NULL)) {
-				skb_reserve(skb, HW_HDR_LEN);
+			} else if ((skb =
+				    dev_alloc_skb(SBUFSIZE + cs->hw_hdr_len))
+				   != NULL) {
+				skb_reserve(skb, cs->hw_hdr_len);
 			} else {
 				dev_warn(cs->dev,
 					 "could not allocate new skb\n");
@@ -314,15 +296,15 @@ static inline int iraw_loop(unsigned char c, unsigned char *src, int numbytes,
 	/* pass data up */
 	if (likely(inputstate & INS_have_data)) {
 		if (likely(!(inputstate & INS_skip_frame))) {
-			gigaset_rcv_skb(skb, cs, bcs);
+			gigaset_skb_rcvd(bcs, skb);
 		}
 		inputstate &= ~(INS_have_data | INS_skip_frame);
 		if (unlikely(bcs->ignore)) {
 			inputstate |= INS_skip_frame;
 			skb = NULL;
-		} else if (likely((skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN))
-				  != NULL)) {
-			skb_reserve(skb, HW_HDR_LEN);
+		} else if ((skb = dev_alloc_skb(SBUFSIZE + cs->hw_hdr_len))
+			   != NULL) {
+			skb_reserve(skb, cs->hw_hdr_len);
 		} else {
 			dev_warn(cs->dev, "could not allocate new skb\n");
 			inputstate |= INS_skip_frame;
@@ -383,7 +365,7 @@ void gigaset_m10x_input(struct inbuf_t *inbuf)
 					/* FIXME use function pointers?  */
 					if (inbuf->inputstate & INS_command)
 						procbytes = cmd_loop(c, src, numbytes, inbuf);
-					else if (inbuf->bcs->proto2 == ISDN_PROTO_L2_HDLC)
+					else if (inbuf->bcs->proto2 == L2_HDLC)
 						procbytes = hdlc_loop(c, src, numbytes, inbuf);
 					else
 						procbytes = iraw_loop(c, src, numbytes, inbuf);
@@ -440,16 +422,16 @@ EXPORT_SYMBOL_GPL(gigaset_m10x_input);
 
 /* == data output ========================================================== */
 
-/* Encoding of a PPP packet into an octet stuffed HDLC frame
- * with FCS, opening and closing flags.
+/*
+ * Encode a data packet into an octet stuffed HDLC frame with FCS,
+ * opening and closing flags, preserving headroom data.
  * parameters:
- *	skb	skb containing original packet (freed upon return)
- *	head	number of headroom bytes to allocate in result skb
- *	tail	number of tailroom bytes to allocate in result skb
+ *	skb		skb containing original packet (freed upon return)
+ *	headroom	number of headroom bytes to preserve
  * Return value:
  *	pointer to newly allocated skb containing the result frame
  */
-static struct sk_buff *HDLC_Encode(struct sk_buff *skb, int head, int tail)
+static struct sk_buff *HDLC_Encode(struct sk_buff *skb, int headroom)
 {
 	struct sk_buff *hdlc_skb;
 	__u16 fcs;
@@ -471,16 +453,17 @@ static struct sk_buff *HDLC_Encode(struct sk_buff *skb, int head, int tail)
 
 	/* size of new buffer: original size + number of stuffing bytes
 	 * + 2 bytes FCS + 2 stuffing bytes for FCS (if needed) + 2 flag bytes
+	 * + room for acknowledgement header
 	 */
-	hdlc_skb = dev_alloc_skb(skb->len + stuf_cnt + 6 + tail + head);
+	hdlc_skb = dev_alloc_skb(skb->len + stuf_cnt + 6 + headroom);
 	if (!hdlc_skb) {
 		dev_kfree_skb(skb);
 		return NULL;
 	}
-	skb_reserve(hdlc_skb, head);
 
-	/* Copy acknowledge request into new skb */
-	memcpy(hdlc_skb->head, skb->head, 2);
+	/* Copy acknowledgement header into new skb */
+	skb_reserve(hdlc_skb, headroom);
+	memcpy(hdlc_skb->head, skb->head, headroom);
 
 	/* Add flag sequence in front of everything.. */
 	*(skb_put(hdlc_skb, 1)) = PPP_FLAG;
@@ -515,15 +498,16 @@ static struct sk_buff *HDLC_Encode(struct sk_buff *skb, int head, int tail)
 	return hdlc_skb;
 }
 
-/* Encoding of a raw packet into an octet stuffed bit inverted frame
+/*
+ * Encode a data packet into an octet stuffed raw bit inverted frame,
+ * preserving headroom data.
  * parameters:
- *	skb	skb containing original packet (freed upon return)
- *	head	number of headroom bytes to allocate in result skb
- *	tail	number of tailroom bytes to allocate in result skb
+ *	skb		skb containing original packet (freed upon return)
+ *	headroom	number of headroom bytes to preserve
  * Return value:
  *	pointer to newly allocated skb containing the result frame
  */
-static struct sk_buff *iraw_encode(struct sk_buff *skb, int head, int tail)
+static struct sk_buff *iraw_encode(struct sk_buff *skb, int headroom)
 {
 	struct sk_buff *iraw_skb;
 	unsigned char c;
@@ -531,12 +515,15 @@ static struct sk_buff *iraw_encode(struct sk_buff *skb, int head, int tail)
 	int len;
 
 	/* worst case: every byte must be stuffed */
-	iraw_skb = dev_alloc_skb(2*skb->len + tail + head);
+	iraw_skb = dev_alloc_skb(2*skb->len + headroom);
 	if (!iraw_skb) {
 		dev_kfree_skb(skb);
 		return NULL;
 	}
-	skb_reserve(iraw_skb, head);
+
+	/* Copy acknowledgement header into new skb */
+	skb_reserve(iraw_skb, headroom);
+	memcpy(iraw_skb->head, skb->head, headroom);
 
 	cp = skb->data;
 	len = skb->len;
@@ -551,27 +538,28 @@ static struct sk_buff *iraw_encode(struct sk_buff *skb, int head, int tail)
 }
 
 /**
- * gigaset_send_skb() - queue an skb for sending
+ * gigaset_m10x_send_skb() - queue an skb for sending
  * @bcs:	B channel descriptor structure.
  * @skb:	data to send.
  *
- * Called by common.c to encode and queue an skb for sending, and start
+ * Called by LL to encode and queue an skb for sending, and start
  * transmission if necessary.
+ * Once the payload data has been transmitted completely, gigaset_skb_sent()
+ * will be called with the first cs->hw_hdr_len bytes of skb->head preserved.
  *
  * 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)
 {
 	unsigned len = skb->len;
 	unsigned long flags;
 
-	if (bcs->proto2 == ISDN_PROTO_L2_HDLC)
-		skb = HDLC_Encode(skb, HW_HDR_LEN, 0);
+	if (bcs->proto2 == L2_HDLC)
+		skb = HDLC_Encode(skb, bcs->cs->hw_hdr_len);
 	else
-		skb = iraw_encode(skb, HW_HDR_LEN, 0);
+		skb = iraw_encode(skb, bcs->cs->hw_hdr_len);
 	if (!skb) {
 		dev_err(bcs->cs->dev,
 			"unable to allocate memory for encoding!\n");
drivers/isdn/gigaset/bas-gigaset.c +2 -2
index 9e7108a..5e7d264 100644
@@ -907,7 +907,7 @@ static int starturbs(struct bc_state *bcs)
 	int rc;
 
 	/* initialize L2 reception */
-	if (bcs->proto2 == ISDN_PROTO_L2_HDLC)
+	if (bcs->proto2 == L2_HDLC)
 		bcs->inputstate |= INS_flag_hunt;
 
 	/* submit all isochronous input URBs */
@@ -1060,7 +1060,7 @@ static int submit_iso_write_urb(struct isow_urbctx_t *ucx)
 					"%s: buffer busy at frame %d",
 					__func__, nframe);
 				/* tasklet will be restarted from
-				   gigaset_send_skb() */
+				   gigaset_isoc_send_skb() */
 			} else {
 				dev_err(ucx->bcs->cs->dev,
 					"%s: buffer error %d at frame %d\n",
drivers/isdn/gigaset/common.c +29 -21

105 lines not on this page · raw message

drivers/isdn/gigaset/ev-layer.c +35 -28

159 lines not on this page · raw message

drivers/isdn/gigaset/gigaset.h +27 -63

167 lines not on this page · raw message

drivers/isdn/gigaset/i4l.c +294 -205

657 lines not on this page · raw message

drivers/isdn/gigaset/isocdata.c +50 -49

186 lines not on this page · raw message

Signature · 1 line
1.6.2.1.214.ge986c
#5 lore raw

RFC PATCH 5/6 gigaset: allow building without I4L

In reply to Tilman Schmidt

Add a dummy LL interface to the Gigaset driver so that it can be built and, in a limited way, used without the ISDN4Linux subsystem.

Impact: new configuration alternative

---
 drivers/isdn/gigaset/Kconfig   |   13 +++++++-
 drivers/isdn/gigaset/Makefile  |    4 ++-
 drivers/isdn/gigaset/dummyll.c |   68 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 83 insertions(+), 2 deletions(-)
 create mode 100644 drivers/isdn/gigaset/dummyll.c
drivers/isdn/gigaset/Kconfig +12 -1
index 18ab865..6fd2dc1 100644
@@ -1,6 +1,5 @@
 menuconfig ISDN_DRV_GIGASET
 	tristate "Siemens Gigaset support"
-	depends on ISDN_I4L
 	select CRC_CCITT
 	select BITREVERSE
 	help
@@ -11,9 +10,21 @@ menuconfig ISDN_DRV_GIGASET
 	  If you have one of these devices, say M here and for at least
 	  one of the connection specific parts that follow.
 	  This will build a module called "gigaset".
+	  Note: If you build the ISDN4Linux subsystem (ISDN_I4L)
+	  as a module, you have to build this driver as a module too,
+	  otherwise the Gigaset device won't show up as an ISDN device.
 
 if ISDN_DRV_GIGASET
 
+config GIGASET_I4L
+	bool
+	depends on ISDN_I4L='y'||(ISDN_I4L='m'&&ISDN_DRV_GIGASET='m')
+	default y
+
+config GIGASET_DUMMYLL
+	bool
+	default !GIGASET_I4L
+
 config GIGASET_BASE
 	tristate "Gigaset base station support"
 	depends on USB
drivers/isdn/gigaset/Makefile +3 -1
index e9d3189..d429202 100644
@@ -1,4 +1,6 @@
-gigaset-y := common.o interface.o proc.o ev-layer.o i4l.o asyncdata.o
+gigaset-y := common.o interface.o proc.o ev-layer.o asyncdata.o
+gigaset-$(CONFIG_GIGASET_I4L) += i4l.o
+gigaset-$(CONFIG_GIGASET_DUMMYLL) += dummyll.o
 usb_gigaset-y := usb-gigaset.o
 ser_gigaset-y := ser-gigaset.o
 bas_gigaset-y := bas-gigaset.o isocdata.o
drivers/isdn/gigaset/dummyll.c new file +68 -0

68 lines not on this page · raw message

Signature · 1 line
1.6.2.1.214.ge986c
#6 lore raw

RFC PATCH 6/6 gigaset: add Kernel CAPI interface

In reply to Tilman Schmidt

Add a Kernel CAPI interface to the Gigaset driver.

Impact: new functionality

---
 drivers/isdn/gigaset/Kconfig    |   18 +-
 drivers/isdn/gigaset/Makefile   |    1 +
 drivers/isdn/gigaset/capi.c     | 1855 +++++++++++++++++++++++++++++++++++++++
 drivers/isdn/gigaset/common.c   |   19 +
 drivers/isdn/gigaset/ev-layer.c |   26 +-
 drivers/isdn/gigaset/gigaset.h  |    7 +-
 6 files changed, 1910 insertions(+), 16 deletions(-)
 create mode 100644 drivers/isdn/gigaset/capi.c
drivers/isdn/gigaset/Kconfig +15 -3
index 6fd2dc1..dcefedc 100644
@@ -10,20 +10,32 @@ menuconfig ISDN_DRV_GIGASET
 	  If you have one of these devices, say M here and for at least
 	  one of the connection specific parts that follow.
 	  This will build a module called "gigaset".
-	  Note: If you build the ISDN4Linux subsystem (ISDN_I4L)
+	  Note: If you build your ISDN subsystem (ISDN_CAPI or ISDN_I4L)
 	  as a module, you have to build this driver as a module too,
 	  otherwise the Gigaset device won't show up as an ISDN device.
 
 if ISDN_DRV_GIGASET
 
+config GIGASET_CAPI
+	bool "Gigaset CAPI support (EXPERIMENTAL)"
+	depends on EXPERIMENTAL
+	depends on ISDN_CAPI='y'||(ISDN_CAPI='m'&&ISDN_DRV_GIGASET='m')
+	default ISDN_I4L='n'
+	help
+	  Build the Gigaset driver as a CAPI 2.0 driver interfacing with
+	  the Kernel CAPI subsystem. To use it with the old ISDN4Linux
+	  subsystem you'll have to enable the capidrv glue driver.
+	  (select ISDN_CAPI_CAPIDRV.)
+	  Say N to build the old native ISDN4Linux variant.
+
 config GIGASET_I4L
 	bool
 	depends on ISDN_I4L='y'||(ISDN_I4L='m'&&ISDN_DRV_GIGASET='m')
-	default y
+	default !GIGASET_CAPI
 
 config GIGASET_DUMMYLL
 	bool
-	default !GIGASET_I4L
+	default !GIGASET_CAPI&&!GIGASET_I4L
 
 config GIGASET_BASE
 	tristate "Gigaset base station support"
drivers/isdn/gigaset/Makefile +1 -0
index d429202..c453b72 100644
@@ -1,4 +1,5 @@
 gigaset-y := common.o interface.o proc.o ev-layer.o asyncdata.o
+gigaset-$(CONFIG_GIGASET_CAPI) += capi.o
 gigaset-$(CONFIG_GIGASET_I4L) += i4l.o
 gigaset-$(CONFIG_GIGASET_DUMMYLL) += dummyll.o
 usb_gigaset-y := usb-gigaset.o
drivers/isdn/gigaset/capi.c new file +1855 -0

1,855 lines not on this page · raw message

drivers/isdn/gigaset/common.c +19 -0
index a2847c2..e72091c 100644
@@ -207,6 +207,25 @@ int gigaset_get_channel(struct bc_state *bcs)
 	return 1;
 }
 
+struct bc_state *gigaset_get_free_channel(struct cardstate *cs)
+{
+	unsigned long flags;
+	int i;
+
+	spin_lock_irqsave(&cs->lock, flags);
+	for (i = 0; i < cs->channels; ++i)
+		if (!cs->bcs[i].use_count) {
+			++cs->bcs[i].use_count;
+			cs->bcs[i].busy = 1;
+			spin_unlock_irqrestore(&cs->lock, flags);
+			gig_dbg(DEBUG_ANY, "allocated channel %d", i);
+			return cs->bcs + i;
+		}
+	spin_unlock_irqrestore(&cs->lock, flags);
+	gig_dbg(DEBUG_ANY, "no free channel");
+	return NULL;
+}
+
 void gigaset_free_channel(struct bc_state *bcs)
 {
 	unsigned long flags;
drivers/isdn/gigaset/ev-layer.c +14 -12
index ad5ad7b..2d6dab8 100644
@@ -291,21 +291,23 @@ struct reply_t gigaset_tab_cid[] =
 	{RSP_OK,      602,602, -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_OK,      605,605, -1,                606, 5, {ACT_CMD+AT_ISO}},
-	{RSP_NULL,    605,605, -1,                606, 5, {ACT_CMD+AT_ISO}},
-	{RSP_OK,      606,606, -1,                607, 5, {0}, "+VLS=17\r"},
-	{RSP_OK,      607,607, -1,                608,-1},
-	{RSP_ZSAU,    608,608,ZSAU_PROCEEDING,    609, 5, {ACT_CMD+AT_DIAL}},
-	{RSP_OK,      609,609, -1,                650, 0, {ACT_DIALING}},
-
-	{RSP_ERROR,   601,609, -1,                  0, 0, {ACT_ABORTDIAL}},
-	{EV_TIMEOUT,  601,609, -1,                  0, 0, {ACT_ABORTDIAL}},
+	{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,    608,651, 17,                 -1,-1, {ACT_DEBUG}},
-	{RSP_ZCTP,    609,651, -1,                 -1,-1, {ACT_DEBUG}},
-	{RSP_ZCPN,    609,651, -1,                 -1,-1, {ACT_DEBUG}},
+	{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 */
drivers/isdn/gigaset/gigaset.h +6 -1
index 8777a9c..4458796 100644
@@ -191,7 +191,9 @@ void gigaset_dbg_buffer(enum debuglevel level, const unsigned char *msg,
 #define AT_PROTO	4
 #define AT_TYPE		5
 #define AT_HLC		6
-#define AT_NUM		7
+#define AT_CLIP		7
+/* total number */
+#define AT_NUM		8
 
 /* variables in struct at_state_t */
 #define VAR_ZSAU	0
@@ -412,6 +414,8 @@ struct bc_state {
 		struct usb_bc_state *usb;	/* usb hardware driver (m105) */
 		struct bas_bc_state *bas;	/* usb hardware driver (base) */
 	} hw;
+
+	void *ap;			/* LL application structure */
 };
 
 struct cardstate {
@@ -725,6 +729,7 @@ void gigaset_bcs_reinit(struct bc_state *bcs);
 void gigaset_at_init(struct at_state_t *at_state, struct bc_state *bcs,
 		     struct cardstate *cs, int cid);
 int gigaset_get_channel(struct bc_state *bcs);
+struct bc_state *gigaset_get_free_channel(struct cardstate *cs);
 void gigaset_free_channel(struct bc_state *bcs);
 int gigaset_get_channels(struct cardstate *cs);
 void gigaset_free_channels(struct cardstate *cs);
Signature · 1 line
1.6.2.1.214.ge986c
maintainer
#7 lore raw
In reply to Tilman Schmidt

From: Tilman Schmidt <[email protected]>
Date: Fri, 21 Aug 2009 19:21:34 +0200 (CEST)

Quoted 6 lines

the following set of six patches adds a configuration option to the Gigaset driver to interface to Kernel CAPI instead of the old ISDN4Linux subsystem. Although my unit test are not quite done yet I would appreciate comments.

From my nieve perspective these changes look good, I hope

the ISDN folks look at them soon :-)