#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>
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)
*/
#include <linux/isdn/capicmd.h>
-int
+static int
isdn_capi_rec_hl_msg(capi_msg *cm) {
int di;
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)
{
if (dev->drv[drvidx]->interface->readstat) {
if (count > dev->drv[drvidx]->stavail)
count = dev->drv[drvidx]->stavail;
- len = dev->drv[drvidx]->interface->
- readstat(buf, count, drvidx,
- isdn_minor2chan(minor));
+ len = dev->drv[drvidx]->interface->readstat(buf, count,
+ drvidx, isdn_minor2chan(minor));
+ if (len < 0) {
+ retval = len;
+ goto out;
+ }
} else {
len = 0;
}
if (arg) {
ulong __user *p = argp;
int i;
- if ((ret = verify_area(VERIFY_WRITE, p,
- sizeof(ulong) * ISDN_MAX_CHANNELS * 2)))
- return ret;
+ if (!access_ok(VERIFY_WRITE, p,
+ sizeof(ulong) * ISDN_MAX_CHANNELS * 2))
+ return -EFAULT;
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
put_user(dev->ibytes[i], p++);
put_user(dev->obytes[i], p++);
char __user *p = argp;
int i;
- if ((ret = verify_area(VERIFY_WRITE, argp,
+ if (!access_ok(VERIFY_WRITE, argp,
(ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN)
- * ISDN_MAX_CHANNELS)))
- return ret;
+ * ISDN_MAX_CHANNELS))
+ return -EFAULT;
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
if (copy_to_user(p, dev->mdm.info[i].emu.profile,
char __user *p = argp;
int i;
- if ((ret = verify_area(VERIFY_READ, argp,
+ if (!access_ok(VERIFY_READ, argp,
(ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN)
- * ISDN_MAX_CHANNELS)))
- return ret;
+ * ISDN_MAX_CHANNELS))
+ return -EFAULT;
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
if (copy_from_user(dev->mdm.info[i].emu.profile, p,
int j = 0;
while (1) {
- if ((ret = verify_area(VERIFY_READ, p, 1)))
- return ret;
+ if (!access_ok(VERIFY_READ, p, 1))
+ return -EFAULT;
get_user(bname[j], p++);
switch (bname[j]) {
case '\0':
drvidx = 0;
if (drvidx == -1)
return -ENODEV;
- if ((ret = verify_area(VERIFY_WRITE, argp,
- sizeof(isdn_ioctl_struct))))
- return ret;
+ if (!access_ok(VERIFY_WRITE, argp,
+ sizeof(isdn_ioctl_struct)))
+ return -EFAULT;
c.driver = drvidx;
c.command = ISDN_CMD_IOCTL;
c.arg = cmd;
return ret;
}
-int
+static int
isdn_add_channels(isdn_driver_t *d, int drvidx, int n, int adding)
{
int j, k, m;
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);