⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tpam_commands.c

📁 内核linux2.4.20,可跟rtlinux3.2打补丁 组成实时linux系统,编译内核
💻 C
📖 第 1 页 / 共 2 页
字号:
/* $Id: tpam_commands.c,v 1.1.2.1 2001/11/20 14:19:37 kai Exp $ * * Turbo PAM ISDN driver for Linux. (Kernel Driver - ISDN commands) * * Copyright 2001 Stelian Pop <stelian.pop@fr.alcove.com>, Alc魐e * * This software may be used and distributed according to the terms * of the GNU General Public License, incorporated herein by reference. * * For all support questions please contact: <support@auvertech.fr> * */#include <linux/module.h>#include <linux/pci.h>#include <linux/sched.h>#include <linux/tqueue.h>#include <linux/interrupt.h>#include <asm/io.h>#include <linux/isdn/tpam.h>#include "tpam.h"/* Local functions prototypes */static int tpam_command_ioctl_dspload(tpam_card *, u32);static int tpam_command_ioctl_dspsave(tpam_card *, u32);static int tpam_command_ioctl_dsprun(tpam_card *);static int tpam_command_ioctl_loopmode(tpam_card *, u8);static int tpam_command_dial(tpam_card *, u32, u8 *);static int tpam_command_setl2(tpam_card *, u32, u8);static int tpam_command_getl2(tpam_card *, u32);static int tpam_command_acceptd(tpam_card *, u32);static int tpam_command_acceptb(tpam_card *, u32);static int tpam_command_hangup(tpam_card *, u32);static int tpam_command_proceed(tpam_card *, u32);static void tpam_statcallb_run(unsigned long);static void tpam_statcallb(tpam_card *, isdn_ctrl);/* * Function called when the ISDN link level send a command to the driver. * * 	c: ISDN command. * * Return: 0 if OK, <0 on errors. */int tpam_command(isdn_ctrl *c) {	tpam_card *card;	unsigned long argp;	dprintk("TurboPAM(tpam_command) card=%d, command=%d\n", 		c->driver, c->command);		/* search for the board */	if (!(card = tpam_findcard(c->driver))) {		printk(KERN_ERR "TurboPAM(tpam_command): invalid driverId %d\n",		       c->driver);			return -ENODEV;	}	/* dispatch the command */	switch (c->command) {		case ISDN_CMD_IOCTL:			argp = c->parm.userdata;			switch (c->arg) {				case TPAM_CMD_DSPLOAD:					return tpam_command_ioctl_dspload(card,									  argp);				case TPAM_CMD_DSPSAVE:					return tpam_command_ioctl_dspsave(card,									  argp);				case TPAM_CMD_DSPRUN:					return tpam_command_ioctl_dsprun(card);				case TPAM_CMD_LOOPMODEON:					return tpam_command_ioctl_loopmode(card,									   1);				case TPAM_CMD_LOOPMODEOFF:					return tpam_command_ioctl_loopmode(card,									   0);				default:					dprintk("TurboPAM(tpam_command): "						"invalid tpam ioctl %ld\n", 						c->arg);						return -EINVAL;			}		case ISDN_CMD_DIAL:			return tpam_command_dial(card, c->arg, 						 c->parm.setup.phone);		case ISDN_CMD_ACCEPTD:			return tpam_command_acceptd(card, c->arg);		case ISDN_CMD_ACCEPTB:			return tpam_command_acceptb(card, c->arg);		case ISDN_CMD_HANGUP:			return tpam_command_hangup(card, c->arg);		case ISDN_CMD_SETL2:			return tpam_command_setl2(card, c->arg & 0xff, 						  c->arg >> 8);		case ISDN_CMD_GETL2:			return tpam_command_getl2(card, c->arg);		case ISDN_CMD_LOCK:			MOD_INC_USE_COUNT;			return 0;		case ISDN_CMD_UNLOCK:			MOD_DEC_USE_COUNT;			return 0;		case ISDN_CMD_PROCEED:			return tpam_command_proceed(card, c->arg);		default:			dprintk("TurboPAM(tpam_command): "				"unknown or unused isdn ioctl %d\n", 				c->command);				return -EINVAL;	}	/* not reached */	return -EINVAL;}/* * Load some data into the board's memory. * * 	card: the board * 	arg: IOCTL argument containing the user space address of  * 		the tpam_dsp_ioctl structure describing the IOCTL. * * Return: 0 if OK, <0 on errors. */static int tpam_command_ioctl_dspload(tpam_card *card, u32 arg) {	tpam_dsp_ioctl tdl;	int ret;	dprintk("TurboPAM(tpam_command_ioctl_dspload): card=%d\n", card->id);	/* get the IOCTL parameter from userspace */	if (copy_from_user(&tdl, (void *)arg, sizeof(tpam_dsp_ioctl)))		return -EFAULT;	/* if the board's firmware was started, protect against writes	 * to unallowed memory areas. If the board's firmware wasn't started,	 * all is allowed. */	if (card->running && tpam_verify_area(tdl.address, tdl.data_len)) 		return -EPERM;	/* write the data in the board's memory */	ret = copy_from_user_to_pam(card, (void *)tdl.address, 				    (void *)arg + sizeof(tpam_dsp_ioctl), 				    tdl.data_len);	return 0;}/* * Extract some data from the board's memory. * * 	card: the board * 	arg: IOCTL argument containing the user space address of  * 		the tpam_dsp_ioctl structure describing the IOCTL. * * Return: 0 if OK, <0 on errors. */static int tpam_command_ioctl_dspsave(tpam_card *card, u32 arg) {	tpam_dsp_ioctl tdl;	int ret;	dprintk("TurboPAM(tpam_command_ioctl_dspsave): card=%d\n", card->id);	/* get the IOCTL parameter from userspace */	if (copy_from_user(&tdl, (void *)arg, sizeof(tpam_dsp_ioctl)))		return -EFAULT;	/* protect against read from unallowed memory areas */	if (tpam_verify_area(tdl.address, tdl.data_len)) 		return -EPERM;	/* read the data from the board's memory */	ret = copy_from_pam_to_user(card, (void *)arg + sizeof(tpam_dsp_ioctl),				    (void *)tdl.address, tdl.data_len);	return ret;}/* * Launch the board's firmware. This function must be called after the  * firmware was loaded into the board's memory using TPAM_CMD_DSPLOAD  * IOCTL commands. After launching the firmware, this function creates * the NCOs and waits for their creation. * * 	card: the board * * Return: 0 if OK, <0 on errors. */static int tpam_command_ioctl_dsprun(tpam_card *card) {	u32 signature = 0, timeout, i;	isdn_ctrl ctrl;	struct sk_buff *skb;	dprintk("TurboPAM(tpam_command_ioctl_dsprun): card=%d\n", card->id);	/* board must _not_ be running */	if (card->running)		return -EBUSY;	/* reset the board */	spin_lock_irq(&card->lock);	copy_to_pam_dword(card, (void *)TPAM_MAGICNUMBER_REGISTER, 0xdeadface);	readl(card->bar0 + TPAM_DSPINT_REGISTER);	readl(card->bar0 + TPAM_HINTACK_REGISTER);	spin_unlock_irq(&card->lock);		/* wait for the board signature */	timeout = jiffies + SIGNATURE_TIMEOUT;	while (time_before(jiffies, timeout)) {		spin_lock_irq(&card->lock);		signature = copy_from_pam_dword(card, 						(void *)TPAM_MAGICNUMBER_REGISTER);		spin_unlock_irq(&card->lock);		if (signature == TPAM_MAGICNUMBER)			break;		set_current_state(TASK_UNINTERRUPTIBLE);		schedule_timeout(2);	}	/* signature not present -> board not started */	if (signature != TPAM_MAGICNUMBER) {		printk(KERN_ERR "TurboPAM(tpam_command_ioctl_dsprun): "		       "card=%d, signature 0x%lx, expected 0x%lx\n", 		       card->id, (unsigned long)signature, 		       (unsigned long)TPAM_MAGICNUMBER);		printk(KERN_ERR "TurboPAM(tpam_command_ioctl_dsprun): "		       "card=%d, firmware not started\n", card->id);		return -EIO;	}	/* the firmware is started */	printk(KERN_INFO "TurboPAM: card=%d, firmware started\n", card->id);	/* init the CRC routines */	init_CRC();	/* create all the NCOs */	for (i = 0; i < TPAM_NBCHANNEL; ++i)		if ((skb = build_ACreateNCOReq("")))			tpam_enqueue(card, skb);	/* wait for NCO creation confirmation */	timeout = jiffies + NCOCREATE_TIMEOUT;	while (time_before(jiffies, timeout)) {		if (card->channels_tested == TPAM_NBCHANNEL)			break;		set_current_state(TASK_UNINTERRUPTIBLE);		schedule_timeout(2);	}	card->running = 1;	if (card->channels_tested != TPAM_NBCHANNEL)		printk(KERN_ERR "TurboPAM(tpam_command_ioctl_dsprun): "		       "card=%d, tried to init %d channels, "		       "got reply from only %d channels\n", card->id, 		       TPAM_NBCHANNEL, card->channels_tested);	/* if all the channels were not initialized, signal to the ISDN	 * link layer that fact that some channels are not usable */	if (card->channels_used != TPAM_NBCHANNEL)		for (i = card->channels_used; i < TPAM_NBCHANNEL; ++i) {			ctrl.driver = card->id;			ctrl.command = ISDN_STAT_DISCH;			ctrl.arg = i;			ctrl.parm.num[0] = 0;			(* card->interface.statcallb)(&ctrl);		}	printk(KERN_INFO "TurboPAM: card=%d, ready, %d channels available\n", 	       card->id, card->channels_used);	/* let's rock ! */	ctrl.driver = card->id;	ctrl.command = ISDN_STAT_RUN;	ctrl.arg = 0;	tpam_statcallb(card, ctrl);	return 0;}/*  * Set/reset the board's looptest mode. * * 	card: the board * 	mode: if 1, sets the board's looptest mode, if 0 resets it. * * Return: 0 if OK, <0 if error. */static int tpam_command_ioctl_loopmode(tpam_card *card, u8 mode) {	/* board must be running */	if (!card->running)		return -ENODEV;	card->loopmode = mode;	return 0;}/* * Issue a dial command. This function builds and sends a CConnectReq. *  * 	card: the board * 	channel: the channel number * 	phone: the remote phone number (EAZ) * * Return: 0 if OK, <0 if error. */static int tpam_command_dial(tpam_card *card, u32 channel, u8 *phone) {	struct sk_buff *skb;	isdn_ctrl ctrl;	dprintk("TurboPAM(tpam_command_dial): card=%d, channel=%lu, phone=%s\n",		card->id, (unsigned long)channel, phone);	/* board must be running */	if (!card->running)		return -ENODEV;	/* initialize channel parameters */	card->channels[channel].realhdlc = card->channels[channel].hdlc;	card->channels[channel].hdlcshift = 0;	card->channels[channel].readytoreceive = 0;	/* build and send a CConnectReq */	skb = build_CConnectReq(card->channels[channel].ncoid, phone, 				card->channels[channel].realhdlc);	if (!skb)		return -ENOMEM;	tpam_enqueue(card, skb);	/* making a connection in modem mode is slow and causes the ISDN	 * link layer to hangup the connection before even it gets a chance	 * to establish... All we can do is simulate a successful connection	 * for now, and send a DHUP later if the connection fails */	if (!card->channels[channel].realhdlc) {		ctrl.driver = card->id;		ctrl.command = ISDN_STAT_DCONN;		ctrl.arg = channel;		tpam_statcallb(card, ctrl);	}		return 0;}/* * Set the level2 protocol (modem or HDLC). * * 	card: the board * 	channel: the channel number * 	proto: the level2 protocol (one of ISDN_PROTO_L2*) * * Return: 0 if OK, <0 if error. */static int tpam_command_setl2(tpam_card *card, u32 channel, u8 proto) {	dprintk("TurboPAM(tpam_command_setl2): card=%d, channel=%lu, proto=%d\n",		card->id, (unsigned long)channel, proto);	/* board must be running */	if (!card->running)		return -ENODEV;	/* set the hdlc/modem mode */	switch (proto) {		case ISDN_PROTO_L2_HDLC:			card->channels[channel].hdlc = 1;			break;		case ISDN_PROTO_L2_MODEM:			card->channels[channel].hdlc = 0;			break;		default:			return -EINVAL;	}	return 0;}/* * Return the level2 protocol (modem or HDLC). * * 	card: the board * 	channel: the channel number * * Return: ISDN_PROTO_L2_HDLC/MODEM if OK, <0 if error. */static int tpam_command_getl2(tpam_card *card, u32 channel) {	dprintk("TurboPAM(tpam_command_getl2): card=%d, channel=%lu\n",		card->id, (unsigned long)channel);		/* board must be running */	if (!card->running)		return -ENODEV;	/* return the current mode */	if (card->channels[channel].realhdlc)		return ISDN_PROTO_L2_HDLC;	else		return ISDN_PROTO_L2_MODEM;}/* * Accept a D-channel connection (incoming connection). This function * builds and sends a CConnectRsp message and signals DCONN to the ISDN * link level. * * 	card: the board * 	channel: the channel number * * Return: 0 if OK, <0 if error. */static int tpam_command_acceptd(tpam_card *card, u32 channel) {	isdn_ctrl ctrl;	struct sk_buff *skb;	dprintk("TurboPAM(tpam_command_acceptd): card=%d, channel=%lu\n",		card->id, (unsigned long)channel);	/* board must be running */	if (!card->running)		return -ENODEV;	/* build and send a CConnectRsp */	skb = build_CConnectRsp(card->channels[channel].ncoid);	if (!skb)		return -ENOMEM;	tpam_enqueue(card, skb);	/* issue DCONN to the ISDN link level */	ctrl.driver = card->id;	ctrl.command = ISDN_STAT_DCONN;	ctrl.arg = channel;	tpam_statcallb(card, ctrl);	return 0;}/* * Accepts a B-channel connection. This is not used by the driver,  * since the TurboPAM is an active card hiding its B-channels from * us. We just signal BCONN to the ISDN link layer. * * 	card: the board * 	channel: the channel number * * Return: 0 if OK, <0 if error. */static int tpam_command_acceptb(tpam_card *card, u32 channel) {	isdn_ctrl ctrl;	dprintk("TurboPAM(tpam_command_acceptb): card=%d, channel=%lu\n",		card->id, (unsigned long)channel);	/* board must be running */	if (!card->running)		return -ENODEV;	/* issue BCONN to the ISDN link level */	ctrl.driver = card->id;	ctrl.command = ISDN_STAT_BCONN;	ctrl.arg = channel;	ctrl.parm.num[0] = '\0';	tpam_statcallb(card, ctrl);	return 0;}/* * Hang up a connection. This function builds and sends a CDisconnectReq. * * 	card: the board * 	channel: the channel number. * * Return: 0 if OK, <0 if error. */static int tpam_command_hangup(tpam_card *card, u32 channel) {	struct sk_buff *skb;	dprintk("TurboPAM(tpam_command_hangup): card=%d, channel=%lu\n",		card->id, (unsigned long)channel);	/* board must be running */	if (!card->running)		return -ENODEV;	/* build and send a CDisconnectReq */	skb = build_CDisconnectReq(card->channels[channel].ncoid);	if (!skb)		return -ENOMEM;	tpam_enqueue(card, skb);	return 0;}/* * Proceed with an incoming connection. This function builds and sends a  * CConnectRsp. * * 	card: the board * 	channel: the channel number. * * Return: 0 if OK, <0 if error. */static int tpam_command_proceed(tpam_card *card, u32 channel) {	struct sk_buff *skb;	dprintk("TurboPAM(tpam_command_proceed): card=%d, channel=%lu\n",		card->id, (unsigned long)channel);	/* board must be running */	if (!card->running)		return -ENODEV;	/* build and send a CConnectRsp */	skb = build_CConnectRsp(card->channels[channel].ncoid);	if (!skb)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -