diff options
Diffstat (limited to 'drivers/isdn/i4l/isdn_common.c')
-rw-r--r-- | drivers/isdn/i4l/isdn_common.c | 112 |
1 files changed, 112 insertions, 0 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 | */ | ||
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 | { |