[PATCH] [MEMSTICK] Updates for the memstick driver

Alex Dubov
2008-01-25T08:02:42Z

* Mark shared inline functions as static

* Use member-at-a-time assignment for protocol structures

* Comments for publicly exported functions

* Use end_queued_request to end unhandled block layer requests

* Use sysfs attribute group to export MSPro attributes

* Fix includes

* Use scnprintf instead of snprintf where string length matters

* Remove spurious get_device/put_device in probe method

diff --git a/drivers/memstick/core/memstick.c b/drivers/memstick/core/memstick.c
index 46e5f9b..bba467f 100644
--- a/drivers/memstick/core/memstick.c
+++ b/drivers/memstick/core/memstick.c
@@ -12,11 +12,10 @@
*
*/

-#include <linux/tifm.h>
#include <linux/memstick.h>
#include <linux/idr.h>
-#include <linux/scatterlist.h>
#include <linux/fs.h>
+#include <linux/delay.h>

#define DRIVER_NAME "memstick"
#define DRIVER_VERSION "0.2"
@@ -86,13 +85,11 @@ static int memstick_device_probe(struct device *dev)
driver);
int rc = -ENODEV;

- get_device(dev);
if (dev->driver && drv->probe) {
rc = drv->probe(card);
if (!rc)
- return 0;
+ get_device(dev);
}
- put_device(dev);
return rc;
}

@@ -205,12 +202,26 @@ static int memstick_dummy_check(struct memstick_dev *card)
return 0;
}

+/**
+ * memstick_detect_change - schedule media detection on memstick host
+ * @host - host to use
+ */
void memstick_detect_change(struct memstick_host *host)
{
queue_work(workqueue, &host->media_checker);
}
EXPORT_SYMBOL(memstick_detect_change);

+/**
+ * memstick_next_req - called by host driver to obtain next request to process
+ * @host - host to use
+ * @mrq - pointer to stick the request to
+ *
+ * Host calls this function from idle state (*mrq == NULL) or after finishing
+ * previous request (*mrq should point to it). If previous request was
+ * unsuccessful, it is retried for predetermined number of times. Return value
+ * of 0 means that new request was assigned to the host.
+ */
int memstick_next_req(struct memstick_host *host, struct memstick_request **mrq)
{
int rc = -ENXIO;
@@ -233,6 +244,10 @@ int memstick_next_req(struct memstick_host *host, struct memstick_request
**mrq)
}
EXPORT_SYMBOL(memstick_next_req);

+/**
+ * memstick_new_req - notify the host that some requests are pending
+ * @host - host to use
+ */
void memstick_new_req(struct memstick_host *host)
{
host->retries = cmd_retries;
@@ -240,6 +255,12 @@ void memstick_new_req(struct memstick_host *host)
}
EXPORT_SYMBOL(memstick_new_req);

