/*
 * free all resources used by the channels and switch off leds and can power
 */
static void pcan_free_channels(struct pcan_pccard *card)
{
	int i;
	u8 led_mask = 0;

	for (i = 0; i < card->chan_count; i++) {
		struct net_device *netdev;
		char name[IFNAMSIZ];

		led_mask |= PCC_LED(i);

		netdev = card->channel[i].netdev;
		if (!netdev)
			continue;

		strncpy(name, netdev->name, IFNAMSIZ);

		unregister_sja1000dev(netdev);

		free_sja1000dev(netdev);

		dev_info(&card->pdev->dev, "%s removed\n", name);
	}

	/* do it only if device not removed */
	if (pcan_pccard_present(card)) {
		pcan_set_leds(card, led_mask, PCC_LED_OFF);
		pcan_set_can_power(card, 0);
	}
}
/*
 * write a sja1000 register
 */
static void pcan_write_canreg(const struct sja1000_priv *priv, int port, u8 v)
{
	struct pcan_pccard *card = priv->priv;
	int c = (priv->reg_base - card->ioport_addr) / PCC_CHAN_SIZE;

	/* sja1000 register changes control the leds state */
	if (port == REG_MOD)
		switch (v) {
		case MOD_RM:
			/* Reset Mode: set led on */
			pcan_set_leds(card, PCC_LED(c), PCC_LED_ON);
			break;
		case 0x00:
			/* Normal Mode: led slow blinking and start led timer */
			pcan_set_leds(card, PCC_LED(c), PCC_LED_SLOW);
			pcan_start_led_timer(card);
			break;
		default:
			break;
		}

	iowrite8(v, priv->reg_base + port);
}
static void pcan_write_canreg(const struct sja1000_priv *priv, int port, u8 v)
{
	struct pcan_pccard *card = priv->priv;
	int c = (priv->reg_base - card->ioport_addr) / PCC_CHAN_SIZE;

	
	if (port == REG_MOD)
		switch (v) {
		case MOD_RM:
			
			pcan_set_leds(card, PCC_LED(c), PCC_LED_ON);
			break;
		case 0x00:
			
			pcan_set_leds(card, PCC_LED(c), PCC_LED_SLOW);
			pcan_start_led_timer(card);
			break;
		default:
			break;
		}

	iowrite8(v, priv->reg_base + port);
}
static void pcan_set_leds(struct pcan_pccard *card, u8 led_mask, u8 state)
{
	u8 ccr = card->ccr;
	int i;

	for (i = 0; i < card->chan_count; i++)
		if (led_mask & PCC_LED(i)) {
			/* clear corresponding led bits in ccr */
			ccr &= ~PCC_CCR_LED_MASK_CHAN(i);
			/* then set new bits */
			ccr |= PCC_CCR_LED_CHAN(state, i);
		}

	/* real write only if something has changed in ccr */
	pcan_write_reg(card, PCC_CCR, ccr);
}
static void pcan_set_leds(struct pcan_pccard *card, u8 led_mask, u8 state)
{
	u8 ccr = card->ccr;
	int i;

	for (i = 0; i < card->chan_count; i++)
		if (led_mask & PCC_LED(i)) {
			
			ccr &= ~PCC_CCR_LED_MASK_CHAN(i);
			
			ccr |= PCC_CCR_LED_CHAN(state, i);
		}

	
	pcan_write_reg(card, PCC_CCR, ccr);
}