diff options
Diffstat (limited to 'drivers/isdn')
-rw-r--r-- | drivers/isdn/capi/capi.c | 3 | ||||
-rw-r--r-- | drivers/isdn/i4l/isdn_common.c | 112 | ||||
-rw-r--r-- | drivers/isdn/i4l/isdn_common.h | 1 | ||||
-rw-r--r-- | drivers/isdn/i4l/isdn_tty.c | 75 |
4 files changed, 150 insertions, 41 deletions
diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c index 11ae0fddea04..623adbb0d13a 100644 --- a/drivers/isdn/capi/capi.c +++ b/drivers/isdn/capi/capi.c | |||
@@ -463,8 +463,7 @@ static int handle_recv_skb(struct capiminor *mp, struct sk_buff *skb) | |||
463 | #endif | 463 | #endif |
464 | goto bad; | 464 | goto bad; |
465 | } | 465 | } |
466 | if (ld->receive_room && | 466 | if (mp->tty->receive_room < datalen) { |
467 | ld->receive_room(mp->tty) < datalen) { | ||
468 | #if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS) | 467 | #if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS) |
469 | printk(KERN_DEBUG "capi: no room in tty\n"); | 468 | printk(KERN_DEBUG "capi: no room in tty\n"); |
470 | #endif | 469 | #endif |
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 | */ | ||
873 | int | ||
874 | isdn_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 | |||
860 | static __inline int | 972 | static __inline int |
861 | isdn_minor2drv(int minor) | 973 | isdn_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); | |||
37 | extern void isdn_unexclusive_channel(int di, int ch); | 37 | extern void isdn_unexclusive_channel(int di, int ch); |
38 | extern int isdn_getnum(char **); | 38 | extern int isdn_getnum(char **); |
39 | extern int isdn_readbchan(int, int, u_char *, u_char *, int, wait_queue_head_t *); | 39 | extern int isdn_readbchan(int, int, u_char *, u_char *, int, wait_queue_head_t *); |
40 | extern int isdn_readbchan_tty(int, int, struct tty_struct *, int); | ||
40 | extern int isdn_get_free_channel(int, int, int, int, int, char *); | 41 | extern int isdn_get_free_channel(int, int, int, int, int, char *); |
41 | extern int isdn_writebuf_skb_stub(int, int, int, struct sk_buff *); | 42 | extern int isdn_writebuf_skb_stub(int, int, int, struct sk_buff *); |
42 | extern int register_isdn(isdn_if * i); | 43 | extern 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 | */ |
539 | static void | 536 | static void |
540 | isdn_tty_modem_do_ncarrier(unsigned long data) | 537 | isdn_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 | ||