diff options
Diffstat (limited to 'drivers/memstick/core/mspro_block.c')
| -rw-r--r-- | drivers/memstick/core/mspro_block.c | 174 |
1 files changed, 85 insertions, 89 deletions
diff --git a/drivers/memstick/core/mspro_block.c b/drivers/memstick/core/mspro_block.c index d3f1a087ece..fc145d202c4 100644 --- a/drivers/memstick/core/mspro_block.c +++ b/drivers/memstick/core/mspro_block.c @@ -18,8 +18,9 @@ #include <linux/kthread.h> #include <linux/delay.h> #include <linux/slab.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <linux/memstick.h> +#include <linux/module.h> #define DRIVER_NAME "mspro_block" @@ -159,6 +160,13 @@ struct mspro_block_data { int (*mrq_handler)(struct memstick_dev *card, struct memstick_request **mrq); + + /* Default request setup function for data access method preferred by + * this host instance. + */ + void (*setup_transfer)(struct memstick_dev *card, + u64 offset, size_t length); + struct attribute_group attr_group; struct scatterlist req_sg[MSPRO_BLOCK_MAX_SEGS]; @@ -180,7 +188,6 @@ static int mspro_block_bd_open(struct block_device *bdev, fmode_t mode) struct mspro_block_data *msb = disk->private_data; int rc = -ENXIO; - lock_kernel(); mutex_lock(&mspro_block_disk_lock); if (msb && msb->card) { @@ -192,13 +199,12 @@ static int mspro_block_bd_open(struct block_device *bdev, fmode_t mode) } mutex_unlock(&mspro_block_disk_lock); - unlock_kernel(); return rc; } -static int mspro_block_disk_release(struct gendisk *disk) +static void mspro_block_disk_release(struct gendisk *disk) { struct mspro_block_data *msb = disk->private_data; int disk_id = MINOR(disk_devt(disk)) >> MSPRO_BLOCK_PART_SHIFT; @@ -218,17 +224,11 @@ static int mspro_block_disk_release(struct gendisk *disk) } mutex_unlock(&mspro_block_disk_lock); - - return 0; } -static int mspro_block_bd_release(struct gendisk *disk, fmode_t mode) +static void mspro_block_bd_release(struct gendisk *disk, fmode_t mode) { - int ret; - lock_kernel(); - ret = mspro_block_disk_release(disk); - unlock_kernel(); - return ret; + mspro_block_disk_release(disk); } static int mspro_block_bd_getgeo(struct block_device *bdev, @@ -662,14 +662,43 @@ has_int_reg: } } +/*** Transfer setup functions for different access methods. ***/ + +/** Setup data transfer request for SET_CMD TPC with arguments in card + * registers. + * + * @card Current media instance + * @offset Target data offset in bytes + * @length Required transfer length in bytes. + */ +static void h_mspro_block_setup_cmd(struct memstick_dev *card, u64 offset, + size_t length) +{ + struct mspro_block_data *msb = memstick_get_drvdata(card); + struct mspro_param_register param = { + .system = msb->system, + .data_count = cpu_to_be16((uint16_t)(length / msb->page_size)), + /* ISO C90 warning precludes direct initialization for now. */ + .data_address = 0, + .tpc_param = 0 + }; + + do_div(offset, msb->page_size); + param.data_address = cpu_to_be32((uint32_t)offset); + + card->next_request = h_mspro_block_req_init; + msb->mrq_handler = h_mspro_block_transfer_data; + memstick_init_req(&card->current_mrq, MS_TPC_WRITE_REG, + ¶m, sizeof(param)); +} + /*** Data transfer ***/ static int mspro_block_issue_req(struct memstick_dev *card, int chunk) { struct mspro_block_data *msb = memstick_get_drvdata(card); - sector_t t_sec; + u64 t_off; unsigned int count; - struct mspro_param_register param; try_again: while (chunk) { @@ -684,30 +713,17 @@ try_again: continue; } - t_sec = blk_rq_pos(msb->block_req) << 9; - sector_div(t_sec, msb->page_size); - + t_off = blk_rq_pos(msb->block_req); + t_off <<= 9; count = blk_rq_bytes(msb->block_req); - count /= msb->page_size; - param.system = msb->system; - param.data_count = cpu_to_be16(count); - param.data_address = cpu_to_be32((uint32_t)t_sec); - param.tpc_param = 0; + msb->setup_transfer(card, t_off, count); msb->data_dir = rq_data_dir(msb->block_req); msb->transfer_cmd = msb->data_dir == READ ? MSPRO_CMD_READ_DATA : MSPRO_CMD_WRITE_DATA; - dev_dbg(&card->dev, "data transfer: cmd %x, " - "lba %x, count %x\n", msb->transfer_cmd, - be32_to_cpu(param.data_address), count); - - card->next_request = h_mspro_block_req_init; - msb->mrq_handler = h_mspro_block_transfer_data; - memstick_init_req(&card->current_mrq, MS_TPC_WRITE_REG, - ¶m, sizeof(param)); memstick_new_req(card->host); return 0; } @@ -956,24 +972,22 @@ try_again: } /* Memory allocated for attributes by this function should be freed by - * mspro_block_data_clear, no matter if the initialization process succeded + * mspro_block_data_clear, no matter if the initialization process succeeded * or failed. */ static int mspro_block_read_attributes(struct memstick_dev *card) { struct mspro_block_data *msb = memstick_get_drvdata(card); - struct mspro_param_register param = { - .system = msb->system, - .data_count = cpu_to_be16(1), - .data_address = 0, - .tpc_param = 0 - }; struct mspro_attribute *attr = NULL; struct mspro_sys_attr *s_attr = NULL; unsigned char *buffer = NULL; int cnt, rc, attr_count; - unsigned int addr; - unsigned short page_count; + /* While normally physical device offsets, represented here by + * attr_offset and attr_len will be of large numeric types, we can be + * sure, that attributes are close enough to the beginning of the + * device, to save ourselves some trouble. + */ + unsigned int addr, attr_offset = 0, attr_len = msb->page_size; attr = kmalloc(msb->page_size, GFP_KERNEL); if (!attr) @@ -986,10 +1000,8 @@ static int mspro_block_read_attributes(struct memstick_dev *card) msb->data_dir = READ; msb->transfer_cmd = MSPRO_CMD_READ_ATRB; - card->next_request = h_mspro_block_req_init; - msb->mrq_handler = h_mspro_block_transfer_data; - memstick_init_req(&card->current_mrq, MS_TPC_WRITE_REG, ¶m, - sizeof(param)); + msb->setup_transfer(card, attr_offset, attr_len); + memstick_new_req(card->host); wait_for_completion(&card->mrq_complete); if (card->current_mrq.error) { @@ -1011,8 +1023,8 @@ static int mspro_block_read_attributes(struct memstick_dev *card) } else attr_count = attr->count; - msb->attr_group.attrs = kzalloc((attr_count + 1) - * sizeof(struct attribute), + msb->attr_group.attrs = kcalloc(attr_count + 1, + sizeof(*msb->attr_group.attrs), GFP_KERNEL); if (!msb->attr_group.attrs) { rc = -ENOMEM; @@ -1020,13 +1032,12 @@ static int mspro_block_read_attributes(struct memstick_dev *card) } msb->attr_group.name = "media_attributes"; - buffer = kmalloc(msb->page_size, GFP_KERNEL); + buffer = kmalloc(attr_len, GFP_KERNEL); if (!buffer) { rc = -ENOMEM; goto out_free_attr; } - memcpy(buffer, (char *)attr, msb->page_size); - page_count = 1; + memcpy(buffer, (char *)attr, attr_len); for (cnt = 0; cnt < attr_count; ++cnt) { s_attr = kzalloc(sizeof(struct mspro_sys_attr), GFP_KERNEL); @@ -1037,9 +1048,10 @@ static int mspro_block_read_attributes(struct memstick_dev *card) 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); + s_attr->size = 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); + "size %zx\n", cnt, attr->entries[cnt].id, addr, + s_attr->size); s_attr->id = attr->entries[cnt].id; if (mspro_block_attr_name(s_attr->id)) snprintf(s_attr->name, sizeof(s_attr->name), "%s", @@ -1053,57 +1065,47 @@ static int mspro_block_read_attributes(struct memstick_dev *card) s_attr->dev_attr.attr.mode = S_IRUGO; s_attr->dev_attr.show = mspro_block_attr_show(s_attr->id); - if (!rc) + if (!s_attr->size) continue; - s_attr->size = rc; - s_attr->data = kmalloc(rc, GFP_KERNEL); + s_attr->data = kmalloc(s_attr->size, GFP_KERNEL); if (!s_attr->data) { rc = -ENOMEM; goto out_free_buffer; } - if (((addr / msb->page_size) - == be32_to_cpu(param.data_address)) - && (((addr + rc - 1) / msb->page_size) - == be32_to_cpu(param.data_address))) { + if (((addr / msb->page_size) == (attr_offset / msb->page_size)) + && (((addr + s_attr->size - 1) / msb->page_size) + == (attr_offset / msb->page_size))) { memcpy(s_attr->data, buffer + addr % msb->page_size, - rc); + s_attr->size); continue; } - if (page_count <= (rc / msb->page_size)) { + attr_offset = (addr / msb->page_size) * msb->page_size; + + if ((attr_offset + attr_len) < (addr + s_attr->size)) { kfree(buffer); - page_count = (rc / msb->page_size) + 1; - buffer = kmalloc(page_count * msb->page_size, - GFP_KERNEL); + attr_len = (((addr + s_attr->size) / msb->page_size) + + 1 ) * msb->page_size - attr_offset; + buffer = kmalloc(attr_len, GFP_KERNEL); if (!buffer) { rc = -ENOMEM; goto out_free_attr; } } - 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.tpc_param = 0; - - sg_init_one(&msb->req_sg[0], buffer, - be16_to_cpu(param.data_count) * msb->page_size); + sg_init_one(&msb->req_sg[0], buffer, attr_len); msb->seg_count = 1; msb->current_seg = 0; msb->current_page = 0; msb->data_dir = READ; msb->transfer_cmd = MSPRO_CMD_READ_ATRB; - dev_dbg(&card->dev, "reading attribute pages %x, %x\n", - be32_to_cpu(param.data_address), - be16_to_cpu(param.data_count)); + dev_dbg(&card->dev, "reading attribute range %x, %x\n", + attr_offset, attr_len); - card->next_request = h_mspro_block_req_init; - msb->mrq_handler = h_mspro_block_transfer_data; - memstick_init_req(&card->current_mrq, MS_TPC_WRITE_REG, - (char *)¶m, sizeof(param)); + msb->setup_transfer(card, attr_offset, attr_len); memstick_new_req(card->host); wait_for_completion(&card->mrq_complete); if (card->current_mrq.error) { @@ -1111,7 +1113,8 @@ static int mspro_block_read_attributes(struct memstick_dev *card) goto out_free_buffer; } - memcpy(s_attr->data, buffer + addr % msb->page_size, rc); + memcpy(s_attr->data, buffer + addr % msb->page_size, + s_attr->size); } rc = 0; @@ -1129,6 +1132,8 @@ static int mspro_block_init_card(struct memstick_dev *card) int rc = 0; msb->system = MEMSTICK_SYS_SERIAL; + msb->setup_transfer = h_mspro_block_setup_cmd; + 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); @@ -1205,20 +1210,11 @@ static int mspro_block_init_disk(struct memstick_dev *card) msb->page_size = be16_to_cpu(sys_info->unit_size); - if (!idr_pre_get(&mspro_block_disk_idr, GFP_KERNEL)) - return -ENOMEM; - mutex_lock(&mspro_block_disk_lock); - rc = idr_get_new(&mspro_block_disk_idr, card, &disk_id); + disk_id = idr_alloc(&mspro_block_disk_idr, card, 0, 256, GFP_KERNEL); mutex_unlock(&mspro_block_disk_lock); - - if (rc) - return rc; - - if ((disk_id << MSPRO_BLOCK_PART_SHIFT) > 255) { - rc = -ENOSPC; - goto out_release_id; - } + if (disk_id < 0) + return disk_id; msb->disk = alloc_disk(1 << MSPRO_BLOCK_PART_SHIFT); if (!msb->disk) { |