+/**
+ * memstick_init_req_sg - set request fields needed for bulk data transfer
+ * @mrq - request to use
+ * @tpc - memstick Transport Protocol Command
+ * @sg - TPC argument
+ */
void memstick_init_req_sg(struct memstick_request *mrq, unsigned char tpc,
struct scatterlist *sg)
{
@@ -261,6 +282,17 @@ void memstick_init_req_sg(struct memstick_request *mrq, unsigned char tpc,
}
EXPORT_SYMBOL(memstick_init_req_sg);

+/**
+ * memstick_init_req - set request fields needed for short data transfer
+ * @mrq - request to use
+ * @tpc - memstick Transport Protocol Command
+ * @buf - TPC argument buffer
+ * @length - TPC argument size
+ *
+ * The intended use of this function (transfer of data items several bytes
+ * in size) allows us to just copy the value between request structure and
+ * user supplied buffer.
+ */
void memstick_init_req(struct memstick_request *mrq, unsigned char tpc,
void *buf, size_t length)
{
@@ -285,6 +317,13 @@ void memstick_init_req(struct memstick_request *mrq, unsigned char tpc,
}
EXPORT_SYMBOL(memstick_init_req);

+/*
+ * Functions prefixed with "h_" are protocol callbacks. They can be called from
+ * interrupt context. Return value of 0 means that request processing is still
+ * ongoing, while special error value of -EAGAIN means that current request is
+ * finished (and request processor should come back some time later).
+ */
+
static int h_memstick_read_dev_id(struct memstick_dev *card,
struct memstick_request **mrq)
{
@@ -298,12 +337,10 @@ static int h_memstick_read_dev_id(struct memstick_dev *card,
} else {
if (!(*mrq)->error) {
memcpy(&id_reg, (*mrq)->data, sizeof(id_reg));
- card->id = (struct memstick_device_id){
- .match_flags = MEMSTICK_MATCH_ALL,
- .type = id_reg.type,
- .category = id_reg.category,
- .class = id_reg.class
- };
+ card->id.match_flags = MEMSTICK_MATCH_ALL;
+ card->id.type = id_reg.type;
+ card->id.category = id_reg.category;
+ card->id.class = id_reg.class;
}
complete(&card->mrq_complete);
return -EAGAIN;
@@ -325,6 +362,11 @@ static int h_memstick_set_rw_addr(struct memstick_dev *card,
}
}

+/**
+ * memstick_set_rw_addr - issue SET_RW_REG_ADDR request and wait for it to
+ * complete
+ * @card - media device to use
+ */
int memstick_set_rw_addr(struct memstick_dev *card)
{
card->next_request = h_memstick_set_rw_addr;
@@ -351,12 +393,10 @@ static struct memstick_dev *memstick_alloc_card(struct memstick_host *host)
card->dev.release = memstick_free_card;
card->check = memstick_dummy_check;

- card->reg_addr = (struct ms_register_addr){
- offsetof(struct ms_register, id),
- sizeof(id_reg),
- offsetof(struct ms_register, id),
- sizeof(id_reg)
- };
+ card->reg_addr.r_offset = offsetof(struct ms_register, id);
+ card->reg_addr.r_length = sizeof(id_reg);
+ card->reg_addr.w_offset = offsetof(struct ms_register, id);
+ card->reg_addr.w_length = sizeof(id_reg);

init_completion(&card->mrq_complete);

@@ -433,6 +473,11 @@ static void memstick_check(struct work_struct *work)
dev_dbg(host->cdev.dev, "memstick_check finished\n");
}

+/**
+ * memstick_alloc_host - allocate a memstick_host structure
+ * @extra: size of the user private data to allocate
+ * @dev: parent device of the host
+ */
struct memstick_host *memstick_alloc_host(unsigned int extra,
struct device *dev)
{
@@ -450,6 +495,10 @@ struct memstick_host *memstick_alloc_host(unsigned int extra,
}
EXPORT_SYMBOL(memstick_alloc_host);

+/**
+ * memstick_add_host - start request processing on memstick host
+ * @host - host to use
+ */
int memstick_add_host(struct memstick_host *host)
{
int rc;
@@ -480,6 +529,10 @@ int memstick_add_host(struct memstick_host *host)
}
EXPORT_SYMBOL(memstick_add_host);

+/**
+ * memstick_remove_host - stop request processing on memstick host
+ * @host - host to use
+ */
void memstick_remove_host(struct memstick_host *host)
{
flush_workqueue(workqueue);
@@ -497,6 +550,10 @@ void memstick_remove_host(struct memstick_host *host)
}
EXPORT_SYMBOL(memstick_remove_host);

+/**
+ * memstick_free_host - free memstick host
+ * @host - host to use
+ */
void memstick_free_host(struct memstick_host *host)
{
mutex_destroy(&host->lock);
diff --git a/drivers/memstick/core/mspro_block.c b/drivers/memstick/core/mspro_block.c
index c029dee..f09b74f 100644
--- a/drivers/memstick/core/mspro_block.c
+++ b/drivers/memstick/core/mspro_block.c
@@ -13,7 +13,6 @@
*/

#include <linux/blkdev.h>
-#include <linux/scatterlist.h>
#include <linux/idr.h>
#include <linux/hdreg.h>
#include <linux/kthread.h>
@@ -44,10 +43,10 @@ enum {

struct mspro_sys_attr {
size_t size;
- unsigned char *data;
+ void *data;
unsigned char id;
char name[32];
- struct device_attribute sys_attr;
+ struct device_attribute dev_attr;
};

struct mspro_attr_entry {
@@ -144,8 +143,7 @@ struct mspro_block_data {
int (*mrq_handler)(struct memstick_dev *card,
struct memstick_request **mrq);

- unsigned char attr_count;
- struct mspro_sys_attr *attributes;
+ struct attribute_group attr_group;

struct scatterlist req_sg[MSPRO_BLOCK_MAX_SEGS];
unsigned int seg_count;
@@ -229,6 +227,13 @@ static struct block_device_operations ms_block_bdops = {

/*** Information ***/

+static struct mspro_sys_attr *mspro_from_sysfs_attr(struct attribute *attr)
+{
+ struct device_attribute *dev_attr
+ = container_of(attr, struct device_attribute, attr);
+ return container_of(dev_attr, struct mspro_sys_attr, dev_attr);
+}
+
static const char *mspro_block_attr_name(unsigned char tag)
{
switch (tag) {
@@ -261,20 +266,20 @@ static ssize_t mspro_block_attr_show_default(struct device *dev,
struct device_attribute *attr,
char *buffer)
{
- struct mspro_sys_attr *x_attr = container_of(attr,
+ struct mspro_sys_attr *s_attr = container_of(attr,
struct mspro_sys_attr,
- sys_attr);
+ dev_attr);

ssize_t cnt, rc = 0;

- for (cnt = 0; cnt < x_attr->size; cnt++) {
+ for (cnt = 0; cnt < s_attr->size; cnt++) {
if (cnt && !(cnt % 16)) {
if (PAGE_SIZE - rc)
buffer[rc++] = '\n';
}

- rc += snprintf(buffer + rc, PAGE_SIZE - rc, "%02x ",
- x_attr->data[cnt]);
+ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "%02x ",
+ ((unsigned char *)s_attr->data)[cnt]);
}
return rc;
}
@@ -285,63 +290,66 @@ static ssize_t mspro_block_attr_show_sysinfo(struct device *dev,
{
struct mspro_sys_attr *x_attr = container_of(attr,
struct mspro_sys_attr,
- sys_attr);
- struct mspro_sys_info *x_sys = (struct mspro_sys_info *)x_attr->data;
+ dev_attr);
+ struct mspro_sys_info *x_sys = x_attr->data;
ssize_t rc = 0;

- rc += snprintf(buffer + rc, PAGE_SIZE - rc, "class: %x\n",
- x_sys->class);
- rc += snprintf(buffer + rc, PAGE_SIZE - rc, "block size: %x\n",
- be16_to_cpu(x_sys->block_size));
- rc += snprintf(buffer + rc, PAGE_SIZE - rc, "block count: %x\n",
- be16_to_cpu(x_sys->block_count));
- rc += snprintf(buffer + rc, PAGE_SIZE - rc, "user block count: %x\n",
- be16_to_cpu(x_sys->user_block_count));
- rc += snprintf(buffer + rc, PAGE_SIZE - rc, "page size: %x\n",
- be16_to_cpu(x_sys->page_size));
- rc += snprintf(buffer + rc, PAGE_SIZE - rc, "assembly date: "
- "%d %04u-%02u-%02u %02u:%02u:%02u\n",
- x_sys->assembly_date[0],
- be16_to_cpu(*(unsigned short *)&x_sys->assembly_date[1]),
- x_sys->assembly_date[3], x_sys->assembly_date[4],
- x_sys->assembly_date[5], x_sys->assembly_date[6],
- x_sys->assembly_date[7]);
- rc += snprintf(buffer + rc, PAGE_SIZE - rc, "serial number: %x\n",
- be32_to_cpu(x_sys->serial_number));
- rc += snprintf(buffer + rc, PAGE_SIZE - rc, "assembly maker code: %x\n",
- x_sys->assembly_maker_code);
- rc += snprintf(buffer + rc, PAGE_SIZE - rc, "assembly model code: "
- "%02x%02x%02x\n", x_sys->assembly_model_code[0],
- x_sys->assembly_model_code[1],
- x_sys->assembly_model_code[2]);
- rc += snprintf(buffer + rc, PAGE_SIZE - rc, "memory maker code: %x\n",
- be16_to_cpu(x_sys->memory_maker_code));
- rc += snprintf(buffer + rc, PAGE_SIZE - rc, "memory model code: %x\n",
- be16_to_cpu(x_sys->memory_model_code));
- rc += snprintf(buffer + rc, PAGE_SIZE - rc, "vcc: %x\n",
- x_sys->vcc);
- rc += snprintf(buffer + rc, PAGE_SIZE - rc, "vpp: %x\n",
- x_sys->vpp);
- rc += snprintf(buffer + rc, PAGE_SIZE - rc, "controller number: %x\n",
- be16_to_cpu(x_sys->controller_number));
- rc += snprintf(buffer + rc, PAGE_SIZE - rc, "controller function: %x\n",
- be16_to_cpu(x_sys->controller_function));
- rc += snprintf(buffer + rc, PAGE_SIZE - rc, "start sector: %x\n",
- be16_to_cpu(x_sys->start_sector));
- rc += snprintf(buffer + rc, PAGE_SIZE - rc, "unit size: %x\n",
- be16_to_cpu(x_sys->unit_size));
- rc += snprintf(buffer + rc, PAGE_SIZE - rc, "sub class: %x\n",
- x_sys->ms_sub_class);
- rc += snprintf(buffer + rc, PAGE_SIZE - rc, "interface type: %x\n",
- x_sys->interface_type);
- rc += snprintf(buffer + rc, PAGE_SIZE - rc, "controller code: %x\n",
- be16_to_cpu(x_sys->controller_code));
- rc += snprintf(buffer + rc, PAGE_SIZE - rc, "format type: %x\n",
- x_sys->format_type);
- rc += snprintf(buffer + rc, PAGE_SIZE - rc, "device type: %x\n",
- x_sys->device_type);
- rc += snprintf(buffer + rc, PAGE_SIZE - rc, "mspro id: %s\n",
- x_sys->mspro_id);
+ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "class: %x\n",
+ x_sys->class);
+ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "block size: %x\n",
+ be16_to_cpu(x_sys->block_size));
+ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "block count: %x\n",
+ be16_to_cpu(x_sys->block_count));
+ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "user block count: %x\n",
+ be16_to_cpu(x_sys->user_block_count));
+ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "page size: %x\n",
+ be16_to_cpu(x_sys->page_size));
+ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "assembly date: "
+ "%d %04u-%02u-%02u %02u:%02u:%02u\n",
+ x_sys->assembly_date[0],
+ be16_to_cpu(*(unsigned short *)
+ &x_sys->assembly_date[1]),
+ x_sys->assembly_date[3], x_sys->assembly_date[4],
+ x_sys->assembly_date[5], x_sys->assembly_date[6],
+ x_sys->assembly_date[7]);
+ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "serial number: %x\n",
+ be32_to_cpu(x_sys->serial_number));
+ rc += scnprintf(buffer + rc, PAGE_SIZE - rc,
+ "assembly maker code: %x\n",
+ x_sys->assembly_maker_code);
+ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "assembly model code: "
+ "%02x%02x%02x\n", x_sys->assembly_model_code[0],
+ x_sys->assembly_model_code[1],
+ x_sys->assembly_model_code[2]);
+ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "memory maker code: %x\n",
+ be16_to_cpu(x_sys->memory_maker_code));
+ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "memory model code: %x\n",
+ be16_to_cpu(x_sys->memory_model_code));
+ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "vcc: %x\n",
+ x_sys->vcc);
+ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "vpp: %x\n",
+ x_sys->vpp);
+ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "controller number: %x\n",
+ be16_to_cpu(x_sys->controller_number));
+ rc += scnprintf(buffer + rc, PAGE_SIZE - rc,
+ "controller function: %x\n",
+ be16_to_cpu(x_sys->controller_function));
+ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "start sector: %x\n",
+ be16_to_cpu(x_sys->start_sector));
+ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "unit size: %x\n",
+ be16_to_cpu(x_sys->unit_size));
+ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "sub class: %x\n",
+ x_sys->ms_sub_class);
+ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "interface type: %x\n",
+ x_sys->interface_type);
+ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "controller code: %x\n",
+ be16_to_cpu(x_sys->controller_code));
+ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "format type: %x\n",
+ x_sys->format_type);
+ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "device type: %x\n",
+ x_sys->device_type);
+ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "mspro id: %s\n",
+ x_sys->mspro_id);
return rc;
}

