예제 #1
0
static void idt77105_int(struct atm_dev *dev)
{
    unsigned char istat;

    istat = GET(ISTAT); /* side effect: clears all interrupt status bits */

    DPRINTK("IDT77105 generated an interrupt, istat=%02x\n", (unsigned)istat);

    if (istat & IDT77105_ISTAT_RSCC) {
        /* Rx Signal Condition Change - line went up or down */
        if (istat & IDT77105_ISTAT_GOODSIG) {   /* signal detected again */
            /* This should not happen (restart timer does it) but JIC */
            atm_dev_signal_change(dev, ATM_PHY_SIG_FOUND);
        } else {    /* signal lost */
            /*
             * Disable interrupts and stop all transmission and
             * reception - the restart timer will restore these.
             */
            PRIV(dev)->old_mcr = GET(MCR);
            PUT(
                (PRIV(dev)->old_mcr|
                 IDT77105_MCR_DREC|
                 IDT77105_MCR_DRIC|
                 IDT77105_MCR_HALTTX
                ) & ~IDT77105_MCR_EIP, MCR);
            atm_dev_signal_change(dev, ATM_PHY_SIG_LOST);
#ifdef CONFIG_DEBUG_PRINTK
            printk(KERN_NOTICE "%s(itf %d): signal lost\n",
                   dev->type,dev->number);
#else
            ;
#endif
        }
    }

    if (istat & IDT77105_ISTAT_RFO) {
        /* Rx FIFO Overrun -- perform a FIFO flush */
        PUT( GET(DIAG) | IDT77105_DIAG_RFLUSH, DIAG);
#ifdef CONFIG_DEBUG_PRINTK
        printk(KERN_NOTICE "%s(itf %d): receive FIFO overrun\n",
               dev->type,dev->number);
#else
        ;
#endif
    }
#ifdef GENERAL_DEBUG
    if (istat & (IDT77105_ISTAT_HECERR | IDT77105_ISTAT_SCR |
                 IDT77105_ISTAT_RSE)) {
        /* normally don't care - just report in stats */
#ifdef CONFIG_DEBUG_PRINTK
        printk(KERN_NOTICE "%s(itf %d): received cell with error\n",
               dev->type,dev->number);
#else
        ;
#endif
    }
#endif
}
static int idt77105_start(struct atm_dev *dev)
{
	unsigned long flags;

	if (!(dev->dev_data = kmalloc(sizeof(struct idt77105_priv),GFP_KERNEL)))
		return -ENOMEM;
	PRIV(dev)->dev = dev;
	spin_lock_irqsave(&idt77105_priv_lock, flags);
	PRIV(dev)->next = idt77105_all;
	idt77105_all = PRIV(dev);
	spin_unlock_irqrestore(&idt77105_priv_lock, flags);
	memset(&PRIV(dev)->stats,0,sizeof(struct idt77105_stats));
        
        /* initialise dev->signal from Good Signal Bit */
	atm_dev_signal_change(dev,
		GET(ISTAT) & IDT77105_ISTAT_GOODSIG ?
		ATM_PHY_SIG_FOUND : ATM_PHY_SIG_LOST);
	if (dev->signal == ATM_PHY_SIG_LOST)
		printk(KERN_WARNING "%s(itf %d): no signal\n",dev->type,
		    dev->number);

        /* initialise loop mode from hardware */
        switch ( GET(DIAG) & IDT77105_DIAG_LCMASK ) {
        case IDT77105_DIAG_LC_NORMAL:
            PRIV(dev)->loop_mode = ATM_LM_NONE;
            break;
        case IDT77105_DIAG_LC_PHY_LOOPBACK:
            PRIV(dev)->loop_mode = ATM_LM_LOC_ATM;
            break;
        case IDT77105_DIAG_LC_LINE_LOOPBACK:
            PRIV(dev)->loop_mode = ATM_LM_RMT_ATM;
            break;
        }
        
        /* enable interrupts, e.g. on loss of signal */
        PRIV(dev)->old_mcr = GET(MCR);
        if (dev->signal == ATM_PHY_SIG_FOUND) {
            PRIV(dev)->old_mcr |= IDT77105_MCR_EIP;
	    PUT(PRIV(dev)->old_mcr, MCR);
        }

                    
	idt77105_stats_timer_func(0); /* clear 77105 counters */
	(void) fetch_stats(dev,NULL,1); /* clear kernel counters */
        
	spin_lock_irqsave(&idt77105_priv_lock, flags);
	if (start_timer) {
		start_timer = 0;
                
		setup_timer(&stats_timer, idt77105_stats_timer_func, 0UL);
		stats_timer.expires = jiffies+IDT77105_STATS_TIMER_PERIOD;
		add_timer(&stats_timer);
                
		setup_timer(&restart_timer, idt77105_restart_timer_func, 0UL);
		restart_timer.expires = jiffies+IDT77105_RESTART_TIMER_PERIOD;
		add_timer(&restart_timer);
	}
	spin_unlock_irqrestore(&idt77105_priv_lock, flags);
	return 0;
}
/*
 * A separate timer func which handles restarting PHY chips which
 * have had the cable re-inserted after being pulled out. This is
 * done by polling the Good Signal Bit in the Interrupt Status
 * register every 5 seconds. The other technique (checking Good
 * Signal Bit in the interrupt handler) cannot be used because PHY
 * interrupts need to be disabled when the cable is pulled out
 * to avoid lots of spurious cell error interrupts.
 */
static void idt77105_restart_timer_func(unsigned long dummy)
{
	struct idt77105_priv *walk;
	struct atm_dev *dev;
        unsigned char istat;

        DPRINTK("IDT77105 checking for cable re-insertion\n");
	for (walk = idt77105_all; walk; walk = walk->next) {
		dev = walk->dev;
                
                if (dev->signal != ATM_PHY_SIG_LOST)
                    continue;
                    
                istat = GET(ISTAT); /* side effect: clears all interrupt status bits */
                if (istat & IDT77105_ISTAT_GOODSIG) {
                    /* Found signal again */
                    atm_dev_signal_change(dev, ATM_PHY_SIG_FOUND);
	            printk(KERN_NOTICE "%s(itf %d): signal detected again\n",
                        dev->type,dev->number);
                    /* flush the receive FIFO */
                    PUT( GET(DIAG) | IDT77105_DIAG_RFLUSH, DIAG);
                    /* re-enable interrupts */
	            PUT( walk->old_mcr ,MCR);
                }
	}
        if (!start_timer) mod_timer(&restart_timer,jiffies+IDT77105_RESTART_TIMER_PERIOD);
}
예제 #4
0
파일: suni.c 프로젝트: avagin/linux
static void poll_los(struct atm_dev *dev)
{
	atm_dev_signal_change(dev,
		GET(RSOP_SIS) & SUNI_RSOP_SIS_LOSV ?
		ATM_PHY_SIG_LOST : ATM_PHY_SIG_FOUND);
}
예제 #5
0
static void cxacru_poll_status(struct work_struct *work)
{
	struct cxacru_data *instance =
		container_of(work, struct cxacru_data, poll_work.work);
	u32 buf[CXINF_MAX] = {};
	struct usbatm_data *usbatm = instance->usbatm;
	struct atm_dev *atm_dev = usbatm->atm_dev;
	int keep_polling = 1;
	int ret;

	ret = cxacru_cm_get_array(instance, CM_REQUEST_CARD_INFO_GET, buf, CXINF_MAX);
	if (ret < 0) {
		if (ret != -ESHUTDOWN)
			atm_warn(usbatm, "poll status: error %d\n", ret);

		mutex_lock(&instance->poll_state_serialize);
		if (instance->poll_state != CXPOLL_SHUTDOWN) {
			instance->poll_state = CXPOLL_STOPPED;

			if (ret != -ESHUTDOWN)
				atm_warn(usbatm, "polling disabled, set adsl_state"
						" to 'start' or 'poll' to resume\n");
		}
		mutex_unlock(&instance->poll_state_serialize);
		goto reschedule;
	}

	memcpy(instance->card_info, buf, sizeof(instance->card_info));

	if (instance->adsl_status != buf[CXINF_LINE_STARTABLE]) {
		instance->adsl_status = buf[CXINF_LINE_STARTABLE];

		switch (instance->adsl_status) {
		case 0:
			atm_printk(KERN_INFO, usbatm, "ADSL state: running\n");
			break;

		case 1:
			atm_printk(KERN_INFO, usbatm, "ADSL state: stopped\n");
			break;

		default:
			atm_printk(KERN_INFO, usbatm, "Unknown adsl status %02x\n", instance->adsl_status);
			break;
		}
	}

	if (instance->line_status == buf[CXINF_LINE_STATUS])
		goto reschedule;

	instance->line_status = buf[CXINF_LINE_STATUS];
	switch (instance->line_status) {
	case 0:
		atm_dev_signal_change(atm_dev, ATM_PHY_SIG_LOST);
		atm_info(usbatm, "ADSL line: down\n");
		break;

	case 1:
		atm_dev_signal_change(atm_dev, ATM_PHY_SIG_LOST);
		atm_info(usbatm, "ADSL line: attempting to activate\n");
		break;

	case 2:
		atm_dev_signal_change(atm_dev, ATM_PHY_SIG_LOST);
		atm_info(usbatm, "ADSL line: training\n");
		break;

	case 3:
		atm_dev_signal_change(atm_dev, ATM_PHY_SIG_LOST);
		atm_info(usbatm, "ADSL line: channel analysis\n");
		break;

	case 4:
		atm_dev_signal_change(atm_dev, ATM_PHY_SIG_LOST);
		atm_info(usbatm, "ADSL line: exchange\n");
		break;

	case 5:
		atm_dev->link_rate = buf[CXINF_DOWNSTREAM_RATE] * 1000 / 424;
		atm_dev_signal_change(atm_dev, ATM_PHY_SIG_FOUND);

		atm_info(usbatm, "ADSL line: up (%d kb/s down | %d kb/s up)\n",
		     buf[CXINF_DOWNSTREAM_RATE], buf[CXINF_UPSTREAM_RATE]);
		break;

	case 6:
		atm_dev_signal_change(atm_dev, ATM_PHY_SIG_LOST);
		atm_info(usbatm, "ADSL line: waiting\n");
		break;

	case 7:
		atm_dev_signal_change(atm_dev, ATM_PHY_SIG_LOST);
		atm_info(usbatm, "ADSL line: initializing\n");
		break;

	default:
		atm_dev_signal_change(atm_dev, ATM_PHY_SIG_UNKNOWN);
		atm_info(usbatm, "Unknown line state %02x\n", instance->line_status);
		break;
	}
reschedule:

	mutex_lock(&instance->poll_state_serialize);
	if (instance->poll_state == CXPOLL_STOPPING &&
				instance->adsl_status == 1 && /* stopped */
				instance->line_status == 0) /* down */
		instance->poll_state = CXPOLL_STOPPED;

	if (instance->poll_state == CXPOLL_STOPPED)
		keep_polling = 0;
	mutex_unlock(&instance->poll_state_serialize);

	if (keep_polling)
		schedule_delayed_work(&instance->poll_work,
				round_jiffies_relative(POLL_INTERVAL*HZ));
}
예제 #6
0
static void speedtch_check_status(struct work_struct *work)
{
	struct speedtch_instance_data *instance =
		container_of(work, struct speedtch_instance_data,
			     status_check_work);
	struct usbatm_data *usbatm = instance->usbatm;
	struct atm_dev *atm_dev = usbatm->atm_dev;
	unsigned char *buf = instance->scratch_buffer;
	int down_speed, up_speed, ret;
	unsigned char status;

#ifdef VERBOSE_DEBUG
	atm_dbg(usbatm, "%s entered\n", __func__);
#endif

	ret = speedtch_read_status(instance);
	if (ret < 0) {
		atm_warn(usbatm, "error %d fetching device status\n", ret);
		instance->poll_delay = min(2 * instance->poll_delay, MAX_POLL_DELAY);
		return;
	}

	instance->poll_delay = max(instance->poll_delay / 2, MIN_POLL_DELAY);

	status = buf[OFFSET_7];

	if ((status != instance->last_status) || !status) {
		atm_dbg(usbatm, "%s: line state 0x%02x\n", __func__, status);

		switch (status) {
		case 0:
			atm_dev_signal_change(atm_dev, ATM_PHY_SIG_LOST);
			if (instance->last_status)
				atm_info(usbatm, "ADSL line is down\n");
			/* It may never resync again unless we ask it to... */
			ret = speedtch_start_synchro(instance);
			break;

		case 0x08:
			atm_dev_signal_change(atm_dev, ATM_PHY_SIG_UNKNOWN);
			atm_info(usbatm, "ADSL line is blocked?\n");
			break;

		case 0x10:
			atm_dev_signal_change(atm_dev, ATM_PHY_SIG_LOST);
			atm_info(usbatm, "ADSL line is synchronising\n");
			break;

		case 0x20:
			down_speed = buf[OFFSET_b] | (buf[OFFSET_b + 1] << 8)
				| (buf[OFFSET_b + 2] << 16) | (buf[OFFSET_b + 3] << 24);
			up_speed = buf[OFFSET_b + 4] | (buf[OFFSET_b + 5] << 8)
				| (buf[OFFSET_b + 6] << 16) | (buf[OFFSET_b + 7] << 24);

			if (!(down_speed & 0x0000ffff) && !(up_speed & 0x0000ffff)) {
				down_speed >>= 16;
				up_speed >>= 16;
			}

			atm_dev->link_rate = down_speed * 1000 / 424;
			atm_dev_signal_change(atm_dev, ATM_PHY_SIG_FOUND);

			atm_info(usbatm,
				 "ADSL line is up (%d kb/s down | %d kb/s up)\n",
				 down_speed, up_speed);
			break;

		default:
			atm_dev_signal_change(atm_dev, ATM_PHY_SIG_UNKNOWN);
			atm_info(usbatm, "unknown line state %02x\n", status);
			break;
		}