patch-2.0.26 linux/drivers/isdn/icn/icn.c
Next file: linux/drivers/isdn/icn/icn.h
Previous file: linux/drivers/cdrom/mcd.c
Back to the patch index
Back to the overall index
- Lines: 453
- Date:
Wed Nov 13 08:36:19 1996
- Orig file:
v2.0.25/linux/drivers/isdn/icn/icn.c
- Orig date:
Sun Sep 1 09:15:32 1996
diff -u --recursive --new-file v2.0.25/linux/drivers/isdn/icn/icn.c linux/drivers/isdn/icn/icn.c
@@ -1,4 +1,4 @@
-/* $Id: icn.c,v 1.29 1996/08/29 20:34:54 fritz Exp $
+/* $Id: icn.c,v 1.31 1996/11/13 02:36:25 fritz Exp $
*
* ISDN low-level module for the ICN active ISDN-Card.
*
@@ -19,6 +19,13 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: icn.c,v $
+ * Revision 1.31 1996/11/13 02:36:25 fritz
+ * Fixed a race condition in writecmd.
+ * Some optimizations and cleanup.
+ *
+ * Revision 1.30 1996/10/22 23:14:09 fritz
+ * Changes for compatibility to 2.0.X and 2.1.X kernels.
+ *
* Revision 1.29 1996/08/29 20:34:54 fritz
* Bugfix in send queue management:
* sndcount was not updated correctly.
@@ -141,7 +148,7 @@
#undef MAP_DEBUG
static char
-*revision = "$Revision: 1.29 $";
+*revision = "$Revision: 1.31 $";
static int icn_addcard(int, char *, char *);
@@ -153,13 +160,9 @@
static void icn_free_queue(struct sk_buff_head *queue)
{
struct sk_buff *skb;
- unsigned long flags;
-
- save_flags(flags);
- cli();
+
while ((skb = skb_dequeue(queue)))
dev_kfree_skb(skb, FREE_WRITE);
- restore_flags(flags);
}
/* Put a value into a shift-register, highest bit first.
@@ -262,7 +265,7 @@
#endif
save_flags(flags);
cli();
- if (dev.chanlock)
+ if (dev.chanlock > 0)
dev.chanlock--;
restore_flags(flags);
}
@@ -275,12 +278,12 @@
{
ulong flags;
- save_flags(flags);
- cli();
#ifdef MAP_DEBUG
printk(KERN_DEBUG "trymaplock c=%d dc=%d l=%d\n", channel, dev.channel,
dev.chanlock);
#endif
+ save_flags(flags);
+ cli();
if ((!dev.chanlock) ||
((dev.channel == channel) && (dev.mcard == card))) {
dev.chanlock++;
@@ -306,12 +309,12 @@
{
ulong flags;
- save_flags(flags);
- cli();
#ifdef MAP_DEBUG
printk(KERN_DEBUG "map_release c=%d l=%d\n", channel, dev.chanlock);
#endif
- if (dev.chanlock)
+ save_flags(flags);
+ cli();
+ if (dev.chanlock > 0)
dev.chanlock--;
if (!dev.chanlock)
icn_map_channel(card,channel);
@@ -381,10 +384,12 @@
struct sk_buff *skb;
isdn_ctrl cmd;
- if (!card->sndcount[channel])
+ if (!(card->sndcount[channel] ||
+ skb_queue_len(&card->spqueue[channel])))
return;
if (icn_trymaplock_channel(card,mch)) {
- while (sbfree && card->sndcount[channel]) {
+ while (sbfree && (card->sndcount[channel] ||
+ skb_queue_len(&card->spqueue[channel]))) {
save_flags(flags);
cli();
if (card->xmit_lock[channel]) {
@@ -567,6 +572,22 @@
return dflag;
}
+static void icn_putmsg(icn_card *card, unsigned char c)
+{
+ ulong flags;
+
+ save_flags(flags);
+ cli();
+ *card->msg_buf_write++ = (c == 0xff) ? '\n' : c;
+ if (card->msg_buf_write == card->msg_buf_read) {
+ if (++card->msg_buf_read > card->msg_buf_end)
+ card->msg_buf_read = card->msg_buf;
+ }
+ if (card->msg_buf_write > card->msg_buf_end)
+ card->msg_buf_write = card->msg_buf;
+ restore_flags(flags);
+}
+
static void icn_polldchan(unsigned long data)
{
icn_card *card = (icn_card *)data;
@@ -585,16 +606,7 @@
avail = msg_avail;
for (left = avail, i = readb(&msg_o); left > 0; i++, left--) {
c = readb(&dev.shmem->comm_buffers.iopc_buf[i & 0xff]);
- save_flags(flags);
- cli();
- *card->msg_buf_write++ = (c == 0xff) ? '\n' : c;
- if (card->msg_buf_write == card->msg_buf_read) {
- if (++card->msg_buf_read > card->msg_buf_end)
- card->msg_buf_read = card->msg_buf;
- }
- if (card->msg_buf_write > card->msg_buf_end)
- card->msg_buf_write = card->msg_buf;
- restore_flags(flags);
+ icn_putmsg(card, c);
if (c == 0xff) {
card->imsg[card->iptr] = 0;
card->iptr = 0;
@@ -833,28 +845,28 @@
printk(KERN_DEBUG "shmem=%08lx\n", (ulong) dev.shmem);
#endif
SLEEP(1);
- save_flags(flags);
- cli();
#ifdef BOOT_DEBUG
printk(KERN_DEBUG "Map Bank 0\n");
#endif
+ save_flags(flags);
+ cli();
icn_map_channel(card,0); /* Select Bank 0 */
icn_lock_channel(card,0); /* Lock Bank 0 */
restore_flags(flags);
SLEEP(1);
- memcpy_fromfs(codebuf, buffer, ICN_CODE_STAGE1);
+ copy_from_user(codebuf, buffer, ICN_CODE_STAGE1);
memcpy_toio(dev.shmem, codebuf, ICN_CODE_STAGE1); /* Copy code */
#ifdef BOOT_DEBUG
printk(KERN_DEBUG "Bootloader transfered\n");
#endif
if (card->doubleS0) {
SLEEP(1);
- save_flags(flags);
- cli();
- icn_release_channel();
#ifdef BOOT_DEBUG
printk(KERN_DEBUG "Map Bank 8\n");
#endif
+ save_flags(flags);
+ cli();
+ icn_release_channel();
icn_map_channel(card,2); /* Select Bank 8 */
icn_lock_channel(card,2); /* Lock Bank 8 */
restore_flags(flags);
@@ -872,11 +884,11 @@
if (!card->doubleS0)
return 0;
/* reached only, if we have a Double-S0-Card */
- save_flags(flags);
- cli();
#ifdef BOOT_DEBUG
printk(KERN_DEBUG "Map Bank 0\n");
#endif
+ save_flags(flags);
+ cli();
icn_map_channel(card,0); /* Select Bank 0 */
icn_lock_channel(card,0); /* Lock Bank 0 */
restore_flags(flags);
@@ -913,7 +925,7 @@
while (left) {
if (sbfree) { /* If there is a free buffer... */
cnt = MIN(256, left);
- memcpy_fromfs(codebuf, p, cnt);
+ copy_from_user(codebuf, p, cnt);
memcpy_toio(&sbuf_l, codebuf, cnt); /* copy data */
sbnext; /* switch to next buffer */
p += cnt;
@@ -957,12 +969,12 @@
schedule();
} else {
if ((card->secondhalf) || (!card->doubleS0)) {
- save_flags(flags);
- cli();
#ifdef BOOT_DEBUG
printk(KERN_DEBUG "Proto loaded, install poll-timer %d\n",
card->secondhalf);
#endif
+ save_flags(flags);
+ cli();
init_timer(&card->st_timer);
card->st_timer.expires = jiffies + ICN_TIMER_DCREAD;
card->st_timer.function = icn_polldchan;
@@ -995,7 +1007,7 @@
if (card->msg_buf_read == card->msg_buf_write)
return count;
if (user)
- put_fs_byte(*card->msg_buf_read++, p);
+ put_user(*card->msg_buf_read++, p);
else
*p = *card->msg_buf_read++;
if (card->msg_buf_read > card->msg_buf_end)
@@ -1005,64 +1017,70 @@
}
/* Put command-strings into the command-queue of the Interface */
-static int icn_writecmd(const u_char * buf, int len, int user, icn_card * card, int waitflg)
+static int icn_writecmd(const u_char * buf, int len, int user, icn_card * card)
{
- int mch = card->secondhalf ? 2 : 0;
+ int mch = card->secondhalf ? 2 : 0;
int avail;
int pp;
int i;
int count;
+ int xcount;
int ocount;
+ int loop;
unsigned long flags;
+ int lastmap_channel;
+ struct icn_card *lastmap_card;
u_char *p;
isdn_ctrl cmd;
u_char msg[0x100];
- while (1) {
- if (icn_trymaplock_channel(card, mch)) {
- avail = cmd_free;
- count = MIN(avail, len);
- if (user)
- memcpy_fromfs(msg, buf, count);
- else
- memcpy(msg, buf, count);
- save_flags(flags);
- cli();
- ocount = 1;
- *card->msg_buf_write++ = '>';
- if (card->msg_buf_write > card->msg_buf_end)
- card->msg_buf_write = card->msg_buf;
- for (p = msg, pp = readb(&cmd_i), i = count; i > 0; i--, p++, pp++) {
- writeb((*p == '\n') ? 0xff : *p,
- &dev.shmem->comm_buffers.pcio_buf[pp & 0xff]);
- *card->msg_buf_write++ = *p;
- if ((*p == '\n') && (i > 1)) {
- *card->msg_buf_write++ = '>';
- if (card->msg_buf_write > card->msg_buf_end)
- card->msg_buf_write = card->msg_buf;
- ocount++;
- }
- /* No checks for buffer overflow of raw-status-device */
- if (card->msg_buf_write > card->msg_buf_end)
- card->msg_buf_write = card->msg_buf;
+ ocount = 1;
+ xcount = loop = 0;
+ while (len) {
+ save_flags(flags);
+ cli();
+ lastmap_card = dev.mcard;
+ lastmap_channel = dev.channel;
+ icn_map_channel(card, mch);
+
+ avail = cmd_free;
+ count = MIN(avail, len);
+ if (user)
+ copy_from_user(msg, buf, count);
+ else
+ memcpy(msg, buf, count);
+ icn_putmsg(card, '>');
+ for (p = msg, pp = readb(&cmd_i), i = count; i > 0; i--, p++, pp
+ ++) {
+ writeb((*p == '\n') ? 0xff : *p,
+ &dev.shmem->comm_buffers.pcio_buf[pp & 0xff]);
+ len--;
+ xcount++;
+ icn_putmsg(card, *p);
+ if ((*p == '\n') && (i > 1)) {
+ icn_putmsg(card, '>');
ocount++;
}
- restore_flags(flags);
- cmd.command = ISDN_STAT_STAVAIL;
- cmd.driver = card->myid;
- cmd.arg = ocount;
- card->interface.statcallb(&cmd);
- writeb((readb(&cmd_i) + count) & 0xff, &cmd_i);
- icn_release_channel();
- waitflg = 0;
+ ocount++;
+ }
+ writeb((readb(&cmd_i) + count) & 0xff, &cmd_i);
+ if (lastmap_card)
+ icn_map_channel(lastmap_card, lastmap_channel);
+ restore_flags(flags);
+ if (len) {
+ udelay(1000);
+ if (loop++ > 20)
+ break;
} else
- count = 0;
- if (!waitflg)
break;
- current->timeout = jiffies + 10;
- schedule();
}
- return count;
+ if (len && (!user))
+ printk(KERN_WARNING "icn: writemsg incomplete!\n");
+ cmd.command = ISDN_STAT_STAVAIL;
+ cmd.driver = card->myid;
+ cmd.arg = ocount;
+ card->interface.statcallb(&cmd);
+ return xcount;
}
/*
@@ -1175,12 +1193,12 @@
(void *) a,
sizeof(ulong) * 2)))
return i;
- memcpy_tofs((char *)a,
+ copy_from_user((char *)a,
(char *)&card, sizeof(ulong));
a += sizeof(ulong);
{
ulong l = (ulong)&dev;
- memcpy_tofs((char *)a,
+ copy_from_user((char *)a,
(char *)&l, sizeof(ulong));
}
return 0;
@@ -1198,7 +1216,7 @@
case ICN_IOCTL_ADDCARD:
if ((i = verify_area(VERIFY_READ, (void *) a, sizeof(icn_cdef))))
return i;
- memcpy_fromfs((char *)&cdef, (char *)a, sizeof(cdef));
+ copy_from_user((char *)&cdef, (char *)a, sizeof(cdef));
return (icn_addcard(cdef.port, cdef.id1, cdef.id2));
break;
case ICN_IOCTL_LEASEDCFG:
@@ -1212,7 +1230,7 @@
current->timeout = jiffies + ICN_BOOT_TIMEOUT1;
schedule();
sprintf(cbuf, "00;FV2ON\n01;EAZ1\n");
- i = icn_writecmd(cbuf, strlen(cbuf), 0, card, 1);
+ i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
printk(KERN_INFO
"icn: (%s) Leased-line mode enabled\n",
CID);
@@ -1225,7 +1243,7 @@
if (card->leased) {
card->leased = 0;
sprintf(cbuf, "00;FV2OFF\n");
- i = icn_writecmd(cbuf, strlen(cbuf), 0, card, 1);
+ i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
printk(KERN_INFO
"icn: (%s) Leased-line mode disabled\n",
CID);
@@ -1275,7 +1293,7 @@
*p2 = '\0';
sprintf(cbuf, "%02d;D%s_R%s,%02d,%02d,%s\n", (int) (a + 1), dcode, dial, si1,
si2, p);
- i = icn_writecmd(cbuf, strlen(cbuf), 0, card, 1);
+ i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
}
break;
case ISDN_CMD_ACCEPTD:
@@ -1292,10 +1310,10 @@
sprintf(cbuf, "%02d;BTRA\n", (int) a);
break;
}
- i = icn_writecmd(cbuf, strlen(cbuf), 0, card, 1);
+ i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
}
sprintf(cbuf, "%02d;DCON_R\n", (int) a);
- i = icn_writecmd(cbuf, strlen(cbuf), 0, card, 1);
+ i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
}
break;
case ISDN_CMD_ACCEPTB:
@@ -1314,7 +1332,7 @@
}
else
sprintf(cbuf, "%02d;BCON_R\n", (int) a);
- i = icn_writecmd(cbuf, strlen(cbuf), 0, card, 1);
+ i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
}
break;
case ISDN_CMD_HANGUP:
@@ -1323,7 +1341,7 @@
if (c->arg < ICN_BCH) {
a = c->arg + 1;
sprintf(cbuf, "%02d;BDIS_R\n%02d;DDIS_R\n", (int) a, (int) a);
- i = icn_writecmd(cbuf, strlen(cbuf), 0, card, 1);
+ i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
}
break;
case ISDN_CMD_SETEAZ:
@@ -1339,7 +1357,7 @@
} else
sprintf(cbuf, "%02d;EAZ%s\n", (int) a,
c->num[0] ? c->num : "0123456789");
- i = icn_writecmd(cbuf, strlen(cbuf), 0, card, 1);
+ i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
}
break;
case ISDN_CMD_CLREAZ:
@@ -1353,7 +1371,7 @@
sprintf(cbuf, "%02d;MSNC\n", (int) a);
else
sprintf(cbuf, "%02d;EAZC\n", (int) a);
- i = icn_writecmd(cbuf, strlen(cbuf), 0, card, 1);
+ i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
}
break;
case ISDN_CMD_SETL2:
@@ -1371,7 +1389,7 @@
default:
return -EINVAL;
}
- i = icn_writecmd(cbuf, strlen(cbuf), 0, card, 1);
+ i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
card->l2_proto[a & 255] = (a >> 8);
}
break;
@@ -1455,7 +1473,7 @@
if (card) {
if (!card->flags & ICN_FLAGS_RUNNING)
return -ENODEV;
- return (icn_writecmd(buf, len, user, card, 0));
+ return (icn_writecmd(buf, len, user, card));
}
printk(KERN_ERR
"icn: if_writecmd called with invalid driverId!\n");
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov