mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Maxim Levitsky <maximlevitsky@gmail.com>
To: Alex Dubov <oakad@yahoo.com>
Cc: Andrew Morton <akpm@linux-foundation.org>,
	LKML <linux-kernel@vger.kernel.org>,
	Maxim Levitsky <maximlevitsky@gmail.com>
Subject: [PATCH 03/29] memstick: core: add new functions
Date: Sat, 23 Oct 2010 01:53:31 +0200	[thread overview]
Message-ID: <1287791637-10329-4-git-send-email-maximlevitsky@gmail.com> (raw)
In-Reply-To: <1287791637-10329-1-git-send-email-maximlevitsky@gmail.com>

Add a lot of support code that will be used later.

Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com>
---
 drivers/memstick/core/memstick.c |  299 ++++++++++++++++++++++++++++++++++++--
 include/linux/memstick.h         |   32 ++++
 2 files changed, 318 insertions(+), 13 deletions(-)

diff --git a/drivers/memstick/core/memstick.c b/drivers/memstick/core/memstick.c
index 5a501a4..9fe36c7 100644
--- a/drivers/memstick/core/memstick.c
+++ b/drivers/memstick/core/memstick.c
@@ -249,6 +249,17 @@ static int h_memstick_set_rw_addr(struct memstick_dev *card,
 	}
 }
 
