Index: zaptel.c
===================================================================
--- zaptel.c	(revision 1253)
+++ zaptel.c	(working copy)
@@ -261,6 +261,9 @@
 
 static int debug;
 
+/* configure spans at registration time (if driver supports it)*/
+static int do_ztcfg = 0;
+
 /* states for transmit signalling */
 typedef enum {ZT_TXSTATE_ONHOOK,ZT_TXSTATE_OFFHOOK,ZT_TXSTATE_START,
 	ZT_TXSTATE_PREWINK,ZT_TXSTATE_WINK,ZT_TXSTATE_PREFLASH,
@@ -3205,6 +3208,207 @@
 #endif
 }
 
+static int zt_chanconfig(struct zt_chanconfig *chan_conf)
+{
+	unsigned long flags;
+	int sigcap;
+	int y;
+	int res = 0;
+	struct zt_chan *newmaster;
+	struct zt_chan *chan;
+
+	VALID_CHANNEL(chan_conf->chan);
+        chan = chans[chan_conf->chan];
+	if (chan_conf->sigtype == ZT_SIG_SLAVE) {
+		/* We have to use the master's sigtype */
+		if ((chan_conf->master < 1) || (chan_conf->master >= ZT_MAX_CHANNELS))
+			return -EINVAL;
+		if (!chans[chan_conf->master])
+			return -EINVAL;
+		chan_conf->sigtype = chans[chan_conf->master]->sig;
+		newmaster = chans[chan_conf->master];
+	} else if ((chan_conf->sigtype & __ZT_SIG_DACS) == __ZT_SIG_DACS) {
+		newmaster = chan;
+		if ((chan_conf->idlebits < 1) || (chan_conf->idlebits >= ZT_MAX_CHANNELS))
+			return -EINVAL;
+		if (!chans[chan_conf->idlebits])
+			return -EINVAL;
+	} else {
+		newmaster = chan;
+	}
+	spin_lock_irqsave(&chan->lock, flags);
+#ifdef CONFIG_ZAPATA_NET
+	if (chan->flags & ZT_FLAG_NETDEV) {
+		if (ztchan_to_dev(chan)->flags & IFF_UP) {
+			spin_unlock_irqrestore(&chan->lock, flags);
+			printk(KERN_WARNING "Can't switch HDLC net mode on channel %s, since current interface is up\n", chan->name);
+			return -EBUSY;
+		}
+#ifdef LINUX26
+		spin_unlock_irqrestore(&chan->lock, flags);
+		unregister_hdlc_device(chan->hdlcnetdev->netdev);
+		spin_lock_irqsave(&chan->lock, flags);
+		free_netdev(chan->hdlcnetdev->netdev);
+#else
+		unregister_hdlc_device(&chan->hdlcnetdev->netdev);
+#endif			
+		kfree(chan->hdlcnetdev);
+		chan->hdlcnetdev = NULL;
+		chan->flags &= ~ZT_FLAG_NETDEV;
+	}
+#else
+	if (chan_conf->sigtype == ZT_SIG_HDLCNET) {
+		spin_unlock_irqrestore(&chan->lock, flags);
+		printk(KERN_WARNING "Zaptel networking not supported by this build.\n");
+		return -ENOSYS;
+	}
+#endif		
+	sigcap = chan->sigcap;
+	/* If they support clear channel, then they support the HDLC and such through
+	   us.  */
+	if (sigcap & ZT_SIG_CLEAR) 
+		sigcap |= (ZT_SIG_HDLCRAW | ZT_SIG_HDLCFCS | ZT_SIG_HDLCNET | ZT_SIG_DACS);
+
+	if ((sigcap & chan_conf->sigtype) != chan_conf->sigtype)
+		res =  -EINVAL;	
+
+	if (!res && chan->span->chanconfig)
+		res = chan->span->chanconfig(chan, chan_conf->sigtype);
+	if (chan->master) {
+		/* Clear the master channel */
+		recalc_slaves(chan->master);
+		chan->nextslave = 0;
+	}
+	if (!res) {
+		chan->sig = chan_conf->sigtype;
+		if (chan->sig == ZT_SIG_CAS)
+			chan->idlebits = chan_conf->idlebits;
+		else
+			chan->idlebits = 0;
+		if ((chan_conf->sigtype & ZT_SIG_CLEAR) == ZT_SIG_CLEAR) {
+			/* Set clear channel flag if appropriate */
+			chan->flags &= ~ZT_FLAG_AUDIO;
+			chan->flags |= ZT_FLAG_CLEAR;
+		} else {
+			/* Set audio flag and not clear channel otherwise */
+			chan->flags |= ZT_FLAG_AUDIO;
+			chan->flags &= ~ZT_FLAG_CLEAR;
+		}
+		if ((chan_conf->sigtype & ZT_SIG_HDLCRAW) == ZT_SIG_HDLCRAW) {
+			/* Set the HDLC flag */
+			chan->flags |= ZT_FLAG_HDLC;
+		} else {
+			/* Clear the HDLC flag */
+			chan->flags &= ~ZT_FLAG_HDLC;
+		}
+		if ((chan_conf->sigtype & ZT_SIG_HDLCFCS) == ZT_SIG_HDLCFCS) {
+			/* Set FCS to be calculated if appropriate */
+			chan->flags |= ZT_FLAG_FCS;
+		} else {
+			/* Clear FCS flag */
+			chan->flags &= ~ZT_FLAG_FCS;
+		}
+		if ((chan_conf->sigtype & __ZT_SIG_DACS) == __ZT_SIG_DACS) {
+			/* Setup conference properly */
+			chan->confmode = ZT_CONF_DIGITALMON;
+			chan->confna = chan_conf->idlebits;
+			if (chan->span && 
+					chan->span->dacs && 
+					chans[chan_conf->idlebits] && 
+					chan->span && 
+					(chan->span->dacs == chans[chan_conf->idlebits]->span->dacs)) 
+				chan->span->dacs(chan, chans[chan_conf->idlebits]);
+		} else if (chan->span && chan->span->dacs)
+			chan->span->dacs(chan, NULL);
+		chan->master = newmaster;
+		/* Note new slave if we are not our own master */
+		if (newmaster != chan) {
+			recalc_slaves(chan->master);
+		}
+		if ((chan_conf->sigtype & ZT_SIG_HARDHDLC) == ZT_SIG_HARDHDLC) {
+			chan->flags &= ~ZT_FLAG_FCS;
+			chan->flags &= ~ZT_FLAG_HDLC;
+			chan->flags |= ZT_FLAG_NOSTDTXRX;
+		} else
+			chan->flags &= ~ZT_FLAG_NOSTDTXRX;
+	}
+#ifdef CONFIG_ZAPATA_NET
+	if (!res && 
+			(newmaster == chan) && 
+			(chan->sig == ZT_SIG_HDLCNET)) {
+		chan->hdlcnetdev = zt_hdlc_alloc();
+		if (chan->hdlcnetdev) {
+			/*				struct hdlc_device *hdlc = chan->hdlcnetdev;
+							struct net_device *d = hdlc_to_dev(hdlc); mmm...get it right later --byg */
+#ifdef LINUX26
+			chan->hdlcnetdev->netdev = alloc_hdlcdev(chan->hdlcnetdev);
+			if (chan->hdlcnetdev->netdev) {
+				chan->hdlcnetdev->chan = chan;
+				SET_MODULE_OWNER(chan->hdlcnetdev->netdev);
+				chan->hdlcnetdev->netdev->irq = chan->span->irq;
+				chan->hdlcnetdev->netdev->tx_queue_len = 50;
+				chan->hdlcnetdev->netdev->do_ioctl = zt_net_ioctl;
+				chan->hdlcnetdev->netdev->open = zt_net_open;
+				chan->hdlcnetdev->netdev->stop = zt_net_stop;
+				dev_to_hdlc(chan->hdlcnetdev->netdev)->attach = zt_net_attach;
+				dev_to_hdlc(chan->hdlcnetdev->netdev)->xmit = zt_xmit;
+				spin_unlock_irqrestore(&chan->lock, flags);
+				/* Briefly restore interrupts while we register the device */
+				res = zt_register_hdlc_device(chan->hdlcnetdev->netdev, chan_conf->netdev_name);
+				spin_lock_irqsave(&chan->lock, flags);
+			} else {
+				printk("Unable to allocate hdlc: *shrug*\n");
+				res = -1;
+			}
+#else /* LINUX26 */
+			chan->hdlcnetdev->chan = chan;
+#ifndef HDLC_MAINTAINERS_ARE_MORE_STUPID_THAN_I_THOUGHT
+			chan->hdlcnetdev->netdev.ioctl = zt_net_ioctl;
+#endif
+			chan->hdlcnetdev->netdev.netdev.do_ioctl = zt_net_ioctl;
+#ifdef NEW_HDLC_INTERFACE
+			chan->hdlcnetdev->netdev.netdev.open = zt_net_open;
+			chan->hdlcnetdev->netdev.netdev.stop = zt_net_stop;
+			chan->hdlcnetdev->netdev.xmit = zt_xmit;
+			chan->hdlcnetdev->netdev.attach = zt_net_attach;
+#else
+			chan->hdlcnetdev->netdev.open = zt_net_open;
+			chan->hdlcnetdev->netdev.close = zt_net_close;
+			chan->hdlcnetdev->netdev.set_mode = NULL;
+			chan->hdlcnetdev->netdev.xmit = zt_xmit;
+#endif /* NEW_HDLC_INTERFACE */
+			chan->hdlcnetdev->netdev.netdev.irq = chan->span->irq;
+			chan->hdlcnetdev->netdev.netdev.tx_queue_len = 50;
+			res = register_hdlc_device(&chan->hdlcnetdev->netdev);
+#endif /* LINUX26 */
+			if (!res)
+				chan->flags |= ZT_FLAG_NETDEV;
+		} else {
+			printk("Unable to allocate netdev: out of memory\n");
+			res = -1;
+		}
+	}
+#endif		
+	if ((chan->sig == ZT_SIG_HDLCNET) && 
+			(chan == newmaster) &&
+			!(chan->flags & ZT_FLAG_NETDEV))
+		printk("Unable to register HDLC device for channel %s\n", chan->name);
+	if (!res) {
+		/* Setup default law */
+		chan->deflaw = chan_conf->deflaw;
+		/* And hangup */
+		zt_hangup(chan);
+		y = zt_q_sig(chan) & 0xff;
+		if (y >= 0) chan->rxsig = (unsigned char)y;
+		chan->rxhooksig = ZT_RXSIG_INITIAL;
+	}
+#ifdef CONFIG_ZAPATA_DEBUG
+	printk("Configured channel %s, flags %04x, sig %04x\n", chan->name, chan->flags, chan->sig);
+#endif		
+	spin_unlock_irqrestore(&chan->lock, flags);
+	return res;
+}
+
 static int zt_ctl_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long data)
 {
 	/* I/O CTL's for control interface */
@@ -3212,10 +3416,8 @@
 	struct zt_lineconfig lc;
 	struct zt_chanconfig ch;
 	struct zt_sfconfig sf;
-	int sigcap;
 	int res = 0;
 	int x,y;
-	struct zt_chan *newmaster;
 	struct zt_dialparams tdp;
 	struct zt_maintinfo maint;
 	struct zt_indirect_data ind;
@@ -3265,200 +3467,13 @@
 	case ZT_CHANCONFIG:
 		if (copy_from_user(&ch, (struct zt_chanconfig *)data, sizeof(ch)))
 			return -EFAULT;
-		VALID_CHANNEL(ch.chan);
-		if (ch.sigtype == ZT_SIG_SLAVE) {
-			/* We have to use the master's sigtype */
-			if ((ch.master < 1) || (ch.master >= ZT_MAX_CHANNELS))
-				return -EINVAL;
-			if (!chans[ch.master])
-				return -EINVAL;
-			ch.sigtype = chans[ch.master]->sig;
-			newmaster = chans[ch.master];
-		} else if ((ch.sigtype & __ZT_SIG_DACS) == __ZT_SIG_DACS) {
-			newmaster = chans[ch.chan];
-			if ((ch.idlebits < 1) || (ch.idlebits >= ZT_MAX_CHANNELS))
-				return -EINVAL;
-			if (!chans[ch.idlebits])
-				return -EINVAL;
-		} else {
-			newmaster = chans[ch.chan];
-		}
-		spin_lock_irqsave(&chans[ch.chan]->lock, flags);
-#ifdef CONFIG_ZAPATA_NET
-		if (chans[ch.chan]->flags & ZT_FLAG_NETDEV) {
-			if (ztchan_to_dev(chans[ch.chan])->flags & IFF_UP) {
-				spin_unlock_irqrestore(&chans[ch.chan]->lock, flags);
-				printk(KERN_WARNING "Can't switch HDLC net mode on channel %s, since current interface is up\n", chans[ch.chan]->name);
-				return -EBUSY;
-			}
-#ifdef LINUX26
-			spin_unlock_irqrestore(&chans[ch.chan]->lock, flags);
-			unregister_hdlc_device(chans[ch.chan]->hdlcnetdev->netdev);
-			spin_lock_irqsave(&chans[ch.chan]->lock, flags);
-			free_netdev(chans[ch.chan]->hdlcnetdev->netdev);
-#else
-			unregister_hdlc_device(&chans[ch.chan]->hdlcnetdev->netdev);
-#endif			
-			kfree(chans[ch.chan]->hdlcnetdev);
-			chans[ch.chan]->hdlcnetdev = NULL;
-			chans[ch.chan]->flags &= ~ZT_FLAG_NETDEV;
-		}
-#else
-		if (ch.sigtype == ZT_SIG_HDLCNET) {
-				spin_unlock_irqrestore(&chans[ch.chan]->lock, flags);
-				printk(KERN_WARNING "Zaptel networking not supported by this build.\n");
-				return -ENOSYS;
-		}
-#endif		
-		sigcap = chans[ch.chan]->sigcap;
-		/* If they support clear channel, then they support the HDLC and such through
-		   us.  */
-		if (sigcap & ZT_SIG_CLEAR) 
-			sigcap |= (ZT_SIG_HDLCRAW | ZT_SIG_HDLCFCS | ZT_SIG_HDLCNET | ZT_SIG_DACS);
-		
-		if ((sigcap & ch.sigtype) != ch.sigtype)
-			res =  -EINVAL;	
-		
-		if (!res && chans[ch.chan]->span->chanconfig)
-			res = chans[ch.chan]->span->chanconfig(chans[ch.chan], ch.sigtype);
-		if (chans[ch.chan]->master) {
-			/* Clear the master channel */
-			recalc_slaves(chans[ch.chan]->master);
-			chans[ch.chan]->nextslave = 0;
-		}
+                res = zt_chanconfig(&ch);
 		if (!res) {
-			chans[ch.chan]->sig = ch.sigtype;
-			if (chans[ch.chan]->sig == ZT_SIG_CAS)
-				chans[ch.chan]->idlebits = ch.idlebits;
-			else
-				chans[ch.chan]->idlebits = 0;
-			if ((ch.sigtype & ZT_SIG_CLEAR) == ZT_SIG_CLEAR) {
-				/* Set clear channel flag if appropriate */
-				chans[ch.chan]->flags &= ~ZT_FLAG_AUDIO;
-				chans[ch.chan]->flags |= ZT_FLAG_CLEAR;
-			} else {
-				/* Set audio flag and not clear channel otherwise */
-				chans[ch.chan]->flags |= ZT_FLAG_AUDIO;
-				chans[ch.chan]->flags &= ~ZT_FLAG_CLEAR;
-			}
-			if ((ch.sigtype & ZT_SIG_HDLCRAW) == ZT_SIG_HDLCRAW) {
-				/* Set the HDLC flag */
-				chans[ch.chan]->flags |= ZT_FLAG_HDLC;
-			} else {
-				/* Clear the HDLC flag */
-				chans[ch.chan]->flags &= ~ZT_FLAG_HDLC;
-			}
-			if ((ch.sigtype & ZT_SIG_HDLCFCS) == ZT_SIG_HDLCFCS) {
-				/* Set FCS to be calculated if appropriate */
-				chans[ch.chan]->flags |= ZT_FLAG_FCS;
-			} else {
-				/* Clear FCS flag */
-				chans[ch.chan]->flags &= ~ZT_FLAG_FCS;
-			}
-			if ((ch.sigtype & __ZT_SIG_DACS) == __ZT_SIG_DACS) {
-				/* Setup conference properly */
-				chans[ch.chan]->confmode = ZT_CONF_DIGITALMON;
-				chans[ch.chan]->confna = ch.idlebits;
-				if (chans[ch.chan]->span && 
-				    chans[ch.chan]->span->dacs && 
-					chans[ch.idlebits] && 
-					chans[ch.chan]->span && 
-					(chans[ch.chan]->span->dacs == chans[ch.idlebits]->span->dacs)) 
-					chans[ch.chan]->span->dacs(chans[ch.chan], chans[ch.idlebits]);
-			} else if (chans[ch.chan]->span && chans[ch.chan]->span->dacs)
-				chans[ch.chan]->span->dacs(chans[ch.chan], NULL);
-			chans[ch.chan]->master = newmaster;
-			/* Note new slave if we are not our own master */
-			if (newmaster != chans[ch.chan]) {
-				recalc_slaves(chans[ch.chan]->master);
-			}
-			if ((ch.sigtype & ZT_SIG_HARDHDLC) == ZT_SIG_HARDHDLC) {
-				chans[ch.chan]->flags &= ~ZT_FLAG_FCS;
-				chans[ch.chan]->flags &= ~ZT_FLAG_HDLC;
-				chans[ch.chan]->flags |= ZT_FLAG_NOSTDTXRX;
-			} else
-				chans[ch.chan]->flags &= ~ZT_FLAG_NOSTDTXRX;
-		}
-#ifdef CONFIG_ZAPATA_NET
-		if (!res && 
-			(newmaster == chans[ch.chan]) && 
-		        (chans[ch.chan]->sig == ZT_SIG_HDLCNET)) {
-			chans[ch.chan]->hdlcnetdev = zt_hdlc_alloc();
-			if (chans[ch.chan]->hdlcnetdev) {
-/*				struct hdlc_device *hdlc = chans[ch.chan]->hdlcnetdev;
-				struct net_device *d = hdlc_to_dev(hdlc); mmm...get it right later --byg */
-#ifdef LINUX26
-				chans[ch.chan]->hdlcnetdev->netdev = alloc_hdlcdev(chans[ch.chan]->hdlcnetdev);
-				if (chans[ch.chan]->hdlcnetdev->netdev) {
-					chans[ch.chan]->hdlcnetdev->chan = chans[ch.chan];
-					SET_MODULE_OWNER(chans[ch.chan]->hdlcnetdev->netdev);
-					chans[ch.chan]->hdlcnetdev->netdev->irq = chans[ch.chan]->span->irq;
-					chans[ch.chan]->hdlcnetdev->netdev->tx_queue_len = 50;
-					chans[ch.chan]->hdlcnetdev->netdev->do_ioctl = zt_net_ioctl;
-					chans[ch.chan]->hdlcnetdev->netdev->open = zt_net_open;
-					chans[ch.chan]->hdlcnetdev->netdev->stop = zt_net_stop;
-					dev_to_hdlc(chans[ch.chan]->hdlcnetdev->netdev)->attach = zt_net_attach;
-					dev_to_hdlc(chans[ch.chan]->hdlcnetdev->netdev)->xmit = zt_xmit;
-					spin_unlock_irqrestore(&chans[ch.chan]->lock, flags);
-					/* Briefly restore interrupts while we register the device */
-					res = zt_register_hdlc_device(chans[ch.chan]->hdlcnetdev->netdev, ch.netdev_name);
-					spin_lock_irqsave(&chans[ch.chan]->lock, flags);
-				} else {
-					printk("Unable to allocate hdlc: *shrug*\n");
-					res = -1;
-				}
-#else /* LINUX26 */
-				chans[ch.chan]->hdlcnetdev->chan = chans[ch.chan];
-#ifndef HDLC_MAINTAINERS_ARE_MORE_STUPID_THAN_I_THOUGHT
-				chans[ch.chan]->hdlcnetdev->netdev.ioctl = zt_net_ioctl;
-#endif
-				chans[ch.chan]->hdlcnetdev->netdev.netdev.do_ioctl = zt_net_ioctl;
-#ifdef NEW_HDLC_INTERFACE
-				chans[ch.chan]->hdlcnetdev->netdev.netdev.open = zt_net_open;
-				chans[ch.chan]->hdlcnetdev->netdev.netdev.stop = zt_net_stop;
-				chans[ch.chan]->hdlcnetdev->netdev.xmit = zt_xmit;
-				chans[ch.chan]->hdlcnetdev->netdev.attach = zt_net_attach;
-#else
-				chans[ch.chan]->hdlcnetdev->netdev.open = zt_net_open;
-				chans[ch.chan]->hdlcnetdev->netdev.close = zt_net_close;
-				chans[ch.chan]->hdlcnetdev->netdev.set_mode = NULL;
-				chans[ch.chan]->hdlcnetdev->netdev.xmit = zt_xmit;
-#endif /* NEW_HDLC_INTERFACE */
-				chans[ch.chan]->hdlcnetdev->netdev.netdev.irq = chans[ch.chan]->span->irq;
-				chans[ch.chan]->hdlcnetdev->netdev.netdev.tx_queue_len = 50;
-				res = register_hdlc_device(&chans[ch.chan]->hdlcnetdev->netdev);
-#endif /* LINUX26 */
-				if (!res)
-					chans[ch.chan]->flags |= ZT_FLAG_NETDEV;
-			} else {
-				printk("Unable to allocate netdev: out of memory\n");
-				res = -1;
-			}
-		}
-#endif		
-		if ((chans[ch.chan]->sig == ZT_SIG_HDLCNET) && 
-		    (chans[ch.chan] == newmaster) &&
-		    !(chans[ch.chan]->flags & ZT_FLAG_NETDEV))
-			printk("Unable to register HDLC device for channel %s\n", chans[ch.chan]->name);
-		if (!res) {
-			/* Setup default law */
-			chans[ch.chan]->deflaw = ch.deflaw;
 			/* Copy back any modified settings */
-			spin_unlock_irqrestore(&chans[ch.chan]->lock, flags);
 			if (copy_to_user((struct zt_chanconfig *)data, &ch, sizeof(ch)))
 				return -EFAULT;
 			spin_lock_irqsave(&chans[ch.chan]->lock, flags);
-			/* And hangup */
-			zt_hangup(chans[ch.chan]);
-			y = zt_q_sig(chans[ch.chan]) & 0xff;
-			if (y >= 0) chans[ch.chan]->rxsig = (unsigned char)y;
-			chans[ch.chan]->rxhooksig = ZT_RXSIG_INITIAL;
 		}
-#ifdef CONFIG_ZAPATA_DEBUG
-		printk("Configured channel %s, flags %04x, sig %04x\n", chans[ch.chan]->name, chans[ch.chan]->flags, chans[ch.chan]->sig);
-#endif		
-		spin_unlock_irqrestore(&chans[ch.chan]->lock, flags);
-		return res;
 	case ZT_SFCONFIG:
 		if (copy_from_user(&sf, (struct zt_chanconfig *)data, sizeof(sf)))
 			return -EFAULT;
@@ -4631,6 +4646,29 @@
 		if (debug)
 			printk("Span ('%s') is new master\n", span->name);
 	}
