drivers/net/can/sja1000/ems_pcmcia.c

Source file repositories/reference/linux-study-clean/drivers/net/can/sja1000/ems_pcmcia.c

File Facts

System
Linux kernel
Corpus path
drivers/net/can/sja1000/ems_pcmcia.c
Extension
.c
Size
7868 bytes
Lines
317
Domain
Driver Families
Bucket
drivers/net
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct ems_pcmcia_card {
	int channels;
	struct pcmcia_device *pcmcia_dev;
	struct net_device *net_dev[EMS_PCMCIA_MAX_CHAN];
	void __iomem *base_addr;
};

#define EMS_PCMCIA_CAN_CLOCK (16000000 / 2)

/*
 * The board configuration is probably following:
 * RX1 is connected to ground.
 * TX1 is not connected.
 * CLKO is not connected.
 * Setting the OCR register to 0xDA is a good idea.
 * This means  normal output mode , push-pull and the correct polarity.
 */
#define EMS_PCMCIA_OCR (OCR_TX0_PUSHPULL | OCR_TX1_PUSHPULL)

/*
 * In the CDR register, you should set CBP to 1.
 * You will probably also want to set the clock divider value to 7
 * (meaning direct oscillator output) because the second SJA1000 chip
 * is driven by the first one CLKOUT output.
 */
#define EMS_PCMCIA_CDR (CDR_CBP | CDR_CLKOUT_MASK)
#define EMS_PCMCIA_MEM_SIZE 4096 /* Size of the remapped io-memory */
#define EMS_PCMCIA_CAN_BASE_OFFSET 0x100 /* Offset where controllers starts */
#define EMS_PCMCIA_CAN_CTRL_SIZE 0x80 /* Memory size for each controller */

#define EMS_CMD_RESET 0x00 /* Perform a reset of the card */
#define EMS_CMD_MAP   0x03 /* Map CAN controllers into card' memory */
#define EMS_CMD_UMAP  0x02 /* Unmap CAN controllers from card' memory */

static struct pcmcia_device_id ems_pcmcia_tbl[] = {
	PCMCIA_DEVICE_PROD_ID123("EMS_T_W", "CPC-Card", "V2.0", 0xeab1ea23,
				 0xa338573f, 0xe4575800),
	PCMCIA_DEVICE_NULL,
};

MODULE_DEVICE_TABLE(pcmcia, ems_pcmcia_tbl);

static u8 ems_pcmcia_read_reg(const struct sja1000_priv *priv, int port)
{
	return readb(priv->reg_base + port);
}

static void ems_pcmcia_write_reg(const struct sja1000_priv *priv, int port,
				 u8 val)
{
	writeb(val, priv->reg_base + port);
}

static irqreturn_t ems_pcmcia_interrupt(int irq, void *dev_id)
{
	struct ems_pcmcia_card *card = dev_id;
	struct net_device *dev;
	irqreturn_t retval = IRQ_NONE;
	int i, again;

	/* Card not present */
	if (readw(card->base_addr) != 0xAA55)
		return IRQ_HANDLED;

	do {
		again = 0;

		/* Check interrupt for each channel */
		for (i = 0; i < card->channels; i++) {
			dev = card->net_dev[i];
			if (!dev)
				continue;

			if (sja1000_interrupt(irq, dev) == IRQ_HANDLED)
				again = 1;
		}
		/* At least one channel handled the interrupt */
		if (again)
			retval = IRQ_HANDLED;

	} while (again);

	return retval;
}

/*
 * Check if a CAN controller is present at the specified location
 * by trying to set 'em into the PeliCAN mode
 */
static inline int ems_pcmcia_check_chan(struct sja1000_priv *priv)

Annotation

Implementation Notes