drivers/media/mmc/siano/smssdio.c

Source file repositories/reference/linux-study-clean/drivers/media/mmc/siano/smssdio.c

File Facts

System
Linux kernel
Corpus path
drivers/media/mmc/siano/smssdio.c
Extension
.c
Size
8239 bytes
Lines
352
Domain
Driver Families
Bucket
drivers/media
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 smssdio_device {
	struct sdio_func *func;

	struct smscore_device_t *coredev;

	struct smscore_buffer_t *split_cb;
};

/*******************************************************************/
/* Siano core callbacks                                            */
/*******************************************************************/

static int smssdio_sendrequest(void *context, void *buffer, size_t size)
{
	int ret = 0;
	struct smssdio_device *smsdev;

	smsdev = context;

	sdio_claim_host(smsdev->func);

	smsendian_handle_tx_message((struct sms_msg_data *) buffer);
	while (size >= smsdev->func->cur_blksize) {
		ret = sdio_memcpy_toio(smsdev->func, SMSSDIO_DATA,
					buffer, smsdev->func->cur_blksize);
		if (ret)
			goto out;

		buffer += smsdev->func->cur_blksize;
		size -= smsdev->func->cur_blksize;
	}

	if (size) {
		ret = sdio_memcpy_toio(smsdev->func, SMSSDIO_DATA,
					buffer, size);
	}

out:
	sdio_release_host(smsdev->func);

	return ret;
}

/*******************************************************************/
/* SDIO callbacks                                                  */
/*******************************************************************/

static void smssdio_interrupt(struct sdio_func *func)
{
	int ret;

	struct smssdio_device *smsdev;
	struct smscore_buffer_t *cb;
	struct sms_msg_hdr *hdr;
	size_t size;

	smsdev = sdio_get_drvdata(func);

	/*
	 * The interrupt register has no defined meaning. It is just
	 * a way of turning of the level triggered interrupt.
	 */
	(void)sdio_readb(func, SMSSDIO_INT, &ret);
	if (ret) {
		pr_err("Unable to read interrupt register!\n");
		return;
	}

	if (smsdev->split_cb == NULL) {
		cb = smscore_getbuffer(smsdev->coredev);
		if (!cb) {
			pr_err("Unable to allocate data buffer!\n");
			return;
		}

		ret = sdio_memcpy_fromio(smsdev->func,
					 cb->p,
					 SMSSDIO_DATA,
					 SMSSDIO_BLOCK_SIZE);
		if (ret) {
			pr_err("Error %d reading initial block!\n", ret);
			return;
		}

		hdr = cb->p;

		if (hdr->msg_flags & MSG_HDR_FLAG_SPLIT_MSG) {
			smsdev->split_cb = cb;
			return;
		}

Annotation

Implementation Notes