From: Grant Likely <[EMAIL PROTECTED]>
Please review and comment. This patch works in my setup, but I haven't
tested exhaustively yet. I also need to fixup the documentation to
reflect new states before I request this patch to be merged.
Question for the block layer experts: I'm using add_disk()/del_gendisk()
functions to inform the kernel of media insertion and removal events. Is
this the best way to do this? I looked at the .media_changed and
.revalidate_disk hooks, but it doesn't seem like they offer the driver
any way to notify the kernel of media removal (as opposed to the kernel
asking the driver)
Cheers,
g.
---
drivers/block/xsysace.c | 265 ++-
1 files changed, 189 insertions(+), 76 deletions(-)
diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c
index 0cdc868..9b3df96 100644
--- a/drivers/block/xsysace.c
+++ b/drivers/block/xsysace.c
@@ -53,7 +53,7 @@
*The request method in particular schedules the tasklet when a new
*request has been indicated by the block layer. Once started, the
*FSM proceeds as far as it can processing the request until it
- *needs on a hardware event. At this point, it must yield execution.
+ *needs a hardware event. At this point, it must yield execution.
*
*A state has two options when yielding execution:
*1. ace_fsm_yield()
@@ -71,7 +71,8 @@
*Additionally, the driver maintains a kernel timer which can process
*the FSM. If the FSM gets stalled, typically due to a missed
*interrupt, then the kernel timer will expire and the driver can
- *continue where it left off.
+ *continue where it left off. The stall timer is also used to watch
+ *for media removal/insertion events.
*
* To Do:
*- Add FPGA configuration control interface.
@@ -90,6 +91,7 @@
#include
#include
#include
+#include
#include
#if defined(CONFIG_OF)
#include
@@ -170,17 +172,18 @@ struct ace_reg_ops;
struct ace_device {
/* driver state data */
int id;
- int media_change;
int users;
struct list_head list;
/* finite state machine data */
struct tasklet_struct fsm_tasklet;
+ struct work_struct fsm_worker;
uint fsm_task; /* Current activity (ACE_TASK_*) */
uint fsm_state; /* Current state (ACE_FSM_STATE_*) */
uint fsm_continue_flag; /* cleared to exit FSM mainloop */
uint fsm_iter_num;
struct timer_list stall_timer;
+ int stall_count;
/* Transfer state/result, use for both id and block request */
struct request *req;/* request being processed */
@@ -189,7 +192,6 @@ struct ace_device {
int data_result;/* Result of transfer; 0 := success */
int id_req_count; /* count of id requests */
- int id_result;
struct completion id_completion;/* used when id req finishes */
int in_irq;
@@ -212,6 +214,7 @@ struct ace_device {
};
static int ace_major;
+struct workqueue_struct *ace_workqueue;
/* -
* Low level register access
@@ -429,21 +432,24 @@ void ace_fix_driveid(struct hd_driveid *id)
#define ACE_TASK_IDENTIFY 1
#define ACE_TASK_READ 2
#define ACE_TASK_WRITE 3
-#define ACE_FSM_NUM_TASKS 4
+#define ACE_NUM_TASKS 4
/* FSM state definitions */
-#define ACE_FSM_STATE_IDLE 0
-#define ACE_FSM_STATE_REQ_LOCK 1
-#define ACE_FSM_STATE_WAIT_LOCK 2
-#define ACE_FSM_STATE_WAIT_CFREADY 3
-#define ACE_FSM_STATE_IDENTIFY_PREPARE 4
-#define ACE_FSM_STATE_IDENTIFY_TRANSFER 5
-#define ACE_FSM_STATE_IDENTIFY_COMPLETE 6
-#define ACE_FSM_STATE_REQ_PREPARE7
-#define ACE_FSM_STATE_REQ_TRANSFER 8
-#define ACE_FSM_STATE_REQ_COMPLETE 9
-#define ACE_FSM_STATE_ERROR 10
-#define ACE_FSM_NUM_STATES 11
+#define ACE_FSM_STATE_NO_MEDIA 0
+#define ACE_FSM_STATE_KICKSTART 1
+#define ACE_FSM_STATE_IDLE 2
+#define ACE_FSM_STATE_REQ_LOCK 3
+#define ACE_FSM_STATE_WAIT_LOCK 4
+#define ACE_FSM_STATE_WAIT_CFREADY 5
+#define ACE_FSM_STATE_IDENTIFY_PREPARE 6
+#define ACE_FSM_STATE_IDENTIFY_TRANSFER 7
+#define ACE_FSM_STATE_IDENTIFY_COMPLETE 8
+#define ACE_FSM_STATE_REQ_PREPARE9
+#define ACE_FSM_STATE_REQ_TRANSFER 10
+#define ACE_FSM_STATE_REQ_COMPLETE 11
+#define ACE_FSM_STATE_INVALIDATE_MEDIA 12
+#define ACE_FSM_STATE_MEDIA_DISABLED13
+#define ACE_FSM_NUM_STATES 14
/* Set flag to exit FSM loop and reschedule tasklet */
static inline void ace_fsm_yield(struct ace_device *ace)
@@ -490,18 +496,53 @@ static void ace_fsm_dostate(struct ace_device *ace)
ace->fsm_state, ace->id_req_count);
#endif
+ /* Before doing anything; check the CF detect bit. If the card
+* is not present; then there a