aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/isdn/i4l
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/isdn/i4l')
-rw-r--r--drivers/isdn/i4l/isdn_common.c112
-rw-r--r--drivers/isdn/i4l/isdn_common.h1
-rw-r--r--drivers/isdn/i4l/isdn_tty.c75
3 files changed, 149 insertions, 39 deletions
diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c
index 4643df097bfe..22759c01746a 100644
--- a/drivers/isdn/i4l/isdn_common.c
+++ b/drivers/isdn/i4l/isdn_common.c
@@ -857,6 +857,118 @@ isdn_readbchan(int di, int channel, u_char * buf, u_char * fp, int len, wait_que
857 return count; 857 return count;
858} 858}
859 859
860/*
861 * isdn_readbchan_tty() tries to get data from the read-queue.
862 * It MUST be called with interrupts off.
863 *
864 * Be aware that this is not an atomic operation when sleep != 0, even though
865 * interrupts are turned off! Well, like that we are currently only called
866 * on behalf of a read system call on raw device files (which are documented
867 * to be dangerous and for for debugging purpose only). The inode semaphore
868 * takes care that this is not called for the same minor device number while
869 * we are sleeping, but access is not serialized against simultaneous read()
870 * from the corresponding ttyI device. Can other ugly events, like changes
871 * of the mapping (di,ch)<->minor, happen during the sleep? --he
872 */
873int
874isdn_readbchan_tty(int di, int channel, struct tty_struct *tty, int cisco_hack)
875{
876 int count;
877 int count_pull;
878 int count_put;
879 int dflag;
880 struct sk_buff *skb;
881 char last = 0;
882 int len;
883
884 if (!dev->drv[di])
885 return 0;
886 if (skb_queue_empty(&dev->drv[di]->rpqueue[channel]))
887 return 0;
888
889 len = tty_buffer_request_room(tty, dev->drv[di]->rcvcount[channel]);
890 if(len == 0)
891 return len;
892
893 count = 0;
894 while (len) {
895 if (!(skb = skb_peek(&dev->drv[di]->rpqueue[channel])))
896 break;
897#ifdef CONFIG_ISDN_AUDIO
898 if (ISDN_AUDIO_SKB_LOCK(skb))
899 break;
900 ISDN_AUDIO_SKB_LOCK(skb) = 1;
901 if ((ISDN_AUDIO_SKB_DLECOUNT(skb)) || (dev->drv[di]->DLEflag & (1 << channel))) {
902 char *p = skb->data;
903 unsigned long DLEmask = (1 << channel);
904
905 dflag = 0;
906 count_pull = count_put = 0;
907 while ((count_pull < skb->len) && (len > 0)) {
908 len--;
909 if (dev->drv[di]->DLEflag & DLEmask) {
910 last = DLE;
911 dev->drv[di]->DLEflag &= ~DLEmask;
912 } else {
913 last = *p;
914 if (last == DLE) {
915 dev->drv[di]->DLEflag |= DLEmask;
916 (ISDN_AUDIO_SKB_DLECOUNT(skb))--;
917 }
918 p++;
919 count_pull++;
920 }
921 count_put++;
922 }
923 if (count_pull >= skb->len)
924 dflag = 1;
925 } else {
926#endif
927 /* No DLE's in buff, so simply copy it */
928 dflag = 1;
929 if ((count_pull = skb->len) > len) {
930 count_pull = len;
931 dflag = 0;
932 }
933 count_put = count_pull;
934 if(count_put > 1)
935 tty_insert_flip_string(tty, skb->data, count_put - 1);
936 last = skb->data[count_put] - 1;
937 len -= count_put;
938#ifdef CONFIG_ISDN_AUDIO
939 }
940#endif
941 count += count_put;
942 if (dflag) {
943 /* We got all the data in this buff.
944 * Now we can dequeue it.
945 */
946 if(cisco_hack)
947 tty_insert_flip_char(tty, last, 0xFF);
948 else
949 tty_insert_flip_char(tty, last, TTY_NORMAL);
950#ifdef CONFIG_ISDN_AUDIO
951 ISDN_AUDIO_SKB_LOCK(skb) = 0;
952#endif
953 skb = skb_dequeue(&dev->drv[di]->rpqueue[channel]);
954 dev_kfree_skb(skb);
955 } else {
956 tty_insert_flip_char(tty, last, TTY_NORMAL);
957 /* Not yet emptied this buff, so it
958 * must stay in the queue, for further calls
959 * but we pull off the data we got until now.
960 */
961 skb_pull(skb, count_pull);
962#ifdef CONFIG_ISDN_AUDIO
963 ISDN_AUDIO_SKB_LOCK(skb) = 0;
964#endif
965 }
966 dev->drv[di]->rcvcount[channel] -= count_put;
967 }
968 return count;
969}
970
971
860static __inline int 972static __inline int
861isdn_minor2drv(int minor) 973isdn_minor2drv(int minor)
862{ 974{
diff --git a/drivers/isdn/i4l/isdn_common.h b/drivers/isdn/i4l/isdn_common.h
index e27e9c3a81ed..082735dbb412 100644
--- a/drivers/isdn/i4l/isdn_common.h
+++ b/drivers/isdn/i4l/isdn_common.h
@@ -37,6 +37,7 @@ extern void isdn_timer_ctrl(int tf, int onoff);
37extern void isdn_unexclusive_channel(int di, int ch); 37extern void isdn_unexclusive_channel(int di, int ch);
38extern int isdn_getnum(char **); 38extern int isdn_getnum(char **);
39extern int isdn_readbchan(int, int, u_char *, u_char *, int, wait_queue_head_t *); 39extern int isdn_readbchan(int, int, u_char *, u_char *, int, wait_queue_head_t *);
40extern int isdn_readbchan_tty(int, int, struct tty_struct *, int);
40extern int isdn_get_free_channel(int, int, int, int, int, char *); 41extern int isdn_get_free_channel(int, int, int, int, int, char *);
41extern int isdn_writebuf_skb_stub(int, int, int, struct sk_buff *); 42extern int isdn_writebuf_skb_stub(int, int, int, struct sk_buff *);
42extern int register_isdn(isdn_if * i); 43extern int register_isdn(isdn_if * i);
diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c
index 8c404b4e2482..f190a99604f0 100644
--- a/drivers/isdn/i4l/isdn_tty.c
+++ b/drivers/isdn/i4l/isdn_tty.c
@@ -64,37 +64,42 @@ isdn_tty_try_read(modem_info * info, struct sk_buff *skb)
64 int c; 64 int c;
65 int len; 65 int len;
66 struct tty_struct *tty; 66 struct tty_struct *tty;
67 char last;
67 68
68 if (info->online) { 69 if (info->online) {
69 if ((tty = info->tty)) { 70 if ((tty = info->tty)) {
70 if (info->mcr & UART_MCR_RTS) { 71 if (info->mcr & UART_MCR_RTS) {
71 c = TTY_FLIPBUF_SIZE - tty->flip.count;
72 len = skb->len 72 len = skb->len
73#ifdef CONFIG_ISDN_AUDIO 73#ifdef CONFIG_ISDN_AUDIO
74 + ISDN_AUDIO_SKB_DLECOUNT(skb) 74 + ISDN_AUDIO_SKB_DLECOUNT(skb)
75#endif 75#endif
76 ; 76 ;
77
78 c = tty_buffer_request_room(tty, len);
77 if (c >= len) { 79 if (c >= len) {
78#ifdef CONFIG_ISDN_AUDIO 80#ifdef CONFIG_ISDN_AUDIO
79 if (ISDN_AUDIO_SKB_DLECOUNT(skb)) 81 if (ISDN_AUDIO_SKB_DLECOUNT(skb)) {
80 while (skb->len--) { 82 int l = skb->len;
83 unsigned char *dp = skb->data;
84 while (--l) {
81 if (*skb->data == DLE) 85 if (*skb->data == DLE)
82 tty_insert_flip_char(tty, DLE, 0); 86 tty_insert_flip_char(tty, DLE, 0);
83 tty_insert_flip_char(tty, *skb->data++, 0); 87 tty_insert_flip_char(tty, *dp++, 0);
88 }
89 last = *dp;
84 } else { 90 } else {
85#endif 91#endif
86 memcpy(tty->flip.char_buf_ptr, 92 if(len > 1)
87 skb->data, len); 93 tty_insert_flip_string(tty, skb->data, len - 1);
88 tty->flip.count += len; 94 last = skb->data[len - 1];
89 tty->flip.char_buf_ptr += len;
90 memset(tty->flip.flag_buf_ptr, 0, len);
91 tty->flip.flag_buf_ptr += len;
92#ifdef CONFIG_ISDN_AUDIO 95#ifdef CONFIG_ISDN_AUDIO
93 } 96 }
94#endif 97#endif
95 if (info->emu.mdmreg[REG_CPPP] & BIT_CPPP) 98 if (info->emu.mdmreg[REG_CPPP] & BIT_CPPP)
96 tty->flip.flag_buf_ptr[len - 1] = 0xff; 99 tty_insert_flip_char(tty, last, 0xFF);
97 schedule_delayed_work(&tty->flip.work, 1); 100 else
101 tty_insert_flip_char(tty, last, TTY_NORMAL);
102 tty_flip_buffer_push(tty);
98 kfree_skb(skb); 103 kfree_skb(skb);
99 return 1; 104 return 1;
100 } 105 }
@@ -114,7 +119,6 @@ isdn_tty_readmodem(void)
114 int resched = 0; 119 int resched = 0;
115 int midx; 120 int midx;
116 int i; 121 int i;
117 int c;
118 int r; 122 int r;
119 struct tty_struct *tty; 123 struct tty_struct *tty;
120 modem_info *info; 124 modem_info *info;
@@ -131,20 +135,13 @@ isdn_tty_readmodem(void)
131#endif 135#endif
132 if ((tty = info->tty)) { 136 if ((tty = info->tty)) {
133 if (info->mcr & UART_MCR_RTS) { 137 if (info->mcr & UART_MCR_RTS) {
134 c = TTY_FLIPBUF_SIZE - tty->flip.count; 138 /* CISCO AsyncPPP Hack */
135 if (c > 0) { 139 if (!(info->emu.mdmreg[REG_CPPP] & BIT_CPPP))
136 r = isdn_readbchan(info->isdn_driver, info->isdn_channel, 140 r = isdn_readbchan_tty(info->isdn_driver, info->isdn_channel, tty, 0);
137 tty->flip.char_buf_ptr, 141 else
138 tty->flip.flag_buf_ptr, c, NULL); 142 r = isdn_readbchan_tty(info->isdn_driver, info->isdn_channel, tty, 1);
139 /* CISCO AsyncPPP Hack */ 143 if (r)
140 if (!(info->emu.mdmreg[REG_CPPP] & BIT_CPPP)) 144 tty_flip_buffer_push(tty);
141 memset(tty->flip.flag_buf_ptr, 0, r);
142 tty->flip.count += r;
143 tty->flip.flag_buf_ptr += r;
144 tty->flip.char_buf_ptr += r;
145 if (r)
146 schedule_delayed_work(&tty->flip.work, 1);
147 }
148 } else 145 } else
149 r = 1; 146 r = 1;
150 } else 147 } else
@@ -249,7 +246,7 @@ isdn_tty_rcv_skb(int i, int di, int channel, struct sk_buff *skb)
249 } 246 }
250#endif 247#endif
251#endif 248#endif
252 /* Try to deliver directly via tty-flip-buf if queue is empty */ 249 /* Try to deliver directly via tty-buf if queue is empty */
253 spin_lock_irqsave(&info->readlock, flags); 250 spin_lock_irqsave(&info->readlock, flags);
254 if (skb_queue_empty(&dev->drv[di]->rpqueue[channel])) 251 if (skb_queue_empty(&dev->drv[di]->rpqueue[channel]))
255 if (isdn_tty_try_read(info, skb)) { 252 if (isdn_tty_try_read(info, skb)) {
@@ -534,7 +531,7 @@ isdn_tty_senddown(modem_info * info)
534/* The next routine is called once from within timer-interrupt 531/* The next routine is called once from within timer-interrupt
535 * triggered within isdn_tty_modem_ncarrier(). It calls 532 * triggered within isdn_tty_modem_ncarrier(). It calls
536 * isdn_tty_modem_result() to stuff a "NO CARRIER" Message 533 * isdn_tty_modem_result() to stuff a "NO CARRIER" Message
537 * into the tty's flip-buffer. 534 * into the tty's buffer.
538 */ 535 */
539static void 536static void
540isdn_tty_modem_do_ncarrier(unsigned long data) 537isdn_tty_modem_do_ncarrier(unsigned long data)
@@ -2347,6 +2344,7 @@ isdn_tty_at_cout(char *msg, modem_info * info)
2347 u_long flags; 2344 u_long flags;
2348 struct sk_buff *skb = NULL; 2345 struct sk_buff *skb = NULL;
2349 char *sp = NULL; 2346 char *sp = NULL;
2347 int l = strlen(msg);
2350 2348
2351 if (!msg) { 2349 if (!msg) {
2352 printk(KERN_WARNING "isdn_tty: Null-Message in isdn_tty_at_cout\n"); 2350 printk(KERN_WARNING "isdn_tty: Null-Message in isdn_tty_at_cout\n");
@@ -2359,16 +2357,16 @@ isdn_tty_at_cout(char *msg, modem_info * info)
2359 return; 2357 return;
2360 } 2358 }
2361 2359
2362 /* use queue instead of direct flip, if online and */ 2360 /* use queue instead of direct, if online and */
2363 /* data is in queue or flip buffer is full */ 2361 /* data is in queue or buffer is full */
2364 if ((info->online) && (((tty->flip.count + strlen(msg)) >= TTY_FLIPBUF_SIZE) || 2362 if ((info->online && tty_buffer_request_room(tty, l) < l) ||
2365 (!skb_queue_empty(&dev->drv[info->isdn_driver]->rpqueue[info->isdn_channel])))) { 2363 (!skb_queue_empty(&dev->drv[info->isdn_driver]->rpqueue[info->isdn_channel]))) {
2366 skb = alloc_skb(strlen(msg), GFP_ATOMIC); 2364 skb = alloc_skb(l, GFP_ATOMIC);
2367 if (!skb) { 2365 if (!skb) {
2368 spin_unlock_irqrestore(&info->readlock, flags); 2366 spin_unlock_irqrestore(&info->readlock, flags);
2369 return; 2367 return;
2370 } 2368 }
2371 sp = skb_put(skb, strlen(msg)); 2369 sp = skb_put(skb, l);
2372#ifdef CONFIG_ISDN_AUDIO 2370#ifdef CONFIG_ISDN_AUDIO
2373 ISDN_AUDIO_SKB_DLECOUNT(skb) = 0; 2371 ISDN_AUDIO_SKB_DLECOUNT(skb) = 0;
2374 ISDN_AUDIO_SKB_LOCK(skb) = 0; 2372 ISDN_AUDIO_SKB_LOCK(skb) = 0;
@@ -2392,9 +2390,8 @@ isdn_tty_at_cout(char *msg, modem_info * info)
2392 if (skb) { 2390 if (skb) {
2393 *sp++ = c; 2391 *sp++ = c;
2394 } else { 2392 } else {
2395 if (tty->flip.count >= TTY_FLIPBUF_SIZE) 2393 if(tty_insert_flip_char(tty, c, TTY_NORMAL) == 0)
2396 break; 2394 break;
2397 tty_insert_flip_char(tty, c, 0);
2398 } 2395 }
2399 } 2396 }
2400 if (skb) { 2397 if (skb) {
@@ -2402,12 +2399,12 @@ isdn_tty_at_cout(char *msg, modem_info * info)
2402 dev->drv[info->isdn_driver]->rcvcount[info->isdn_channel] += skb->len; 2399 dev->drv[info->isdn_driver]->rcvcount[info->isdn_channel] += skb->len;
2403 spin_unlock_irqrestore(&info->readlock, flags); 2400 spin_unlock_irqrestore(&info->readlock, flags);
2404 /* Schedule dequeuing */ 2401 /* Schedule dequeuing */
2405 if ((dev->modempoll) && (info->rcvsched)) 2402 if (dev->modempoll && info->rcvsched)
2406 isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1); 2403 isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);
2407 2404
2408 } else { 2405 } else {
2409 spin_unlock_irqrestore(&info->readlock, flags); 2406 spin_unlock_irqrestore(&info->readlock, flags);
2410 schedule_delayed_work(&tty->flip.work, 1); 2407 tty_flip_buffer_push(tty);
2411 } 2408 }
2412} 2409}
2413 2410