@@ -349,11 +357,11 @@ static ssize_t mspro_block_attr_show_modelname(struct device *dev,
struct device_attribute *attr,
char *buffer)
{
- struct mspro_sys_attr *x_attr = container_of(attr,
+ struct mspro_sys_attr *s_attr = container_of(attr,
struct mspro_sys_attr,
- sys_attr);
+ dev_attr);

- return snprintf(buffer, PAGE_SIZE, "%s", x_attr->data);
+ return scnprintf(buffer, PAGE_SIZE, "%s", (char *)s_attr->data);
}

static ssize_t mspro_block_attr_show_mbr(struct device *dev,
@@ -362,31 +370,31 @@ static ssize_t mspro_block_attr_show_mbr(struct device *dev,
{
struct mspro_sys_attr *x_attr = container_of(attr,
struct mspro_sys_attr,
- sys_attr);
- struct mspro_mbr *x_mbr = (struct mspro_mbr *)x_attr->data;
+ dev_attr);
+ struct mspro_mbr *x_mbr = x_attr->data;
ssize_t rc = 0;

- rc += snprintf(buffer + rc, PAGE_SIZE - rc, "boot partition: %x\n",
- x_mbr->boot_partition);
- rc += snprintf(buffer + rc, PAGE_SIZE - rc, "start head: %x\n",
- x_mbr->start_head);
- rc += snprintf(buffer + rc, PAGE_SIZE - rc, "start sector: %x\n",
- x_mbr->start_sector);
- rc += snprintf(buffer + rc, PAGE_SIZE - rc, "start cylinder: %x\n",
- x_mbr->start_cylinder);
- rc += snprintf(buffer + rc, PAGE_SIZE - rc, "partition type: %x\n",
- x_mbr->partition_type);
- rc += snprintf(buffer + rc, PAGE_SIZE - rc, "end head: %x\n",
- x_mbr->end_head);
- rc += snprintf(buffer + rc, PAGE_SIZE - rc, "end sector: %x\n",
- x_mbr->end_sector);
- rc += snprintf(buffer + rc, PAGE_SIZE - rc, "end cylinder: %x\n",
- x_mbr->end_cylinder);
- rc += snprintf(buffer + rc, PAGE_SIZE - rc, "start sectors: %x\n",
- x_mbr->start_sectors);
- rc += snprintf(buffer + rc, PAGE_SIZE - rc,
- "sectors per partition: %x\n",
- x_mbr->sectors_per_partition);
+ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "boot partition: %x\n",
+ x_mbr->boot_partition);
+ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "start head: %x\n",
+ x_mbr->start_head);
+ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "start sector: %x\n",
+ x_mbr->start_sector);
+ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "start cylinder: %x\n",
+ x_mbr->start_cylinder);
+ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "partition type: %x\n",
+ x_mbr->partition_type);
+ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "end head: %x\n",
+ x_mbr->end_head);
+ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "end sector: %x\n",
+ x_mbr->end_sector);
+ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "end cylinder: %x\n",
+ x_mbr->end_cylinder);
+ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "start sectors: %x\n",
+ x_mbr->start_sectors);
+ rc += scnprintf(buffer + rc, PAGE_SIZE - rc,
+ "sectors per partition: %x\n",
+ x_mbr->sectors_per_partition);
return rc;
}

