Enscript Output

extractedLnx/linux-2.6.38/drivers/telephony/ixj.c_do_ixj_ioctl.c

static long do_ixj_ioctl(struct file *file_p, unsigned int cmd, unsigned long arg)
{
	IXJ_TONE ti;
	IXJ_FILTER jf;
	IXJ_FILTER_RAW jfr;
	void __user *argp = (void __user *)arg;
	struct inode *inode = file_p->f_path.dentry->d_inode;
	unsigned int minor = iminor(inode);
	unsigned int raise, mant;
	int board = NUM(inode);

	IXJ *j = get_ixj(NUM(inode));

	int retval = 0;

	/*
	 *    Set up locks to ensure that only one process is talking to the DSP at a time.
	 *    This is necessary to keep the DSP from locking up.
	 */
	while(test_and_set_bit(board, (void *)&j->busyflags) != 0)
		schedule_timeout_interruptible(1);
	if (ixjdebug & 0x0040)
		printk("phone%d ioctl, cmd: 0x%x, arg: 0x%lx\n", minor, cmd, arg);
	if (minor >= IXJMAX) {
		clear_bit(board, &j->busyflags);
		return -ENODEV;
	}
	/*
	 *    Check ioctls only root can use.
	 */
	if (!capable(CAP_SYS_ADMIN)) {
		switch (cmd) {
		case IXJCTL_TESTRAM:
		case IXJCTL_HZ:
			retval = -EPERM;
		}
	}
	switch (cmd) {
	case IXJCTL_TESTRAM:
		ixj_testram(j);
		retval = (j->ssr.high << 8) + j->ssr.low;
		break;
	case IXJCTL_CARDTYPE:
		retval = j->cardtype;
		break;
	case IXJCTL_SERIAL:
		retval = j->serial;
		break;
	case IXJCTL_VERSION:
		{
			char arg_str[100];
			snprintf(arg_str, sizeof(arg_str),
				"\nDriver version %i.%i.%i", IXJ_VER_MAJOR,
				IXJ_VER_MINOR, IXJ_BLD_VER);
			if (copy_to_user(argp, arg_str, strlen(arg_str)))
				retval = -EFAULT;
		}
		break;
	case PHONE_RING_CADENCE:
		j->ring_cadence = arg;
		break;
	case IXJCTL_CIDCW:
		if(arg) {
			if (copy_from_user(&j->cid_send, argp, sizeof(PHONE_CID))) {
				retval = -EFAULT;
				break;
			}
		} else {
			memset(&j->cid_send, 0, sizeof(PHONE_CID));
		}
		ixj_write_cidcw(j);
		break;
        /* Binary compatbility */
        case OLD_PHONE_RING_START:
                arg = 0;
                /* Fall through */
 	case PHONE_RING_START:
		if(arg) {
			if (copy_from_user(&j->cid_send, argp, sizeof(PHONE_CID))) {
				retval = -EFAULT;
				break;
			}
			ixj_write_cid(j);
		} else {
			memset(&j->cid_send, 0, sizeof(PHONE_CID));
		}
		ixj_ring_start(j);
		break;
	case PHONE_RING_STOP:
		j->flags.cringing = 0;
		if(j->cadence_f[5].enable) {
			j->cadence_f[5].state = 0;
		}
		ixj_ring_off(j);
		break;
	case PHONE_RING:
		retval = ixj_ring(j);
		break;
	case PHONE_EXCEPTION:
		retval = j->ex.bytes;
		if(j->ex.bits.flash) {
			j->flash_end = 0;
			j->ex.bits.flash = 0;
		}
		j->ex.bits.pstn_ring = 0;
		j->ex.bits.caller_id = 0;
		j->ex.bits.pstn_wink = 0;
		j->ex.bits.f0 = 0;
		j->ex.bits.f1 = 0;
		j->ex.bits.f2 = 0;
		j->ex.bits.f3 = 0;
		j->ex.bits.fc0 = 0;
		j->ex.bits.fc1 = 0;
		j->ex.bits.fc2 = 0;
		j->ex.bits.fc3 = 0;
		j->ex.bits.reserved = 0;
		break;
	case PHONE_HOOKSTATE:
		j->ex.bits.hookstate = 0;
		retval = j->hookstate;  //j->r_hook;
		break;
	case IXJCTL_SET_LED:
		LED_SetState(arg, j);
		break;
	case PHONE_FRAME:
		retval = set_base_frame(j, arg);
		break;
	case PHONE_REC_CODEC:
		retval = set_rec_codec(j, arg);
		break;
	case PHONE_VAD:
		ixj_vad(j, arg);
		break;
	case PHONE_REC_START:
		ixj_record_start(j);
		break;
	case PHONE_REC_STOP:
		ixj_record_stop(j);
		break;
	case PHONE_REC_DEPTH:
		set_rec_depth(j, arg);
		break;
	case PHONE_REC_VOLUME:
		if(arg == -1) {
			retval = get_rec_volume(j);
		}
		else {
			set_rec_volume(j, arg);
			retval = arg;
		}
		break;
	case PHONE_REC_VOLUME_LINEAR:
		if(arg == -1) {
			retval = get_rec_volume_linear(j);
		}
		else {
			set_rec_volume_linear(j, arg);
			retval = arg;
		}
		break;
	case IXJCTL_DTMF_PRESCALE:
		if(arg == -1) {
			retval = get_dtmf_prescale(j);
		}
		else {
			set_dtmf_prescale(j, arg);
			retval = arg;
		}
		break;
	case PHONE_REC_LEVEL:
		retval = get_rec_level(j);
		break;
	case IXJCTL_SC_RXG:
		retval = ixj_siadc(j, arg);
		break;
	case IXJCTL_SC_TXG:
		retval = ixj_sidac(j, arg);
		break;
	case IXJCTL_AEC_START:
		ixj_aec_start(j, arg);
		break;
	case IXJCTL_AEC_STOP:
		aec_stop(j);
		break;
	case IXJCTL_AEC_GET_LEVEL:
		retval = j->aec_level;
		break;
	case PHONE_PLAY_CODEC:
		retval = set_play_codec(j, arg);
		break;
	case PHONE_PLAY_START:
		retval = ixj_play_start(j);
		break;
	case PHONE_PLAY_STOP:
		ixj_play_stop(j);
		break;
	case PHONE_PLAY_DEPTH:
		set_play_depth(j, arg);
		break;
	case PHONE_PLAY_VOLUME:
		if(arg == -1) {
			retval = get_play_volume(j);
		}
		else {
			set_play_volume(j, arg);
			retval = arg;
		}
		break;
	case PHONE_PLAY_VOLUME_LINEAR:
		if(arg == -1) {
			retval = get_play_volume_linear(j);
		}
		else {
			set_play_volume_linear(j, arg);
			retval = arg;
		}
		break;
	case PHONE_PLAY_LEVEL:
		retval = get_play_level(j);
		break;
	case IXJCTL_DSP_TYPE:
		retval = (j->dsp.high << 8) + j->dsp.low;
		break;
	case IXJCTL_DSP_VERSION:
		retval = (j->ver.high << 8) + j->ver.low;
		break;
	case IXJCTL_HZ:
		hertz = arg;
		break;
	case IXJCTL_RATE:
		if (arg > hertz)
			retval = -1;
		else
			samplerate = arg;
		break;
	case IXJCTL_DRYBUFFER_READ:
		put_user(j->drybuffer, (unsigned long __user *) argp);
		break;
	case IXJCTL_DRYBUFFER_CLEAR:
		j->drybuffer = 0;
		break;
	case IXJCTL_FRAMES_READ:
		put_user(j->framesread, (unsigned long __user *) argp);
		break;
	case IXJCTL_FRAMES_WRITTEN:
		put_user(j->frameswritten, (unsigned long __user *) argp);
		break;
	case IXJCTL_READ_WAIT:
		put_user(j->read_wait, (unsigned long __user *) argp);
		break;
	case IXJCTL_WRITE_WAIT:
		put_user(j->write_wait, (unsigned long __user *) argp);
		break;
	case PHONE_MAXRINGS:
		j->maxrings = arg;
		break;
	case PHONE_SET_TONE_ON_TIME:
		ixj_set_tone_on(arg, j);
		break;
	case PHONE_SET_TONE_OFF_TIME:
		ixj_set_tone_off(arg, j);
		break;
	case PHONE_GET_TONE_ON_TIME:
		if (ixj_get_tone_on(j)) {
			retval = -1;
		} else {
			retval = (j->ssr.high << 8) + j->ssr.low;
		}
		break;
	case PHONE_GET_TONE_OFF_TIME:
		if (ixj_get_tone_off(j)) {
			retval = -1;
		} else {
			retval = (j->ssr.high << 8) + j->ssr.low;
		}
		break;
	case PHONE_PLAY_TONE:
		if (!j->tone_state)
			retval = ixj_play_tone(j, arg);
		else
			retval = -1;
		break;
	case PHONE_GET_TONE_STATE:
		retval = j->tone_state;
		break;
	case PHONE_DTMF_READY:
		retval = j->ex.bits.dtmf_ready;
		break;
	case PHONE_GET_DTMF:
		if (ixj_hookstate(j)) {
			if (j->dtmf_rp != j->dtmf_wp) {
				retval = j->dtmfbuffer[j->dtmf_rp];
				j->dtmf_rp++;
				if (j->dtmf_rp == 79)
					j->dtmf_rp = 0;
				if (j->dtmf_rp == j->dtmf_wp) {
					j->ex.bits.dtmf_ready = j->dtmf_rp = j->dtmf_wp = 0;
				}
			}
		}
		break;
	case PHONE_GET_DTMF_ASCII:
		if (ixj_hookstate(j)) {
			if (j->dtmf_rp != j->dtmf_wp) {
				switch (j->dtmfbuffer[j->dtmf_rp]) {
				case 10:
					retval = 42;	/* '*'; */

					break;
				case 11:
					retval = 48;	/*'0'; */

					break;
				case 12:
					retval = 35;	/*'#'; */

					break;
				case 28:
					retval = 65;	/*'A'; */

					break;
				case 29:
					retval = 66;	/*'B'; */

					break;
				case 30:
					retval = 67;	/*'C'; */

					break;
				case 31:
					retval = 68;	/*'D'; */

					break;
				default:
					retval = 48 + j->dtmfbuffer[j->dtmf_rp];
					break;
				}
				j->dtmf_rp++;
				if (j->dtmf_rp == 79)
					j->dtmf_rp = 0;
				if(j->dtmf_rp == j->dtmf_wp)
				{
					j->ex.bits.dtmf_ready = j->dtmf_rp = j->dtmf_wp = 0;
				}
			}
		}
		break;
	case PHONE_DTMF_OOB:
		j->flags.dtmf_oob = arg;
		break;
	case PHONE_DIALTONE:
		ixj_dialtone(j);
		break;
	case PHONE_BUSY:
		ixj_busytone(j);
		break;
	case PHONE_RINGBACK:
		ixj_ringback(j);
		break;
	case PHONE_WINK:
		if(j->cardtype == QTI_PHONEJACK) 
			retval = -1;
		else 
			retval = ixj_wink(j);
		break;
	case PHONE_CPT_STOP:
		ixj_cpt_stop(j);
		break;
        case PHONE_QUERY_CODEC:
        {
                struct phone_codec_data pd;
                int val;
                int proto_size[] = {
                        -1,
                        12, 10, 16, 9, 8, 48, 5,
                        40, 40, 80, 40, 40, 6
                };
                if(copy_from_user(&pd, argp, sizeof(pd))) {
                        retval = -EFAULT;
			break;
		}
                if(pd.type<1 || pd.type>13) {
                        retval = -EPROTONOSUPPORT;
			break;
		}
                if(pd.type<G729)
                        val=proto_size[pd.type];
                else switch(j->baseframe.low)
                {
                        case 0xA0:val=2*proto_size[pd.type];break;
                        case 0x50:val=proto_size[pd.type];break;
                        default:val=proto_size[pd.type]*3;break;
                }
                pd.buf_min=pd.buf_max=pd.buf_opt=val;
                if(copy_to_user(argp, &pd, sizeof(pd)))
                        retval = -EFAULT;
        	break;
        }
	case IXJCTL_DSP_IDLE:
		idle(j);
		break;
	case IXJCTL_MIXER:
                if ((arg & 0xff) == 0xff)
			retval = ixj_get_mixer(arg, j);
                else
			ixj_mixer(arg, j);
		break;
	case IXJCTL_DAA_COEFF_SET:
		switch (arg) {
		case DAA_US:
			DAA_Coeff_US(j);
			retval = ixj_daa_write(j);
			break;
		case DAA_UK:
			DAA_Coeff_UK(j);
			retval = ixj_daa_write(j);
			break;
		case DAA_FRANCE:
			DAA_Coeff_France(j);
			retval = ixj_daa_write(j);
			break;
		case DAA_GERMANY:
			DAA_Coeff_Germany(j);
			retval = ixj_daa_write(j);
			break;
		case DAA_AUSTRALIA:
			DAA_Coeff_Australia(j);
			retval = ixj_daa_write(j);
			break;
		case DAA_JAPAN:
			DAA_Coeff_Japan(j);
			retval = ixj_daa_write(j);
			break;
		default:
			retval = 1;
			break;
		}
		break;
	case IXJCTL_DAA_AGAIN:
		ixj_daa_cr4(j, arg | 0x02);
		break;
	case IXJCTL_PSTN_LINETEST:
		retval = ixj_linetest(j);
		break;
	case IXJCTL_VMWI:
		ixj_write_vmwi(j, arg);
		break;
	case IXJCTL_CID:
		if (copy_to_user(argp, &j->cid, sizeof(PHONE_CID))) 
			retval = -EFAULT;
		j->ex.bits.caller_id = 0;
		break;
	case IXJCTL_WINK_DURATION:
		j->winktime = arg;
		break;
	case IXJCTL_PORT:
		if (arg)
			retval = ixj_set_port(j, arg);
		else
			retval = j->port;
		break;
	case IXJCTL_POTS_PSTN:
		retval = ixj_set_pots(j, arg);
		break;
	case PHONE_CAPABILITIES:
		add_caps(j);
		retval = j->caps;
		break;
	case PHONE_CAPABILITIES_LIST:
		add_caps(j);
		if (copy_to_user(argp, j->caplist, sizeof(struct phone_capability) * j->caps)) 
			retval = -EFAULT;
		break;
	case PHONE_CAPABILITIES_CHECK:
		{
			struct phone_capability cap;
			if (copy_from_user(&cap, argp, sizeof(cap))) 
				retval = -EFAULT;
			else {
				add_caps(j);
				retval = capabilities_check(j, &cap);
			}
		}
		break;
	case PHONE_PSTN_SET_STATE:
		daa_set_mode(j, arg);
		break;
	case PHONE_PSTN_GET_STATE:
		retval = j->daa_mode;
		j->ex.bits.pstn_ring = 0;
		break;
	case IXJCTL_SET_FILTER:
		if (copy_from_user(&jf, argp, sizeof(jf))) 
			retval = -EFAULT;
		else
			retval = ixj_init_filter(j, &jf);
		break;
	case IXJCTL_SET_FILTER_RAW:
		if (copy_from_user(&jfr, argp, sizeof(jfr))) 
			retval = -EFAULT;
		else
			retval = ixj_init_filter_raw(j, &jfr);
		break;
	case IXJCTL_GET_FILTER_HIST:
		if(arg<0||arg>3)
			retval = -EINVAL;
		else
			retval = j->filter_hist[arg];
		break;
	case IXJCTL_INIT_TONE:
		if (copy_from_user(&ti, argp, sizeof(ti)))
			retval = -EFAULT;
		else
			retval = ixj_init_tone(j, &ti);
		break;
	case IXJCTL_TONE_CADENCE:
		retval = ixj_build_cadence(j, argp);
		break;
	case IXJCTL_FILTER_CADENCE:
		retval = ixj_build_filter_cadence(j, argp);
		break;
	case IXJCTL_SIGCTL:
		if (copy_from_user(&j->sigdef, argp, sizeof(IXJ_SIGDEF))) {
			retval = -EFAULT;
			break;
		}
		j->ixj_signals[j->sigdef.event] = j->sigdef.signal;
		if(j->sigdef.event < 33) {
			raise = 1;
			for(mant = 0; mant < j->sigdef.event; mant++){
				raise *= 2;
			}
			if(j->sigdef.signal)
				j->ex_sig.bytes |= raise; 
			else
				j->ex_sig.bytes &= (raise^0xffff); 
		}
		break;
	case IXJCTL_INTERCOM_STOP:
		if(arg < 0 || arg >= IXJMAX)
			return -EINVAL;
		j->intercom = -1;
		ixj_record_stop(j);
		ixj_play_stop(j);
		idle(j);
		get_ixj(arg)->intercom = -1;
		ixj_record_stop(get_ixj(arg));
		ixj_play_stop(get_ixj(arg));
		idle(get_ixj(arg));
		break;
	case IXJCTL_INTERCOM_START:
		if(arg < 0 || arg >= IXJMAX)
			return -EINVAL;
		j->intercom = arg;
		ixj_record_start(j);
		ixj_play_start(j);
		get_ixj(arg)->intercom = board;
		ixj_play_start(get_ixj(arg));
		ixj_record_start(get_ixj(arg));
		break;
	}
	if (ixjdebug & 0x0040)
		printk("phone%d ioctl end, cmd: 0x%x, arg: 0x%lx\n", minor, cmd, arg);
	clear_bit(board, &j->busyflags);
	return retval;
}

Generated by GNU enscript 1.6.4.