Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / drivers / isdn / i4l / isdn_common.c
index c406df6..22759c0 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/init.h>
-#include <linux/version.h>
 #include <linux/poll.h>
 #include <linux/vmalloc.h>
 #include <linux/isdn.h>
@@ -67,7 +66,7 @@ static isdn_divert_if *divert_if; /* = NULL */
 static int isdn_writebuf_stub(int, int, const u_char __user *, int);
 static void set_global_features(void);
 static int isdn_wildmat(char *s, char *p);
-
+static int isdn_add_channels(isdn_driver_t *d, int drvidx, int n, int adding);
 
 static inline void
 isdn_lock_driver(isdn_driver_t *drv)
@@ -388,7 +387,7 @@ isdn_all_eaz(int di, int ch)
  */
 #include <linux/isdn/capicmd.h>
 
-int
+static int
 isdn_capi_rec_hl_msg(capi_msg *cm) {
        
        int di;
@@ -858,6 +857,118 @@ isdn_readbchan(int di, int channel, u_char * buf, u_char * fp, int len, wait_que
        return count;
 }
 
+/*
+ * isdn_readbchan_tty() tries to get data from the read-queue.
+ * It MUST be called with interrupts off.
+ *
+ * Be aware that this is not an atomic operation when sleep != 0, even though
+ * interrupts are turned off! Well, like that we are currently only called
+ * on behalf of a read system call on raw device files (which are documented
+ * to be dangerous and for for debugging purpose only). The inode semaphore
+ * takes care that this is not called for the same minor device number while
+ * we are sleeping, but access is not serialized against simultaneous read()
+ * from the corresponding ttyI device. Can other ugly events, like changes
+ * of the mapping (di,ch)<->minor, happen during the sleep? --he
+ */
+int
+isdn_readbchan_tty(int di, int channel, struct tty_struct *tty, int cisco_hack)
+{
+       int count;
+       int count_pull;
+       int count_put;
+       int dflag;
+       struct sk_buff *skb;
+       char last = 0;
+       int len;
+
+       if (!dev->drv[di])
+               return 0;
+       if (skb_queue_empty(&dev->drv[di]->rpqueue[channel]))
+                       return 0;
+
+       len = tty_buffer_request_room(tty, dev->drv[di]->rcvcount[channel]);
+       if(len == 0)
+               return len;
+
+       count = 0;
+       while (len) {
+               if (!(skb = skb_peek(&dev->drv[di]->rpqueue[channel])))
+                       break;
+#ifdef CONFIG_ISDN_AUDIO
+               if (ISDN_AUDIO_SKB_LOCK(skb))
+                       break;
+               ISDN_AUDIO_SKB_LOCK(skb) = 1;
+               if ((ISDN_AUDIO_SKB_DLECOUNT(skb)) || (dev->drv[di]->DLEflag & (1 << channel))) {
+                       char *p = skb->data;
+                       unsigned long DLEmask = (1 << channel);
+
+                       dflag = 0;
+                       count_pull = count_put = 0;
+                       while ((count_pull < skb->len) && (len > 0)) {
+                               len--;
+                               if (dev->drv[di]->DLEflag & DLEmask) {
+                                       last = DLE;
+                                       dev->drv[di]->DLEflag &= ~DLEmask;
+                               } else {
+                                       last = *p;
+                                       if (last == DLE) {
+                                               dev->drv[di]->DLEflag |= DLEmask;
+                                               (ISDN_AUDIO_SKB_DLECOUNT(skb))--;
+                                       }
+                                       p++;
+                                       count_pull++;
+                               }
+                               count_put++;
+                       }
+                       if (count_pull >= skb->len)
+                               dflag = 1;
+               } else {
+#endif
+                       /* No DLE's in buff, so simply copy it */
+                       dflag = 1;
+                       if ((count_pull = skb->len) > len) {
+                               count_pull = len;
+                               dflag = 0;
+                       }
+                       count_put = count_pull;
+                       if(count_put > 1)
+                               tty_insert_flip_string(tty, skb->data, count_put - 1);
+                       last = skb->data[count_put] - 1;
+                       len -= count_put;
+#ifdef CONFIG_ISDN_AUDIO
+               }
+#endif
+               count += count_put;
+               if (dflag) {
+                       /* We got all the data in this buff.
+                        * Now we can dequeue it.
+                        */
+                       if(cisco_hack)
+                               tty_insert_flip_char(tty, last, 0xFF);
+                       else
+                               tty_insert_flip_char(tty, last, TTY_NORMAL);
+#ifdef CONFIG_ISDN_AUDIO
+                       ISDN_AUDIO_SKB_LOCK(skb) = 0;
+#endif
+                       skb = skb_dequeue(&dev->drv[di]->rpqueue[channel]);
+                       dev_kfree_skb(skb);
+               } else {
+                       tty_insert_flip_char(tty, last, TTY_NORMAL);
+                       /* Not yet emptied this buff, so it
+                        * must stay in the queue, for further calls
+                        * but we pull off the data we got until now.
+                        */
+                       skb_pull(skb, count_pull);
+#ifdef CONFIG_ISDN_AUDIO
+                       ISDN_AUDIO_SKB_LOCK(skb) = 0;
+#endif
+               }
+               dev->drv[di]->rcvcount[channel] -= count_put;
+       }
+       return count;
+}
+
+
 static __inline int
 isdn_minor2drv(int minor)
 {
@@ -1923,7 +2034,7 @@ isdn_writebuf_skb_stub(int drvidx, int chan, int ack, struct sk_buff *skb)
        return ret;
 }
 
-int
+static int
 isdn_add_channels(isdn_driver_t *d, int drvidx, int n, int adding)
 {
        int j, k, m;
@@ -1953,7 +2064,8 @@ isdn_add_channels(isdn_driver_t *d, int drvidx, int n, int adding)
                kfree(d->rcvcount);
        if (!(d->rcvcount = kmalloc(sizeof(int) * m, GFP_ATOMIC))) {
                printk(KERN_WARNING "register_isdn: Could not alloc rcvcount\n");
-               if (!adding) kfree(d->rcverr);
+               if (!adding)
+                       kfree(d->rcverr);
                return -1;
        }
        memset((char *) d->rcvcount, 0, sizeof(int) * m);