@@ -396,20 +404,20 @@ static ssize_t mspro_block_attr_show_devinfo(struct device *dev,
{
struct mspro_sys_attr *x_attr = container_of(attr,
struct mspro_sys_attr,
- sys_attr);
- struct mspro_devinfo *x_devinfo = (struct mspro_devinfo *)x_attr->data;
+ dev_attr);
+ struct mspro_devinfo *x_devinfo = x_attr->data;
ssize_t rc = 0;

- rc += snprintf(buffer + rc, PAGE_SIZE - rc, "cylinders: %x\n",
- be16_to_cpu(x_devinfo->cylinders));
- rc += snprintf(buffer + rc, PAGE_SIZE - rc, "heads: %x\n",
- be16_to_cpu(x_devinfo->heads));
- rc += snprintf(buffer + rc, PAGE_SIZE - rc, "bytes per track: %x\n",
- be16_to_cpu(x_devinfo->bytes_per_track));
- rc += snprintf(buffer + rc, PAGE_SIZE - rc, "bytes per sector: %x\n",
- be16_to_cpu(x_devinfo->bytes_per_sector));
- rc += snprintf(buffer + rc, PAGE_SIZE - rc, "sectors per track: %x\n",
- be16_to_cpu(x_devinfo->sectors_per_track));
+ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "cylinders: %x\n",
+ be16_to_cpu(x_devinfo->cylinders));
+ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "heads: %x\n",
+ be16_to_cpu(x_devinfo->heads));
+ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "bytes per track: %x\n",
+ be16_to_cpu(x_devinfo->bytes_per_track));
+ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "bytes per sector: %x\n",
+ be16_to_cpu(x_devinfo->bytes_per_sector));
+ rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "sectors per track: %x\n",
+ be16_to_cpu(x_devinfo->sectors_per_track));
return rc;
}

