proc_fops: convert drivers/isdn/ to seq_file
[safe/jmp/linux-2.6] / drivers / isdn / gigaset / capi.c
index c276a92..6f0ae32 100644 (file)
@@ -13,6 +13,8 @@
 
 #include "gigaset.h"
 #include <linux/ctype.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
 #include <linux/isdn/capilli.h>
 #include <linux/isdn/capicmd.h>
 #include <linux/isdn/capiutil.h>
@@ -168,14 +170,6 @@ static inline void ignore_cstruct_param(struct cardstate *cs, _cstruct param,
                         msgname, paramname);
 }
 
-static inline void ignore_cmstruct_param(struct cardstate *cs, _cmstruct param,
-                                      char *msgname, char *paramname)
-{
-       if (param != CAPI_DEFAULT)
-               dev_warn(cs->dev, "%s: ignoring unsupported parameter: %s\n",
-                        msgname, paramname);
-}
-
 /*
  * check for legal hex digit
  */
@@ -370,6 +364,7 @@ void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *dskb)
        struct cardstate *cs = bcs->cs;
        struct gigaset_capi_ctr *iif = cs->iif;
        struct gigaset_capi_appl *ap = bcs->ap;
+       unsigned char *req = skb_mac_header(dskb);
        struct sk_buff *cskb;
        u16 flags;
 
@@ -388,7 +383,7 @@ void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *dskb)
        }
 
        /* ToDo: honor unset "delivery confirmation" bit */
-       flags = CAPIMSG_FLAGS(dskb->head);
+       flags = CAPIMSG_FLAGS(req);
 
        /* build DATA_B3_CONF message */
        cskb = alloc_skb(CAPI_DATA_B3_CONF_LEN, GFP_ATOMIC);
@@ -401,11 +396,11 @@ void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *dskb)
        CAPIMSG_SETAPPID(cskb->data, ap->id);
        CAPIMSG_SETCOMMAND(cskb->data, CAPI_DATA_B3);
        CAPIMSG_SETSUBCOMMAND(cskb->data,  CAPI_CONF);
-       CAPIMSG_SETMSGID(cskb->data, CAPIMSG_MSGID(dskb->head));
+       CAPIMSG_SETMSGID(cskb->data, CAPIMSG_MSGID(req));
        CAPIMSG_SETCONTROLLER(cskb->data, iif->ctr.cnr);
        CAPIMSG_SETPLCI_PART(cskb->data, bcs->channel + 1);
        CAPIMSG_SETNCCI_PART(cskb->data, 1);
-       CAPIMSG_SETHANDLE_CONF(cskb->data, CAPIMSG_HANDLE_REQ(dskb->head));
+       CAPIMSG_SETHANDLE_CONF(cskb->data, CAPIMSG_HANDLE_REQ(req));
        if (flags & ~CAPI_FLAGS_DELIVERY_CONFIRMATION)
                CAPIMSG_SETINFO_CONF(cskb->data,
                                     CapiFlagsNotSupportedByProtocol);
@@ -445,7 +440,7 @@ void gigaset_skb_rcvd(struct bc_state *bcs, struct sk_buff *skb)
        /* don't send further B3 messages if disconnected */
        if (ap->connected < APCONN_ACTIVE) {
                gig_dbg(DEBUG_LLDATA, "disconnected, discarding data");
-               dev_kfree_skb(skb);
+               dev_kfree_skb_any(skb);
                return;
        }
 
