Path: blob/master/drivers/memstick/core/mspro_block.c
15111 views
/*1* Sony MemoryStick Pro storage support2*3* Copyright (C) 2007 Alex Dubov <[email protected]>4*5* This program is free software; you can redistribute it and/or modify6* it under the terms of the GNU General Public License version 2 as7* published by the Free Software Foundation.8*9* Special thanks to Carlos Corbacho for providing various MemoryStick cards10* that made this driver possible.11*12*/1314#include <linux/blkdev.h>15#include <linux/idr.h>16#include <linux/hdreg.h>17#include <linux/kthread.h>18#include <linux/delay.h>19#include <linux/slab.h>20#include <linux/mutex.h>21#include <linux/memstick.h>2223#define DRIVER_NAME "mspro_block"2425static int major;26module_param(major, int, 0644);2728#define MSPRO_BLOCK_MAX_SEGS 3229#define MSPRO_BLOCK_MAX_PAGES ((2 << 16) - 1)3031#define MSPRO_BLOCK_SIGNATURE 0xa5c332#define MSPRO_BLOCK_MAX_ATTRIBUTES 413334#define MSPRO_BLOCK_PART_SHIFT 33536enum {37MSPRO_BLOCK_ID_SYSINFO = 0x10,38MSPRO_BLOCK_ID_MODELNAME = 0x15,39MSPRO_BLOCK_ID_MBR = 0x20,40MSPRO_BLOCK_ID_PBR16 = 0x21,41MSPRO_BLOCK_ID_PBR32 = 0x22,42MSPRO_BLOCK_ID_SPECFILEVALUES1 = 0x25,43MSPRO_BLOCK_ID_SPECFILEVALUES2 = 0x26,44MSPRO_BLOCK_ID_DEVINFO = 0x3045};4647struct mspro_sys_attr {48size_t size;49void *data;50unsigned char id;51char name[32];52struct device_attribute dev_attr;53};5455struct mspro_attr_entry {56__be32 address;57__be32 size;58unsigned char id;59unsigned char reserved[3];60} __attribute__((packed));6162struct mspro_attribute {63__be16 signature;64unsigned short version;65unsigned char count;66unsigned char reserved[11];67struct mspro_attr_entry entries[];68} __attribute__((packed));6970struct mspro_sys_info {71unsigned char class;72unsigned char reserved0;73__be16 block_size;74__be16 block_count;75__be16 user_block_count;76__be16 page_size;77unsigned char reserved1[2];78unsigned char assembly_date[8];79__be32 serial_number;80unsigned char assembly_maker_code;81unsigned char assembly_model_code[3];82__be16 memory_maker_code;83__be16 memory_model_code;84unsigned char reserved2[4];85unsigned char vcc;86unsigned char vpp;87__be16 controller_number;88__be16 controller_function;89__be16 start_sector;90__be16 unit_size;91unsigned char ms_sub_class;92unsigned char reserved3[4];93unsigned char interface_type;94__be16 controller_code;95unsigned char format_type;96unsigned char reserved4;97unsigned char device_type;98unsigned char reserved5[7];99unsigned char mspro_id[16];100unsigned char reserved6[16];101} __attribute__((packed));102103struct mspro_mbr {104unsigned char boot_partition;105unsigned char start_head;106unsigned char start_sector;107unsigned char start_cylinder;108unsigned char partition_type;109unsigned char end_head;110unsigned char end_sector;111unsigned char end_cylinder;112unsigned int start_sectors;113unsigned int sectors_per_partition;114} __attribute__((packed));115116struct mspro_specfile {117char name[8];118char ext[3];119unsigned char attr;120unsigned char reserved[10];121unsigned short time;122unsigned short date;123unsigned short cluster;124unsigned int size;125} __attribute__((packed));126127struct mspro_devinfo {128__be16 cylinders;129__be16 heads;130__be16 bytes_per_track;131__be16 bytes_per_sector;132__be16 sectors_per_track;133unsigned char reserved[6];134} __attribute__((packed));135136struct mspro_block_data {137struct memstick_dev *card;138unsigned int usage_count;139unsigned int caps;140struct gendisk *disk;141struct request_queue *queue;142struct request *block_req;143spinlock_t q_lock;144145unsigned short page_size;146unsigned short cylinders;147unsigned short heads;148unsigned short sectors_per_track;149150unsigned char system;151unsigned char read_only:1,152eject:1,153has_request:1,154data_dir:1,155active:1;156unsigned char transfer_cmd;157158int (*mrq_handler)(struct memstick_dev *card,159struct memstick_request **mrq);160161162/* Default request setup function for data access method preferred by163* this host instance.164*/165void (*setup_transfer)(struct memstick_dev *card,166u64 offset, size_t length);167168struct attribute_group attr_group;169170struct scatterlist req_sg[MSPRO_BLOCK_MAX_SEGS];171unsigned int seg_count;172unsigned int current_seg;173unsigned int current_page;174};175176static DEFINE_IDR(mspro_block_disk_idr);177static DEFINE_MUTEX(mspro_block_disk_lock);178179static int mspro_block_complete_req(struct memstick_dev *card, int error);180181/*** Block device ***/182183static int mspro_block_bd_open(struct block_device *bdev, fmode_t mode)184{185struct gendisk *disk = bdev->bd_disk;186struct mspro_block_data *msb = disk->private_data;187int rc = -ENXIO;188189mutex_lock(&mspro_block_disk_lock);190191if (msb && msb->card) {192msb->usage_count++;193if ((mode & FMODE_WRITE) && msb->read_only)194rc = -EROFS;195else196rc = 0;197}198199mutex_unlock(&mspro_block_disk_lock);200201return rc;202}203204205static int mspro_block_disk_release(struct gendisk *disk)206{207struct mspro_block_data *msb = disk->private_data;208int disk_id = MINOR(disk_devt(disk)) >> MSPRO_BLOCK_PART_SHIFT;209210mutex_lock(&mspro_block_disk_lock);211212if (msb) {213if (msb->usage_count)214msb->usage_count--;215216if (!msb->usage_count) {217kfree(msb);218disk->private_data = NULL;219idr_remove(&mspro_block_disk_idr, disk_id);220put_disk(disk);221}222}223224mutex_unlock(&mspro_block_disk_lock);225226return 0;227}228229static int mspro_block_bd_release(struct gendisk *disk, fmode_t mode)230{231return mspro_block_disk_release(disk);232}233234static int mspro_block_bd_getgeo(struct block_device *bdev,235struct hd_geometry *geo)236{237struct mspro_block_data *msb = bdev->bd_disk->private_data;238239geo->heads = msb->heads;240geo->sectors = msb->sectors_per_track;241geo->cylinders = msb->cylinders;242243return 0;244}245246static const struct block_device_operations ms_block_bdops = {247.open = mspro_block_bd_open,248.release = mspro_block_bd_release,249.getgeo = mspro_block_bd_getgeo,250.owner = THIS_MODULE251};252253/*** Information ***/254255static struct mspro_sys_attr *mspro_from_sysfs_attr(struct attribute *attr)256{257struct device_attribute *dev_attr258= container_of(attr, struct device_attribute, attr);259return container_of(dev_attr, struct mspro_sys_attr, dev_attr);260}261262static const char *mspro_block_attr_name(unsigned char tag)263{264switch (tag) {265case MSPRO_BLOCK_ID_SYSINFO:266return "attr_sysinfo";267case MSPRO_BLOCK_ID_MODELNAME:268return "attr_modelname";269case MSPRO_BLOCK_ID_MBR:270return "attr_mbr";271case MSPRO_BLOCK_ID_PBR16:272return "attr_pbr16";273case MSPRO_BLOCK_ID_PBR32:274return "attr_pbr32";275case MSPRO_BLOCK_ID_SPECFILEVALUES1:276return "attr_specfilevalues1";277case MSPRO_BLOCK_ID_SPECFILEVALUES2:278return "attr_specfilevalues2";279case MSPRO_BLOCK_ID_DEVINFO:280return "attr_devinfo";281default:282return NULL;283};284}285286typedef ssize_t (*sysfs_show_t)(struct device *dev,287struct device_attribute *attr,288char *buffer);289290static ssize_t mspro_block_attr_show_default(struct device *dev,291struct device_attribute *attr,292char *buffer)293{294struct mspro_sys_attr *s_attr = container_of(attr,295struct mspro_sys_attr,296dev_attr);297298ssize_t cnt, rc = 0;299300for (cnt = 0; cnt < s_attr->size; cnt++) {301if (cnt && !(cnt % 16)) {302if (PAGE_SIZE - rc)303buffer[rc++] = '\n';304}305306rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "%02x ",307((unsigned char *)s_attr->data)[cnt]);308}309return rc;310}311312static ssize_t mspro_block_attr_show_sysinfo(struct device *dev,313struct device_attribute *attr,314char *buffer)315{316struct mspro_sys_attr *x_attr = container_of(attr,317struct mspro_sys_attr,318dev_attr);319struct mspro_sys_info *x_sys = x_attr->data;320ssize_t rc = 0;321int date_tz = 0, date_tz_f = 0;322323if (x_sys->assembly_date[0] > 0x80U) {324date_tz = (~x_sys->assembly_date[0]) + 1;325date_tz_f = date_tz & 3;326date_tz >>= 2;327date_tz = -date_tz;328date_tz_f *= 15;329} else if (x_sys->assembly_date[0] < 0x80U) {330date_tz = x_sys->assembly_date[0];331date_tz_f = date_tz & 3;332date_tz >>= 2;333date_tz_f *= 15;334}335336rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "class: %x\n",337x_sys->class);338rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "block size: %x\n",339be16_to_cpu(x_sys->block_size));340rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "block count: %x\n",341be16_to_cpu(x_sys->block_count));342rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "user block count: %x\n",343be16_to_cpu(x_sys->user_block_count));344rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "page size: %x\n",345be16_to_cpu(x_sys->page_size));346rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "assembly date: "347"GMT%+d:%d %04u-%02u-%02u %02u:%02u:%02u\n",348date_tz, date_tz_f,349be16_to_cpup((__be16 *)&x_sys->assembly_date[1]),350x_sys->assembly_date[3], x_sys->assembly_date[4],351x_sys->assembly_date[5], x_sys->assembly_date[6],352x_sys->assembly_date[7]);353rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "serial number: %x\n",354be32_to_cpu(x_sys->serial_number));355rc += scnprintf(buffer + rc, PAGE_SIZE - rc,356"assembly maker code: %x\n",357x_sys->assembly_maker_code);358rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "assembly model code: "359"%02x%02x%02x\n", x_sys->assembly_model_code[0],360x_sys->assembly_model_code[1],361x_sys->assembly_model_code[2]);362rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "memory maker code: %x\n",363be16_to_cpu(x_sys->memory_maker_code));364rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "memory model code: %x\n",365be16_to_cpu(x_sys->memory_model_code));366rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "vcc: %x\n",367x_sys->vcc);368rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "vpp: %x\n",369x_sys->vpp);370rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "controller number: %x\n",371be16_to_cpu(x_sys->controller_number));372rc += scnprintf(buffer + rc, PAGE_SIZE - rc,373"controller function: %x\n",374be16_to_cpu(x_sys->controller_function));375rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "start sector: %x\n",376be16_to_cpu(x_sys->start_sector));377rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "unit size: %x\n",378be16_to_cpu(x_sys->unit_size));379rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "sub class: %x\n",380x_sys->ms_sub_class);381rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "interface type: %x\n",382x_sys->interface_type);383rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "controller code: %x\n",384be16_to_cpu(x_sys->controller_code));385rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "format type: %x\n",386x_sys->format_type);387rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "device type: %x\n",388x_sys->device_type);389rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "mspro id: %s\n",390x_sys->mspro_id);391return rc;392}393394static ssize_t mspro_block_attr_show_modelname(struct device *dev,395struct device_attribute *attr,396char *buffer)397{398struct mspro_sys_attr *s_attr = container_of(attr,399struct mspro_sys_attr,400dev_attr);401402return scnprintf(buffer, PAGE_SIZE, "%s", (char *)s_attr->data);403}404405static ssize_t mspro_block_attr_show_mbr(struct device *dev,406struct device_attribute *attr,407char *buffer)408{409struct mspro_sys_attr *x_attr = container_of(attr,410struct mspro_sys_attr,411dev_attr);412struct mspro_mbr *x_mbr = x_attr->data;413ssize_t rc = 0;414415rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "boot partition: %x\n",416x_mbr->boot_partition);417rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "start head: %x\n",418x_mbr->start_head);419rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "start sector: %x\n",420x_mbr->start_sector);421rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "start cylinder: %x\n",422x_mbr->start_cylinder);423rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "partition type: %x\n",424x_mbr->partition_type);425rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "end head: %x\n",426x_mbr->end_head);427rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "end sector: %x\n",428x_mbr->end_sector);429rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "end cylinder: %x\n",430x_mbr->end_cylinder);431rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "start sectors: %x\n",432x_mbr->start_sectors);433rc += scnprintf(buffer + rc, PAGE_SIZE - rc,434"sectors per partition: %x\n",435x_mbr->sectors_per_partition);436return rc;437}438439static ssize_t mspro_block_attr_show_specfile(struct device *dev,440struct device_attribute *attr,441char *buffer)442{443struct mspro_sys_attr *x_attr = container_of(attr,444struct mspro_sys_attr,445dev_attr);446struct mspro_specfile *x_spfile = x_attr->data;447char name[9], ext[4];448ssize_t rc = 0;449450memcpy(name, x_spfile->name, 8);451name[8] = 0;452memcpy(ext, x_spfile->ext, 3);453ext[3] = 0;454455rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "name: %s\n", name);456rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "ext: %s\n", ext);457rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "attribute: %x\n",458x_spfile->attr);459rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "time: %d:%d:%d\n",460x_spfile->time >> 11,461(x_spfile->time >> 5) & 0x3f,462(x_spfile->time & 0x1f) * 2);463rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "date: %d-%d-%d\n",464(x_spfile->date >> 9) + 1980,465(x_spfile->date >> 5) & 0xf,466x_spfile->date & 0x1f);467rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "start cluster: %x\n",468x_spfile->cluster);469rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "size: %x\n",470x_spfile->size);471return rc;472}473474static ssize_t mspro_block_attr_show_devinfo(struct device *dev,475struct device_attribute *attr,476char *buffer)477{478struct mspro_sys_attr *x_attr = container_of(attr,479struct mspro_sys_attr,480dev_attr);481struct mspro_devinfo *x_devinfo = x_attr->data;482ssize_t rc = 0;483484rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "cylinders: %x\n",485be16_to_cpu(x_devinfo->cylinders));486rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "heads: %x\n",487be16_to_cpu(x_devinfo->heads));488rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "bytes per track: %x\n",489be16_to_cpu(x_devinfo->bytes_per_track));490rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "bytes per sector: %x\n",491be16_to_cpu(x_devinfo->bytes_per_sector));492rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "sectors per track: %x\n",493be16_to_cpu(x_devinfo->sectors_per_track));494return rc;495}496497static sysfs_show_t mspro_block_attr_show(unsigned char tag)498{499switch (tag) {500case MSPRO_BLOCK_ID_SYSINFO:501return mspro_block_attr_show_sysinfo;502case MSPRO_BLOCK_ID_MODELNAME:503return mspro_block_attr_show_modelname;504case MSPRO_BLOCK_ID_MBR:505return mspro_block_attr_show_mbr;506case MSPRO_BLOCK_ID_SPECFILEVALUES1:507case MSPRO_BLOCK_ID_SPECFILEVALUES2:508return mspro_block_attr_show_specfile;509case MSPRO_BLOCK_ID_DEVINFO:510return mspro_block_attr_show_devinfo;511default:512return mspro_block_attr_show_default;513}514}515516/*** Protocol handlers ***/517518/*519* Functions prefixed with "h_" are protocol callbacks. They can be called from520* interrupt context. Return value of 0 means that request processing is still521* ongoing, while special error value of -EAGAIN means that current request is522* finished (and request processor should come back some time later).523*/524525static int h_mspro_block_req_init(struct memstick_dev *card,526struct memstick_request **mrq)527{528struct mspro_block_data *msb = memstick_get_drvdata(card);529530*mrq = &card->current_mrq;531card->next_request = msb->mrq_handler;532return 0;533}534535static int h_mspro_block_default(struct memstick_dev *card,536struct memstick_request **mrq)537{538return mspro_block_complete_req(card, (*mrq)->error);539}540541static int h_mspro_block_default_bad(struct memstick_dev *card,542struct memstick_request **mrq)543{544return -ENXIO;545}546547static int h_mspro_block_get_ro(struct memstick_dev *card,548struct memstick_request **mrq)549{550struct mspro_block_data *msb = memstick_get_drvdata(card);551552if (!(*mrq)->error) {553if ((*mrq)->data[offsetof(struct ms_status_register, status0)]554& MEMSTICK_STATUS0_WP)555msb->read_only = 1;556else557msb->read_only = 0;558}559560return mspro_block_complete_req(card, (*mrq)->error);561}562563static int h_mspro_block_wait_for_ced(struct memstick_dev *card,564struct memstick_request **mrq)565{566dev_dbg(&card->dev, "wait for ced: value %x\n", (*mrq)->data[0]);567568if (!(*mrq)->error) {569if ((*mrq)->data[0] & (MEMSTICK_INT_CMDNAK | MEMSTICK_INT_ERR))570(*mrq)->error = -EFAULT;571else if (!((*mrq)->data[0] & MEMSTICK_INT_CED))572return 0;573}574575return mspro_block_complete_req(card, (*mrq)->error);576}577578static int h_mspro_block_transfer_data(struct memstick_dev *card,579struct memstick_request **mrq)580{581struct mspro_block_data *msb = memstick_get_drvdata(card);582unsigned char t_val = 0;583struct scatterlist t_sg = { 0 };584size_t t_offset;585586if ((*mrq)->error)587return mspro_block_complete_req(card, (*mrq)->error);588589switch ((*mrq)->tpc) {590case MS_TPC_WRITE_REG:591memstick_init_req(*mrq, MS_TPC_SET_CMD, &msb->transfer_cmd, 1);592(*mrq)->need_card_int = 1;593return 0;594case MS_TPC_SET_CMD:595t_val = (*mrq)->int_reg;596memstick_init_req(*mrq, MS_TPC_GET_INT, NULL, 1);597if (msb->caps & MEMSTICK_CAP_AUTO_GET_INT)598goto has_int_reg;599return 0;600case MS_TPC_GET_INT:601t_val = (*mrq)->data[0];602has_int_reg:603if (t_val & (MEMSTICK_INT_CMDNAK | MEMSTICK_INT_ERR)) {604t_val = MSPRO_CMD_STOP;605memstick_init_req(*mrq, MS_TPC_SET_CMD, &t_val, 1);606card->next_request = h_mspro_block_default;607return 0;608}609610if (msb->current_page611== (msb->req_sg[msb->current_seg].length612/ msb->page_size)) {613msb->current_page = 0;614msb->current_seg++;615616if (msb->current_seg == msb->seg_count) {617if (t_val & MEMSTICK_INT_CED) {618return mspro_block_complete_req(card,6190);620} else {621card->next_request622= h_mspro_block_wait_for_ced;623memstick_init_req(*mrq, MS_TPC_GET_INT,624NULL, 1);625return 0;626}627}628}629630if (!(t_val & MEMSTICK_INT_BREQ)) {631memstick_init_req(*mrq, MS_TPC_GET_INT, NULL, 1);632return 0;633}634635t_offset = msb->req_sg[msb->current_seg].offset;636t_offset += msb->current_page * msb->page_size;637638sg_set_page(&t_sg,639nth_page(sg_page(&(msb->req_sg[msb->current_seg])),640t_offset >> PAGE_SHIFT),641msb->page_size, offset_in_page(t_offset));642643memstick_init_req_sg(*mrq, msb->data_dir == READ644? MS_TPC_READ_LONG_DATA645: MS_TPC_WRITE_LONG_DATA,646&t_sg);647(*mrq)->need_card_int = 1;648return 0;649case MS_TPC_READ_LONG_DATA:650case MS_TPC_WRITE_LONG_DATA:651msb->current_page++;652if (msb->caps & MEMSTICK_CAP_AUTO_GET_INT) {653t_val = (*mrq)->int_reg;654goto has_int_reg;655} else {656memstick_init_req(*mrq, MS_TPC_GET_INT, NULL, 1);657return 0;658}659660default:661BUG();662}663}664665/*** Transfer setup functions for different access methods. ***/666667/** Setup data transfer request for SET_CMD TPC with arguments in card668* registers.669*670* @card Current media instance671* @offset Target data offset in bytes672* @length Required transfer length in bytes.673*/674static void h_mspro_block_setup_cmd(struct memstick_dev *card, u64 offset,675size_t length)676{677struct mspro_block_data *msb = memstick_get_drvdata(card);678struct mspro_param_register param = {679.system = msb->system,680.data_count = cpu_to_be16((uint16_t)(length / msb->page_size)),681/* ISO C90 warning precludes direct initialization for now. */682.data_address = 0,683.tpc_param = 0684};685686do_div(offset, msb->page_size);687param.data_address = cpu_to_be32((uint32_t)offset);688689card->next_request = h_mspro_block_req_init;690msb->mrq_handler = h_mspro_block_transfer_data;691memstick_init_req(&card->current_mrq, MS_TPC_WRITE_REG,692¶m, sizeof(param));693}694695/*** Data transfer ***/696697static int mspro_block_issue_req(struct memstick_dev *card, int chunk)698{699struct mspro_block_data *msb = memstick_get_drvdata(card);700u64 t_off;701unsigned int count;702703try_again:704while (chunk) {705msb->current_page = 0;706msb->current_seg = 0;707msb->seg_count = blk_rq_map_sg(msb->block_req->q,708msb->block_req,709msb->req_sg);710711if (!msb->seg_count) {712chunk = __blk_end_request_cur(msb->block_req, -ENOMEM);713continue;714}715716t_off = blk_rq_pos(msb->block_req);717t_off <<= 9;718count = blk_rq_bytes(msb->block_req);719720msb->setup_transfer(card, t_off, count);721722msb->data_dir = rq_data_dir(msb->block_req);723msb->transfer_cmd = msb->data_dir == READ724? MSPRO_CMD_READ_DATA725: MSPRO_CMD_WRITE_DATA;726727memstick_new_req(card->host);728return 0;729}730731dev_dbg(&card->dev, "blk_fetch\n");732msb->block_req = blk_fetch_request(msb->queue);733if (!msb->block_req) {734dev_dbg(&card->dev, "issue end\n");735return -EAGAIN;736}737738dev_dbg(&card->dev, "trying again\n");739chunk = 1;740goto try_again;741}742743static int mspro_block_complete_req(struct memstick_dev *card, int error)744{745struct mspro_block_data *msb = memstick_get_drvdata(card);746int chunk, cnt;747unsigned int t_len = 0;748unsigned long flags;749750spin_lock_irqsave(&msb->q_lock, flags);751dev_dbg(&card->dev, "complete %d, %d\n", msb->has_request ? 1 : 0,752error);753754if (msb->has_request) {755/* Nothing to do - not really an error */756if (error == -EAGAIN)757error = 0;758759if (error || (card->current_mrq.tpc == MSPRO_CMD_STOP)) {760if (msb->data_dir == READ) {761for (cnt = 0; cnt < msb->current_seg; cnt++)762t_len += msb->req_sg[cnt].length763/ msb->page_size;764765if (msb->current_page)766t_len += msb->current_page - 1;767768t_len *= msb->page_size;769}770} else771t_len = blk_rq_bytes(msb->block_req);772773dev_dbg(&card->dev, "transferred %x (%d)\n", t_len, error);774775if (error && !t_len)776t_len = blk_rq_cur_bytes(msb->block_req);777778chunk = __blk_end_request(msb->block_req, error, t_len);779780error = mspro_block_issue_req(card, chunk);781782if (!error)783goto out;784else785msb->has_request = 0;786} else {787if (!error)788error = -EAGAIN;789}790791card->next_request = h_mspro_block_default_bad;792complete_all(&card->mrq_complete);793out:794spin_unlock_irqrestore(&msb->q_lock, flags);795return error;796}797798static void mspro_block_stop(struct memstick_dev *card)799{800struct mspro_block_data *msb = memstick_get_drvdata(card);801int rc = 0;802unsigned long flags;803804while (1) {805spin_lock_irqsave(&msb->q_lock, flags);806if (!msb->has_request) {807blk_stop_queue(msb->queue);808rc = 1;809}810spin_unlock_irqrestore(&msb->q_lock, flags);811812if (rc)813break;814815wait_for_completion(&card->mrq_complete);816}817}818819static void mspro_block_start(struct memstick_dev *card)820{821struct mspro_block_data *msb = memstick_get_drvdata(card);822unsigned long flags;823824spin_lock_irqsave(&msb->q_lock, flags);825blk_start_queue(msb->queue);826spin_unlock_irqrestore(&msb->q_lock, flags);827}828829static int mspro_block_prepare_req(struct request_queue *q, struct request *req)830{831if (req->cmd_type != REQ_TYPE_FS &&832req->cmd_type != REQ_TYPE_BLOCK_PC) {833blk_dump_rq_flags(req, "MSPro unsupported request");834return BLKPREP_KILL;835}836837req->cmd_flags |= REQ_DONTPREP;838839return BLKPREP_OK;840}841842static void mspro_block_submit_req(struct request_queue *q)843{844struct memstick_dev *card = q->queuedata;845struct mspro_block_data *msb = memstick_get_drvdata(card);846struct request *req = NULL;847848if (msb->has_request)849return;850851if (msb->eject) {852while ((req = blk_fetch_request(q)) != NULL)853__blk_end_request_all(req, -ENODEV);854855return;856}857858msb->has_request = 1;859if (mspro_block_issue_req(card, 0))860msb->has_request = 0;861}862863/*** Initialization ***/864865static int mspro_block_wait_for_ced(struct memstick_dev *card)866{867struct mspro_block_data *msb = memstick_get_drvdata(card);868869card->next_request = h_mspro_block_req_init;870msb->mrq_handler = h_mspro_block_wait_for_ced;871memstick_init_req(&card->current_mrq, MS_TPC_GET_INT, NULL, 1);872memstick_new_req(card->host);873wait_for_completion(&card->mrq_complete);874return card->current_mrq.error;875}876877static int mspro_block_set_interface(struct memstick_dev *card,878unsigned char sys_reg)879{880struct memstick_host *host = card->host;881struct mspro_block_data *msb = memstick_get_drvdata(card);882struct mspro_param_register param = {883.system = sys_reg,884.data_count = 0,885.data_address = 0,886.tpc_param = 0887};888889card->next_request = h_mspro_block_req_init;890msb->mrq_handler = h_mspro_block_default;891memstick_init_req(&card->current_mrq, MS_TPC_WRITE_REG, ¶m,892sizeof(param));893memstick_new_req(host);894wait_for_completion(&card->mrq_complete);895return card->current_mrq.error;896}897898static int mspro_block_switch_interface(struct memstick_dev *card)899{900struct memstick_host *host = card->host;901struct mspro_block_data *msb = memstick_get_drvdata(card);902int rc = 0;903904try_again:905if (msb->caps & MEMSTICK_CAP_PAR4)906rc = mspro_block_set_interface(card, MEMSTICK_SYS_PAR4);907else908return 0;909910if (rc) {911printk(KERN_WARNING912"%s: could not switch to 4-bit mode, error %d\n",913dev_name(&card->dev), rc);914return 0;915}916917msb->system = MEMSTICK_SYS_PAR4;918host->set_param(host, MEMSTICK_INTERFACE, MEMSTICK_PAR4);919printk(KERN_INFO "%s: switching to 4-bit parallel mode\n",920dev_name(&card->dev));921922if (msb->caps & MEMSTICK_CAP_PAR8) {923rc = mspro_block_set_interface(card, MEMSTICK_SYS_PAR8);924925if (!rc) {926msb->system = MEMSTICK_SYS_PAR8;927host->set_param(host, MEMSTICK_INTERFACE,928MEMSTICK_PAR8);929printk(KERN_INFO930"%s: switching to 8-bit parallel mode\n",931dev_name(&card->dev));932} else933printk(KERN_WARNING934"%s: could not switch to 8-bit mode, error %d\n",935dev_name(&card->dev), rc);936}937938card->next_request = h_mspro_block_req_init;939msb->mrq_handler = h_mspro_block_default;940memstick_init_req(&card->current_mrq, MS_TPC_GET_INT, NULL, 1);941memstick_new_req(card->host);942wait_for_completion(&card->mrq_complete);943rc = card->current_mrq.error;944945if (rc) {946printk(KERN_WARNING947"%s: interface error, trying to fall back to serial\n",948dev_name(&card->dev));949msb->system = MEMSTICK_SYS_SERIAL;950host->set_param(host, MEMSTICK_POWER, MEMSTICK_POWER_OFF);951msleep(10);952host->set_param(host, MEMSTICK_POWER, MEMSTICK_POWER_ON);953host->set_param(host, MEMSTICK_INTERFACE, MEMSTICK_SERIAL);954955rc = memstick_set_rw_addr(card);956if (!rc)957rc = mspro_block_set_interface(card, msb->system);958959if (!rc) {960msleep(150);961rc = mspro_block_wait_for_ced(card);962if (rc)963return rc;964965if (msb->caps & MEMSTICK_CAP_PAR8) {966msb->caps &= ~MEMSTICK_CAP_PAR8;967goto try_again;968}969}970}971return rc;972}973974/* Memory allocated for attributes by this function should be freed by975* mspro_block_data_clear, no matter if the initialization process succeeded976* or failed.977*/978static int mspro_block_read_attributes(struct memstick_dev *card)979{980struct mspro_block_data *msb = memstick_get_drvdata(card);981struct mspro_attribute *attr = NULL;982struct mspro_sys_attr *s_attr = NULL;983unsigned char *buffer = NULL;984int cnt, rc, attr_count;985/* While normally physical device offsets, represented here by986* attr_offset and attr_len will be of large numeric types, we can be987* sure, that attributes are close enough to the beginning of the988* device, to save ourselves some trouble.989*/990unsigned int addr, attr_offset = 0, attr_len = msb->page_size;991992attr = kmalloc(msb->page_size, GFP_KERNEL);993if (!attr)994return -ENOMEM;995996sg_init_one(&msb->req_sg[0], attr, msb->page_size);997msb->seg_count = 1;998msb->current_seg = 0;999msb->current_page = 0;1000msb->data_dir = READ;1001msb->transfer_cmd = MSPRO_CMD_READ_ATRB;10021003msb->setup_transfer(card, attr_offset, attr_len);10041005memstick_new_req(card->host);1006wait_for_completion(&card->mrq_complete);1007if (card->current_mrq.error) {1008rc = card->current_mrq.error;1009goto out_free_attr;1010}10111012if (be16_to_cpu(attr->signature) != MSPRO_BLOCK_SIGNATURE) {1013printk(KERN_ERR "%s: unrecognized device signature %x\n",1014dev_name(&card->dev), be16_to_cpu(attr->signature));1015rc = -ENODEV;1016goto out_free_attr;1017}10181019if (attr->count > MSPRO_BLOCK_MAX_ATTRIBUTES) {1020printk(KERN_WARNING "%s: way too many attribute entries\n",1021dev_name(&card->dev));1022attr_count = MSPRO_BLOCK_MAX_ATTRIBUTES;1023} else1024attr_count = attr->count;10251026msb->attr_group.attrs = kzalloc((attr_count + 1)1027* sizeof(struct attribute),1028GFP_KERNEL);1029if (!msb->attr_group.attrs) {1030rc = -ENOMEM;1031goto out_free_attr;1032}1033msb->attr_group.name = "media_attributes";10341035buffer = kmalloc(attr_len, GFP_KERNEL);1036if (!buffer) {1037rc = -ENOMEM;1038goto out_free_attr;1039}1040memcpy(buffer, (char *)attr, attr_len);10411042for (cnt = 0; cnt < attr_count; ++cnt) {1043s_attr = kzalloc(sizeof(struct mspro_sys_attr), GFP_KERNEL);1044if (!s_attr) {1045rc = -ENOMEM;1046goto out_free_buffer;1047}10481049msb->attr_group.attrs[cnt] = &s_attr->dev_attr.attr;1050addr = be32_to_cpu(attr->entries[cnt].address);1051s_attr->size = be32_to_cpu(attr->entries[cnt].size);1052dev_dbg(&card->dev, "adding attribute %d: id %x, address %x, "1053"size %zx\n", cnt, attr->entries[cnt].id, addr,1054s_attr->size);1055s_attr->id = attr->entries[cnt].id;1056if (mspro_block_attr_name(s_attr->id))1057snprintf(s_attr->name, sizeof(s_attr->name), "%s",1058mspro_block_attr_name(attr->entries[cnt].id));1059else1060snprintf(s_attr->name, sizeof(s_attr->name),1061"attr_x%02x", attr->entries[cnt].id);10621063sysfs_attr_init(&s_attr->dev_attr.attr);1064s_attr->dev_attr.attr.name = s_attr->name;1065s_attr->dev_attr.attr.mode = S_IRUGO;1066s_attr->dev_attr.show = mspro_block_attr_show(s_attr->id);10671068if (!s_attr->size)1069continue;10701071s_attr->data = kmalloc(s_attr->size, GFP_KERNEL);1072if (!s_attr->data) {1073rc = -ENOMEM;1074goto out_free_buffer;1075}10761077if (((addr / msb->page_size) == (attr_offset / msb->page_size))1078&& (((addr + s_attr->size - 1) / msb->page_size)1079== (attr_offset / msb->page_size))) {1080memcpy(s_attr->data, buffer + addr % msb->page_size,1081s_attr->size);1082continue;1083}10841085attr_offset = (addr / msb->page_size) * msb->page_size;10861087if ((attr_offset + attr_len) < (addr + s_attr->size)) {1088kfree(buffer);1089attr_len = (((addr + s_attr->size) / msb->page_size)1090+ 1 ) * msb->page_size - attr_offset;1091buffer = kmalloc(attr_len, GFP_KERNEL);1092if (!buffer) {1093rc = -ENOMEM;1094goto out_free_attr;1095}1096}10971098sg_init_one(&msb->req_sg[0], buffer, attr_len);1099msb->seg_count = 1;1100msb->current_seg = 0;1101msb->current_page = 0;1102msb->data_dir = READ;1103msb->transfer_cmd = MSPRO_CMD_READ_ATRB;11041105dev_dbg(&card->dev, "reading attribute range %x, %x\n",1106attr_offset, attr_len);11071108msb->setup_transfer(card, attr_offset, attr_len);1109memstick_new_req(card->host);1110wait_for_completion(&card->mrq_complete);1111if (card->current_mrq.error) {1112rc = card->current_mrq.error;1113goto out_free_buffer;1114}11151116memcpy(s_attr->data, buffer + addr % msb->page_size,1117s_attr->size);1118}11191120rc = 0;1121out_free_buffer:1122kfree(buffer);1123out_free_attr:1124kfree(attr);1125return rc;1126}11271128static int mspro_block_init_card(struct memstick_dev *card)1129{1130struct mspro_block_data *msb = memstick_get_drvdata(card);1131struct memstick_host *host = card->host;1132int rc = 0;11331134msb->system = MEMSTICK_SYS_SERIAL;1135msb->setup_transfer = h_mspro_block_setup_cmd;11361137card->reg_addr.r_offset = offsetof(struct mspro_register, status);1138card->reg_addr.r_length = sizeof(struct ms_status_register);1139card->reg_addr.w_offset = offsetof(struct mspro_register, param);1140card->reg_addr.w_length = sizeof(struct mspro_param_register);11411142if (memstick_set_rw_addr(card))1143return -EIO;11441145msb->caps = host->caps;11461147msleep(150);1148rc = mspro_block_wait_for_ced(card);1149if (rc)1150return rc;11511152rc = mspro_block_switch_interface(card);1153if (rc)1154return rc;11551156dev_dbg(&card->dev, "card activated\n");1157if (msb->system != MEMSTICK_SYS_SERIAL)1158msb->caps |= MEMSTICK_CAP_AUTO_GET_INT;11591160card->next_request = h_mspro_block_req_init;1161msb->mrq_handler = h_mspro_block_get_ro;1162memstick_init_req(&card->current_mrq, MS_TPC_READ_REG, NULL,1163sizeof(struct ms_status_register));1164memstick_new_req(card->host);1165wait_for_completion(&card->mrq_complete);1166if (card->current_mrq.error)1167return card->current_mrq.error;11681169dev_dbg(&card->dev, "card r/w status %d\n", msb->read_only ? 0 : 1);11701171msb->page_size = 512;1172rc = mspro_block_read_attributes(card);1173if (rc)1174return rc;11751176dev_dbg(&card->dev, "attributes loaded\n");1177return 0;11781179}11801181static int mspro_block_init_disk(struct memstick_dev *card)1182{1183struct mspro_block_data *msb = memstick_get_drvdata(card);1184struct memstick_host *host = card->host;1185struct mspro_devinfo *dev_info = NULL;1186struct mspro_sys_info *sys_info = NULL;1187struct mspro_sys_attr *s_attr = NULL;1188int rc, disk_id;1189u64 limit = BLK_BOUNCE_HIGH;1190unsigned long capacity;11911192if (host->dev.dma_mask && *(host->dev.dma_mask))1193limit = *(host->dev.dma_mask);11941195for (rc = 0; msb->attr_group.attrs[rc]; ++rc) {1196s_attr = mspro_from_sysfs_attr(msb->attr_group.attrs[rc]);11971198if (s_attr->id == MSPRO_BLOCK_ID_DEVINFO)1199dev_info = s_attr->data;1200else if (s_attr->id == MSPRO_BLOCK_ID_SYSINFO)1201sys_info = s_attr->data;1202}12031204if (!dev_info || !sys_info)1205return -ENODEV;12061207msb->cylinders = be16_to_cpu(dev_info->cylinders);1208msb->heads = be16_to_cpu(dev_info->heads);1209msb->sectors_per_track = be16_to_cpu(dev_info->sectors_per_track);12101211msb->page_size = be16_to_cpu(sys_info->unit_size);12121213mutex_lock(&mspro_block_disk_lock);1214if (!idr_pre_get(&mspro_block_disk_idr, GFP_KERNEL)) {1215mutex_unlock(&mspro_block_disk_lock);1216return -ENOMEM;1217}12181219rc = idr_get_new(&mspro_block_disk_idr, card, &disk_id);1220mutex_unlock(&mspro_block_disk_lock);12211222if (rc)1223return rc;12241225if ((disk_id << MSPRO_BLOCK_PART_SHIFT) > 255) {1226rc = -ENOSPC;1227goto out_release_id;1228}12291230msb->disk = alloc_disk(1 << MSPRO_BLOCK_PART_SHIFT);1231if (!msb->disk) {1232rc = -ENOMEM;1233goto out_release_id;1234}12351236msb->queue = blk_init_queue(mspro_block_submit_req, &msb->q_lock);1237if (!msb->queue) {1238rc = -ENOMEM;1239goto out_put_disk;1240}12411242msb->queue->queuedata = card;1243blk_queue_prep_rq(msb->queue, mspro_block_prepare_req);12441245blk_queue_bounce_limit(msb->queue, limit);1246blk_queue_max_hw_sectors(msb->queue, MSPRO_BLOCK_MAX_PAGES);1247blk_queue_max_segments(msb->queue, MSPRO_BLOCK_MAX_SEGS);1248blk_queue_max_segment_size(msb->queue,1249MSPRO_BLOCK_MAX_PAGES * msb->page_size);12501251msb->disk->major = major;1252msb->disk->first_minor = disk_id << MSPRO_BLOCK_PART_SHIFT;1253msb->disk->fops = &ms_block_bdops;1254msb->usage_count = 1;1255msb->disk->private_data = msb;1256msb->disk->queue = msb->queue;1257msb->disk->driverfs_dev = &card->dev;12581259sprintf(msb->disk->disk_name, "mspblk%d", disk_id);12601261blk_queue_logical_block_size(msb->queue, msb->page_size);12621263capacity = be16_to_cpu(sys_info->user_block_count);1264capacity *= be16_to_cpu(sys_info->block_size);1265capacity *= msb->page_size >> 9;1266set_capacity(msb->disk, capacity);1267dev_dbg(&card->dev, "capacity set %ld\n", capacity);12681269add_disk(msb->disk);1270msb->active = 1;1271return 0;12721273out_put_disk:1274put_disk(msb->disk);1275out_release_id:1276mutex_lock(&mspro_block_disk_lock);1277idr_remove(&mspro_block_disk_idr, disk_id);1278mutex_unlock(&mspro_block_disk_lock);1279return rc;1280}12811282static void mspro_block_data_clear(struct mspro_block_data *msb)1283{1284int cnt;1285struct mspro_sys_attr *s_attr;12861287if (msb->attr_group.attrs) {1288for (cnt = 0; msb->attr_group.attrs[cnt]; ++cnt) {1289s_attr = mspro_from_sysfs_attr(msb->attr_group1290.attrs[cnt]);1291kfree(s_attr->data);1292kfree(s_attr);1293}1294kfree(msb->attr_group.attrs);1295}12961297msb->card = NULL;1298}12991300static int mspro_block_check_card(struct memstick_dev *card)1301{1302struct mspro_block_data *msb = memstick_get_drvdata(card);13031304return (msb->active == 1);1305}13061307static int mspro_block_probe(struct memstick_dev *card)1308{1309struct mspro_block_data *msb;1310int rc = 0;13111312msb = kzalloc(sizeof(struct mspro_block_data), GFP_KERNEL);1313if (!msb)1314return -ENOMEM;1315memstick_set_drvdata(card, msb);1316msb->card = card;1317spin_lock_init(&msb->q_lock);13181319rc = mspro_block_init_card(card);13201321if (rc)1322goto out_free;13231324rc = sysfs_create_group(&card->dev.kobj, &msb->attr_group);1325if (rc)1326goto out_free;13271328rc = mspro_block_init_disk(card);1329if (!rc) {1330card->check = mspro_block_check_card;1331card->stop = mspro_block_stop;1332card->start = mspro_block_start;1333return 0;1334}13351336sysfs_remove_group(&card->dev.kobj, &msb->attr_group);1337out_free:1338memstick_set_drvdata(card, NULL);1339mspro_block_data_clear(msb);1340kfree(msb);1341return rc;1342}13431344static void mspro_block_remove(struct memstick_dev *card)1345{1346struct mspro_block_data *msb = memstick_get_drvdata(card);1347unsigned long flags;13481349spin_lock_irqsave(&msb->q_lock, flags);1350msb->eject = 1;1351blk_start_queue(msb->queue);1352spin_unlock_irqrestore(&msb->q_lock, flags);13531354del_gendisk(msb->disk);1355dev_dbg(&card->dev, "mspro block remove\n");13561357blk_cleanup_queue(msb->queue);1358msb->queue = NULL;13591360sysfs_remove_group(&card->dev.kobj, &msb->attr_group);13611362mutex_lock(&mspro_block_disk_lock);1363mspro_block_data_clear(msb);1364mutex_unlock(&mspro_block_disk_lock);13651366mspro_block_disk_release(msb->disk);1367memstick_set_drvdata(card, NULL);1368}13691370#ifdef CONFIG_PM13711372static int mspro_block_suspend(struct memstick_dev *card, pm_message_t state)1373{1374struct mspro_block_data *msb = memstick_get_drvdata(card);1375unsigned long flags;13761377spin_lock_irqsave(&msb->q_lock, flags);1378blk_stop_queue(msb->queue);1379msb->active = 0;1380spin_unlock_irqrestore(&msb->q_lock, flags);13811382return 0;1383}13841385static int mspro_block_resume(struct memstick_dev *card)1386{1387struct mspro_block_data *msb = memstick_get_drvdata(card);1388unsigned long flags;1389int rc = 0;13901391#ifdef CONFIG_MEMSTICK_UNSAFE_RESUME13921393struct mspro_block_data *new_msb;1394struct memstick_host *host = card->host;1395struct mspro_sys_attr *s_attr, *r_attr;1396unsigned char cnt;13971398mutex_lock(&host->lock);1399new_msb = kzalloc(sizeof(struct mspro_block_data), GFP_KERNEL);1400if (!new_msb) {1401rc = -ENOMEM;1402goto out_unlock;1403}14041405new_msb->card = card;1406memstick_set_drvdata(card, new_msb);1407if (mspro_block_init_card(card))1408goto out_free;14091410for (cnt = 0; new_msb->attr_group.attrs[cnt]1411&& msb->attr_group.attrs[cnt]; ++cnt) {1412s_attr = mspro_from_sysfs_attr(new_msb->attr_group.attrs[cnt]);1413r_attr = mspro_from_sysfs_attr(msb->attr_group.attrs[cnt]);14141415if (s_attr->id == MSPRO_BLOCK_ID_SYSINFO1416&& r_attr->id == s_attr->id) {1417if (memcmp(s_attr->data, r_attr->data, s_attr->size))1418break;14191420msb->active = 1;1421break;1422}1423}14241425out_free:1426memstick_set_drvdata(card, msb);1427mspro_block_data_clear(new_msb);1428kfree(new_msb);1429out_unlock:1430mutex_unlock(&host->lock);14311432#endif /* CONFIG_MEMSTICK_UNSAFE_RESUME */14331434spin_lock_irqsave(&msb->q_lock, flags);1435blk_start_queue(msb->queue);1436spin_unlock_irqrestore(&msb->q_lock, flags);1437return rc;1438}14391440#else14411442#define mspro_block_suspend NULL1443#define mspro_block_resume NULL14441445#endif /* CONFIG_PM */14461447static struct memstick_device_id mspro_block_id_tbl[] = {1448{MEMSTICK_MATCH_ALL, MEMSTICK_TYPE_PRO, MEMSTICK_CATEGORY_STORAGE_DUO,1449MEMSTICK_CLASS_DUO},1450{}1451};145214531454static struct memstick_driver mspro_block_driver = {1455.driver = {1456.name = DRIVER_NAME,1457.owner = THIS_MODULE1458},1459.id_table = mspro_block_id_tbl,1460.probe = mspro_block_probe,1461.remove = mspro_block_remove,1462.suspend = mspro_block_suspend,1463.resume = mspro_block_resume1464};14651466static int __init mspro_block_init(void)1467{1468int rc = -ENOMEM;14691470rc = register_blkdev(major, DRIVER_NAME);1471if (rc < 0) {1472printk(KERN_ERR DRIVER_NAME ": failed to register "1473"major %d, error %d\n", major, rc);1474return rc;1475}1476if (!major)1477major = rc;14781479rc = memstick_register_driver(&mspro_block_driver);1480if (rc)1481unregister_blkdev(major, DRIVER_NAME);1482return rc;1483}14841485static void __exit mspro_block_exit(void)1486{1487memstick_unregister_driver(&mspro_block_driver);1488unregister_blkdev(major, DRIVER_NAME);1489idr_destroy(&mspro_block_disk_idr);1490}14911492module_init(mspro_block_init);1493module_exit(mspro_block_exit);14941495MODULE_LICENSE("GPL");1496MODULE_AUTHOR("Alex Dubov");1497MODULE_DESCRIPTION("Sony MemoryStickPro block device driver");1498MODULE_DEVICE_TABLE(memstick, mspro_block_id_tbl);149915001501