@@ -429,39 +437,15 @@ static sysfs_show_t mspro_block_attr_show(unsigned char tag)
}
}

-static int mspro_block_sysfs_register(struct memstick_dev *card)
-{
- struct mspro_block_data *msb = memstick_get_drvdata(card);
- int cnt, rc = 0;
-
- for (cnt = 0; cnt < msb->attr_count; cnt++) {
- rc = device_create_file(&card->dev,
- &msb->attributes[cnt].sys_attr);
-
- if (rc) {
- if (cnt) {
- for (cnt--; cnt >= 0; cnt--)
- device_remove_file(&card->dev,
- &msb->attributes[cnt]
- .sys_attr);
- }
- break;
- }
- }
- return rc;
-}
-
-static void mspro_block_sysfs_unregister(struct memstick_dev *card)
-{
- struct mspro_block_data *msb = memstick_get_drvdata(card);
- int cnt;
-
- for (cnt = 0; cnt < msb->attr_count; cnt++)
- device_remove_file(&card->dev, &msb->attributes[cnt].sys_attr);
-}
-
/*** Protocol handlers ***/

+/*
+ * Functions prefixed with "h_" are protocol callbacks. They can be called from
+ * interrupt context. Return value of 0 means that request processing is still
+ * ongoing, while special error value of -EAGAIN means that current request is
+ * finished (and request processor should come back some time later).
+ */
+
static int h_mspro_block_req_init(struct memstick_dev *card,
struct memstick_request **mrq)
{
@@ -642,12 +626,10 @@ static void mspro_block_process_request(struct memstick_dev *card,

t_sec = req->sector;
sector_div(t_sec, msb->page_size >> 9);
- param = (struct mspro_param_register) {
- .system = msb->system,
- .data_count = cpu_to_be16(page_count),
- .data_address = cpu_to_be32((uint32_t)t_sec),
- .cmd_param = 0
- };
+ param.system = msb->system;
+ param.data_count = cpu_to_be16(page_count);
+ param.data_address = cpu_to_be32((uint32_t)t_sec);
+ param.cmd_param = 0;

msb->data_dir = rq_data_dir(req);
msb->transfer_cmd = msb->data_dir == READ
@@ -755,17 +737,12 @@ static void mspro_block_request(struct request_queue *q)
struct mspro_block_data *msb = memstick_get_drvdata(card);
struct request *req = NULL;

- if (!msb->q_thread) {
- for (req = elv_next_request(q); req;
- req = elv_next_request(q)) {
- while (end_that_request_chunk(req, -ENODEV,
- req->current_nr_sectors
- << 9)) {}
- end_that_request_last(req, -ENODEV);
- }
- } else {
+ if (msb->q_thread) {
msb->has_request = 1;
wake_up_all(&msb->q_wait);
+ } else {
+ while ((req = elv_next_request(q)) != NULL)
+ end_queued_request(req, -ENODEV);
}
}

@@ -821,6 +798,10 @@ static int mspro_block_switch_to_parallel(struct memstick_dev *card)
return 0;
}

+/* Memory allocated for attributes by this function should be freed by
+ * mspro_block_data_clear, no matter if the initialization process succeded
+ * or failed.
+ */
static int mspro_block_read_attributes(struct memstick_dev *card)
{
struct mspro_block_data *msb = memstick_get_drvdata(card);
@@ -831,8 +812,9 @@ static int mspro_block_read_attributes(struct memstick_dev *card)
.cmd_param = 0
};
struct mspro_attribute *attr = NULL;
+ struct mspro_sys_attr *s_attr = NULL;
unsigned char *buffer = NULL;
- int cnt, rc;
+ int cnt, rc, attr_count;
unsigned int addr;
unsigned short page_count;

@@ -868,18 +850,18 @@ static int mspro_block_read_attributes(struct memstick_dev *card)
if (attr->count > MSPRO_BLOCK_MAX_ATTRIBUTES) {
printk(KERN_WARNING "%s: way too many attribute entries\n",
card->dev.bus_id);
- msb->attr_count = MSPRO_BLOCK_MAX_ATTRIBUTES;
+ attr_count = MSPRO_BLOCK_MAX_ATTRIBUTES;
} else
- msb->attr_count = attr->count;
+ attr_count = attr->count;

- msb->attributes = kzalloc(msb->attr_count
- * sizeof(struct mspro_sys_attr),
- GFP_KERNEL);
- if (!msb->attributes) {
- msb->attr_count = 0;
+ msb->attr_group.attrs = kzalloc((attr_count + 1)
+ * sizeof(struct attribute),
+ GFP_KERNEL);
+ if (!msb->attr_group.attrs) {
rc = -ENOMEM;
goto out_free_attr;
}
+ msb->attr_group.name = "media_attributes";

buffer = kmalloc(msb->page_size, GFP_KERNEL);
if (!buffer) {
@@ -889,40 +871,37 @@ static int mspro_block_read_attributes(struct memstick_dev *card)
memcpy(buffer, (char *)attr, msb->page_size);
page_count = 1;

- for (cnt = 0; cnt < msb->attr_count; cnt++) {
+ for (cnt = 0; cnt < attr_count; ++cnt) {
+ s_attr = kzalloc(sizeof(struct mspro_sys_attr), GFP_KERNEL);
+ if (!s_attr) {
+ rc = -ENOMEM;
+ goto out_free_buffer;
+ }
+
+ msb->attr_group.attrs[cnt] = &s_attr->dev_attr.attr;
addr = be32_to_cpu(attr->entries[cnt].address);
rc = be32_to_cpu(attr->entries[cnt].size);
dev_dbg(&card->dev, "adding attribute %d: id %x, address %x, "
"size %x\n", cnt, attr->entries[cnt].id, addr, rc);
- msb->attributes[cnt].id = attr->entries[cnt].id;
- if (mspro_block_attr_name(attr->entries[cnt].id))
- snprintf(msb->attributes[cnt].name,
- sizeof(msb->attributes[cnt].name), "%s",
+ s_attr->id = attr->entries[cnt].id;
+ if (mspro_block_attr_name(s_attr->id))
+ snprintf(s_attr->name, sizeof(s_attr->name), "%s",
mspro_block_attr_name(attr->entries[cnt].id));
else
- snprintf(msb->attributes[cnt].name,
- sizeof(msb->attributes[cnt].name),
- "attr_x%02x",
- attr->entries[cnt].id);
-
- msb->attributes[cnt].sys_attr
- = (struct device_attribute){
- .attr = {
- .name = msb->attributes[cnt].name,
- .mode = S_IRUGO,
- .owner = THIS_MODULE
- },
- .show = mspro_block_attr_show(
- msb->attributes[cnt].id),
- .store = NULL
- };
+ snprintf(s_attr->name, sizeof(s_attr->name),
+ "attr_x%02x", attr->entries[cnt].id);
+
+ s_attr->dev_attr.attr.name = s_attr->name;
+ s_attr->dev_attr.attr.mode = S_IRUGO;
+ s_attr->dev_attr.attr.owner = THIS_MODULE;
+ s_attr->dev_attr.show = mspro_block_attr_show(s_attr->id);

if (!rc)
continue;

- msb->attributes[cnt].size = rc;
- msb->attributes[cnt].data = kmalloc(rc, GFP_KERNEL);
- if (!msb->attributes[cnt].data) {
+ s_attr->size = rc;
+ s_attr->data = kmalloc(rc, GFP_KERNEL);
+ if (!s_attr->data) {
rc = -ENOMEM;
goto out_free_buffer;
}
@@ -931,8 +910,7 @@ static int mspro_block_read_attributes(struct memstick_dev *card)
== be32_to_cpu(param.data_address))
&& (((addr + rc - 1) / msb->page_size)
== be32_to_cpu(param.data_address))) {
- memcpy(msb->attributes[cnt].data,
- buffer + addr % msb->page_size,
+ memcpy(s_attr->data, buffer + addr % msb->page_size,
rc);
continue;
}
@@ -948,12 +926,10 @@ static int mspro_block_read_attributes(struct memstick_dev *card)
}
}

- param = (struct mspro_param_register){
- .system = msb->system,
- .data_count = cpu_to_be16((rc / msb->page_size) + 1),
- .data_address = cpu_to_be32(addr / msb->page_size),
- .cmd_param = 0
- };
+ param.system = msb->system;
+ param.data_count = cpu_to_be16((rc / msb->page_size) + 1);
+ param.data_address = cpu_to_be32(addr / msb->page_size);
+ param.cmd_param = 0;

sg_init_one(&msb->req_sg[0], buffer,
be16_to_cpu(param.data_count) * msb->page_size);
@@ -978,9 +954,7 @@ static int mspro_block_read_attributes(struct memstick_dev *card)
goto out_free_buffer;
}

- memcpy(msb->attributes[cnt].data,
- buffer + addr % msb->page_size,
- rc);
+ memcpy(s_attr->data, buffer + addr % msb->page_size, rc);
}

rc = 0;
@@ -998,12 +972,10 @@ static int mspro_block_init_card(struct memstick_dev *card)
int rc = 0;

msb->system = 0x80;
- card->reg_addr = (struct ms_register_addr){
- offsetof(struct mspro_register, status),
- sizeof(struct ms_status_register),
- offsetof(struct mspro_register, param),
- sizeof(struct mspro_param_register)
- };
+ card->reg_addr.r_offset = offsetof(struct mspro_register, status);
+ card->reg_addr.r_length = sizeof(struct ms_status_register);
+ card->reg_addr.w_offset = offsetof(struct mspro_register, param);
+ card->reg_addr.w_length = sizeof(struct mspro_param_register);

if (memstick_set_rw_addr(card))
return -EIO;
@@ -1046,6 +1018,7 @@ static int mspro_block_init_disk(struct memstick_dev *card)
struct memstick_host *host = card->host;
struct mspro_devinfo *dev_info = NULL;
struct mspro_sys_info *sys_info = NULL;
+ struct mspro_sys_attr *s_attr = NULL;
int rc, disk_id;
u64 limit = BLK_BOUNCE_HIGH;
unsigned long capacity;
@@ -1053,13 +1026,13 @@ static int mspro_block_init_disk(struct memstick_dev *card)
if (host->cdev.dev->dma_mask && *(host->cdev.dev->dma_mask))
limit = *(host->cdev.dev->dma_mask);

- for (rc = 0; rc < msb->attr_count; rc++) {
- if (msb->attributes[rc].id == MSPRO_BLOCK_ID_DEVINFO)
- dev_info = (struct mspro_devinfo *)msb->attributes[rc]
- .data;
- if (msb->attributes[rc].id == MSPRO_BLOCK_ID_SYSINFO)
- sys_info = (struct mspro_sys_info *)msb->attributes[rc]
- .data;
+ for (rc = 0; msb->attr_group.attrs[rc]; ++rc) {
+ s_attr = mspro_from_sysfs_attr(msb->attr_group.attrs[rc]);
+
+ if (s_attr->id == MSPRO_BLOCK_ID_DEVINFO)
+ dev_info = s_attr->data;
+ else if (s_attr->id == MSPRO_BLOCK_ID_SYSINFO)
+ sys_info = s_attr->data;
}

if (!dev_info || !sys_info)
@@ -1150,11 +1123,18 @@ out_release_id:
static void mspro_block_data_clear(struct mspro_block_data *msb)
{
int cnt;
+ struct mspro_sys_attr *s_attr;
+
+ if (msb->attr_group.attrs) {
+ for (cnt = 0; msb->attr_group.attrs[cnt]; ++cnt) {
+ s_attr = mspro_from_sysfs_attr(msb->attr_group
+ .attrs[cnt]);
+ kfree(s_attr->data);
+ kfree(s_attr);
+ }
+ kfree(msb->attr_group.attrs);
+ }

- for (cnt = 0; cnt < msb->attr_count; cnt++)
- kfree(msb->attributes[cnt].data);
-
- kfree(msb->attributes);
msb->card = NULL;
}

@@ -1181,7 +1161,7 @@ static int mspro_block_probe(struct memstick_dev *card)
if (rc)
goto out_free;

- rc = mspro_block_sysfs_register(card);
+ rc = sysfs_create_group(&card->dev.kobj, &msb->attr_group);
if (rc)
goto out_free;

@@ -1191,7 +1171,7 @@ static int mspro_block_probe(struct memstick_dev *card)
return 0;
}

- mspro_block_sysfs_unregister(card);
+ sysfs_remove_group(&card->dev.kobj, &msb->attr_group);
out_free:
memstick_set_drvdata(card, NULL);
mspro_block_data_clear(msb);
@@ -1223,7 +1203,7 @@ static void mspro_block_remove(struct memstick_dev *card)

blk_cleanup_queue(msb->queue);

- mspro_block_sysfs_unregister(card);
+ sysfs_remove_group(&card->dev.kobj, &msb->attr_group);

mutex_lock(&mspro_block_disk_lock);
mspro_block_data_clear(msb);
@@ -1264,6 +1244,7 @@ static int mspro_block_resume(struct memstick_dev *card)

struct mspro_block_data *new_msb;
struct memstick_host *host = card->host;
+ struct mspro_sys_attr s_attr, r_attr;
unsigned char cnt;

mutex_lock(&host->lock);
@@ -1278,13 +1259,18 @@ static int mspro_block_resume(struct memstick_dev *card)
if (mspro_block_init_card(card))
goto out_free;

- for (cnt = 0; cnt < new_msb->attr_count; cnt++) {
- if (new_msb->attributes[cnt].id == MSPRO_BLOCK_ID_SYSINFO
- && cnt < msb->attr_count
- && msb->attributes[cnt].id == MSPRO_BLOCK_ID_SYSINFO) {
- if (memcmp(new_msb->attributes[cnt].data,
- msb->attributes[cnt].data,
- msb->attributes[cnt].size))
+ for (cnt = 0; new_msb->attr_group.attrs[cnt]
+ && msb->attr_group.attrs[cnt]; ++cnt) {
+ s_attr = container_of(new_msb->attr_group.attrs[cnt],
+ struct mspro_sys_attr,
+ dev_attr);
+ r_attr = container_of(msb->attr_group.attrs[cnt],
+ struct mspro_sys_attr,
+ dev_attr);
+
+ if (s_attr->id == MSPRO_BLOCK_ID_SYSINFO
+ && r_attr->id == s_attr->id) {
+ if (memcmp(s_attr->data, r_attr->data, s_attr->size))
break;

memstick_set_drvdata(card, msb);
diff --git a/include/linux/memstick.h b/include/linux/memstick.h
index dc5ac9d..334d059 100644
--- a/include/linux/memstick.h
+++ b/include/linux/memstick.h
@@ -13,6 +13,10 @@
#define _MEMSTICK_H

#include <linux/workqueue.h>
+#include <linux/scatterlist.h>
+#include <linux/device.h>
+
+/*** Hardware based structures ***/

struct ms_status_register {
unsigned char reserved;
@@ -151,6 +155,8 @@ enum {
*/
};

+/*** Driver structures and functions ***/
+
#define MEMSTICK_PART_SHIFT 3

enum memstick_param { MEMSTICK_POWER = 1, MEMSTICK_INTERFACE };
@@ -212,7 +218,9 @@ struct memstick_dev {
struct completion mrq_complete;
struct memstick_request current_mrq;

+ /* Check that media driver is still willing to operate the device. */
int (*check)(struct memstick_dev *card);
+ /* Get next request from the media driver. */
int (*next_request)(struct memstick_dev *card,
struct memstick_request **mrq);

@@ -232,7 +240,9 @@ struct memstick_host {
struct memstick_dev *card;
unsigned int retries;

+ /* Notify the host that some requests are pending. */
void (*request)(struct memstick_host *host);
+ /* Set host IO parameters (power, clock, etc). */
void (*set_param)(struct memstick_host *host,
enum memstick_param param,
int value);
@@ -271,17 +281,17 @@ void memstick_new_req(struct memstick_host *host);

int memstick_set_rw_addr(struct memstick_dev *card);

-inline void *memstick_priv(struct memstick_host *host)
+static inline void *memstick_priv(struct memstick_host *host)
{
return (void *)host->private;
}

-inline void *memstick_get_drvdata(struct memstick_dev *card)
+static inline void *memstick_get_drvdata(struct memstick_dev *card)
{
return dev_get_drvdata(&card->dev);
}

-inline void memstick_set_drvdata(struct memstick_dev *card, void *data)
+static inline void memstick_set_drvdata(struct memstick_dev *card, void *data)
{
dev_set_drvdata(&card->dev, data);
}

____________________________________________________________________________________
Be a better friend, newshound, and
know-it-all with Yahoo! Mobile. Try it now. http://mobile.yahoo.com/;_ylt=Ahu06i62sR8HDtDypao8Wcj9tAcJ