mspro_block.c revision 8a78362c4eefc1deddbefe2c7f38aabbc2429d6b
1baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov/* 2baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov * Sony MemoryStick Pro storage support 3baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov * 4baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov * Copyright (C) 2007 Alex Dubov <oakad@yahoo.com> 5baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov * 6baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov * This program is free software; you can redistribute it and/or modify 7baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov * it under the terms of the GNU General Public License version 2 as 8baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov * published by the Free Software Foundation. 9baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov * 10baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov * Special thanks to Carlos Corbacho for providing various MemoryStick cards 11baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov * that made this driver possible. 12baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov * 13baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov */ 14baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 15baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov#include <linux/blkdev.h> 16baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov#include <linux/idr.h> 17baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov#include <linux/hdreg.h> 18baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov#include <linux/kthread.h> 19593672582e71a688cf8c3fc1c59ec7c44d3799e5Alex Dubov#include <linux/delay.h> 20baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov#include <linux/memstick.h> 21baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 22baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov#define DRIVER_NAME "mspro_block" 23baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 24baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstatic int major; 25baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovmodule_param(major, int, 0644); 26baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 27baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov#define MSPRO_BLOCK_MAX_SEGS 32 28baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov#define MSPRO_BLOCK_MAX_PAGES ((2 << 16) - 1) 29baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 30baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov#define MSPRO_BLOCK_SIGNATURE 0xa5c3 31baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov#define MSPRO_BLOCK_MAX_ATTRIBUTES 41 32baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 338e82f8c34b1759ae0d80fe96101746ec51fb1ba4Alex Dubov#define MSPRO_BLOCK_PART_SHIFT 3 348e82f8c34b1759ae0d80fe96101746ec51fb1ba4Alex Dubov 35baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovenum { 36baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov MSPRO_BLOCK_ID_SYSINFO = 0x10, 37baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov MSPRO_BLOCK_ID_MODELNAME = 0x15, 38baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov MSPRO_BLOCK_ID_MBR = 0x20, 39baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov MSPRO_BLOCK_ID_PBR16 = 0x21, 40baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov MSPRO_BLOCK_ID_PBR32 = 0x22, 41baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov MSPRO_BLOCK_ID_SPECFILEVALUES1 = 0x25, 42baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov MSPRO_BLOCK_ID_SPECFILEVALUES2 = 0x26, 43baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov MSPRO_BLOCK_ID_DEVINFO = 0x30 44baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov}; 45baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 46baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstruct mspro_sys_attr { 47baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov size_t size; 48baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov void *data; 49baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char id; 50baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov char name[32]; 51baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct device_attribute dev_attr; 52baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov}; 53baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 54baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstruct mspro_attr_entry { 5569347a236b22c3962ea812511495e502dedfd50cHarvey Harrison __be32 address; 5669347a236b22c3962ea812511495e502dedfd50cHarvey Harrison __be32 size; 57baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char id; 58baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char reserved[3]; 59baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} __attribute__((packed)); 60baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 61baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstruct mspro_attribute { 6269347a236b22c3962ea812511495e502dedfd50cHarvey Harrison __be16 signature; 63baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned short version; 64baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char count; 65baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char reserved[11]; 66baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_attr_entry entries[]; 67baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} __attribute__((packed)); 68baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 69baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstruct mspro_sys_info { 70baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char class; 71baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char reserved0; 7269347a236b22c3962ea812511495e502dedfd50cHarvey Harrison __be16 block_size; 7369347a236b22c3962ea812511495e502dedfd50cHarvey Harrison __be16 block_count; 7469347a236b22c3962ea812511495e502dedfd50cHarvey Harrison __be16 user_block_count; 7569347a236b22c3962ea812511495e502dedfd50cHarvey Harrison __be16 page_size; 76baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char reserved1[2]; 77baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char assembly_date[8]; 7869347a236b22c3962ea812511495e502dedfd50cHarvey Harrison __be32 serial_number; 79baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char assembly_maker_code; 80baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char assembly_model_code[3]; 8169347a236b22c3962ea812511495e502dedfd50cHarvey Harrison __be16 memory_maker_code; 8269347a236b22c3962ea812511495e502dedfd50cHarvey Harrison __be16 memory_model_code; 83baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char reserved2[4]; 84baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char vcc; 85baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char vpp; 8669347a236b22c3962ea812511495e502dedfd50cHarvey Harrison __be16 controller_number; 8769347a236b22c3962ea812511495e502dedfd50cHarvey Harrison __be16 controller_function; 8869347a236b22c3962ea812511495e502dedfd50cHarvey Harrison __be16 start_sector; 8969347a236b22c3962ea812511495e502dedfd50cHarvey Harrison __be16 unit_size; 90baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char ms_sub_class; 91baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char reserved3[4]; 92baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char interface_type; 9369347a236b22c3962ea812511495e502dedfd50cHarvey Harrison __be16 controller_code; 94baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char format_type; 95baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char reserved4; 96baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char device_type; 97baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char reserved5[7]; 98baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char mspro_id[16]; 99baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char reserved6[16]; 100baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} __attribute__((packed)); 101baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 102baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstruct mspro_mbr { 103baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char boot_partition; 104baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char start_head; 105baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char start_sector; 106baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char start_cylinder; 107baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char partition_type; 108baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char end_head; 109baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char end_sector; 110baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char end_cylinder; 111baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned int start_sectors; 112baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned int sectors_per_partition; 113baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} __attribute__((packed)); 114baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 115efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubovstruct mspro_specfile { 116efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov char name[8]; 117efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov char ext[3]; 118efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov unsigned char attr; 119efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov unsigned char reserved[10]; 120efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov unsigned short time; 121efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov unsigned short date; 122efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov unsigned short cluster; 123efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov unsigned int size; 124efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov} __attribute__((packed)); 125efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov 126baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstruct mspro_devinfo { 12769347a236b22c3962ea812511495e502dedfd50cHarvey Harrison __be16 cylinders; 12869347a236b22c3962ea812511495e502dedfd50cHarvey Harrison __be16 heads; 12969347a236b22c3962ea812511495e502dedfd50cHarvey Harrison __be16 bytes_per_track; 13069347a236b22c3962ea812511495e502dedfd50cHarvey Harrison __be16 bytes_per_sector; 13169347a236b22c3962ea812511495e502dedfd50cHarvey Harrison __be16 sectors_per_track; 132baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char reserved[6]; 133baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} __attribute__((packed)); 134baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 135baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstruct mspro_block_data { 136baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct memstick_dev *card; 137baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned int usage_count; 138ead70773608a5d97f81cb492f117d20b5e9f323eAlex Dubov unsigned int caps; 139baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct gendisk *disk; 140baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct request_queue *queue; 141f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov struct request *block_req; 142baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov spinlock_t q_lock; 143baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 144baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned short page_size; 145baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned short cylinders; 146baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned short heads; 147baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned short sectors_per_track; 148baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 149baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char system; 150baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char read_only:1, 151f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov eject:1, 152baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov has_request:1, 153f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov data_dir:1, 154f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov active:1; 155baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char transfer_cmd; 156baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 157baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov int (*mrq_handler)(struct memstick_dev *card, 158baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct memstick_request **mrq); 159baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 160baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct attribute_group attr_group; 161baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 162baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct scatterlist req_sg[MSPRO_BLOCK_MAX_SEGS]; 163baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned int seg_count; 164baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned int current_seg; 165f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov unsigned int current_page; 166baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov}; 167baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 168baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstatic DEFINE_IDR(mspro_block_disk_idr); 169baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstatic DEFINE_MUTEX(mspro_block_disk_lock); 170baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 171f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubovstatic int mspro_block_complete_req(struct memstick_dev *card, int error); 172f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov 173baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov/*** Block device ***/ 174baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1755d9a54b66584bdae90e88198ce763702545a68e7Al Virostatic int mspro_block_bd_open(struct block_device *bdev, fmode_t mode) 176baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 1775d9a54b66584bdae90e88198ce763702545a68e7Al Viro struct gendisk *disk = bdev->bd_disk; 178baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_block_data *msb = disk->private_data; 179baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov int rc = -ENXIO; 180baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 181baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov mutex_lock(&mspro_block_disk_lock); 182baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 183baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (msb && msb->card) { 184baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->usage_count++; 1855d9a54b66584bdae90e88198ce763702545a68e7Al Viro if ((mode & FMODE_WRITE) && msb->read_only) 186baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc = -EROFS; 187baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov else 188baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc = 0; 189baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 190baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 191baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov mutex_unlock(&mspro_block_disk_lock); 192baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 193baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return rc; 194baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 195baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 196baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 197baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstatic int mspro_block_disk_release(struct gendisk *disk) 198baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 199baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_block_data *msb = disk->private_data; 200f331c0296f2a9fee0d396a70598b954062603015Tejun Heo int disk_id = MINOR(disk_devt(disk)) >> MSPRO_BLOCK_PART_SHIFT; 201baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 202baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov mutex_lock(&mspro_block_disk_lock); 203baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 204f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov if (msb) { 205f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov if (msb->usage_count) 206f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov msb->usage_count--; 207f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov 208baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (!msb->usage_count) { 209baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov kfree(msb); 210baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov disk->private_data = NULL; 211baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov idr_remove(&mspro_block_disk_idr, disk_id); 212baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov put_disk(disk); 213baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 214baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 215baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 216baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov mutex_unlock(&mspro_block_disk_lock); 217baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 218baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return 0; 219baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 220baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 2215d9a54b66584bdae90e88198ce763702545a68e7Al Virostatic int mspro_block_bd_release(struct gendisk *disk, fmode_t mode) 222baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 223baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return mspro_block_disk_release(disk); 224baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 225baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 226baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstatic int mspro_block_bd_getgeo(struct block_device *bdev, 227baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct hd_geometry *geo) 228baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 229baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_block_data *msb = bdev->bd_disk->private_data; 230baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 231baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov geo->heads = msb->heads; 232baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov geo->sectors = msb->sectors_per_track; 233baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov geo->cylinders = msb->cylinders; 234baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 235baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return 0; 236baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 237baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 23883d5cde47dedf01b6a4a4331882cbc0a7eea3c2eAlexey Dobriyanstatic const struct block_device_operations ms_block_bdops = { 2395d9a54b66584bdae90e88198ce763702545a68e7Al Viro .open = mspro_block_bd_open, 2405d9a54b66584bdae90e88198ce763702545a68e7Al Viro .release = mspro_block_bd_release, 241baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov .getgeo = mspro_block_bd_getgeo, 242baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov .owner = THIS_MODULE 243baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov}; 244baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 245baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov/*** Information ***/ 246baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 247baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstatic struct mspro_sys_attr *mspro_from_sysfs_attr(struct attribute *attr) 248baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 249baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct device_attribute *dev_attr 250baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov = container_of(attr, struct device_attribute, attr); 251baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return container_of(dev_attr, struct mspro_sys_attr, dev_attr); 252baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 253baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 254baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstatic const char *mspro_block_attr_name(unsigned char tag) 255baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 256baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov switch (tag) { 257baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov case MSPRO_BLOCK_ID_SYSINFO: 258baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return "attr_sysinfo"; 259baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov case MSPRO_BLOCK_ID_MODELNAME: 260baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return "attr_modelname"; 261baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov case MSPRO_BLOCK_ID_MBR: 262baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return "attr_mbr"; 263baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov case MSPRO_BLOCK_ID_PBR16: 264baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return "attr_pbr16"; 265baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov case MSPRO_BLOCK_ID_PBR32: 266baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return "attr_pbr32"; 267baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov case MSPRO_BLOCK_ID_SPECFILEVALUES1: 268baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return "attr_specfilevalues1"; 269baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov case MSPRO_BLOCK_ID_SPECFILEVALUES2: 270baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return "attr_specfilevalues2"; 271baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov case MSPRO_BLOCK_ID_DEVINFO: 272baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return "attr_devinfo"; 273baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov default: 274baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return NULL; 275baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov }; 276baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 277baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 278baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovtypedef ssize_t (*sysfs_show_t)(struct device *dev, 279baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct device_attribute *attr, 280baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov char *buffer); 281baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 282baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstatic ssize_t mspro_block_attr_show_default(struct device *dev, 283baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct device_attribute *attr, 284baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov char *buffer) 285baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 286baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_sys_attr *s_attr = container_of(attr, 287baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_sys_attr, 288baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov dev_attr); 289baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 290baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov ssize_t cnt, rc = 0; 291baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 292baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov for (cnt = 0; cnt < s_attr->size; cnt++) { 293baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (cnt && !(cnt % 16)) { 294baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (PAGE_SIZE - rc) 295baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov buffer[rc++] = '\n'; 296baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 297baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 298baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "%02x ", 299baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov ((unsigned char *)s_attr->data)[cnt]); 300baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 301baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return rc; 302baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 303baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 304baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstatic ssize_t mspro_block_attr_show_sysinfo(struct device *dev, 305baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct device_attribute *attr, 306baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov char *buffer) 307baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 308baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_sys_attr *x_attr = container_of(attr, 309baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_sys_attr, 310baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov dev_attr); 311baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_sys_info *x_sys = x_attr->data; 312baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov ssize_t rc = 0; 313251cc9b9df065cb2c170ea45f566c0d9456186c2Alex Dubov int date_tz = 0, date_tz_f = 0; 314251cc9b9df065cb2c170ea45f566c0d9456186c2Alex Dubov 315251cc9b9df065cb2c170ea45f566c0d9456186c2Alex Dubov if (x_sys->assembly_date[0] > 0x80U) { 316251cc9b9df065cb2c170ea45f566c0d9456186c2Alex Dubov date_tz = (~x_sys->assembly_date[0]) + 1; 317251cc9b9df065cb2c170ea45f566c0d9456186c2Alex Dubov date_tz_f = date_tz & 3; 318251cc9b9df065cb2c170ea45f566c0d9456186c2Alex Dubov date_tz >>= 2; 319251cc9b9df065cb2c170ea45f566c0d9456186c2Alex Dubov date_tz = -date_tz; 320251cc9b9df065cb2c170ea45f566c0d9456186c2Alex Dubov date_tz_f *= 15; 321251cc9b9df065cb2c170ea45f566c0d9456186c2Alex Dubov } else if (x_sys->assembly_date[0] < 0x80U) { 322251cc9b9df065cb2c170ea45f566c0d9456186c2Alex Dubov date_tz = x_sys->assembly_date[0]; 323251cc9b9df065cb2c170ea45f566c0d9456186c2Alex Dubov date_tz_f = date_tz & 3; 324251cc9b9df065cb2c170ea45f566c0d9456186c2Alex Dubov date_tz >>= 2; 325251cc9b9df065cb2c170ea45f566c0d9456186c2Alex Dubov date_tz_f *= 15; 326251cc9b9df065cb2c170ea45f566c0d9456186c2Alex Dubov } 327baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 328baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "class: %x\n", 329baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov x_sys->class); 330baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "block size: %x\n", 331baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov be16_to_cpu(x_sys->block_size)); 332baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "block count: %x\n", 333baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov be16_to_cpu(x_sys->block_count)); 334baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "user block count: %x\n", 335baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov be16_to_cpu(x_sys->user_block_count)); 336baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "page size: %x\n", 337baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov be16_to_cpu(x_sys->page_size)); 338baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "assembly date: " 339251cc9b9df065cb2c170ea45f566c0d9456186c2Alex Dubov "GMT%+d:%d %04u-%02u-%02u %02u:%02u:%02u\n", 340251cc9b9df065cb2c170ea45f566c0d9456186c2Alex Dubov date_tz, date_tz_f, 34169347a236b22c3962ea812511495e502dedfd50cHarvey Harrison be16_to_cpup((__be16 *)&x_sys->assembly_date[1]), 342baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov x_sys->assembly_date[3], x_sys->assembly_date[4], 343baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov x_sys->assembly_date[5], x_sys->assembly_date[6], 344baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov x_sys->assembly_date[7]); 345baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "serial number: %x\n", 346baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov be32_to_cpu(x_sys->serial_number)); 347baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, 348baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov "assembly maker code: %x\n", 349baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov x_sys->assembly_maker_code); 350baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "assembly model code: " 351baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov "%02x%02x%02x\n", x_sys->assembly_model_code[0], 352baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov x_sys->assembly_model_code[1], 353baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov x_sys->assembly_model_code[2]); 354baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "memory maker code: %x\n", 355baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov be16_to_cpu(x_sys->memory_maker_code)); 356baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "memory model code: %x\n", 357baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov be16_to_cpu(x_sys->memory_model_code)); 358baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "vcc: %x\n", 359baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov x_sys->vcc); 360baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "vpp: %x\n", 361baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov x_sys->vpp); 362baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "controller number: %x\n", 363baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov be16_to_cpu(x_sys->controller_number)); 364baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, 365baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov "controller function: %x\n", 366baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov be16_to_cpu(x_sys->controller_function)); 367baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "start sector: %x\n", 368baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov be16_to_cpu(x_sys->start_sector)); 369baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "unit size: %x\n", 370baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov be16_to_cpu(x_sys->unit_size)); 371baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "sub class: %x\n", 372baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov x_sys->ms_sub_class); 373baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "interface type: %x\n", 374baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov x_sys->interface_type); 375baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "controller code: %x\n", 376baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov be16_to_cpu(x_sys->controller_code)); 377baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "format type: %x\n", 378baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov x_sys->format_type); 379baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "device type: %x\n", 380baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov x_sys->device_type); 381baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "mspro id: %s\n", 382baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov x_sys->mspro_id); 383baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return rc; 384baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 385baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 386baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstatic ssize_t mspro_block_attr_show_modelname(struct device *dev, 387baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct device_attribute *attr, 388baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov char *buffer) 389baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 390baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_sys_attr *s_attr = container_of(attr, 391baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_sys_attr, 392baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov dev_attr); 393baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 394baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return scnprintf(buffer, PAGE_SIZE, "%s", (char *)s_attr->data); 395baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 396baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 397baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstatic ssize_t mspro_block_attr_show_mbr(struct device *dev, 398baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct device_attribute *attr, 399baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov char *buffer) 400baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 401baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_sys_attr *x_attr = container_of(attr, 402baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_sys_attr, 403baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov dev_attr); 404baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_mbr *x_mbr = x_attr->data; 405baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov ssize_t rc = 0; 406baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 407baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "boot partition: %x\n", 408baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov x_mbr->boot_partition); 409baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "start head: %x\n", 410baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov x_mbr->start_head); 411baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "start sector: %x\n", 412baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov x_mbr->start_sector); 413baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "start cylinder: %x\n", 414baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov x_mbr->start_cylinder); 415baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "partition type: %x\n", 416baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov x_mbr->partition_type); 417baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "end head: %x\n", 418baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov x_mbr->end_head); 419baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "end sector: %x\n", 420baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov x_mbr->end_sector); 421baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "end cylinder: %x\n", 422baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov x_mbr->end_cylinder); 423baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "start sectors: %x\n", 424baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov x_mbr->start_sectors); 425baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, 426baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov "sectors per partition: %x\n", 427baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov x_mbr->sectors_per_partition); 428baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return rc; 429baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 430baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 431efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubovstatic ssize_t mspro_block_attr_show_specfile(struct device *dev, 432efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov struct device_attribute *attr, 433efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov char *buffer) 434efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov{ 435efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov struct mspro_sys_attr *x_attr = container_of(attr, 436efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov struct mspro_sys_attr, 437efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov dev_attr); 438efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov struct mspro_specfile *x_spfile = x_attr->data; 439efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov char name[9], ext[4]; 440efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov ssize_t rc = 0; 441efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov 442efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov memcpy(name, x_spfile->name, 8); 443efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov name[8] = 0; 444efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov memcpy(ext, x_spfile->ext, 3); 445efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov ext[3] = 0; 446efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov 447efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "name: %s\n", name); 448efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "ext: %s\n", ext); 449efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "attribute: %x\n", 450efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov x_spfile->attr); 451efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "time: %d:%d:%d\n", 452efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov x_spfile->time >> 11, 453efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov (x_spfile->time >> 5) & 0x3f, 454efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov (x_spfile->time & 0x1f) * 2); 455efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "date: %d-%d-%d\n", 456efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov (x_spfile->date >> 9) + 1980, 457efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov (x_spfile->date >> 5) & 0xf, 458efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov x_spfile->date & 0x1f); 459efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "start cluster: %x\n", 460efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov x_spfile->cluster); 461efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "size: %x\n", 462efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov x_spfile->size); 463efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov return rc; 464efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov} 465efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov 466baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstatic ssize_t mspro_block_attr_show_devinfo(struct device *dev, 467baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct device_attribute *attr, 468baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov char *buffer) 469baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 470baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_sys_attr *x_attr = container_of(attr, 471baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_sys_attr, 472baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov dev_attr); 473baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_devinfo *x_devinfo = x_attr->data; 474baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov ssize_t rc = 0; 475baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 476baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "cylinders: %x\n", 477baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov be16_to_cpu(x_devinfo->cylinders)); 478baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "heads: %x\n", 479baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov be16_to_cpu(x_devinfo->heads)); 480baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "bytes per track: %x\n", 481baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov be16_to_cpu(x_devinfo->bytes_per_track)); 482baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "bytes per sector: %x\n", 483baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov be16_to_cpu(x_devinfo->bytes_per_sector)); 484baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "sectors per track: %x\n", 485baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov be16_to_cpu(x_devinfo->sectors_per_track)); 486baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return rc; 487baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 488baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 489baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstatic sysfs_show_t mspro_block_attr_show(unsigned char tag) 490baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 491baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov switch (tag) { 492baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov case MSPRO_BLOCK_ID_SYSINFO: 493baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return mspro_block_attr_show_sysinfo; 494baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov case MSPRO_BLOCK_ID_MODELNAME: 495baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return mspro_block_attr_show_modelname; 496baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov case MSPRO_BLOCK_ID_MBR: 497baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return mspro_block_attr_show_mbr; 498efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov case MSPRO_BLOCK_ID_SPECFILEVALUES1: 499efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov case MSPRO_BLOCK_ID_SPECFILEVALUES2: 500efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov return mspro_block_attr_show_specfile; 501baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov case MSPRO_BLOCK_ID_DEVINFO: 502baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return mspro_block_attr_show_devinfo; 503baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov default: 504baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return mspro_block_attr_show_default; 505baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 506baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 507baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 508baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov/*** Protocol handlers ***/ 509baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 510baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov/* 511baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov * Functions prefixed with "h_" are protocol callbacks. They can be called from 512baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov * interrupt context. Return value of 0 means that request processing is still 513baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov * ongoing, while special error value of -EAGAIN means that current request is 514baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov * finished (and request processor should come back some time later). 515baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov */ 516baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 517baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstatic int h_mspro_block_req_init(struct memstick_dev *card, 518baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct memstick_request **mrq) 519baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 520baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_block_data *msb = memstick_get_drvdata(card); 521baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 522baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov *mrq = &card->current_mrq; 523baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov card->next_request = msb->mrq_handler; 524baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return 0; 525baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 526baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 527baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstatic int h_mspro_block_default(struct memstick_dev *card, 528baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct memstick_request **mrq) 529baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 530f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov return mspro_block_complete_req(card, (*mrq)->error); 531f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov} 532f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov 533f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubovstatic int h_mspro_block_default_bad(struct memstick_dev *card, 534f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov struct memstick_request **mrq) 535f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov{ 536f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov return -ENXIO; 537baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 538baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 539baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstatic int h_mspro_block_get_ro(struct memstick_dev *card, 540baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct memstick_request **mrq) 541baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 542baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_block_data *msb = memstick_get_drvdata(card); 543baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 544f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov if (!(*mrq)->error) { 545f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov if ((*mrq)->data[offsetof(struct ms_status_register, status0)] 546f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov & MEMSTICK_STATUS0_WP) 547f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov msb->read_only = 1; 548f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov else 549f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov msb->read_only = 0; 550baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 551baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 552f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov return mspro_block_complete_req(card, (*mrq)->error); 553baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 554baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 555baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstatic int h_mspro_block_wait_for_ced(struct memstick_dev *card, 556baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct memstick_request **mrq) 557baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 558baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov dev_dbg(&card->dev, "wait for ced: value %x\n", (*mrq)->data[0]); 559baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 560f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov if (!(*mrq)->error) { 561f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov if ((*mrq)->data[0] & (MEMSTICK_INT_CMDNAK | MEMSTICK_INT_ERR)) 562f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov (*mrq)->error = -EFAULT; 563f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov else if (!((*mrq)->data[0] & MEMSTICK_INT_CED)) 564f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov return 0; 565baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 566baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 567f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov return mspro_block_complete_req(card, (*mrq)->error); 568baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 569baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 570baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstatic int h_mspro_block_transfer_data(struct memstick_dev *card, 571baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct memstick_request **mrq) 572baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 573baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_block_data *msb = memstick_get_drvdata(card); 574baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char t_val = 0; 575baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct scatterlist t_sg = { 0 }; 576baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov size_t t_offset; 577baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 578f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov if ((*mrq)->error) 579f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov return mspro_block_complete_req(card, (*mrq)->error); 580baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 581baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov switch ((*mrq)->tpc) { 582baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov case MS_TPC_WRITE_REG: 583baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov memstick_init_req(*mrq, MS_TPC_SET_CMD, &msb->transfer_cmd, 1); 584ead70773608a5d97f81cb492f117d20b5e9f323eAlex Dubov (*mrq)->need_card_int = 1; 585baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return 0; 586baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov case MS_TPC_SET_CMD: 587baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov t_val = (*mrq)->int_reg; 588baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov memstick_init_req(*mrq, MS_TPC_GET_INT, NULL, 1); 589ead70773608a5d97f81cb492f117d20b5e9f323eAlex Dubov if (msb->caps & MEMSTICK_CAP_AUTO_GET_INT) 590baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov goto has_int_reg; 591baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return 0; 592baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov case MS_TPC_GET_INT: 593baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov t_val = (*mrq)->data[0]; 594baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovhas_int_reg: 595baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (t_val & (MEMSTICK_INT_CMDNAK | MEMSTICK_INT_ERR)) { 596baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov t_val = MSPRO_CMD_STOP; 597baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov memstick_init_req(*mrq, MS_TPC_SET_CMD, &t_val, 1); 598baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov card->next_request = h_mspro_block_default; 599baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return 0; 600baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 601baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 602baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (msb->current_page 603baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov == (msb->req_sg[msb->current_seg].length 604baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov / msb->page_size)) { 605baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->current_page = 0; 606baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->current_seg++; 607baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 608baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (msb->current_seg == msb->seg_count) { 609baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (t_val & MEMSTICK_INT_CED) { 610f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov return mspro_block_complete_req(card, 611f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov 0); 612baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } else { 613baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov card->next_request 614baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov = h_mspro_block_wait_for_ced; 615baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov memstick_init_req(*mrq, MS_TPC_GET_INT, 616baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov NULL, 1); 617baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return 0; 618baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 619baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 620baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 621baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 622baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (!(t_val & MEMSTICK_INT_BREQ)) { 623baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov memstick_init_req(*mrq, MS_TPC_GET_INT, NULL, 1); 624baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return 0; 625baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 626baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 627baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov t_offset = msb->req_sg[msb->current_seg].offset; 628baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov t_offset += msb->current_page * msb->page_size; 629baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 630baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov sg_set_page(&t_sg, 631baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov nth_page(sg_page(&(msb->req_sg[msb->current_seg])), 632baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov t_offset >> PAGE_SHIFT), 633baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->page_size, offset_in_page(t_offset)); 634baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 635baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov memstick_init_req_sg(*mrq, msb->data_dir == READ 636baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov ? MS_TPC_READ_LONG_DATA 637baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov : MS_TPC_WRITE_LONG_DATA, 638baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov &t_sg); 639ead70773608a5d97f81cb492f117d20b5e9f323eAlex Dubov (*mrq)->need_card_int = 1; 640baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return 0; 641baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov case MS_TPC_READ_LONG_DATA: 642baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov case MS_TPC_WRITE_LONG_DATA: 643baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->current_page++; 644ead70773608a5d97f81cb492f117d20b5e9f323eAlex Dubov if (msb->caps & MEMSTICK_CAP_AUTO_GET_INT) { 645baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov t_val = (*mrq)->int_reg; 646baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov goto has_int_reg; 647baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } else { 648baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov memstick_init_req(*mrq, MS_TPC_GET_INT, NULL, 1); 649baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return 0; 650baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 651baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 652baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov default: 653baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov BUG(); 654baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 655baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 656baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 657baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov/*** Data transfer ***/ 658baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 659f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubovstatic int mspro_block_issue_req(struct memstick_dev *card, int chunk) 660baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 661baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_block_data *msb = memstick_get_drvdata(card); 662baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov sector_t t_sec; 663f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov unsigned int count; 664f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov struct mspro_param_register param; 665baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 666f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubovtry_again: 667f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov while (chunk) { 668f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov msb->current_page = 0; 669baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->current_seg = 0; 670f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov msb->seg_count = blk_rq_map_sg(msb->block_req->q, 671f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov msb->block_req, 672f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov msb->req_sg); 673baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 674f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov if (!msb->seg_count) { 675296b2f6ae654581adc27f0d6f0af454c7f3d06eeTejun Heo chunk = __blk_end_request_cur(msb->block_req, -ENOMEM); 676f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov continue; 677f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov } 678baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 67983096ebf1263b2c1ee5e653ba37d993d02e3eb7bTejun Heo t_sec = blk_rq_pos(msb->block_req) << 9; 680f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov sector_div(t_sec, msb->page_size); 681baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 6821011c1b9f2e45ce7c6e38888d2b83936aec38771Tejun Heo count = blk_rq_bytes(msb->block_req); 683f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov count /= msb->page_size; 684baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 685f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov param.system = msb->system; 686f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov param.data_count = cpu_to_be16(count); 687f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov param.data_address = cpu_to_be32((uint32_t)t_sec); 688f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov param.tpc_param = 0; 689f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov 690f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov msb->data_dir = rq_data_dir(msb->block_req); 691f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov msb->transfer_cmd = msb->data_dir == READ 692f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov ? MSPRO_CMD_READ_DATA 693f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov : MSPRO_CMD_WRITE_DATA; 694f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov 695f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov dev_dbg(&card->dev, "data transfer: cmd %x, " 696f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov "lba %x, count %x\n", msb->transfer_cmd, 697f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov be32_to_cpu(param.data_address), count); 698f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov 699f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov card->next_request = h_mspro_block_req_init; 700f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov msb->mrq_handler = h_mspro_block_transfer_data; 701f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov memstick_init_req(&card->current_mrq, MS_TPC_WRITE_REG, 702f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov ¶m, sizeof(param)); 703f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov memstick_new_req(card->host); 704f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov return 0; 705f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov } 706f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov 7079934c8c04561413609d2bc38c6b9f268cba774a4Tejun Heo dev_dbg(&card->dev, "blk_fetch\n"); 7089934c8c04561413609d2bc38c6b9f268cba774a4Tejun Heo msb->block_req = blk_fetch_request(msb->queue); 709f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov if (!msb->block_req) { 710f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov dev_dbg(&card->dev, "issue end\n"); 711f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov return -EAGAIN; 712f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov } 713f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov 714f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov dev_dbg(&card->dev, "trying again\n"); 715f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov chunk = 1; 716f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov goto try_again; 717baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 718baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 719f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubovstatic int mspro_block_complete_req(struct memstick_dev *card, int error) 720baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 721f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov struct mspro_block_data *msb = memstick_get_drvdata(card); 722f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov int chunk, cnt; 723f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov unsigned int t_len = 0; 724baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned long flags; 725baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 726baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov spin_lock_irqsave(&msb->q_lock, flags); 727f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov dev_dbg(&card->dev, "complete %d, %d\n", msb->has_request ? 1 : 0, 728f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov error); 729f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov 730f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov if (msb->has_request) { 731f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov /* Nothing to do - not really an error */ 732f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov if (error == -EAGAIN) 733f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov error = 0; 734f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov 735f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov if (error || (card->current_mrq.tpc == MSPRO_CMD_STOP)) { 736f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov if (msb->data_dir == READ) { 737f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov for (cnt = 0; cnt < msb->current_seg; cnt++) 738f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov t_len += msb->req_sg[cnt].length 739f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov / msb->page_size; 740f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov 741f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov if (msb->current_page) 742f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov t_len += msb->current_page - 1; 743f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov 744f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov t_len *= msb->page_size; 745f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov } 746f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov } else 7471011c1b9f2e45ce7c6e38888d2b83936aec38771Tejun Heo t_len = blk_rq_bytes(msb->block_req); 748f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov 749f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov dev_dbg(&card->dev, "transferred %x (%d)\n", t_len, error); 750f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov 751f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov if (error && !t_len) 752f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov t_len = blk_rq_cur_bytes(msb->block_req); 753f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov 754f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov chunk = __blk_end_request(msb->block_req, error, t_len); 755f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov 756f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov error = mspro_block_issue_req(card, chunk); 757f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov 758f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov if (!error) 759f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov goto out; 760f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov else 761f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov msb->has_request = 0; 762f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov } else { 763f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov if (!error) 764f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov error = -EAGAIN; 765f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov } 766f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov 767f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov card->next_request = h_mspro_block_default_bad; 768f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov complete_all(&card->mrq_complete); 769f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubovout: 770baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov spin_unlock_irqrestore(&msb->q_lock, flags); 771f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov return error; 772baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 773baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 77417017d8d2c005734d7088d8281ce2daab8fcb097Alex Dubovstatic void mspro_block_stop(struct memstick_dev *card) 77517017d8d2c005734d7088d8281ce2daab8fcb097Alex Dubov{ 77617017d8d2c005734d7088d8281ce2daab8fcb097Alex Dubov struct mspro_block_data *msb = memstick_get_drvdata(card); 77717017d8d2c005734d7088d8281ce2daab8fcb097Alex Dubov int rc = 0; 77817017d8d2c005734d7088d8281ce2daab8fcb097Alex Dubov unsigned long flags; 77917017d8d2c005734d7088d8281ce2daab8fcb097Alex Dubov 78017017d8d2c005734d7088d8281ce2daab8fcb097Alex Dubov while (1) { 78117017d8d2c005734d7088d8281ce2daab8fcb097Alex Dubov spin_lock_irqsave(&msb->q_lock, flags); 78217017d8d2c005734d7088d8281ce2daab8fcb097Alex Dubov if (!msb->has_request) { 78317017d8d2c005734d7088d8281ce2daab8fcb097Alex Dubov blk_stop_queue(msb->queue); 78417017d8d2c005734d7088d8281ce2daab8fcb097Alex Dubov rc = 1; 78517017d8d2c005734d7088d8281ce2daab8fcb097Alex Dubov } 78617017d8d2c005734d7088d8281ce2daab8fcb097Alex Dubov spin_unlock_irqrestore(&msb->q_lock, flags); 78717017d8d2c005734d7088d8281ce2daab8fcb097Alex Dubov 78817017d8d2c005734d7088d8281ce2daab8fcb097Alex Dubov if (rc) 78917017d8d2c005734d7088d8281ce2daab8fcb097Alex Dubov break; 79017017d8d2c005734d7088d8281ce2daab8fcb097Alex Dubov 79117017d8d2c005734d7088d8281ce2daab8fcb097Alex Dubov wait_for_completion(&card->mrq_complete); 79217017d8d2c005734d7088d8281ce2daab8fcb097Alex Dubov } 79317017d8d2c005734d7088d8281ce2daab8fcb097Alex Dubov} 79417017d8d2c005734d7088d8281ce2daab8fcb097Alex Dubov 79517017d8d2c005734d7088d8281ce2daab8fcb097Alex Dubovstatic void mspro_block_start(struct memstick_dev *card) 79617017d8d2c005734d7088d8281ce2daab8fcb097Alex Dubov{ 79717017d8d2c005734d7088d8281ce2daab8fcb097Alex Dubov struct mspro_block_data *msb = memstick_get_drvdata(card); 79817017d8d2c005734d7088d8281ce2daab8fcb097Alex Dubov unsigned long flags; 79917017d8d2c005734d7088d8281ce2daab8fcb097Alex Dubov 80017017d8d2c005734d7088d8281ce2daab8fcb097Alex Dubov spin_lock_irqsave(&msb->q_lock, flags); 80117017d8d2c005734d7088d8281ce2daab8fcb097Alex Dubov blk_start_queue(msb->queue); 80217017d8d2c005734d7088d8281ce2daab8fcb097Alex Dubov spin_unlock_irqrestore(&msb->q_lock, flags); 80317017d8d2c005734d7088d8281ce2daab8fcb097Alex Dubov} 80417017d8d2c005734d7088d8281ce2daab8fcb097Alex Dubov 805f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubovstatic int mspro_block_prepare_req(struct request_queue *q, struct request *req) 806baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 807f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov if (!blk_fs_request(req) && !blk_pc_request(req)) { 808f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov blk_dump_rq_flags(req, "MSPro unsupported request"); 809f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov return BLKPREP_KILL; 810f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov } 811baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 812f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov req->cmd_flags |= REQ_DONTPREP; 813baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 814f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov return BLKPREP_OK; 815baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 816baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 817f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubovstatic void mspro_block_submit_req(struct request_queue *q) 818baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 819baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct memstick_dev *card = q->queuedata; 820baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_block_data *msb = memstick_get_drvdata(card); 821baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct request *req = NULL; 822baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 823f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov if (msb->has_request) 824f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov return; 825f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov 826f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov if (msb->eject) { 8279934c8c04561413609d2bc38c6b9f268cba774a4Tejun Heo while ((req = blk_fetch_request(q)) != NULL) 82840cbbb781d3eba5d6ac0860db078af490e5c7c6bTejun Heo __blk_end_request_all(req, -ENODEV); 829f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov 830f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov return; 831baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 832f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov 833f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov msb->has_request = 1; 834f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov if (mspro_block_issue_req(card, 0)) 835f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov msb->has_request = 0; 836baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 837baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 838baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov/*** Initialization ***/ 839baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 840baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstatic int mspro_block_wait_for_ced(struct memstick_dev *card) 841baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 842baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_block_data *msb = memstick_get_drvdata(card); 843baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 844baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov card->next_request = h_mspro_block_req_init; 845baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->mrq_handler = h_mspro_block_wait_for_ced; 846baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov memstick_init_req(&card->current_mrq, MS_TPC_GET_INT, NULL, 1); 847baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov memstick_new_req(card->host); 848baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov wait_for_completion(&card->mrq_complete); 849baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return card->current_mrq.error; 850baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 851baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 852962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubovstatic int mspro_block_set_interface(struct memstick_dev *card, 853962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov unsigned char sys_reg) 854baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 855baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct memstick_host *host = card->host; 856baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_block_data *msb = memstick_get_drvdata(card); 857baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_param_register param = { 858962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov .system = sys_reg, 859baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov .data_count = 0, 860baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov .data_address = 0, 861e1f19995f55294fbb00ea22ba85d7b0d80ba3813Alex Dubov .tpc_param = 0 862baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov }; 863baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 864baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov card->next_request = h_mspro_block_req_init; 865baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->mrq_handler = h_mspro_block_default; 866baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov memstick_init_req(&card->current_mrq, MS_TPC_WRITE_REG, ¶m, 867baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov sizeof(param)); 868baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov memstick_new_req(host); 869baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov wait_for_completion(&card->mrq_complete); 870962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov return card->current_mrq.error; 871962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov} 872962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov 873962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubovstatic int mspro_block_switch_interface(struct memstick_dev *card) 874962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov{ 875962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov struct memstick_host *host = card->host; 876962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov struct mspro_block_data *msb = memstick_get_drvdata(card); 877962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov int rc = 0; 878962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov 8798e82f8c34b1759ae0d80fe96101746ec51fb1ba4Alex Dubovtry_again: 880962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov if (msb->caps & MEMSTICK_CAP_PAR4) 881962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov rc = mspro_block_set_interface(card, MEMSTICK_SYS_PAR4); 882962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov else 883962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov return 0; 884962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov 885962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov if (rc) { 886962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov printk(KERN_WARNING 887962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov "%s: could not switch to 4-bit mode, error %d\n", 8880252c3b4f0188ceb9ce48a340e6bfd17ab28afa7Kay Sievers dev_name(&card->dev), rc); 889962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov return 0; 890962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov } 891baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 892e1f19995f55294fbb00ea22ba85d7b0d80ba3813Alex Dubov msb->system = MEMSTICK_SYS_PAR4; 893e1f19995f55294fbb00ea22ba85d7b0d80ba3813Alex Dubov host->set_param(host, MEMSTICK_INTERFACE, MEMSTICK_PAR4); 894962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov printk(KERN_INFO "%s: switching to 4-bit parallel mode\n", 8950252c3b4f0188ceb9ce48a340e6bfd17ab28afa7Kay Sievers dev_name(&card->dev)); 896962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov 897962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov if (msb->caps & MEMSTICK_CAP_PAR8) { 898962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov rc = mspro_block_set_interface(card, MEMSTICK_SYS_PAR8); 899962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov 900962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov if (!rc) { 901962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov msb->system = MEMSTICK_SYS_PAR8; 902962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov host->set_param(host, MEMSTICK_INTERFACE, 903962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov MEMSTICK_PAR8); 904962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov printk(KERN_INFO 905962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov "%s: switching to 8-bit parallel mode\n", 9060252c3b4f0188ceb9ce48a340e6bfd17ab28afa7Kay Sievers dev_name(&card->dev)); 907962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov } else 908962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov printk(KERN_WARNING 909962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov "%s: could not switch to 8-bit mode, error %d\n", 9100252c3b4f0188ceb9ce48a340e6bfd17ab28afa7Kay Sievers dev_name(&card->dev), rc); 911962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov } 912baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 913baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov card->next_request = h_mspro_block_req_init; 914baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->mrq_handler = h_mspro_block_default; 915baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov memstick_init_req(&card->current_mrq, MS_TPC_GET_INT, NULL, 1); 916baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov memstick_new_req(card->host); 917baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov wait_for_completion(&card->mrq_complete); 918962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov rc = card->current_mrq.error; 919baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 920962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov if (rc) { 921962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov printk(KERN_WARNING 922962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov "%s: interface error, trying to fall back to serial\n", 9230252c3b4f0188ceb9ce48a340e6bfd17ab28afa7Kay Sievers dev_name(&card->dev)); 924593672582e71a688cf8c3fc1c59ec7c44d3799e5Alex Dubov msb->system = MEMSTICK_SYS_SERIAL; 925593672582e71a688cf8c3fc1c59ec7c44d3799e5Alex Dubov host->set_param(host, MEMSTICK_POWER, MEMSTICK_POWER_OFF); 926962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov msleep(10); 927593672582e71a688cf8c3fc1c59ec7c44d3799e5Alex Dubov host->set_param(host, MEMSTICK_POWER, MEMSTICK_POWER_ON); 928baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov host->set_param(host, MEMSTICK_INTERFACE, MEMSTICK_SERIAL); 929593672582e71a688cf8c3fc1c59ec7c44d3799e5Alex Dubov 930962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov rc = memstick_set_rw_addr(card); 931962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov if (!rc) 932962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov rc = mspro_block_set_interface(card, msb->system); 9338e82f8c34b1759ae0d80fe96101746ec51fb1ba4Alex Dubov 9348e82f8c34b1759ae0d80fe96101746ec51fb1ba4Alex Dubov if (!rc) { 9358e82f8c34b1759ae0d80fe96101746ec51fb1ba4Alex Dubov msleep(150); 9368e82f8c34b1759ae0d80fe96101746ec51fb1ba4Alex Dubov rc = mspro_block_wait_for_ced(card); 9378e82f8c34b1759ae0d80fe96101746ec51fb1ba4Alex Dubov if (rc) 9388e82f8c34b1759ae0d80fe96101746ec51fb1ba4Alex Dubov return rc; 9398e82f8c34b1759ae0d80fe96101746ec51fb1ba4Alex Dubov 9408e82f8c34b1759ae0d80fe96101746ec51fb1ba4Alex Dubov if (msb->caps & MEMSTICK_CAP_PAR8) { 9418e82f8c34b1759ae0d80fe96101746ec51fb1ba4Alex Dubov msb->caps &= ~MEMSTICK_CAP_PAR8; 9428e82f8c34b1759ae0d80fe96101746ec51fb1ba4Alex Dubov goto try_again; 9438e82f8c34b1759ae0d80fe96101746ec51fb1ba4Alex Dubov } 9448e82f8c34b1759ae0d80fe96101746ec51fb1ba4Alex Dubov } 945baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 946962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov return rc; 947baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 948baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 949baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov/* Memory allocated for attributes by this function should be freed by 950baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov * mspro_block_data_clear, no matter if the initialization process succeded 951baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov * or failed. 952baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov */ 953baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstatic int mspro_block_read_attributes(struct memstick_dev *card) 954baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 955baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_block_data *msb = memstick_get_drvdata(card); 956baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_param_register param = { 957baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov .system = msb->system, 958baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov .data_count = cpu_to_be16(1), 959baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov .data_address = 0, 960e1f19995f55294fbb00ea22ba85d7b0d80ba3813Alex Dubov .tpc_param = 0 961baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov }; 962baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_attribute *attr = NULL; 963baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_sys_attr *s_attr = NULL; 964baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char *buffer = NULL; 965baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov int cnt, rc, attr_count; 966baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned int addr; 967baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned short page_count; 968baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 969baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov attr = kmalloc(msb->page_size, GFP_KERNEL); 970baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (!attr) 971baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return -ENOMEM; 972baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 973baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov sg_init_one(&msb->req_sg[0], attr, msb->page_size); 974baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->seg_count = 1; 975baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->current_seg = 0; 976baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->current_page = 0; 977baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->data_dir = READ; 978baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->transfer_cmd = MSPRO_CMD_READ_ATRB; 979baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 980baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov card->next_request = h_mspro_block_req_init; 981baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->mrq_handler = h_mspro_block_transfer_data; 982baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov memstick_init_req(&card->current_mrq, MS_TPC_WRITE_REG, ¶m, 983baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov sizeof(param)); 984baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov memstick_new_req(card->host); 985baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov wait_for_completion(&card->mrq_complete); 986baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (card->current_mrq.error) { 987baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc = card->current_mrq.error; 988baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov goto out_free_attr; 989baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 990baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 991baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (be16_to_cpu(attr->signature) != MSPRO_BLOCK_SIGNATURE) { 992baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov printk(KERN_ERR "%s: unrecognized device signature %x\n", 9930252c3b4f0188ceb9ce48a340e6bfd17ab28afa7Kay Sievers dev_name(&card->dev), be16_to_cpu(attr->signature)); 994baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc = -ENODEV; 995baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov goto out_free_attr; 996baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 997baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 998baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (attr->count > MSPRO_BLOCK_MAX_ATTRIBUTES) { 999baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov printk(KERN_WARNING "%s: way too many attribute entries\n", 10000252c3b4f0188ceb9ce48a340e6bfd17ab28afa7Kay Sievers dev_name(&card->dev)); 1001baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov attr_count = MSPRO_BLOCK_MAX_ATTRIBUTES; 1002baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } else 1003baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov attr_count = attr->count; 1004baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1005baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->attr_group.attrs = kzalloc((attr_count + 1) 1006baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov * sizeof(struct attribute), 1007baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov GFP_KERNEL); 1008baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (!msb->attr_group.attrs) { 1009baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc = -ENOMEM; 1010baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov goto out_free_attr; 1011baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 1012baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->attr_group.name = "media_attributes"; 1013baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1014baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov buffer = kmalloc(msb->page_size, GFP_KERNEL); 1015baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (!buffer) { 1016baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc = -ENOMEM; 1017baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov goto out_free_attr; 1018baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 1019baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov memcpy(buffer, (char *)attr, msb->page_size); 1020baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov page_count = 1; 1021baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1022baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov for (cnt = 0; cnt < attr_count; ++cnt) { 1023baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov s_attr = kzalloc(sizeof(struct mspro_sys_attr), GFP_KERNEL); 1024baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (!s_attr) { 1025baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc = -ENOMEM; 1026baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov goto out_free_buffer; 1027baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 1028baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1029baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->attr_group.attrs[cnt] = &s_attr->dev_attr.attr; 1030baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov addr = be32_to_cpu(attr->entries[cnt].address); 1031baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc = be32_to_cpu(attr->entries[cnt].size); 1032baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov dev_dbg(&card->dev, "adding attribute %d: id %x, address %x, " 1033baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov "size %x\n", cnt, attr->entries[cnt].id, addr, rc); 1034baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov s_attr->id = attr->entries[cnt].id; 1035baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (mspro_block_attr_name(s_attr->id)) 1036baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov snprintf(s_attr->name, sizeof(s_attr->name), "%s", 1037baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov mspro_block_attr_name(attr->entries[cnt].id)); 1038baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov else 1039baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov snprintf(s_attr->name, sizeof(s_attr->name), 1040baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov "attr_x%02x", attr->entries[cnt].id); 1041baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1042baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov s_attr->dev_attr.attr.name = s_attr->name; 1043baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov s_attr->dev_attr.attr.mode = S_IRUGO; 1044baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov s_attr->dev_attr.show = mspro_block_attr_show(s_attr->id); 1045baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1046baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (!rc) 1047baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov continue; 1048baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1049baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov s_attr->size = rc; 1050baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov s_attr->data = kmalloc(rc, GFP_KERNEL); 1051baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (!s_attr->data) { 1052baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc = -ENOMEM; 1053baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov goto out_free_buffer; 1054baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 1055baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1056baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (((addr / msb->page_size) 1057baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov == be32_to_cpu(param.data_address)) 1058baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov && (((addr + rc - 1) / msb->page_size) 1059baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov == be32_to_cpu(param.data_address))) { 1060baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov memcpy(s_attr->data, buffer + addr % msb->page_size, 1061baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc); 1062baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov continue; 1063baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 1064baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1065baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (page_count <= (rc / msb->page_size)) { 1066baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov kfree(buffer); 1067baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov page_count = (rc / msb->page_size) + 1; 1068baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov buffer = kmalloc(page_count * msb->page_size, 1069baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov GFP_KERNEL); 1070baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (!buffer) { 1071baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc = -ENOMEM; 1072baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov goto out_free_attr; 1073baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 1074baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 1075baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1076baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov param.system = msb->system; 1077baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov param.data_count = cpu_to_be16((rc / msb->page_size) + 1); 1078baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov param.data_address = cpu_to_be32(addr / msb->page_size); 1079e1f19995f55294fbb00ea22ba85d7b0d80ba3813Alex Dubov param.tpc_param = 0; 1080baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1081baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov sg_init_one(&msb->req_sg[0], buffer, 1082baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov be16_to_cpu(param.data_count) * msb->page_size); 1083baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->seg_count = 1; 1084baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->current_seg = 0; 1085baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->current_page = 0; 1086baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->data_dir = READ; 1087baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->transfer_cmd = MSPRO_CMD_READ_ATRB; 1088baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1089baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov dev_dbg(&card->dev, "reading attribute pages %x, %x\n", 1090baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov be32_to_cpu(param.data_address), 1091baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov be16_to_cpu(param.data_count)); 1092baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1093baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov card->next_request = h_mspro_block_req_init; 1094baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->mrq_handler = h_mspro_block_transfer_data; 1095baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov memstick_init_req(&card->current_mrq, MS_TPC_WRITE_REG, 1096baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov (char *)¶m, sizeof(param)); 1097baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov memstick_new_req(card->host); 1098baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov wait_for_completion(&card->mrq_complete); 1099baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (card->current_mrq.error) { 1100baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc = card->current_mrq.error; 1101baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov goto out_free_buffer; 1102baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 1103baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1104baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov memcpy(s_attr->data, buffer + addr % msb->page_size, rc); 1105baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 1106baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1107baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc = 0; 1108baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovout_free_buffer: 1109baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov kfree(buffer); 1110baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovout_free_attr: 1111baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov kfree(attr); 1112baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return rc; 1113baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 1114baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1115baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstatic int mspro_block_init_card(struct memstick_dev *card) 1116baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 1117baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_block_data *msb = memstick_get_drvdata(card); 1118baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct memstick_host *host = card->host; 1119baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov int rc = 0; 1120baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1121e1f19995f55294fbb00ea22ba85d7b0d80ba3813Alex Dubov msb->system = MEMSTICK_SYS_SERIAL; 1122baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov card->reg_addr.r_offset = offsetof(struct mspro_register, status); 1123baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov card->reg_addr.r_length = sizeof(struct ms_status_register); 1124baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov card->reg_addr.w_offset = offsetof(struct mspro_register, param); 1125baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov card->reg_addr.w_length = sizeof(struct mspro_param_register); 1126baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1127baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (memstick_set_rw_addr(card)) 1128baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return -EIO; 1129baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1130ead70773608a5d97f81cb492f117d20b5e9f323eAlex Dubov msb->caps = host->caps; 11318e82f8c34b1759ae0d80fe96101746ec51fb1ba4Alex Dubov 11328e82f8c34b1759ae0d80fe96101746ec51fb1ba4Alex Dubov msleep(150); 11338e82f8c34b1759ae0d80fe96101746ec51fb1ba4Alex Dubov rc = mspro_block_wait_for_ced(card); 1134962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov if (rc) 1135962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov return rc; 1136baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 11378e82f8c34b1759ae0d80fe96101746ec51fb1ba4Alex Dubov rc = mspro_block_switch_interface(card); 1138baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (rc) 1139baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return rc; 11408e82f8c34b1759ae0d80fe96101746ec51fb1ba4Alex Dubov 1141baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov dev_dbg(&card->dev, "card activated\n"); 1142ead70773608a5d97f81cb492f117d20b5e9f323eAlex Dubov if (msb->system != MEMSTICK_SYS_SERIAL) 1143ead70773608a5d97f81cb492f117d20b5e9f323eAlex Dubov msb->caps |= MEMSTICK_CAP_AUTO_GET_INT; 1144baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1145baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov card->next_request = h_mspro_block_req_init; 1146baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->mrq_handler = h_mspro_block_get_ro; 1147baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov memstick_init_req(&card->current_mrq, MS_TPC_READ_REG, NULL, 1148baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov sizeof(struct ms_status_register)); 1149baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov memstick_new_req(card->host); 1150baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov wait_for_completion(&card->mrq_complete); 1151baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (card->current_mrq.error) 1152baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return card->current_mrq.error; 1153baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1154baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov dev_dbg(&card->dev, "card r/w status %d\n", msb->read_only ? 0 : 1); 1155baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1156baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->page_size = 512; 1157baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc = mspro_block_read_attributes(card); 1158baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (rc) 1159baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return rc; 1160baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1161baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov dev_dbg(&card->dev, "attributes loaded\n"); 1162baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return 0; 1163baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1164baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 1165baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1166baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstatic int mspro_block_init_disk(struct memstick_dev *card) 1167baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 1168baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_block_data *msb = memstick_get_drvdata(card); 1169baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct memstick_host *host = card->host; 1170baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_devinfo *dev_info = NULL; 1171baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_sys_info *sys_info = NULL; 1172baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_sys_attr *s_attr = NULL; 1173baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov int rc, disk_id; 1174baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov u64 limit = BLK_BOUNCE_HIGH; 1175baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned long capacity; 1176baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1177c4c66cf1787d408066fbfc69209185701f5df15fGreg Kroah-Hartman if (host->dev.dma_mask && *(host->dev.dma_mask)) 1178c4c66cf1787d408066fbfc69209185701f5df15fGreg Kroah-Hartman limit = *(host->dev.dma_mask); 1179baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1180baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov for (rc = 0; msb->attr_group.attrs[rc]; ++rc) { 1181baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov s_attr = mspro_from_sysfs_attr(msb->attr_group.attrs[rc]); 1182baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1183baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (s_attr->id == MSPRO_BLOCK_ID_DEVINFO) 1184baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov dev_info = s_attr->data; 1185baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov else if (s_attr->id == MSPRO_BLOCK_ID_SYSINFO) 1186baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov sys_info = s_attr->data; 1187baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 1188baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1189baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (!dev_info || !sys_info) 1190baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return -ENODEV; 1191baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1192baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->cylinders = be16_to_cpu(dev_info->cylinders); 1193baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->heads = be16_to_cpu(dev_info->heads); 1194baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->sectors_per_track = be16_to_cpu(dev_info->sectors_per_track); 1195baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1196baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->page_size = be16_to_cpu(sys_info->unit_size); 1197baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1198baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (!idr_pre_get(&mspro_block_disk_idr, GFP_KERNEL)) 1199baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return -ENOMEM; 1200baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1201baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov mutex_lock(&mspro_block_disk_lock); 1202baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc = idr_get_new(&mspro_block_disk_idr, card, &disk_id); 1203baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov mutex_unlock(&mspro_block_disk_lock); 1204baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1205baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (rc) 1206baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return rc; 1207baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 12088e82f8c34b1759ae0d80fe96101746ec51fb1ba4Alex Dubov if ((disk_id << MSPRO_BLOCK_PART_SHIFT) > 255) { 1209baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc = -ENOSPC; 1210baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov goto out_release_id; 1211baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 1212baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 12138e82f8c34b1759ae0d80fe96101746ec51fb1ba4Alex Dubov msb->disk = alloc_disk(1 << MSPRO_BLOCK_PART_SHIFT); 1214baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (!msb->disk) { 1215baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc = -ENOMEM; 1216baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov goto out_release_id; 1217baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 1218baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1219f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov msb->queue = blk_init_queue(mspro_block_submit_req, &msb->q_lock); 1220baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (!msb->queue) { 1221baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc = -ENOMEM; 1222baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov goto out_put_disk; 1223baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 1224baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1225baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->queue->queuedata = card; 1226f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov blk_queue_prep_rq(msb->queue, mspro_block_prepare_req); 1227baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1228baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov blk_queue_bounce_limit(msb->queue, limit); 1229086fa5ff0854c676ec333760f4c0154b3b242616Martin K. Petersen blk_queue_max_hw_sectors(msb->queue, MSPRO_BLOCK_MAX_PAGES); 12308a78362c4eefc1deddbefe2c7f38aabbc2429d6bMartin K. Petersen blk_queue_max_segments(msb->queue, MSPRO_BLOCK_MAX_SEGS); 1231baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov blk_queue_max_segment_size(msb->queue, 1232baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov MSPRO_BLOCK_MAX_PAGES * msb->page_size); 1233baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1234baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->disk->major = major; 12358e82f8c34b1759ae0d80fe96101746ec51fb1ba4Alex Dubov msb->disk->first_minor = disk_id << MSPRO_BLOCK_PART_SHIFT; 1236baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->disk->fops = &ms_block_bdops; 1237baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->usage_count = 1; 1238baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->disk->private_data = msb; 1239baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->disk->queue = msb->queue; 1240baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->disk->driverfs_dev = &card->dev; 1241baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1242baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov sprintf(msb->disk->disk_name, "mspblk%d", disk_id); 1243baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1244e1defc4ff0cf57aca6c5e3ff99fa503f5943c1f1Martin K. Petersen blk_queue_logical_block_size(msb->queue, msb->page_size); 1245baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1246baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov capacity = be16_to_cpu(sys_info->user_block_count); 1247baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov capacity *= be16_to_cpu(sys_info->block_size); 1248baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov capacity *= msb->page_size >> 9; 1249baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov set_capacity(msb->disk, capacity); 1250baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov dev_dbg(&card->dev, "capacity set %ld\n", capacity); 1251baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1252baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov add_disk(msb->disk); 1253baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->active = 1; 1254baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return 0; 1255baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1256baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovout_put_disk: 1257baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov put_disk(msb->disk); 1258baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovout_release_id: 1259baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov mutex_lock(&mspro_block_disk_lock); 1260baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov idr_remove(&mspro_block_disk_idr, disk_id); 1261baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov mutex_unlock(&mspro_block_disk_lock); 1262baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return rc; 1263baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 1264baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1265baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstatic void mspro_block_data_clear(struct mspro_block_data *msb) 1266baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 1267baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov int cnt; 1268baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_sys_attr *s_attr; 1269baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1270baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (msb->attr_group.attrs) { 1271baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov for (cnt = 0; msb->attr_group.attrs[cnt]; ++cnt) { 1272baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov s_attr = mspro_from_sysfs_attr(msb->attr_group 1273baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov .attrs[cnt]); 1274baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov kfree(s_attr->data); 1275baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov kfree(s_attr); 1276baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 1277baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov kfree(msb->attr_group.attrs); 1278baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 1279baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1280baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->card = NULL; 1281baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 1282baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1283baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstatic int mspro_block_check_card(struct memstick_dev *card) 1284baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 1285baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_block_data *msb = memstick_get_drvdata(card); 1286baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1287baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return (msb->active == 1); 1288baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 1289baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1290baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstatic int mspro_block_probe(struct memstick_dev *card) 1291baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 1292baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_block_data *msb; 1293baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov int rc = 0; 1294baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1295baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb = kzalloc(sizeof(struct mspro_block_data), GFP_KERNEL); 1296baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (!msb) 1297baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return -ENOMEM; 1298baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov memstick_set_drvdata(card, msb); 1299baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->card = card; 1300f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov spin_lock_init(&msb->q_lock); 1301baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1302baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc = mspro_block_init_card(card); 1303baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1304baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (rc) 1305baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov goto out_free; 1306baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1307baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc = sysfs_create_group(&card->dev.kobj, &msb->attr_group); 1308baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (rc) 1309baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov goto out_free; 1310baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1311baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc = mspro_block_init_disk(card); 1312baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (!rc) { 1313baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov card->check = mspro_block_check_card; 131417017d8d2c005734d7088d8281ce2daab8fcb097Alex Dubov card->stop = mspro_block_stop; 131517017d8d2c005734d7088d8281ce2daab8fcb097Alex Dubov card->start = mspro_block_start; 1316baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return 0; 1317baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 1318baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1319baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov sysfs_remove_group(&card->dev.kobj, &msb->attr_group); 1320baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovout_free: 1321baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov memstick_set_drvdata(card, NULL); 1322baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov mspro_block_data_clear(msb); 1323baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov kfree(msb); 1324baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return rc; 1325baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 1326baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1327baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstatic void mspro_block_remove(struct memstick_dev *card) 1328baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 1329baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_block_data *msb = memstick_get_drvdata(card); 1330baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned long flags; 1331baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1332baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov del_gendisk(msb->disk); 1333baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov dev_dbg(&card->dev, "mspro block remove\n"); 1334baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov spin_lock_irqsave(&msb->q_lock, flags); 1335f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov msb->eject = 1; 1336f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov blk_start_queue(msb->queue); 1337baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov spin_unlock_irqrestore(&msb->q_lock, flags); 1338baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1339baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov blk_cleanup_queue(msb->queue); 1340f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov msb->queue = NULL; 1341baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1342baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov sysfs_remove_group(&card->dev.kobj, &msb->attr_group); 1343baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1344baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov mutex_lock(&mspro_block_disk_lock); 1345baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov mspro_block_data_clear(msb); 1346baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov mutex_unlock(&mspro_block_disk_lock); 1347baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1348baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov mspro_block_disk_release(msb->disk); 1349baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov memstick_set_drvdata(card, NULL); 1350baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 1351baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1352baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov#ifdef CONFIG_PM 1353baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1354baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstatic int mspro_block_suspend(struct memstick_dev *card, pm_message_t state) 1355baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 1356baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_block_data *msb = memstick_get_drvdata(card); 1357baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned long flags; 1358baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1359baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov spin_lock_irqsave(&msb->q_lock, flags); 1360baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov blk_stop_queue(msb->queue); 1361f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov msb->active = 0; 1362baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov spin_unlock_irqrestore(&msb->q_lock, flags); 1363baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1364baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return 0; 1365baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 1366baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1367baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstatic int mspro_block_resume(struct memstick_dev *card) 1368baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 1369baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_block_data *msb = memstick_get_drvdata(card); 1370baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned long flags; 1371baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov int rc = 0; 1372baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1373baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov#ifdef CONFIG_MEMSTICK_UNSAFE_RESUME 1374baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1375baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_block_data *new_msb; 1376baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct memstick_host *host = card->host; 1377baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_sys_attr *s_attr, *r_attr; 1378baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char cnt; 1379baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1380baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov mutex_lock(&host->lock); 1381baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov new_msb = kzalloc(sizeof(struct mspro_block_data), GFP_KERNEL); 1382baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (!new_msb) { 1383baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc = -ENOMEM; 1384baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov goto out_unlock; 1385baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 1386baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1387baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov new_msb->card = card; 1388baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov memstick_set_drvdata(card, new_msb); 1389baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (mspro_block_init_card(card)) 1390baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov goto out_free; 1391baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1392baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov for (cnt = 0; new_msb->attr_group.attrs[cnt] 1393baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov && msb->attr_group.attrs[cnt]; ++cnt) { 1394baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov s_attr = mspro_from_sysfs_attr(new_msb->attr_group.attrs[cnt]); 1395baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov r_attr = mspro_from_sysfs_attr(msb->attr_group.attrs[cnt]); 1396baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1397baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (s_attr->id == MSPRO_BLOCK_ID_SYSINFO 1398baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov && r_attr->id == s_attr->id) { 1399baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (memcmp(s_attr->data, r_attr->data, s_attr->size)) 1400baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov break; 1401baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1402f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov msb->active = 1; 1403baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov break; 1404baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 1405baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 1406baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1407baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovout_free: 1408baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov memstick_set_drvdata(card, msb); 1409baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov mspro_block_data_clear(new_msb); 1410baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov kfree(new_msb); 1411baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovout_unlock: 1412baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov mutex_unlock(&host->lock); 1413baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1414baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov#endif /* CONFIG_MEMSTICK_UNSAFE_RESUME */ 1415baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1416baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov spin_lock_irqsave(&msb->q_lock, flags); 1417baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov blk_start_queue(msb->queue); 1418baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov spin_unlock_irqrestore(&msb->q_lock, flags); 1419baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return rc; 1420baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 1421baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1422baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov#else 1423baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1424baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov#define mspro_block_suspend NULL 1425baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov#define mspro_block_resume NULL 1426baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1427baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov#endif /* CONFIG_PM */ 1428baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1429baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstatic struct memstick_device_id mspro_block_id_tbl[] = { 1430baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov {MEMSTICK_MATCH_ALL, MEMSTICK_TYPE_PRO, MEMSTICK_CATEGORY_STORAGE_DUO, 14318e82f8c34b1759ae0d80fe96101746ec51fb1ba4Alex Dubov MEMSTICK_CLASS_DUO}, 1432baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov {} 1433baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov}; 1434baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1435baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1436baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstatic struct memstick_driver mspro_block_driver = { 1437baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov .driver = { 1438baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov .name = DRIVER_NAME, 1439baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov .owner = THIS_MODULE 1440baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov }, 1441baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov .id_table = mspro_block_id_tbl, 1442baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov .probe = mspro_block_probe, 1443baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov .remove = mspro_block_remove, 1444baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov .suspend = mspro_block_suspend, 1445baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov .resume = mspro_block_resume 1446baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov}; 1447baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1448baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstatic int __init mspro_block_init(void) 1449baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 1450baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov int rc = -ENOMEM; 1451baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1452baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc = register_blkdev(major, DRIVER_NAME); 1453baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (rc < 0) { 1454baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov printk(KERN_ERR DRIVER_NAME ": failed to register " 1455baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov "major %d, error %d\n", major, rc); 1456baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return rc; 1457baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 1458baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (!major) 1459baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov major = rc; 1460baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1461baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc = memstick_register_driver(&mspro_block_driver); 1462baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (rc) 1463baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unregister_blkdev(major, DRIVER_NAME); 1464baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return rc; 1465baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 1466baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1467baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstatic void __exit mspro_block_exit(void) 1468baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 1469baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov memstick_unregister_driver(&mspro_block_driver); 1470baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unregister_blkdev(major, DRIVER_NAME); 1471baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov idr_destroy(&mspro_block_disk_idr); 1472baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 1473baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1474baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovmodule_init(mspro_block_init); 1475baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovmodule_exit(mspro_block_exit); 1476baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1477baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex DubovMODULE_LICENSE("GPL"); 1478baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex DubovMODULE_AUTHOR("Alex Dubov"); 1479baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex DubovMODULE_DESCRIPTION("Sony MemoryStickPro block device driver"); 1480baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex DubovMODULE_DEVICE_TABLE(memstick, mspro_block_id_tbl); 1481