+
+	/* give channels a sane default configuration, if possible */
+	if (do_ztcfg) {
+		/* FIXME: we have two copies of struct chanconfig on the stack.
+		 * And we actually don't use any of its longer fields
+		 * (name, netdev) */
+		struct zt_chanconfig chan_conf = {};
+		for (x = 0; x < span->channels; x++) {
+			/* if channel only supports one of the two 
+			 * fxsks/fxoks: sedefault to use it */
+			/* TODO: fix the driver of wctdm so its drivers 
+			 * reflect the current modules in the capabilities */
+			int req_sig = 
+				span->chans[x].sigcap & 
+				(ZT_SIG_FXSKS | ZT_SIG_FXOKS);
+			if (! ((req_sig == ZT_SIG_FXOKS) ||
+			       (req_sig == ZT_SIG_FXSKS)   ))
+				continue;
+			chan_conf.chan = span->chans[x].channo;
+			chan_conf.sigtype = req_sig;
+			zt_chanconfig(&chan_conf); /* ignore fails for now */
+		}
+	}
 	return 0;
 }
 
@@ -6795,9 +6833,11 @@
 #ifdef LINUX26
 module_param(debug, int, 0600);
 module_param(deftaps, int, 0600);
+module_param(do_ztcfg, int, 0600);
 #else
 MODULE_PARM(debug, "i");
 MODULE_PARM(deftaps, "i");
+MODULE_PARM(do_ztcfg, "i");
 #endif
 
 static struct file_operations zt_fops = {