+static int h_memstick_default_bad(struct memstick_dev *card,
+				     struct memstick_request **mrq)
+{
+	return -ENXIO;
+}
+
+static void memstick_invalidate_reg_window(struct memstick_dev *card)
+{
+	memset(&card->reg_addr, 0, sizeof(card->reg_addr));
+}
+
 
 static struct memstick_dev *memstick_alloc_card(struct memstick_host *host)
 {
@@ -293,14 +304,23 @@ err_out:
 
 int memstick_power_on(struct memstick_host *host)
 {
-	int rc = host->set_param(host, MEMSTICK_POWER, MEMSTICK_POWER_ON);
+	int rc;
 
+	if (host->card)
+		memstick_invalidate_reg_window(host->card);
+
+	rc = host->set_param(host, MEMSTICK_POWER, MEMSTICK_POWER_ON);
 	if (!rc)
 		rc = host->set_param(host, MEMSTICK_INTERFACE, MEMSTICK_SERIAL);
 
 	return rc;
 }
 
+int memstick_power_off(struct memstick_host *host)
+{
+	return host->set_param(host, MEMSTICK_POWER, MEMSTICK_POWER_OFF);
+}
+
 static void memstick_check(struct work_struct *work)
 {
 	struct memstick_host *host = container_of(work, struct memstick_host,
@@ -347,7 +367,7 @@ static void memstick_check(struct work_struct *work)
 
 out_power_off:
 	if (!host->card)
-		host->set_param(host, MEMSTICK_POWER, MEMSTICK_POWER_OFF);
+		memstick_power_off(host);
 
 	mutex_unlock(&host->lock);
 	dev_dbg(&host->dev, "memstick_check finished\n");
@@ -356,10 +376,9 @@ out_power_off:
 /*** card driver interface ***/
 
 /**
-  * memstick_register_driver - Register new card driver
-  * @drv - the driver descriptior
-  */
-
+ * memstick_register_driver - register new card driver
+ * @drv - the driver info structure
+ */
 int memstick_register_driver(struct memstick_driver *drv)
 {
 	drv->driver.bus = &memstick_bus_type;
@@ -369,10 +388,10 @@ int memstick_register_driver(struct memstick_driver *drv)
 EXPORT_SYMBOL(memstick_register_driver);
 
 /**
-  * memstick_unregister_driver - deregister new card driver
-  * @drv - the driver descriptior
-  */
-
+ * memstick_unregister_driver - unregister a card driver
+ * usually called on card driver unload
+ * @drv - the driver info structure
+ */
 void memstick_unregister_driver(struct memstick_driver *drv)
 {
 	driver_unregister(&drv->driver);
@@ -396,8 +415,6 @@ int memstick_set_rw_addr(struct memstick_dev *card)
 EXPORT_SYMBOL(memstick_set_rw_addr);
 
 
-
-
 /**
  * memstick_new_req - notify the host that some requests are pending
  * @host - host to use
@@ -412,6 +429,93 @@ void memstick_new_req(struct memstick_host *host)
 }
 EXPORT_SYMBOL(memstick_new_req);
 
+
+/*** state machine support code ***/
+
+/**
+ * memstick_run_state_machine - runs IO state machine
+ * DON'T call from state machine code!
+ * Usefull for blocking IO in the card drivers.
+ * @card - card to use
+ * @state_func - the state machine
+ * @sync - if true, will wait till state machine exits using
+ * memstick_exit_state_machine
+ */
+int memstick_run_state_machine(struct memstick_dev *card,
+	int   (*state_func)(struct memstick_dev *card,
+			struct memstick_request **mrq), bool sync)
+{
+	WARN_ON(card->state != -1);
+
+	/* Init everything to prevent stale data from creeping in */
+	memset(&card->current_mrq, 0, sizeof(card->current_mrq));
+	card->int_polling = false;
+	card->state = 0;
+	card->exit_error = 0;
+
+
+	card->next_request = state_func;
+	card->host->retries = cmd_retries;
+	INIT_COMPLETION(card->mrq_complete);
+	card->host->request(card->host);
+
+	if (!sync)
+		return 0;
+
+	wait_for_completion(&card->mrq_complete);
+
+	WARN_ON(card->state != -1);
+	return card->exit_error;
+}
+EXPORT_SYMBOL(memstick_run_state_machine);
+
+
+/**
+ * memstick_exit_state_machine - signal that request is completed
+ * @card - card to use
+ * @mrq - request to use
+ * @error - result of the request
+ *
+ * State machines call this to signal quit
+ */
+int memstick_exit_state_machine(struct memstick_dev *card,
+			struct memstick_request *req, int error)
+{
+	if (error)
+		req->error = error;
+
+	card->state = -1;
+	card->exit_error = error;
+	card->next_request = h_memstick_default_bad;
+
+	/* Invalidate reg window on errors */
+	if (error)
+		memstick_invalidate_reg_window(card);
+
+	complete(&card->mrq_complete);
+	return -ENXIO;
+}
+EXPORT_SYMBOL(memstick_exit_state_machine);
+
+/**
+ * memstick_allocate_request - create new request for use in request handler
+ * @card - card to use
+ * @mrq - request to initialize
+ */
+void memstick_allocate_request(struct memstick_dev *card,
+					struct memstick_request **mrq)
+{
+	if (*mrq == NULL) {
+		*mrq = &card->current_mrq;
+		(*mrq)->error = 0;
+		(*mrq)->need_card_int = 0;
+		card->int_polling = false;
+		card->state = 0;
+	}
+}
+EXPORT_SYMBOL(memstick_allocate_request);
+
+
 /**
  * memstick_init_req_sg - set request fields needed for bulk data transfer
  * @mrq - request to use
@@ -470,6 +574,175 @@ void memstick_init_req(struct memstick_request *mrq, unsigned char tpc,
 }
 EXPORT_SYMBOL(memstick_init_req);
 
+/**
+ * memstick_read_int_reg - read INT status from the card
+ * if last request already contains the int flags, will return 0
+ * returns 1 if new request was initialized
+ * Will artifictially return MEMSTICK_INT_CMDNAK if more that 'timeout' msecs
+ * passed after last MS_TPC_GET_INT request (and no requests in between)
+ * if timeout == -1, then it is set to default value of 500 msec
+ * @card - card to use
+ * @timeout - the timeout. if -1, then uses default
+ */
+int memstick_read_int_reg(struct memstick_dev *card,
+				struct memstick_request *req, long timeout)
+{
+
+	if (!card->int_polling) {
+		card->int_timeout = jiffies +
+			msecs_to_jiffies(timeout == -1 ? 500 : timeout);
+		card->int_polling = true;
+	} else if (time_after(jiffies, card->int_timeout)) {
+		req->data[0] = MEMSTICK_INT_CMDNAK;
+		return 0;
+	}
+
+	if (((card->caps | card->host->caps) & MEMSTICK_CAP_AUTO_GET_INT) &&
+							req->need_card_int) {
+		BUG_ON(req->error);
+		req->data[0] = req->int_reg;
+		req->need_card_int = 0;
+		return 0;
+	} else {
+		memstick_init_req(req, MS_TPC_GET_INT, NULL, 1);
+		return 1;
+	}
+}
+EXPORT_SYMBOL(memstick_read_int_reg);
+
+
+/**
+ * memstick_read_int_reg_cleanup - cleanup after series of calls to
+ * memstick_read_int_reg. Used to cancel timeout.
+ * Use this if you use memstick_read_int_reg
+ * @card - card to use
+ */
+void memstick_read_int_reg_cleanup(struct memstick_dev *card)
+{
+	card->int_polling = false;
+}
+EXPORT_SYMBOL(memstick_read_int_reg_cleanup);
+
+
+/**
+ * memstick_read_regs - read the ms registers
+ * If there is need to change the R/W window,
+ * it will create the MS_TPC_SET_RW_REG_ADRS request and return 0,
+ * otherwise it will create a request for register read and return 1
+ * @card - card to use
+ * @offset - offset of first register to read
+ * @len - number of bytes to read
+ * @req - request to use
+ */
+
+int memstick_read_regs(struct memstick_dev *card, int offset, int len,
+	struct memstick_request *req)
+{
+	if (card->reg_addr.r_offset != offset ||
+					card->reg_addr.r_length != len) {
+		card->reg_addr.r_offset = offset;
+		card->reg_addr.r_length = len;
+
+		/* Set dummy window after reg invalidation to prevent
+			possible rejection of 0,0 window by the card */
+		if (!card->reg_addr.w_length) {
+			card->reg_addr.w_offset =
+					offsetof(struct ms_register, id);
+			card->reg_addr.w_length = sizeof(struct ms_id_register);
+		}
+
+		memstick_init_req(req, MS_TPC_SET_RW_REG_ADRS, &card->reg_addr,
+			sizeof(card->reg_addr));
+		return 0;
+	}
+
+	memstick_init_req(req, MS_TPC_READ_REG, NULL, len);
+	return 1;
+}
+EXPORT_SYMBOL(memstick_read_regs);
+
+/**
+ * memstick_write_regs - write the ms registers.
+ * If there is need to change the R/W window,
+ * it will create the MS_TPC_SET_RW_REG_ADRS request and return 0,
+ * otherwise it will create a request for register write and return 1
+ * @card - card to use
+ * @offset - offset of first register to read
+ * @len - number of bytes to read
+ * @buf - the register data to write
+ * @req - request to use
+ */
+int memstick_write_regs(struct memstick_dev *card, int offset, int len,
+	char *buf, struct memstick_request *req)
+{
+	if (card->reg_addr.w_offset != offset ||
+					card->reg_addr.w_length != len) {
+		card->reg_addr.w_offset = offset;
+		card->reg_addr.w_length = len;
+
+		/* Set dummy window after reg invalidation to prevent
+			possible rejection of 0,0 window by the card */
+		if (!card->reg_addr.r_length) {
+			card->reg_addr.r_offset =
+					offsetof(struct ms_register, id);
+
+			card->reg_addr.r_length = sizeof(struct ms_id_register);
+		}
+
+		memstick_init_req(req, MS_TPC_SET_RW_REG_ADRS, &card->reg_addr,
+			sizeof(card->reg_addr));
+		return 0;
+	}
+
+	memstick_init_req(req, MS_TPC_WRITE_REG, buf, len);
+	return 1;
+}
+EXPORT_SYMBOL(memstick_write_regs);
+
+
+static const char *tpc_names[] = {
+	"MS_TPC_READ_MG_STATUS",
+	"MS_TPC_READ_LONG_DATA",
+	"MS_TPC_READ_SHORT_DATA",
+	"MS_TPC_READ_REG",
+	"MS_TPC_READ_QUAD_DATA",
+	"INVALID",
+	"MS_TPC_GET_INT",
+	"MS_TPC_SET_RW_REG_ADRS",
+	"MS_TPC_EX_SET_CMD",
+	"MS_TPC_WRITE_QUAD_DATA",
+	"MS_TPC_WRITE_REG",
+	"MS_TPC_WRITE_SHORT_DATA",
+	"MS_TPC_WRITE_LONG_DATA",
+	"MS_TPC_SET_CMD",
+};
+
+/**
+ * memstick_debug_get_tpc_name - debug helper that returns string for
+ * a TPC number
+ */
+const char *memstick_debug_get_tpc_name(int tpc)
+{
+	return tpc_names[tpc-1];
+}
+EXPORT_SYMBOL(memstick_debug_get_tpc_name);
+
+/**
+ * memstick_reset - power cycles the host
+ */
+int memstick_reset(struct memstick_host *host)
+{
+	int error = memstick_power_off(host);
+	if (error)
+		return error;
+
+	/* TODO: why this delay ? */
+	msleep(50);
+
+	return memstick_power_on(host);
+}
+EXPORT_SYMBOL(memstick_reset);
+
 /*** low level (host) driver interface ***/
 
 /**
@@ -566,7 +839,7 @@ EXPORT_SYMBOL(memstick_free_host);
 void memstick_suspend_host(struct memstick_host *host)
 {
 	mutex_lock(&host->lock);
-	host->set_param(host, MEMSTICK_POWER, MEMSTICK_POWER_OFF);
+	memstick_power_off(host);
 	mutex_unlock(&host->lock);
 }
 EXPORT_SYMBOL(memstick_suspend_host);
diff --git a/include/linux/memstick.h b/include/linux/memstick.h
index 428c4a1..73586cb 100644
--- a/include/linux/memstick.h
+++ b/include/linux/memstick.h
@@ -296,6 +296,13 @@ struct memstick_dev {
 	void                     (*start)(struct memstick_dev *card);
 
 	struct device            dev;
+	int			 caps;
+
+	/* state machine's state */
+	int			 state;
+	int			 exit_error;
+	bool			 int_polling;
+	unsigned long		 int_timeout;
 };
 
 struct memstick_host {
@@ -349,6 +356,16 @@ void memstick_unregister_driver(struct memstick_driver *drv);
 
 int memstick_set_rw_addr(struct memstick_dev *card);
 
+int memstick_run_state_machine(struct memstick_dev *card,
+	int   (*state_func)(struct memstick_dev *card,
+			struct memstick_request **mrq), bool sync);
+
+int memstick_exit_state_machine(struct memstick_dev *card,
+			struct memstick_request *req, int error);
+
+void memstick_allocate_request(struct memstick_dev *card,
+					struct memstick_request **mrq);
+
 void memstick_new_req(struct memstick_host *host);
 
 void memstick_init_req_sg(struct memstick_request *mrq, unsigned char tpc,
@@ -356,6 +373,21 @@ void memstick_init_req_sg(struct memstick_request *mrq, unsigned char tpc,
 void memstick_init_req(struct memstick_request *mrq, unsigned char tpc,
 		       const void *buf, size_t length);
 
+int memstick_read_int_reg(struct memstick_dev *card,
+				struct memstick_request *req, long timeout);
+
+void memstick_read_int_reg_cleanup(struct memstick_dev *card);
+
+int memstick_read_regs(struct memstick_dev *card, int offset, int len,
+	struct memstick_request *req);
+
+int memstick_write_regs(struct memstick_dev *card, int offset, int len,
+	char *buf, struct memstick_request *req);
+
+const char *memstick_debug_get_tpc_name(int tpc);
+
+int memstick_reset(struct memstick_host *host);
+
 /* Interface for low-level (host) drivers */
 
 struct memstick_host *memstick_alloc_host(unsigned int extra,
-- 
1.7.1


  parent reply	other threads:[~2010-10-22 23:54 UTC|newest]

Thread overview: 84+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-10-22 23:53 [PATCH 0/29] My patch queue for memorystick subsystem Maxim Levitsky
2010-10-22 23:53 ` [PATCH 01/29] memstick: core: header cleanups Maxim Levitsky
2010-10-25 14:44   ` Alex Dubov
2010-10-26  1:10     ` Maxim Levitsky
2010-10-22 23:53 ` [PATCH 02/29] memstick: core: reorder functions This patch just reorders functions in memstick.c So that host specific and card driver specific functions are now grouped together. This makes it easier to understand the code Maxim Levitsky
2010-10-25 14:50   ` Alex Dubov
2010-10-26  1:14     ` Maxim Levitsky
2010-10-22 23:53 ` Maxim Levitsky [this message]
2010-10-25 14:56   ` [PATCH 03/29] memstick: core: add new functions Alex Dubov
2010-10-26  1:20     ` Maxim Levitsky
2010-10-22 23:53 ` [PATCH 04/29] memstick: core: rework state machines Maxim Levitsky
2010-10-25 15:01   ` Alex Dubov
2010-10-26  1:34     ` Maxim Levitsky
2010-10-22 23:53 ` [PATCH 05/29] memstick: mspro_block: move declarations to header and refactor things a bit Maxim Levitsky
2010-10-25 15:07   ` Alex Dubov
2010-10-26  1:46     ` Maxim Levitsky
2010-10-22 23:53 ` [PATCH 06/29] memstick: mspro: kill the BKL Maxim Levitsky
2010-10-25 15:12   ` Alex Dubov
2010-10-26  1:50     ` Maxim Levitsky
2010-10-22 23:53 ` [PATCH 07/29] memstick: mspro: two fixes Maxim Levitsky
2010-10-25 15:13   ` Alex Dubov
2010-10-26  1:51     ` Maxim Levitsky
2010-10-22 23:53 ` [PATCH 08/29] memstick: mspro: add comments to few functions Maxim Levitsky
2010-10-25 15:18   ` Alex Dubov
2010-10-26  1:54     ` Maxim Levitsky
2010-10-22 23:53 ` [PATCH 09/29] memstick: rework state machines + attribute read function Maxim Levitsky
2010-10-25 15:23   ` Alex Dubov
2010-10-26  1:57     ` Maxim Levitsky
2010-10-22 23:53 ` [PATCH 10/29] memstick: mspro: create _setup_io helper Maxim Levitsky
2010-10-25 15:25   ` Alex Dubov
2010-10-26  1:58     ` Maxim Levitsky
2010-10-22 23:53 ` [PATCH 11/29] memstick: mspro: use MS_TPC_EX_SET_CMD Maxim Levitsky
2010-10-25 15:27   ` Alex Dubov
2010-10-26  2:00     ` Maxim Levitsky
2010-10-22 23:53 ` [PATCH 12/29] memstick: mspro: rework interface switch Maxim Levitsky
2010-10-25 15:28   ` Alex Dubov
2010-10-26  2:01     ` Maxim Levitsky
2010-10-22 23:53 ` [PATCH 13/29] memstick: core: stop passing pointer to card->current_mrq Maxim Levitsky
2010-10-25 15:41   ` Alex Dubov
2010-10-26  2:04     ` Maxim Levitsky
2010-10-22 23:53 ` [PATCH 14/29] memstick: remove the memstick_set_rw_addr Maxim Levitsky
2010-10-25 15:55   ` Alex Dubov
2010-10-26  2:08     ` Maxim Levitsky
2010-10-22 23:53 ` [PATCH 15/29] memstick: jmb38x_ms: Create header Maxim Levitsky
2010-10-25 15:56   ` Alex Dubov
2010-10-26  2:10     ` Maxim Levitsky
2010-10-22 23:53 ` [PATCH 16/29] memstick: jmb38x_ms: s/jmb38x_ms/j38ms/g Maxim Levitsky
2010-10-25 15:58   ` Alex Dubov
2010-10-26  2:13     ` Maxim Levitsky
2010-10-22 23:53 ` [PATCH 17/29] memstick: jmb38x_ms: move "reg_data" functions together Maxim Levitsky
2010-10-25 16:00   ` Alex Dubov
2010-10-26  2:14     ` Maxim Levitsky
2010-10-22 23:53 ` [PATCH 18/29] memstick: jmb38x_ms: rename functions Maxim Levitsky
2010-10-25 16:00   ` Alex Dubov
2010-10-26  2:17     ` Maxim Levitsky
2010-10-22 23:53 ` [PATCH 19/29] memstick: jmb38x_ms: add register read/write functions Maxim Levitsky
2010-10-25 16:03   ` Alex Dubov
2010-10-26  2:19     ` Maxim Levitsky
2010-10-22 23:53 ` [PATCH 20/29] memstick: jmb38x_ms: rework PIO Maxim Levitsky
2010-10-25 16:05   ` Alex Dubov
2010-10-26  2:21     ` Maxim Levitsky
2010-10-22 23:53 ` [PATCH 21/29] memstick: jmb38x_ms: rework TPC execution Maxim Levitsky
2010-10-25 16:08   ` Alex Dubov
2010-10-26  2:22     ` Maxim Levitsky
2010-10-22 23:53 ` [PATCH 22/29] memstick: jmb38x_ms: rework ISR Maxim Levitsky
2010-10-25 16:11   ` Alex Dubov
2010-10-26  2:23     ` Maxim Levitsky
2010-10-22 23:53 ` [PATCH 23/29] memstick: jmb38x_ms: use DMA for all TPCs with len greater that 8 by default Maxim Levitsky
2010-10-25 16:12   ` Alex Dubov
2010-10-26  2:29     ` Maxim Levitsky
2010-10-22 23:53 ` [PATCH 24/29] memstick: jmb38x_ms: rework processing of the TPC one after another Maxim Levitsky
2010-10-25 16:14   ` Alex Dubov
2010-10-22 23:53 ` [PATCH 25/29] memstick: jmb38x_ms: pass j38ms_host to few functions instead of memstick_host Maxim Levitsky
2010-10-22 23:53 ` [PATCH 26/29] memstick: jmb38x_ms: rework hardware setup/reset Maxim Levitsky
2010-10-25 16:17   ` Alex Dubov
2010-10-22 23:53 ` [PATCH 27/29] memstick: jmb38x_ms: minor additions Maxim Levitsky
2010-10-22 23:53 ` [PATCH 28/29] memstick: add support for legacy memorysticks Maxim Levitsky
2010-10-22 23:53 ` [PATCH 29/29] memstick: Add driver for Ricoh R5C592 Card reader Maxim Levitsky
2010-10-25  2:01 ` [PATCH 0/29] My patch queue for memorystick subsystem Maxim Levitsky
2010-10-25 14:39   ` Alex Dubov
2010-10-25 16:07     ` Andrew Morton
2010-10-25 16:10       ` Alex Dubov
2010-10-26  2:32       ` Maxim Levitsky
2010-10-25 16:25   ` Alex Dubov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1287791637-10329-4-git-send-email-maximlevitsky@gmail.com \
    --to=maximlevitsky@gmail.com \
    --cc=akpm@linux-foundation.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=oakad@yahoo.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

Powered by JetHome