@@ -1062,6 +1057,7 @@ static void do_facility_req(struct gigaset_capi_ctr *iif,
                            struct sk_buff *skb)
 {
        struct cardstate *cs = iif->ctr.driverdata;
+       _cmsg *cmsg = &iif->acmsg;
        struct sk_buff *cskb;
        u8 *pparam;
        unsigned int msgsize = CAPI_FACILITY_CONF_BASELEN;
@@ -1069,14 +1065,14 @@ static void do_facility_req(struct gigaset_capi_ctr *iif,
        static u8 confparam[10];        /* max. 9 octets + length byte */
 
        /* decode message */
-       capi_message2cmsg(&iif->acmsg, skb->data);
-       dump_cmsg(DEBUG_CMD, __func__, &iif->acmsg);
+       capi_message2cmsg(cmsg, skb->data);
+       dump_cmsg(DEBUG_CMD, __func__, cmsg);
 
        /*
         * Facility Request Parameter is not decoded by capi_message2cmsg()
         * encoding depends on Facility Selector
         */
-       switch (iif->acmsg.FacilitySelector) {
+       switch (cmsg->FacilitySelector) {
        case CAPI_FACILITY_DTMF:        /* ToDo */
                info = CapiFacilityNotSupported;
                confparam[0] = 2;       /* length */
@@ -1093,7 +1089,7 @@ static void do_facility_req(struct gigaset_capi_ctr *iif,
 
        case CAPI_FACILITY_SUPPSVC:
                /* decode Function parameter */
-               pparam = iif->acmsg.FacilityRequestParameter;
+               pparam = cmsg->FacilityRequestParameter;
                if (pparam == NULL || *pparam < 2) {
                        dev_notice(cs->dev, "%s: %s missing\n", "FACILITY_REQ",
                                   "Facility Request Parameter");
@@ -1141,18 +1137,18 @@ static void do_facility_req(struct gigaset_capi_ctr *iif,
        }
 
        /* send FACILITY_CONF with given Info and confirmation parameter */
-       capi_cmsg_answer(&iif->acmsg);
-       iif->acmsg.Info = info;
-       iif->acmsg.FacilityConfirmationParameter = confparam;
+       capi_cmsg_answer(cmsg);
+       cmsg->Info = info;
+       cmsg->FacilityConfirmationParameter = confparam;
        msgsize += confparam[0];        /* length */
        cskb = alloc_skb(msgsize, GFP_ATOMIC);
        if (!cskb) {
                dev_err(cs->dev, "%s: out of memory\n", __func__);
                return;
        }
-       capi_cmsg2message(&iif->acmsg, __skb_put(cskb, msgsize));
-       dump_cmsg(DEBUG_CMD, __func__, &iif->acmsg);
-               capi_ctr_handle_message(&iif->ctr, ap->id, cskb);
+       capi_cmsg2message(cmsg, __skb_put(cskb, msgsize));
+       dump_cmsg(DEBUG_CMD, __func__, cmsg);
+       capi_ctr_handle_message(&iif->ctr, ap->id, cskb);
 }
 
 
@@ -1207,8 +1203,8 @@ static void do_connect_req(struct gigaset_capi_ctr *iif,
        u16 info;
 
        /* decode message */
-       capi_message2cmsg(&iif->acmsg, skb->data);
-       dump_cmsg(DEBUG_CMD, __func__, &iif->acmsg);
+       capi_message2cmsg(cmsg, skb->data);
+       dump_cmsg(DEBUG_CMD, __func__, cmsg);
 
        /* get free B channel & construct PLCI */
        bcs = gigaset_get_free_channel(cs);
@@ -1261,7 +1257,7 @@ static void do_connect_req(struct gigaset_capi_ctr *iif,
        commands[AT_DIAL] = kmalloc(l+3, GFP_KERNEL);
        if (!commands[AT_DIAL])
                goto oom;
-       snprintf(commands[AT_DIAL], l+3, "D%*s\r", l, pp);
+       snprintf(commands[AT_DIAL], l+3, "D%.*s\r", l, pp);
 
        /* encode parameter: Calling party number */
        pp = cmsg->CallingPartyNumber;
@@ -1411,8 +1407,16 @@ static void do_connect_req(struct gigaset_capi_ctr *iif,
                                        "CONNECT_REQ", "Calling pty subaddr");
        ignore_cstruct_param(cs, cmsg->LLC,
                                        "CONNECT_REQ", "LLC");
-       ignore_cmstruct_param(cs, cmsg->AdditionalInfo,
-                                       "CONNECT_REQ", "Additional Info");
+       if (cmsg->AdditionalInfo != CAPI_DEFAULT) {
+               ignore_cstruct_param(cs, cmsg->BChannelinformation,
+                                       "CONNECT_REQ", "B Channel Information");
+               ignore_cstruct_param(cs, cmsg->Keypadfacility,
+                                       "CONNECT_REQ", "Keypad Facility");
+               ignore_cstruct_param(cs, cmsg->Useruserdata,
+                                       "CONNECT_REQ", "User-User Data");
+               ignore_cstruct_param(cs, cmsg->Facilitydataarray,
+                                       "CONNECT_REQ", "Facility Data Array");
+       }
 
        /* encode parameter: B channel to use */
        commands[AT_ISO] = kmalloc(9, GFP_KERNEL);
@@ -1458,9 +1462,9 @@ static void do_connect_resp(struct gigaset_capi_ctr *iif,
        int channel;
 
        /* decode message */
-       capi_message2cmsg(&iif->acmsg, skb->data);
-       dump_cmsg(DEBUG_CMD, __func__, &iif->acmsg);
-       dev_kfree_skb(skb);
+       capi_message2cmsg(cmsg, skb->data);
+       dump_cmsg(DEBUG_CMD, __func__, cmsg);
+       dev_kfree_skb_any(skb);
 
        /* extract and check channel number from PLCI */
        channel = (cmsg->adr.adrPLCI >> 8) & 0xff;
@@ -1524,8 +1528,16 @@ static void do_connect_resp(struct gigaset_capi_ctr *iif,
                                        "CONNECT_RESP", "Connected Subaddress");
                ignore_cstruct_param(cs, cmsg->LLC,
                                        "CONNECT_RESP", "LLC");
-               ignore_cmstruct_param(cs, cmsg->AdditionalInfo,
-                                       "CONNECT_RESP", "Additional Info");
+               if (cmsg->AdditionalInfo != CAPI_DEFAULT) {
+                       ignore_cstruct_param(cs, cmsg->BChannelinformation,
+                                       "CONNECT_RESP", "BChannel Information");
+                       ignore_cstruct_param(cs, cmsg->Keypadfacility,
+                                       "CONNECT_RESP", "Keypad Facility");
+                       ignore_cstruct_param(cs, cmsg->Useruserdata,
+                                       "CONNECT_RESP", "User-User Data");
+                       ignore_cstruct_param(cs, cmsg->Facilitydataarray,
+                                       "CONNECT_RESP", "Facility Data Array");
+               }
 
                /* Accept call */
                if (!gigaset_add_event(cs, &cs->bcs[channel-1].at_state,
@@ -1587,17 +1599,18 @@ static void do_connect_b3_req(struct gigaset_capi_ctr *iif,
                              struct sk_buff *skb)
 {
        struct cardstate *cs = iif->ctr.driverdata;
+       _cmsg *cmsg = &iif->acmsg;
        int channel;
 
        /* decode message */
-       capi_message2cmsg(&iif->acmsg, skb->data);
-       dump_cmsg(DEBUG_CMD, __func__, &iif->acmsg);
+       capi_message2cmsg(cmsg, skb->data);
+       dump_cmsg(DEBUG_CMD, __func__, cmsg);
 
        /* extract and check channel number from PLCI */
-       channel = (iif->acmsg.adr.adrPLCI >> 8) & 0xff;
+       channel = (cmsg->adr.adrPLCI >> 8) & 0xff;
        if (!channel || channel > cs->channels) {
                dev_notice(cs->dev, "%s: invalid %s 0x%02x\n",
-                          "CONNECT_B3_REQ", "PLCI", iif->acmsg.adr.adrPLCI);
+                          "CONNECT_B3_REQ", "PLCI", cmsg->adr.adrPLCI);
                send_conf(iif, ap, skb, CapiIllContrPlciNcci);
                return;
        }
@@ -1606,14 +1619,12 @@ static void do_connect_b3_req(struct gigaset_capi_ctr *iif,
        ap->connected = APCONN_ACTIVE;
 
        /* build NCCI: always 1 (one B3 connection only) */
-       iif->acmsg.adr.adrNCCI |= 1 << 16;
+       cmsg->adr.adrNCCI |= 1 << 16;
 
        /* NCPI parameter: not applicable for B3 Transparent */
-       ignore_cstruct_param(cs, iif->acmsg.NCPI,
-                               "CONNECT_B3_REQ", "NCPI");
-       send_conf(iif, ap, skb,
-                 (iif->acmsg.NCPI && iif->acmsg.NCPI[0]) ?
-                       CapiNcpiNotSupportedByProtocol : CapiSuccess);
+       ignore_cstruct_param(cs, cmsg->NCPI, "CONNECT_B3_REQ", "NCPI");
+       send_conf(iif, ap, skb, (cmsg->NCPI && cmsg->NCPI[0]) ?
+                               CapiNcpiNotSupportedByProtocol : CapiSuccess);
 }
 
 /*
@@ -1628,27 +1639,28 @@ static void do_connect_b3_resp(struct gigaset_capi_ctr *iif,
                               struct sk_buff *skb)
 {
        struct cardstate *cs = iif->ctr.driverdata;
-       struct bc_state *bcs = NULL;
+       _cmsg *cmsg = &iif->acmsg;
+       struct bc_state *bcs;
        int channel;
        unsigned int msgsize;
        u8 command;
 
        /* decode message */
-       capi_message2cmsg(&iif->acmsg, skb->data);
-       dump_cmsg(DEBUG_CMD, __func__, &iif->acmsg);
+       capi_message2cmsg(cmsg, skb->data);
+       dump_cmsg(DEBUG_CMD, __func__, cmsg);
 
        /* extract and check channel number and NCCI */
-       channel = (iif->acmsg.adr.adrNCCI >> 8) & 0xff;
+       channel = (cmsg->adr.adrNCCI >> 8) & 0xff;
        if (!channel || channel > cs->channels ||
-           ((iif->acmsg.adr.adrNCCI >> 16) & 0xffff) != 1) {
+           ((cmsg->adr.adrNCCI >> 16) & 0xffff) != 1) {
                dev_notice(cs->dev, "%s: invalid %s 0x%02x\n",
-                          "CONNECT_B3_RESP", "NCCI", iif->acmsg.adr.adrNCCI);
-               dev_kfree_skb(skb);
+                          "CONNECT_B3_RESP", "NCCI", cmsg->adr.adrNCCI);
+               dev_kfree_skb_any(skb);
                return;
        }
        bcs = &cs->bcs[channel-1];
 
-       if (iif->acmsg.Reject) {
+       if (cmsg->Reject) {
                /* Reject: clear B3 connect received flag */
                ap->connected = APCONN_SETUP;
 
@@ -1656,7 +1668,7 @@ static void do_connect_b3_resp(struct gigaset_capi_ctr *iif,
                if (!gigaset_add_event(cs, &bcs->at_state,
                                       EV_HUP, NULL, 0, NULL)) {
                        dev_err(cs->dev, "%s: out of memory\n", __func__);
-                       dev_kfree_skb(skb);
+                       dev_kfree_skb_any(skb);
                        return;
                }
                gig_dbg(DEBUG_CMD, "scheduling HUP");
@@ -1673,11 +1685,11 @@ static void do_connect_b3_resp(struct gigaset_capi_ctr *iif,
                command = CAPI_CONNECT_B3_ACTIVE;
                msgsize = CAPI_CONNECT_B3_ACTIVE_IND_BASELEN;
        }
-       capi_cmsg_header(&iif->acmsg, ap->id, command, CAPI_IND,
-                        ap->nextMessageNumber++, iif->acmsg.adr.adrNCCI);
+       capi_cmsg_header(cmsg, ap->id, command, CAPI_IND,
+                        ap->nextMessageNumber++, cmsg->adr.adrNCCI);
        __skb_trim(skb, msgsize);
-       capi_cmsg2message(&iif->acmsg, skb->data);
-       dump_cmsg(DEBUG_CMD, __func__, &iif->acmsg);
+       capi_cmsg2message(cmsg, skb->data);
+       dump_cmsg(DEBUG_CMD, __func__, cmsg);
        capi_ctr_handle_message(&iif->ctr, ap->id, skb);
 }
 
@@ -1691,28 +1703,37 @@ static void do_disconnect_req(struct gigaset_capi_ctr *iif,
                              struct sk_buff *skb)
 {
        struct cardstate *cs = iif->ctr.driverdata;
+       _cmsg *cmsg = &iif->acmsg;
        struct bc_state *bcs;
        _cmsg *b3cmsg;
        struct sk_buff *b3skb;
        int channel;
 
        /* decode message */
-       capi_message2cmsg(&iif->acmsg, skb->data);
-       dump_cmsg(DEBUG_CMD, __func__, &iif->acmsg);
+       capi_message2cmsg(cmsg, skb->data);
+       dump_cmsg(DEBUG_CMD, __func__, cmsg);
 
        /* extract and check channel number from PLCI */
-       channel = (iif->acmsg.adr.adrPLCI >> 8) & 0xff;
+       channel = (cmsg->adr.adrPLCI >> 8) & 0xff;
        if (!channel || channel > cs->channels) {
                dev_notice(cs->dev, "%s: invalid %s 0x%02x\n",
-                          "DISCONNECT_REQ", "PLCI", iif->acmsg.adr.adrPLCI);
+                          "DISCONNECT_REQ", "PLCI", cmsg->adr.adrPLCI);
                send_conf(iif, ap, skb, CapiIllContrPlciNcci);
                return;
        }
        bcs = cs->bcs + channel - 1;
 
        /* ToDo: process parameter: Additional info */
-       ignore_cmstruct_param(cs, iif->acmsg.AdditionalInfo,
-                             "DISCONNECT_REQ", "Additional Info");
+       if (cmsg->AdditionalInfo != CAPI_DEFAULT) {
+               ignore_cstruct_param(cs, cmsg->BChannelinformation,
+                                    "DISCONNECT_REQ", "B Channel Information");
+               ignore_cstruct_param(cs, cmsg->Keypadfacility,
+                                    "DISCONNECT_REQ", "Keypad Facility");
+               ignore_cstruct_param(cs, cmsg->Useruserdata,
+                                    "DISCONNECT_REQ", "User-User Data");
+               ignore_cstruct_param(cs, cmsg->Facilitydataarray,
+                                    "DISCONNECT_REQ", "Facility Data Array");
+       }
 
        /* skip if DISCONNECT_IND already sent */
        if (!ap->connected)
@@ -1733,7 +1754,7 @@ static void do_disconnect_req(struct gigaset_capi_ctr *iif,
                }
                capi_cmsg_header(b3cmsg, ap->id, CAPI_DISCONNECT_B3, CAPI_IND,
                                 ap->nextMessageNumber++,
-                                iif->acmsg.adr.adrPLCI | (1 << 16));
+                                cmsg->adr.adrPLCI | (1 << 16));
                b3cmsg->Reason_B3 = CapiProtocolErrorLayer1;
                b3skb = alloc_skb(CAPI_DISCONNECT_B3_IND_BASELEN, GFP_KERNEL);
                if (b3skb == NULL) {
@@ -1769,18 +1790,19 @@ static void do_disconnect_b3_req(struct gigaset_capi_ctr *iif,
                                 struct sk_buff *skb)
 {
        struct cardstate *cs = iif->ctr.driverdata;
+       _cmsg *cmsg = &iif->acmsg;
        int channel;
 
        /* decode message */
-       capi_message2cmsg(&iif->acmsg, skb->data);
-       dump_cmsg(DEBUG_CMD, __func__, &iif->acmsg);
+       capi_message2cmsg(cmsg, skb->data);
+       dump_cmsg(DEBUG_CMD, __func__, cmsg);
 
        /* extract and check channel number and NCCI */
-       channel = (iif->acmsg.adr.adrNCCI >> 8) & 0xff;
+       channel = (cmsg->adr.adrNCCI >> 8) & 0xff;
        if (!channel || channel > cs->channels ||
-           ((iif->acmsg.adr.adrNCCI >> 16) & 0xffff) != 1) {
+           ((cmsg->adr.adrNCCI >> 16) & 0xffff) != 1) {
                dev_notice(cs->dev, "%s: invalid %s 0x%02x\n",
-                          "DISCONNECT_B3_REQ", "NCCI", iif->acmsg.adr.adrNCCI);
+                          "DISCONNECT_B3_REQ", "NCCI", cmsg->adr.adrNCCI);
                send_conf(iif, ap, skb, CapiIllContrPlciNcci);
                return;
        }
@@ -1803,11 +1825,10 @@ static void do_disconnect_b3_req(struct gigaset_capi_ctr *iif,
        gigaset_schedule_event(cs);
 
        /* NCPI parameter: not applicable for B3 Transparent */
-       ignore_cstruct_param(cs, iif->acmsg.NCPI,
+       ignore_cstruct_param(cs, cmsg->NCPI,
                                "DISCONNECT_B3_REQ", "NCPI");
-       send_conf(iif, ap, skb,
-                 (iif->acmsg.NCPI && iif->acmsg.NCPI[0]) ?
-                       CapiNcpiNotSupportedByProtocol : CapiSuccess);
+       send_conf(iif, ap, skb, (cmsg->NCPI && cmsg->NCPI[0]) ?
+                               CapiNcpiNotSupportedByProtocol : CapiSuccess);
 }
 
 /*
@@ -1862,12 +1883,12 @@ static void do_data_b3_req(struct gigaset_capi_ctr *iif,
                return;
        }
 
-       /*
-        * pull CAPI message from skb,
-        * pass payload data to device-specific module
-        * CAPI message will be preserved in headroom
-        */
+       /* pull CAPI message into link layer header */
+       skb_reset_mac_header(skb);
+       skb->mac_len = msglen;
        skb_pull(skb, msglen);
+
+       /* pass to device-specific module */
        if (cs->ops->send_skb(&cs->bcs[channel-1], skb) < 0) {
                send_conf(iif, ap, skb, CAPI_MSGOSRESOURCEERR);
                return;
@@ -1928,7 +1949,7 @@ static void do_nothing(struct gigaset_capi_ctr *iif,
                capi_message2cmsg(&iif->acmsg, skb->data);
                dump_cmsg(DEBUG_CMD, __func__, &iif->acmsg);
        }
-       dev_kfree_skb(skb);
+       dev_kfree_skb_any(skb);
 }
 
 static void do_data_b3_resp(struct gigaset_capi_ctr *iif,
@@ -1936,7 +1957,7 @@ static void do_data_b3_resp(struct gigaset_capi_ctr *iif,
                            struct sk_buff *skb)
 {
        dump_rawmsg(DEBUG_LLDATA, __func__, skb->data);
-       dev_kfree_skb(skb);
+       dev_kfree_skb_any(skb);
 }
 
 /* table of outgoing CAPI message handlers with lookup function */
@@ -2087,35 +2108,22 @@ static char *gigaset_procinfo(struct capi_ctr *ctr)
        return ctr->name;       /* ToDo: more? */
 }
 
-/**
- * gigaset_ctr_read_proc() - build controller proc file entry
- * @page:      buffer of PAGE_SIZE bytes for receiving the entry.
- * @start:     unused.
- * @off:       unused.
- * @count:     unused.
- * @eof:       unused.
- * @ctr:       controller descriptor structure.
- *
- * Return value: length of generated entry
- */
-static int gigaset_ctr_read_proc(char *page, char **start, off_t off,
-                         int count, int *eof, struct capi_ctr *ctr)
+static int gigaset_proc_show(struct seq_file *m, void *v)
 {
+       struct capi_ctr *ctr = m->private;
        struct cardstate *cs = ctr->driverdata;
        char *s;
        int i;
-       int len = 0;
-       len += sprintf(page+len, "%-16s %s\n", "name", ctr->name);
-       len += sprintf(page+len, "%-16s %s %s\n", "dev",
+
+       seq_printf(m, "%-16s %s\n", "name", ctr->name);
+       seq_printf(m, "%-16s %s %s\n", "dev",
                        dev_driver_string(cs->dev), dev_name(cs->dev));
-       len += sprintf(page+len, "%-16s %d\n", "id", cs->myid);
+       seq_printf(m, "%-16s %d\n", "id", cs->myid);
        if (cs->gotfwver)
-               len += sprintf(page+len, "%-16s %d.%d.%d.%d\n", "firmware",
+               seq_printf(m, "%-16s %d.%d.%d.%d\n", "firmware",
                        cs->fwver[0], cs->fwver[1], cs->fwver[2], cs->fwver[3]);
-       len += sprintf(page+len, "%-16s %d\n", "channels",
-                       cs->channels);
-       len += sprintf(page+len, "%-16s %s\n", "onechannel",
-                       cs->onechannel ? "yes" : "no");
+       seq_printf(m, "%-16s %d\n", "channels", cs->channels);
+       seq_printf(m, "%-16s %s\n", "onechannel", cs->onechannel ? "yes" : "no");
 
        switch (cs->mode) {
        case M_UNKNOWN:
@@ -2133,7 +2141,7 @@ static int gigaset_ctr_read_proc(char *page, char **start, off_t off,
        default:
                s = "??";
        }
-       len += sprintf(page+len, "%-16s %s\n", "mode", s);
+       seq_printf(m, "%-16s %s\n", "mode", s);
 
        switch (cs->mstate) {
        case MS_UNINITIALIZED:
@@ -2157,25 +2165,21 @@ static int gigaset_ctr_read_proc(char *page, char **start, off_t off,
        default:
                s = "??";
        }
-       len += sprintf(page+len, "%-16s %s\n", "mstate", s);
+       seq_printf(m, "%-16s %s\n", "mstate", s);
 
-       len += sprintf(page+len, "%-16s %s\n", "running",
-                       cs->running ? "yes" : "no");
-       len += sprintf(page+len, "%-16s %s\n", "connected",
-                       cs->connected ? "yes" : "no");
-       len += sprintf(page+len, "%-16s %s\n", "isdn_up",
-                       cs->isdn_up ? "yes" : "no");
-       len += sprintf(page+len, "%-16s %s\n", "cidmode",
-                       cs->cidmode ? "yes" : "no");
+       seq_printf(m, "%-16s %s\n", "running", cs->running ? "yes" : "no");
+       seq_printf(m, "%-16s %s\n", "connected", cs->connected ? "yes" : "no");
+       seq_printf(m, "%-16s %s\n", "isdn_up", cs->isdn_up ? "yes" : "no");
+       seq_printf(m, "%-16s %s\n", "cidmode", cs->cidmode ? "yes" : "no");
 
        for (i = 0; i < cs->channels; i++) {
-               len += sprintf(page+len, "[%d]%-13s %d\n", i, "corrupted",
+               seq_printf(m, "[%d]%-13s %d\n", i, "corrupted",
                                cs->bcs[i].corrupted);
-               len += sprintf(page+len, "[%d]%-13s %d\n", i, "trans_down",
+               seq_printf(m, "[%d]%-13s %d\n", i, "trans_down",
                                cs->bcs[i].trans_down);
-               len += sprintf(page+len, "[%d]%-13s %d\n", i, "trans_up",
+               seq_printf(m, "[%d]%-13s %d\n", i, "trans_up",
                                cs->bcs[i].trans_up);
-               len += sprintf(page+len, "[%d]%-13s %d\n", i, "chstate",
+               seq_printf(m, "[%d]%-13s %d\n", i, "chstate",
                                cs->bcs[i].chstate);
                switch (cs->bcs[i].proto2) {
                case L2_BITSYNC:
@@ -2190,11 +2194,23 @@ static int gigaset_ctr_read_proc(char *page, char **start, off_t off,
                default:
                        s = "??";
                }
-               len += sprintf(page+len, "[%d]%-13s %s\n", i, "proto2", s);
+               seq_printf(m, "[%d]%-13s %s\n", i, "proto2", s);
        }
-       return len;
+       return 0;
+}
+
+static int gigaset_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, gigaset_proc_show, PDE(inode)->data);
 }
 
+static const struct file_operations gigaset_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = gigaset_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
 
 static struct capi_driver capi_driver_gigaset = {
        .name           = "gigaset",
@@ -2237,7 +2253,7 @@ int gigaset_isdn_register(struct cardstate *cs, const char *isdnid)
        iif->ctr.release_appl  = gigaset_release_appl;
        iif->ctr.send_message  = gigaset_send_message;
        iif->ctr.procinfo      = gigaset_procinfo;
-       iif->ctr.ctr_read_proc = gigaset_ctr_read_proc;
+       iif->ctr.proc_fops = &gigaset_proc_fops;
        INIT_LIST_HEAD(&iif->appls);
        skb_queue_head_init(&iif->sendqueue);
        atomic_set(&iif->sendqlen, 0);