extractedLnx/linux-2.6.9/drivers/telephony/ixj.c_ixj_ioctl.c
static int ixj_ioctl(struct inode *inode, 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;
unsigned int raise, mant;
unsigned int minor = iminor(inode);
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) {
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(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:
if (copy_to_user(argp, ixj_c_revision, strlen(ixj_c_revision)))
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;
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.