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> 205a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 212a48fc0ab24241755dc93bfd4f01d68efab47f5aArnd Bergmann#include <linux/mutex.h> 22baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov#include <linux/memstick.h> 23c47e789328719073cdddf1623e970c7dc1c581a8Paul Gortmaker#include <linux/module.h> 24baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 25baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov#define DRIVER_NAME "mspro_block" 26baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 27baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstatic int major; 28baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovmodule_param(major, int, 0644); 29baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 30baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov#define MSPRO_BLOCK_MAX_SEGS 32 31baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov#define MSPRO_BLOCK_MAX_PAGES ((2 << 16) - 1) 32baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 33baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov#define MSPRO_BLOCK_SIGNATURE 0xa5c3 34baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov#define MSPRO_BLOCK_MAX_ATTRIBUTES 41 35baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 368e82f8c34b1759ae0d80fe96101746ec51fb1ba4Alex Dubov#define MSPRO_BLOCK_PART_SHIFT 3 378e82f8c34b1759ae0d80fe96101746ec51fb1ba4Alex Dubov 38baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovenum { 39baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov MSPRO_BLOCK_ID_SYSINFO = 0x10, 40baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov MSPRO_BLOCK_ID_MODELNAME = 0x15, 41baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov MSPRO_BLOCK_ID_MBR = 0x20, 42baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov MSPRO_BLOCK_ID_PBR16 = 0x21, 43baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov MSPRO_BLOCK_ID_PBR32 = 0x22, 44baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov MSPRO_BLOCK_ID_SPECFILEVALUES1 = 0x25, 45baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov MSPRO_BLOCK_ID_SPECFILEVALUES2 = 0x26, 46baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov MSPRO_BLOCK_ID_DEVINFO = 0x30 47baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov}; 48baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 49baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstruct mspro_sys_attr { 50baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov size_t size; 51baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov void *data; 52baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char id; 53baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov char name[32]; 54baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct device_attribute dev_attr; 55baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov}; 56baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 57baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstruct mspro_attr_entry { 5869347a236b22c3962ea812511495e502dedfd50cHarvey Harrison __be32 address; 5969347a236b22c3962ea812511495e502dedfd50cHarvey Harrison __be32 size; 60baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char id; 61baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char reserved[3]; 62baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} __attribute__((packed)); 63baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 64baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstruct mspro_attribute { 6569347a236b22c3962ea812511495e502dedfd50cHarvey Harrison __be16 signature; 66baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned short version; 67baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char count; 68baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char reserved[11]; 69baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_attr_entry entries[]; 70baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} __attribute__((packed)); 71baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 72baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstruct mspro_sys_info { 73baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char class; 74baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char reserved0; 7569347a236b22c3962ea812511495e502dedfd50cHarvey Harrison __be16 block_size; 7669347a236b22c3962ea812511495e502dedfd50cHarvey Harrison __be16 block_count; 7769347a236b22c3962ea812511495e502dedfd50cHarvey Harrison __be16 user_block_count; 7869347a236b22c3962ea812511495e502dedfd50cHarvey Harrison __be16 page_size; 79baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char reserved1[2]; 80baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char assembly_date[8]; 8169347a236b22c3962ea812511495e502dedfd50cHarvey Harrison __be32 serial_number; 82baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char assembly_maker_code; 83baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char assembly_model_code[3]; 8469347a236b22c3962ea812511495e502dedfd50cHarvey Harrison __be16 memory_maker_code; 8569347a236b22c3962ea812511495e502dedfd50cHarvey Harrison __be16 memory_model_code; 86baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char reserved2[4]; 87baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char vcc; 88baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char vpp; 8969347a236b22c3962ea812511495e502dedfd50cHarvey Harrison __be16 controller_number; 9069347a236b22c3962ea812511495e502dedfd50cHarvey Harrison __be16 controller_function; 9169347a236b22c3962ea812511495e502dedfd50cHarvey Harrison __be16 start_sector; 9269347a236b22c3962ea812511495e502dedfd50cHarvey Harrison __be16 unit_size; 93baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char ms_sub_class; 94baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char reserved3[4]; 95baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char interface_type; 9669347a236b22c3962ea812511495e502dedfd50cHarvey Harrison __be16 controller_code; 97baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char format_type; 98baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char reserved4; 99baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char device_type; 100baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char reserved5[7]; 101baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char mspro_id[16]; 102baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char reserved6[16]; 103baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} __attribute__((packed)); 104baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 105baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstruct mspro_mbr { 106baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char boot_partition; 107baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char start_head; 108baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char start_sector; 109baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char start_cylinder; 110baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char partition_type; 111baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char end_head; 112baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char end_sector; 113baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char end_cylinder; 114baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned int start_sectors; 115baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned int sectors_per_partition; 116baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} __attribute__((packed)); 117baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 118efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubovstruct mspro_specfile { 119efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov char name[8]; 120efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov char ext[3]; 121efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov unsigned char attr; 122efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov unsigned char reserved[10]; 123efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov unsigned short time; 124efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov unsigned short date; 125efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov unsigned short cluster; 126efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov unsigned int size; 127efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov} __attribute__((packed)); 128efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov 129baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstruct mspro_devinfo { 13069347a236b22c3962ea812511495e502dedfd50cHarvey Harrison __be16 cylinders; 13169347a236b22c3962ea812511495e502dedfd50cHarvey Harrison __be16 heads; 13269347a236b22c3962ea812511495e502dedfd50cHarvey Harrison __be16 bytes_per_track; 13369347a236b22c3962ea812511495e502dedfd50cHarvey Harrison __be16 bytes_per_sector; 13469347a236b22c3962ea812511495e502dedfd50cHarvey Harrison __be16 sectors_per_track; 135baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char reserved[6]; 136baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} __attribute__((packed)); 137baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 138baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstruct mspro_block_data { 139baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct memstick_dev *card; 140baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned int usage_count; 141ead70773608a5d97f81cb492f117d20b5e9f323eAlex Dubov unsigned int caps; 142baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct gendisk *disk; 143baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct request_queue *queue; 144f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov struct request *block_req; 145baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov spinlock_t q_lock; 146baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 147baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned short page_size; 148baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned short cylinders; 149baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned short heads; 150baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned short sectors_per_track; 151baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 152baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char system; 153baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char read_only:1, 154f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov eject:1, 155baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov has_request:1, 156f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov data_dir:1, 157f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov active:1; 158baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char transfer_cmd; 159baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 160baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov int (*mrq_handler)(struct memstick_dev *card, 161baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct memstick_request **mrq); 162baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 163496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov 164496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov /* Default request setup function for data access method preferred by 165496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov * this host instance. 166496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov */ 167496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov void (*setup_transfer)(struct memstick_dev *card, 168496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov u64 offset, size_t length); 169496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov 170baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct attribute_group attr_group; 171baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 172baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct scatterlist req_sg[MSPRO_BLOCK_MAX_SEGS]; 173baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned int seg_count; 174baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned int current_seg; 175f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov unsigned int current_page; 176baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov}; 177baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 178baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstatic DEFINE_IDR(mspro_block_disk_idr); 179baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstatic DEFINE_MUTEX(mspro_block_disk_lock); 180baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 181f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubovstatic int mspro_block_complete_req(struct memstick_dev *card, int error); 182f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov 183baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov/*** Block device ***/ 184baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1855d9a54b66584bdae90e88198ce763702545a68e7Al Virostatic int mspro_block_bd_open(struct block_device *bdev, fmode_t mode) 186baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 1875d9a54b66584bdae90e88198ce763702545a68e7Al Viro struct gendisk *disk = bdev->bd_disk; 188baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_block_data *msb = disk->private_data; 189baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov int rc = -ENXIO; 190baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 191baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov mutex_lock(&mspro_block_disk_lock); 192baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 193baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (msb && msb->card) { 194baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->usage_count++; 1955d9a54b66584bdae90e88198ce763702545a68e7Al Viro if ((mode & FMODE_WRITE) && msb->read_only) 196baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc = -EROFS; 197baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov else 198baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc = 0; 199baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 200baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 201baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov mutex_unlock(&mspro_block_disk_lock); 202baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 203baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return rc; 204baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 205baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 206baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 207baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstatic int mspro_block_disk_release(struct gendisk *disk) 208baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 209baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_block_data *msb = disk->private_data; 210f331c0296f2a9fee0d396a70598b954062603015Tejun Heo int disk_id = MINOR(disk_devt(disk)) >> MSPRO_BLOCK_PART_SHIFT; 211baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 212baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov mutex_lock(&mspro_block_disk_lock); 213baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 214f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov if (msb) { 215f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov if (msb->usage_count) 216f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov msb->usage_count--; 217f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov 218baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (!msb->usage_count) { 219baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov kfree(msb); 220baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov disk->private_data = NULL; 221baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov idr_remove(&mspro_block_disk_idr, disk_id); 222baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov put_disk(disk); 223baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 224baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 225baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 226baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov mutex_unlock(&mspro_block_disk_lock); 227baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 228baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return 0; 229baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 230baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 2315d9a54b66584bdae90e88198ce763702545a68e7Al Virostatic int mspro_block_bd_release(struct gendisk *disk, fmode_t mode) 232baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 233edb50b3b1d9bf6d51dc68f7f885e78285f8d6f18Alex Dubov return mspro_block_disk_release(disk); 234baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 235baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 236baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstatic int mspro_block_bd_getgeo(struct block_device *bdev, 237baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct hd_geometry *geo) 238baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 239baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_block_data *msb = bdev->bd_disk->private_data; 240baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 241baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov geo->heads = msb->heads; 242baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov geo->sectors = msb->sectors_per_track; 243baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov geo->cylinders = msb->cylinders; 244baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 245baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return 0; 246baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 247baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 24883d5cde47dedf01b6a4a4331882cbc0a7eea3c2eAlexey Dobriyanstatic const struct block_device_operations ms_block_bdops = { 2495d9a54b66584bdae90e88198ce763702545a68e7Al Viro .open = mspro_block_bd_open, 2505d9a54b66584bdae90e88198ce763702545a68e7Al Viro .release = mspro_block_bd_release, 251baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov .getgeo = mspro_block_bd_getgeo, 252baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov .owner = THIS_MODULE 253baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov}; 254baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 255baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov/*** Information ***/ 256baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 257baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstatic struct mspro_sys_attr *mspro_from_sysfs_attr(struct attribute *attr) 258baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 259baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct device_attribute *dev_attr 260baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov = container_of(attr, struct device_attribute, attr); 261baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return container_of(dev_attr, struct mspro_sys_attr, dev_attr); 262baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 263baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 264baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstatic const char *mspro_block_attr_name(unsigned char tag) 265baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 266baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov switch (tag) { 267baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov case MSPRO_BLOCK_ID_SYSINFO: 268baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return "attr_sysinfo"; 269baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov case MSPRO_BLOCK_ID_MODELNAME: 270baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return "attr_modelname"; 271baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov case MSPRO_BLOCK_ID_MBR: 272baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return "attr_mbr"; 273baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov case MSPRO_BLOCK_ID_PBR16: 274baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return "attr_pbr16"; 275baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov case MSPRO_BLOCK_ID_PBR32: 276baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return "attr_pbr32"; 277baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov case MSPRO_BLOCK_ID_SPECFILEVALUES1: 278baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return "attr_specfilevalues1"; 279baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov case MSPRO_BLOCK_ID_SPECFILEVALUES2: 280baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return "attr_specfilevalues2"; 281baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov case MSPRO_BLOCK_ID_DEVINFO: 282baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return "attr_devinfo"; 283baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov default: 284baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return NULL; 285baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov }; 286baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 287baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 288baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovtypedef ssize_t (*sysfs_show_t)(struct device *dev, 289baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct device_attribute *attr, 290baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov char *buffer); 291baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 292baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstatic ssize_t mspro_block_attr_show_default(struct device *dev, 293baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct device_attribute *attr, 294baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov char *buffer) 295baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 296baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_sys_attr *s_attr = container_of(attr, 297baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_sys_attr, 298baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov dev_attr); 299baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 300baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov ssize_t cnt, rc = 0; 301baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 302baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov for (cnt = 0; cnt < s_attr->size; cnt++) { 303baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (cnt && !(cnt % 16)) { 304baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (PAGE_SIZE - rc) 305baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov buffer[rc++] = '\n'; 306baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 307baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 308baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "%02x ", 309baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov ((unsigned char *)s_attr->data)[cnt]); 310baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 311baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return rc; 312baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 313baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 314baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstatic ssize_t mspro_block_attr_show_sysinfo(struct device *dev, 315baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct device_attribute *attr, 316baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov char *buffer) 317baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 318baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_sys_attr *x_attr = container_of(attr, 319baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_sys_attr, 320baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov dev_attr); 321baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_sys_info *x_sys = x_attr->data; 322baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov ssize_t rc = 0; 323251cc9b9df065cb2c170ea45f566c0d9456186c2Alex Dubov int date_tz = 0, date_tz_f = 0; 324251cc9b9df065cb2c170ea45f566c0d9456186c2Alex Dubov 325251cc9b9df065cb2c170ea45f566c0d9456186c2Alex Dubov if (x_sys->assembly_date[0] > 0x80U) { 326251cc9b9df065cb2c170ea45f566c0d9456186c2Alex Dubov date_tz = (~x_sys->assembly_date[0]) + 1; 327251cc9b9df065cb2c170ea45f566c0d9456186c2Alex Dubov date_tz_f = date_tz & 3; 328251cc9b9df065cb2c170ea45f566c0d9456186c2Alex Dubov date_tz >>= 2; 329251cc9b9df065cb2c170ea45f566c0d9456186c2Alex Dubov date_tz = -date_tz; 330251cc9b9df065cb2c170ea45f566c0d9456186c2Alex Dubov date_tz_f *= 15; 331251cc9b9df065cb2c170ea45f566c0d9456186c2Alex Dubov } else if (x_sys->assembly_date[0] < 0x80U) { 332251cc9b9df065cb2c170ea45f566c0d9456186c2Alex Dubov date_tz = x_sys->assembly_date[0]; 333251cc9b9df065cb2c170ea45f566c0d9456186c2Alex Dubov date_tz_f = date_tz & 3; 334251cc9b9df065cb2c170ea45f566c0d9456186c2Alex Dubov date_tz >>= 2; 335251cc9b9df065cb2c170ea45f566c0d9456186c2Alex Dubov date_tz_f *= 15; 336251cc9b9df065cb2c170ea45f566c0d9456186c2Alex Dubov } 337baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 338baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "class: %x\n", 339baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov x_sys->class); 340baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "block size: %x\n", 341baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov be16_to_cpu(x_sys->block_size)); 342baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "block count: %x\n", 343baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov be16_to_cpu(x_sys->block_count)); 344baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "user block count: %x\n", 345baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov be16_to_cpu(x_sys->user_block_count)); 346baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "page size: %x\n", 347baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov be16_to_cpu(x_sys->page_size)); 348baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "assembly date: " 349251cc9b9df065cb2c170ea45f566c0d9456186c2Alex Dubov "GMT%+d:%d %04u-%02u-%02u %02u:%02u:%02u\n", 350251cc9b9df065cb2c170ea45f566c0d9456186c2Alex Dubov date_tz, date_tz_f, 35169347a236b22c3962ea812511495e502dedfd50cHarvey Harrison be16_to_cpup((__be16 *)&x_sys->assembly_date[1]), 352baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov x_sys->assembly_date[3], x_sys->assembly_date[4], 353baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov x_sys->assembly_date[5], x_sys->assembly_date[6], 354baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov x_sys->assembly_date[7]); 355baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "serial number: %x\n", 356baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov be32_to_cpu(x_sys->serial_number)); 357baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, 358baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov "assembly maker code: %x\n", 359baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov x_sys->assembly_maker_code); 360baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "assembly model code: " 361baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov "%02x%02x%02x\n", x_sys->assembly_model_code[0], 362baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov x_sys->assembly_model_code[1], 363baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov x_sys->assembly_model_code[2]); 364baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "memory maker code: %x\n", 365baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov be16_to_cpu(x_sys->memory_maker_code)); 366baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "memory model code: %x\n", 367baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov be16_to_cpu(x_sys->memory_model_code)); 368baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "vcc: %x\n", 369baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov x_sys->vcc); 370baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "vpp: %x\n", 371baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov x_sys->vpp); 372baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "controller number: %x\n", 373baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov be16_to_cpu(x_sys->controller_number)); 374baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, 375baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov "controller function: %x\n", 376baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov be16_to_cpu(x_sys->controller_function)); 377baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "start sector: %x\n", 378baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov be16_to_cpu(x_sys->start_sector)); 379baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "unit size: %x\n", 380baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov be16_to_cpu(x_sys->unit_size)); 381baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "sub class: %x\n", 382baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov x_sys->ms_sub_class); 383baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "interface type: %x\n", 384baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov x_sys->interface_type); 385baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "controller code: %x\n", 386baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov be16_to_cpu(x_sys->controller_code)); 387baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "format type: %x\n", 388baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov x_sys->format_type); 389baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "device type: %x\n", 390baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov x_sys->device_type); 391baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "mspro id: %s\n", 392baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov x_sys->mspro_id); 393baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return rc; 394baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 395baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 396baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstatic ssize_t mspro_block_attr_show_modelname(struct device *dev, 397baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct device_attribute *attr, 398baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov char *buffer) 399baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 400baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_sys_attr *s_attr = container_of(attr, 401baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_sys_attr, 402baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov dev_attr); 403baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 404baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return scnprintf(buffer, PAGE_SIZE, "%s", (char *)s_attr->data); 405baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 406baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 407baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstatic ssize_t mspro_block_attr_show_mbr(struct device *dev, 408baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct device_attribute *attr, 409baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov char *buffer) 410baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 411baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_sys_attr *x_attr = container_of(attr, 412baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_sys_attr, 413baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov dev_attr); 414baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_mbr *x_mbr = x_attr->data; 415baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov ssize_t rc = 0; 416baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 417baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "boot partition: %x\n", 418baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov x_mbr->boot_partition); 419baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "start head: %x\n", 420baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov x_mbr->start_head); 421baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "start sector: %x\n", 422baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov x_mbr->start_sector); 423baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "start cylinder: %x\n", 424baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov x_mbr->start_cylinder); 425baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "partition type: %x\n", 426baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov x_mbr->partition_type); 427baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "end head: %x\n", 428baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov x_mbr->end_head); 429baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "end sector: %x\n", 430baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov x_mbr->end_sector); 431baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "end cylinder: %x\n", 432baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov x_mbr->end_cylinder); 433baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "start sectors: %x\n", 434baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov x_mbr->start_sectors); 435baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, 436baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov "sectors per partition: %x\n", 437baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov x_mbr->sectors_per_partition); 438baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return rc; 439baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 440baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 441efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubovstatic ssize_t mspro_block_attr_show_specfile(struct device *dev, 442efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov struct device_attribute *attr, 443efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov char *buffer) 444efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov{ 445efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov struct mspro_sys_attr *x_attr = container_of(attr, 446efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov struct mspro_sys_attr, 447efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov dev_attr); 448efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov struct mspro_specfile *x_spfile = x_attr->data; 449efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov char name[9], ext[4]; 450efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov ssize_t rc = 0; 451efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov 452efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov memcpy(name, x_spfile->name, 8); 453efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov name[8] = 0; 454efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov memcpy(ext, x_spfile->ext, 3); 455efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov ext[3] = 0; 456efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov 457efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "name: %s\n", name); 458efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "ext: %s\n", ext); 459efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "attribute: %x\n", 460efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov x_spfile->attr); 461efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "time: %d:%d:%d\n", 462efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov x_spfile->time >> 11, 463efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov (x_spfile->time >> 5) & 0x3f, 464efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov (x_spfile->time & 0x1f) * 2); 465efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "date: %d-%d-%d\n", 466efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov (x_spfile->date >> 9) + 1980, 467efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov (x_spfile->date >> 5) & 0xf, 468efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov x_spfile->date & 0x1f); 469efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "start cluster: %x\n", 470efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov x_spfile->cluster); 471efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "size: %x\n", 472efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov x_spfile->size); 473efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov return rc; 474efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov} 475efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov 476baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstatic ssize_t mspro_block_attr_show_devinfo(struct device *dev, 477baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct device_attribute *attr, 478baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov char *buffer) 479baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 480baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_sys_attr *x_attr = container_of(attr, 481baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_sys_attr, 482baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov dev_attr); 483baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_devinfo *x_devinfo = x_attr->data; 484baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov ssize_t rc = 0; 485baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 486baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "cylinders: %x\n", 487baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov be16_to_cpu(x_devinfo->cylinders)); 488baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "heads: %x\n", 489baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov be16_to_cpu(x_devinfo->heads)); 490baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "bytes per track: %x\n", 491baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov be16_to_cpu(x_devinfo->bytes_per_track)); 492baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "bytes per sector: %x\n", 493baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov be16_to_cpu(x_devinfo->bytes_per_sector)); 494baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "sectors per track: %x\n", 495baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov be16_to_cpu(x_devinfo->sectors_per_track)); 496baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return rc; 497baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 498baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 499baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstatic sysfs_show_t mspro_block_attr_show(unsigned char tag) 500baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 501baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov switch (tag) { 502baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov case MSPRO_BLOCK_ID_SYSINFO: 503baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return mspro_block_attr_show_sysinfo; 504baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov case MSPRO_BLOCK_ID_MODELNAME: 505baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return mspro_block_attr_show_modelname; 506baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov case MSPRO_BLOCK_ID_MBR: 507baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return mspro_block_attr_show_mbr; 508efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov case MSPRO_BLOCK_ID_SPECFILEVALUES1: 509efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov case MSPRO_BLOCK_ID_SPECFILEVALUES2: 510efb2742e5ddd03197fcf066e2d2a75d36cf04fd1Alex Dubov return mspro_block_attr_show_specfile; 511baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov case MSPRO_BLOCK_ID_DEVINFO: 512baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return mspro_block_attr_show_devinfo; 513baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov default: 514baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return mspro_block_attr_show_default; 515baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 516baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 517baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 518baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov/*** Protocol handlers ***/ 519baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 520baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov/* 521baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov * Functions prefixed with "h_" are protocol callbacks. They can be called from 522baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov * interrupt context. Return value of 0 means that request processing is still 523baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov * ongoing, while special error value of -EAGAIN means that current request is 524baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov * finished (and request processor should come back some time later). 525baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov */ 526baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 527baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstatic int h_mspro_block_req_init(struct memstick_dev *card, 528baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct memstick_request **mrq) 529baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 530baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_block_data *msb = memstick_get_drvdata(card); 531baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 532baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov *mrq = &card->current_mrq; 533baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov card->next_request = msb->mrq_handler; 534baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return 0; 535baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 536baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 537baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstatic int h_mspro_block_default(struct memstick_dev *card, 538baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct memstick_request **mrq) 539baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 540f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov return mspro_block_complete_req(card, (*mrq)->error); 541f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov} 542f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov 543f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubovstatic int h_mspro_block_default_bad(struct memstick_dev *card, 544f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov struct memstick_request **mrq) 545f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov{ 546f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov return -ENXIO; 547baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 548baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 549baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstatic int h_mspro_block_get_ro(struct memstick_dev *card, 550baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct memstick_request **mrq) 551baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 552baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_block_data *msb = memstick_get_drvdata(card); 553baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 554f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov if (!(*mrq)->error) { 555f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov if ((*mrq)->data[offsetof(struct ms_status_register, status0)] 556f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov & MEMSTICK_STATUS0_WP) 557f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov msb->read_only = 1; 558f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov else 559f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov msb->read_only = 0; 560baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 561baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 562f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov return mspro_block_complete_req(card, (*mrq)->error); 563baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 564baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 565baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstatic int h_mspro_block_wait_for_ced(struct memstick_dev *card, 566baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct memstick_request **mrq) 567baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 568baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov dev_dbg(&card->dev, "wait for ced: value %x\n", (*mrq)->data[0]); 569baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 570f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov if (!(*mrq)->error) { 571f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov if ((*mrq)->data[0] & (MEMSTICK_INT_CMDNAK | MEMSTICK_INT_ERR)) 572f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov (*mrq)->error = -EFAULT; 573f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov else if (!((*mrq)->data[0] & MEMSTICK_INT_CED)) 574f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov return 0; 575baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 576baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 577f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov return mspro_block_complete_req(card, (*mrq)->error); 578baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 579baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 580baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstatic int h_mspro_block_transfer_data(struct memstick_dev *card, 581baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct memstick_request **mrq) 582baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 583baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_block_data *msb = memstick_get_drvdata(card); 584baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char t_val = 0; 585baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct scatterlist t_sg = { 0 }; 586baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov size_t t_offset; 587baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 588f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov if ((*mrq)->error) 589f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov return mspro_block_complete_req(card, (*mrq)->error); 590baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 591baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov switch ((*mrq)->tpc) { 592baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov case MS_TPC_WRITE_REG: 593baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov memstick_init_req(*mrq, MS_TPC_SET_CMD, &msb->transfer_cmd, 1); 594ead70773608a5d97f81cb492f117d20b5e9f323eAlex Dubov (*mrq)->need_card_int = 1; 595baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return 0; 596baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov case MS_TPC_SET_CMD: 597baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov t_val = (*mrq)->int_reg; 598baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov memstick_init_req(*mrq, MS_TPC_GET_INT, NULL, 1); 599ead70773608a5d97f81cb492f117d20b5e9f323eAlex Dubov if (msb->caps & MEMSTICK_CAP_AUTO_GET_INT) 600baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov goto has_int_reg; 601baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return 0; 602baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov case MS_TPC_GET_INT: 603baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov t_val = (*mrq)->data[0]; 604baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovhas_int_reg: 605baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (t_val & (MEMSTICK_INT_CMDNAK | MEMSTICK_INT_ERR)) { 606baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov t_val = MSPRO_CMD_STOP; 607baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov memstick_init_req(*mrq, MS_TPC_SET_CMD, &t_val, 1); 608baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov card->next_request = h_mspro_block_default; 609baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return 0; 610baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 611baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 612baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (msb->current_page 613baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov == (msb->req_sg[msb->current_seg].length 614baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov / msb->page_size)) { 615baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->current_page = 0; 616baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->current_seg++; 617baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 618baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (msb->current_seg == msb->seg_count) { 619baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (t_val & MEMSTICK_INT_CED) { 620f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov return mspro_block_complete_req(card, 621f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov 0); 622baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } else { 623baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov card->next_request 624baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov = h_mspro_block_wait_for_ced; 625baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov memstick_init_req(*mrq, MS_TPC_GET_INT, 626baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov NULL, 1); 627baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return 0; 628baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 629baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 630baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 631baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 632baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (!(t_val & MEMSTICK_INT_BREQ)) { 633baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov memstick_init_req(*mrq, MS_TPC_GET_INT, NULL, 1); 634baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return 0; 635baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 636baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 637baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov t_offset = msb->req_sg[msb->current_seg].offset; 638baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov t_offset += msb->current_page * msb->page_size; 639baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 640baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov sg_set_page(&t_sg, 641baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov nth_page(sg_page(&(msb->req_sg[msb->current_seg])), 642baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov t_offset >> PAGE_SHIFT), 643baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->page_size, offset_in_page(t_offset)); 644baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 645baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov memstick_init_req_sg(*mrq, msb->data_dir == READ 646baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov ? MS_TPC_READ_LONG_DATA 647baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov : MS_TPC_WRITE_LONG_DATA, 648baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov &t_sg); 649ead70773608a5d97f81cb492f117d20b5e9f323eAlex Dubov (*mrq)->need_card_int = 1; 650baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return 0; 651baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov case MS_TPC_READ_LONG_DATA: 652baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov case MS_TPC_WRITE_LONG_DATA: 653baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->current_page++; 654ead70773608a5d97f81cb492f117d20b5e9f323eAlex Dubov if (msb->caps & MEMSTICK_CAP_AUTO_GET_INT) { 655baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov t_val = (*mrq)->int_reg; 656baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov goto has_int_reg; 657baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } else { 658baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov memstick_init_req(*mrq, MS_TPC_GET_INT, NULL, 1); 659baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return 0; 660baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 661baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 662baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov default: 663baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov BUG(); 664baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 665baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 666baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 667496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov/*** Transfer setup functions for different access methods. ***/ 668496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov 669496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov/** Setup data transfer request for SET_CMD TPC with arguments in card 670496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov * registers. 671496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov * 672496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov * @card Current media instance 673496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov * @offset Target data offset in bytes 674496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov * @length Required transfer length in bytes. 675496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov */ 676496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubovstatic void h_mspro_block_setup_cmd(struct memstick_dev *card, u64 offset, 677496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov size_t length) 678496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov{ 679496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov struct mspro_block_data *msb = memstick_get_drvdata(card); 680496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov struct mspro_param_register param = { 681496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov .system = msb->system, 682496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov .data_count = cpu_to_be16((uint16_t)(length / msb->page_size)), 683496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov /* ISO C90 warning precludes direct initialization for now. */ 684496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov .data_address = 0, 685496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov .tpc_param = 0 686496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov }; 687496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov 688496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov do_div(offset, msb->page_size); 689496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov param.data_address = cpu_to_be32((uint32_t)offset); 690496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov 691496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov card->next_request = h_mspro_block_req_init; 692496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov msb->mrq_handler = h_mspro_block_transfer_data; 693496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov memstick_init_req(&card->current_mrq, MS_TPC_WRITE_REG, 694496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov ¶m, sizeof(param)); 695496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov} 696496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov 697baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov/*** Data transfer ***/ 698baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 699f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubovstatic int mspro_block_issue_req(struct memstick_dev *card, int chunk) 700baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 701baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_block_data *msb = memstick_get_drvdata(card); 702496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov u64 t_off; 703f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov unsigned int count; 704baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 705f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubovtry_again: 706f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov while (chunk) { 707f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov msb->current_page = 0; 708baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->current_seg = 0; 709f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov msb->seg_count = blk_rq_map_sg(msb->block_req->q, 710f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov msb->block_req, 711f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov msb->req_sg); 712baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 713f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov if (!msb->seg_count) { 714296b2f6ae654581adc27f0d6f0af454c7f3d06eeTejun Heo chunk = __blk_end_request_cur(msb->block_req, -ENOMEM); 715f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov continue; 716f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov } 717baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 718496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov t_off = blk_rq_pos(msb->block_req); 719496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov t_off <<= 9; 7201011c1b9f2e45ce7c6e38888d2b83936aec38771Tejun Heo count = blk_rq_bytes(msb->block_req); 721baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 722496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov msb->setup_transfer(card, t_off, count); 723f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov 724f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov msb->data_dir = rq_data_dir(msb->block_req); 725f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov msb->transfer_cmd = msb->data_dir == READ 726f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov ? MSPRO_CMD_READ_DATA 727f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov : MSPRO_CMD_WRITE_DATA; 728f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov 729f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov memstick_new_req(card->host); 730f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov return 0; 731f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov } 732f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov 7339934c8c04561413609d2bc38c6b9f268cba774a4Tejun Heo dev_dbg(&card->dev, "blk_fetch\n"); 7349934c8c04561413609d2bc38c6b9f268cba774a4Tejun Heo msb->block_req = blk_fetch_request(msb->queue); 735f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov if (!msb->block_req) { 736f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov dev_dbg(&card->dev, "issue end\n"); 737f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov return -EAGAIN; 738f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov } 739f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov 740f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov dev_dbg(&card->dev, "trying again\n"); 741f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov chunk = 1; 742f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov goto try_again; 743baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 744baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 745f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubovstatic int mspro_block_complete_req(struct memstick_dev *card, int error) 746baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 747f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov struct mspro_block_data *msb = memstick_get_drvdata(card); 748f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov int chunk, cnt; 749f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov unsigned int t_len = 0; 750baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned long flags; 751baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 752baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov spin_lock_irqsave(&msb->q_lock, flags); 753f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov dev_dbg(&card->dev, "complete %d, %d\n", msb->has_request ? 1 : 0, 754f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov error); 755f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov 756f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov if (msb->has_request) { 757f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov /* Nothing to do - not really an error */ 758f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov if (error == -EAGAIN) 759f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov error = 0; 760f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov 761f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov if (error || (card->current_mrq.tpc == MSPRO_CMD_STOP)) { 762f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov if (msb->data_dir == READ) { 763f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov for (cnt = 0; cnt < msb->current_seg; cnt++) 764f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov t_len += msb->req_sg[cnt].length 765f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov / msb->page_size; 766f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov 767f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov if (msb->current_page) 768f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov t_len += msb->current_page - 1; 769f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov 770f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov t_len *= msb->page_size; 771f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov } 772f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov } else 7731011c1b9f2e45ce7c6e38888d2b83936aec38771Tejun Heo t_len = blk_rq_bytes(msb->block_req); 774f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov 775f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov dev_dbg(&card->dev, "transferred %x (%d)\n", t_len, error); 776f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov 777f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov if (error && !t_len) 778f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov t_len = blk_rq_cur_bytes(msb->block_req); 779f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov 780f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov chunk = __blk_end_request(msb->block_req, error, t_len); 781f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov 782f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov error = mspro_block_issue_req(card, chunk); 783f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov 784f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov if (!error) 785f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov goto out; 786f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov else 787f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov msb->has_request = 0; 788f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov } else { 789f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov if (!error) 790f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov error = -EAGAIN; 791f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov } 792f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov 793f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov card->next_request = h_mspro_block_default_bad; 794f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov complete_all(&card->mrq_complete); 795f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubovout: 796baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov spin_unlock_irqrestore(&msb->q_lock, flags); 797f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov return error; 798baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 799baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 80017017d8d2c005734d7088d8281ce2daab8fcb097Alex Dubovstatic void mspro_block_stop(struct memstick_dev *card) 80117017d8d2c005734d7088d8281ce2daab8fcb097Alex Dubov{ 80217017d8d2c005734d7088d8281ce2daab8fcb097Alex Dubov struct mspro_block_data *msb = memstick_get_drvdata(card); 80317017d8d2c005734d7088d8281ce2daab8fcb097Alex Dubov int rc = 0; 80417017d8d2c005734d7088d8281ce2daab8fcb097Alex Dubov unsigned long flags; 80517017d8d2c005734d7088d8281ce2daab8fcb097Alex Dubov 80617017d8d2c005734d7088d8281ce2daab8fcb097Alex Dubov while (1) { 80717017d8d2c005734d7088d8281ce2daab8fcb097Alex Dubov spin_lock_irqsave(&msb->q_lock, flags); 80817017d8d2c005734d7088d8281ce2daab8fcb097Alex Dubov if (!msb->has_request) { 80917017d8d2c005734d7088d8281ce2daab8fcb097Alex Dubov blk_stop_queue(msb->queue); 81017017d8d2c005734d7088d8281ce2daab8fcb097Alex Dubov rc = 1; 81117017d8d2c005734d7088d8281ce2daab8fcb097Alex Dubov } 81217017d8d2c005734d7088d8281ce2daab8fcb097Alex Dubov spin_unlock_irqrestore(&msb->q_lock, flags); 81317017d8d2c005734d7088d8281ce2daab8fcb097Alex Dubov 81417017d8d2c005734d7088d8281ce2daab8fcb097Alex Dubov if (rc) 81517017d8d2c005734d7088d8281ce2daab8fcb097Alex Dubov break; 81617017d8d2c005734d7088d8281ce2daab8fcb097Alex Dubov 81717017d8d2c005734d7088d8281ce2daab8fcb097Alex Dubov wait_for_completion(&card->mrq_complete); 81817017d8d2c005734d7088d8281ce2daab8fcb097Alex Dubov } 81917017d8d2c005734d7088d8281ce2daab8fcb097Alex Dubov} 82017017d8d2c005734d7088d8281ce2daab8fcb097Alex Dubov 82117017d8d2c005734d7088d8281ce2daab8fcb097Alex Dubovstatic void mspro_block_start(struct memstick_dev *card) 82217017d8d2c005734d7088d8281ce2daab8fcb097Alex Dubov{ 82317017d8d2c005734d7088d8281ce2daab8fcb097Alex Dubov struct mspro_block_data *msb = memstick_get_drvdata(card); 82417017d8d2c005734d7088d8281ce2daab8fcb097Alex Dubov unsigned long flags; 82517017d8d2c005734d7088d8281ce2daab8fcb097Alex Dubov 82617017d8d2c005734d7088d8281ce2daab8fcb097Alex Dubov spin_lock_irqsave(&msb->q_lock, flags); 82717017d8d2c005734d7088d8281ce2daab8fcb097Alex Dubov blk_start_queue(msb->queue); 82817017d8d2c005734d7088d8281ce2daab8fcb097Alex Dubov spin_unlock_irqrestore(&msb->q_lock, flags); 82917017d8d2c005734d7088d8281ce2daab8fcb097Alex Dubov} 83017017d8d2c005734d7088d8281ce2daab8fcb097Alex Dubov 831f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubovstatic int mspro_block_prepare_req(struct request_queue *q, struct request *req) 832baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 83333659ebbae262228eef4e0fe990f393d1f0ed941Christoph Hellwig if (req->cmd_type != REQ_TYPE_FS && 83433659ebbae262228eef4e0fe990f393d1f0ed941Christoph Hellwig req->cmd_type != REQ_TYPE_BLOCK_PC) { 835f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov blk_dump_rq_flags(req, "MSPro unsupported request"); 836f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov return BLKPREP_KILL; 837f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov } 838baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 839f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov req->cmd_flags |= REQ_DONTPREP; 840baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 841f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov return BLKPREP_OK; 842baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 843baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 844f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubovstatic void mspro_block_submit_req(struct request_queue *q) 845baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 846baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct memstick_dev *card = q->queuedata; 847baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_block_data *msb = memstick_get_drvdata(card); 848baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct request *req = NULL; 849baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 850f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov if (msb->has_request) 851f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov return; 852f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov 853f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov if (msb->eject) { 8549934c8c04561413609d2bc38c6b9f268cba774a4Tejun Heo while ((req = blk_fetch_request(q)) != NULL) 85540cbbb781d3eba5d6ac0860db078af490e5c7c6bTejun Heo __blk_end_request_all(req, -ENODEV); 856f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov 857f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov return; 858baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 859f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov 860f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov msb->has_request = 1; 861f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov if (mspro_block_issue_req(card, 0)) 862f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov msb->has_request = 0; 863baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 864baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 865baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov/*** Initialization ***/ 866baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 867baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstatic int mspro_block_wait_for_ced(struct memstick_dev *card) 868baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 869baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_block_data *msb = memstick_get_drvdata(card); 870baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 871baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov card->next_request = h_mspro_block_req_init; 872baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->mrq_handler = h_mspro_block_wait_for_ced; 873baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov memstick_init_req(&card->current_mrq, MS_TPC_GET_INT, NULL, 1); 874baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov memstick_new_req(card->host); 875baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov wait_for_completion(&card->mrq_complete); 876baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return card->current_mrq.error; 877baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 878baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 879962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubovstatic int mspro_block_set_interface(struct memstick_dev *card, 880962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov unsigned char sys_reg) 881baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 882baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct memstick_host *host = card->host; 883baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_block_data *msb = memstick_get_drvdata(card); 884baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_param_register param = { 885962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov .system = sys_reg, 886baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov .data_count = 0, 887baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov .data_address = 0, 888e1f19995f55294fbb00ea22ba85d7b0d80ba3813Alex Dubov .tpc_param = 0 889baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov }; 890baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 891baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov card->next_request = h_mspro_block_req_init; 892baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->mrq_handler = h_mspro_block_default; 893baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov memstick_init_req(&card->current_mrq, MS_TPC_WRITE_REG, ¶m, 894baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov sizeof(param)); 895baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov memstick_new_req(host); 896baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov wait_for_completion(&card->mrq_complete); 897962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov return card->current_mrq.error; 898962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov} 899962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov 900962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubovstatic int mspro_block_switch_interface(struct memstick_dev *card) 901962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov{ 902962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov struct memstick_host *host = card->host; 903962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov struct mspro_block_data *msb = memstick_get_drvdata(card); 904962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov int rc = 0; 905962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov 9068e82f8c34b1759ae0d80fe96101746ec51fb1ba4Alex Dubovtry_again: 907962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov if (msb->caps & MEMSTICK_CAP_PAR4) 908962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov rc = mspro_block_set_interface(card, MEMSTICK_SYS_PAR4); 909962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov else 910962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov return 0; 911962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov 912962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov if (rc) { 913962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov printk(KERN_WARNING 914962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov "%s: could not switch to 4-bit mode, error %d\n", 9150252c3b4f0188ceb9ce48a340e6bfd17ab28afa7Kay Sievers dev_name(&card->dev), rc); 916962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov return 0; 917962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov } 918baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 919e1f19995f55294fbb00ea22ba85d7b0d80ba3813Alex Dubov msb->system = MEMSTICK_SYS_PAR4; 920e1f19995f55294fbb00ea22ba85d7b0d80ba3813Alex Dubov host->set_param(host, MEMSTICK_INTERFACE, MEMSTICK_PAR4); 921962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov printk(KERN_INFO "%s: switching to 4-bit parallel mode\n", 9220252c3b4f0188ceb9ce48a340e6bfd17ab28afa7Kay Sievers dev_name(&card->dev)); 923962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov 924962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov if (msb->caps & MEMSTICK_CAP_PAR8) { 925962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov rc = mspro_block_set_interface(card, MEMSTICK_SYS_PAR8); 926962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov 927962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov if (!rc) { 928962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov msb->system = MEMSTICK_SYS_PAR8; 929962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov host->set_param(host, MEMSTICK_INTERFACE, 930962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov MEMSTICK_PAR8); 931962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov printk(KERN_INFO 932962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov "%s: switching to 8-bit parallel mode\n", 9330252c3b4f0188ceb9ce48a340e6bfd17ab28afa7Kay Sievers dev_name(&card->dev)); 934962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov } else 935962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov printk(KERN_WARNING 936962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov "%s: could not switch to 8-bit mode, error %d\n", 9370252c3b4f0188ceb9ce48a340e6bfd17ab28afa7Kay Sievers dev_name(&card->dev), rc); 938962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov } 939baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 940baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov card->next_request = h_mspro_block_req_init; 941baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->mrq_handler = h_mspro_block_default; 942baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov memstick_init_req(&card->current_mrq, MS_TPC_GET_INT, NULL, 1); 943baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov memstick_new_req(card->host); 944baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov wait_for_completion(&card->mrq_complete); 945962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov rc = card->current_mrq.error; 946baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 947962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov if (rc) { 948962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov printk(KERN_WARNING 949962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov "%s: interface error, trying to fall back to serial\n", 9500252c3b4f0188ceb9ce48a340e6bfd17ab28afa7Kay Sievers dev_name(&card->dev)); 951593672582e71a688cf8c3fc1c59ec7c44d3799e5Alex Dubov msb->system = MEMSTICK_SYS_SERIAL; 952593672582e71a688cf8c3fc1c59ec7c44d3799e5Alex Dubov host->set_param(host, MEMSTICK_POWER, MEMSTICK_POWER_OFF); 953962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov msleep(10); 954593672582e71a688cf8c3fc1c59ec7c44d3799e5Alex Dubov host->set_param(host, MEMSTICK_POWER, MEMSTICK_POWER_ON); 955baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov host->set_param(host, MEMSTICK_INTERFACE, MEMSTICK_SERIAL); 956593672582e71a688cf8c3fc1c59ec7c44d3799e5Alex Dubov 957962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov rc = memstick_set_rw_addr(card); 958962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov if (!rc) 959962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov rc = mspro_block_set_interface(card, msb->system); 9608e82f8c34b1759ae0d80fe96101746ec51fb1ba4Alex Dubov 9618e82f8c34b1759ae0d80fe96101746ec51fb1ba4Alex Dubov if (!rc) { 9628e82f8c34b1759ae0d80fe96101746ec51fb1ba4Alex Dubov msleep(150); 9638e82f8c34b1759ae0d80fe96101746ec51fb1ba4Alex Dubov rc = mspro_block_wait_for_ced(card); 9648e82f8c34b1759ae0d80fe96101746ec51fb1ba4Alex Dubov if (rc) 9658e82f8c34b1759ae0d80fe96101746ec51fb1ba4Alex Dubov return rc; 9668e82f8c34b1759ae0d80fe96101746ec51fb1ba4Alex Dubov 9678e82f8c34b1759ae0d80fe96101746ec51fb1ba4Alex Dubov if (msb->caps & MEMSTICK_CAP_PAR8) { 9688e82f8c34b1759ae0d80fe96101746ec51fb1ba4Alex Dubov msb->caps &= ~MEMSTICK_CAP_PAR8; 9698e82f8c34b1759ae0d80fe96101746ec51fb1ba4Alex Dubov goto try_again; 9708e82f8c34b1759ae0d80fe96101746ec51fb1ba4Alex Dubov } 9718e82f8c34b1759ae0d80fe96101746ec51fb1ba4Alex Dubov } 972baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 973962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov return rc; 974baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 975baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 976baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov/* Memory allocated for attributes by this function should be freed by 97725985edcedea6396277003854657b5f3cb31a628Lucas De Marchi * mspro_block_data_clear, no matter if the initialization process succeeded 978baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov * or failed. 979baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov */ 980baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstatic int mspro_block_read_attributes(struct memstick_dev *card) 981baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 982baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_block_data *msb = memstick_get_drvdata(card); 983baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_attribute *attr = NULL; 984baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_sys_attr *s_attr = NULL; 985baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char *buffer = NULL; 986baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov int cnt, rc, attr_count; 987496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov /* While normally physical device offsets, represented here by 988496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov * attr_offset and attr_len will be of large numeric types, we can be 989496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov * sure, that attributes are close enough to the beginning of the 990496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov * device, to save ourselves some trouble. 991496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov */ 992496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov unsigned int addr, attr_offset = 0, attr_len = msb->page_size; 993baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 994baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov attr = kmalloc(msb->page_size, GFP_KERNEL); 995baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (!attr) 996baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return -ENOMEM; 997baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 998baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov sg_init_one(&msb->req_sg[0], attr, msb->page_size); 999baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->seg_count = 1; 1000baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->current_seg = 0; 1001baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->current_page = 0; 1002baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->data_dir = READ; 1003baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->transfer_cmd = MSPRO_CMD_READ_ATRB; 1004baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1005496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov msb->setup_transfer(card, attr_offset, attr_len); 1006496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov 1007baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov memstick_new_req(card->host); 1008baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov wait_for_completion(&card->mrq_complete); 1009baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (card->current_mrq.error) { 1010baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc = card->current_mrq.error; 1011baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov goto out_free_attr; 1012baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 1013baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1014baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (be16_to_cpu(attr->signature) != MSPRO_BLOCK_SIGNATURE) { 1015baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov printk(KERN_ERR "%s: unrecognized device signature %x\n", 10160252c3b4f0188ceb9ce48a340e6bfd17ab28afa7Kay Sievers dev_name(&card->dev), be16_to_cpu(attr->signature)); 1017baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc = -ENODEV; 1018baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov goto out_free_attr; 1019baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 1020baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1021baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (attr->count > MSPRO_BLOCK_MAX_ATTRIBUTES) { 1022baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov printk(KERN_WARNING "%s: way too many attribute entries\n", 10230252c3b4f0188ceb9ce48a340e6bfd17ab28afa7Kay Sievers dev_name(&card->dev)); 1024baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov attr_count = MSPRO_BLOCK_MAX_ATTRIBUTES; 1025baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } else 1026baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov attr_count = attr->count; 1027baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1028baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->attr_group.attrs = kzalloc((attr_count + 1) 1029baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov * sizeof(struct attribute), 1030baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov GFP_KERNEL); 1031baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (!msb->attr_group.attrs) { 1032baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc = -ENOMEM; 1033baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov goto out_free_attr; 1034baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 1035baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->attr_group.name = "media_attributes"; 1036baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1037496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov buffer = kmalloc(attr_len, GFP_KERNEL); 1038baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (!buffer) { 1039baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc = -ENOMEM; 1040baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov goto out_free_attr; 1041baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 1042496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov memcpy(buffer, (char *)attr, attr_len); 1043baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1044baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov for (cnt = 0; cnt < attr_count; ++cnt) { 1045baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov s_attr = kzalloc(sizeof(struct mspro_sys_attr), GFP_KERNEL); 1046baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (!s_attr) { 1047baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc = -ENOMEM; 1048baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov goto out_free_buffer; 1049baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 1050baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1051baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->attr_group.attrs[cnt] = &s_attr->dev_attr.attr; 1052baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov addr = be32_to_cpu(attr->entries[cnt].address); 1053496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov s_attr->size = be32_to_cpu(attr->entries[cnt].size); 1054baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov dev_dbg(&card->dev, "adding attribute %d: id %x, address %x, " 1055496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov "size %zx\n", cnt, attr->entries[cnt].id, addr, 1056496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov s_attr->size); 1057baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov s_attr->id = attr->entries[cnt].id; 1058baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (mspro_block_attr_name(s_attr->id)) 1059baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov snprintf(s_attr->name, sizeof(s_attr->name), "%s", 1060baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov mspro_block_attr_name(attr->entries[cnt].id)); 1061baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov else 1062baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov snprintf(s_attr->name, sizeof(s_attr->name), 1063baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov "attr_x%02x", attr->entries[cnt].id); 1064baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 106521fd0495ea61d53e0ebe575330e343ce4e6d2a61Maxim Levitsky sysfs_attr_init(&s_attr->dev_attr.attr); 1066baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov s_attr->dev_attr.attr.name = s_attr->name; 1067baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov s_attr->dev_attr.attr.mode = S_IRUGO; 1068baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov s_attr->dev_attr.show = mspro_block_attr_show(s_attr->id); 1069baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1070496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov if (!s_attr->size) 1071baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov continue; 1072baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1073496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov s_attr->data = kmalloc(s_attr->size, GFP_KERNEL); 1074baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (!s_attr->data) { 1075baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc = -ENOMEM; 1076baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov goto out_free_buffer; 1077baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 1078baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1079496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov if (((addr / msb->page_size) == (attr_offset / msb->page_size)) 1080496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov && (((addr + s_attr->size - 1) / msb->page_size) 1081496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov == (attr_offset / msb->page_size))) { 1082baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov memcpy(s_attr->data, buffer + addr % msb->page_size, 1083496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov s_attr->size); 1084baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov continue; 1085baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 1086baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1087496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov attr_offset = (addr / msb->page_size) * msb->page_size; 1088496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov 1089496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov if ((attr_offset + attr_len) < (addr + s_attr->size)) { 1090baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov kfree(buffer); 1091496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov attr_len = (((addr + s_attr->size) / msb->page_size) 1092496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov + 1 ) * msb->page_size - attr_offset; 1093496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov buffer = kmalloc(attr_len, GFP_KERNEL); 1094baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (!buffer) { 1095baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc = -ENOMEM; 1096baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov goto out_free_attr; 1097baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 1098baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 1099baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1100496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov sg_init_one(&msb->req_sg[0], buffer, attr_len); 1101baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->seg_count = 1; 1102baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->current_seg = 0; 1103baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->current_page = 0; 1104baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->data_dir = READ; 1105baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->transfer_cmd = MSPRO_CMD_READ_ATRB; 1106baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1107496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov dev_dbg(&card->dev, "reading attribute range %x, %x\n", 1108496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov attr_offset, attr_len); 1109baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1110496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov msb->setup_transfer(card, attr_offset, attr_len); 1111baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov memstick_new_req(card->host); 1112baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov wait_for_completion(&card->mrq_complete); 1113baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (card->current_mrq.error) { 1114baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc = card->current_mrq.error; 1115baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov goto out_free_buffer; 1116baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 1117baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1118496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov memcpy(s_attr->data, buffer + addr % msb->page_size, 1119496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov s_attr->size); 1120baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 1121baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1122baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc = 0; 1123baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovout_free_buffer: 1124baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov kfree(buffer); 1125baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovout_free_attr: 1126baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov kfree(attr); 1127baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return rc; 1128baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 1129baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1130baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstatic int mspro_block_init_card(struct memstick_dev *card) 1131baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 1132baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_block_data *msb = memstick_get_drvdata(card); 1133baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct memstick_host *host = card->host; 1134baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov int rc = 0; 1135baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1136e1f19995f55294fbb00ea22ba85d7b0d80ba3813Alex Dubov msb->system = MEMSTICK_SYS_SERIAL; 1137496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov msb->setup_transfer = h_mspro_block_setup_cmd; 1138496fc1a68a45ae159d26331775411f6fea36d4d3Alex Dubov 1139baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov card->reg_addr.r_offset = offsetof(struct mspro_register, status); 1140baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov card->reg_addr.r_length = sizeof(struct ms_status_register); 1141baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov card->reg_addr.w_offset = offsetof(struct mspro_register, param); 1142baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov card->reg_addr.w_length = sizeof(struct mspro_param_register); 1143baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1144baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (memstick_set_rw_addr(card)) 1145baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return -EIO; 1146baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1147ead70773608a5d97f81cb492f117d20b5e9f323eAlex Dubov msb->caps = host->caps; 11488e82f8c34b1759ae0d80fe96101746ec51fb1ba4Alex Dubov 11498e82f8c34b1759ae0d80fe96101746ec51fb1ba4Alex Dubov msleep(150); 11508e82f8c34b1759ae0d80fe96101746ec51fb1ba4Alex Dubov rc = mspro_block_wait_for_ced(card); 1151962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov if (rc) 1152962ee1b10bff5e99e9ecb2a5f4e6399a0214c9cfAlex Dubov return rc; 1153baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 11548e82f8c34b1759ae0d80fe96101746ec51fb1ba4Alex Dubov rc = mspro_block_switch_interface(card); 1155baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (rc) 1156baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return rc; 11578e82f8c34b1759ae0d80fe96101746ec51fb1ba4Alex Dubov 1158baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov dev_dbg(&card->dev, "card activated\n"); 1159ead70773608a5d97f81cb492f117d20b5e9f323eAlex Dubov if (msb->system != MEMSTICK_SYS_SERIAL) 1160ead70773608a5d97f81cb492f117d20b5e9f323eAlex Dubov msb->caps |= MEMSTICK_CAP_AUTO_GET_INT; 1161baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1162baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov card->next_request = h_mspro_block_req_init; 1163baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->mrq_handler = h_mspro_block_get_ro; 1164baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov memstick_init_req(&card->current_mrq, MS_TPC_READ_REG, NULL, 1165baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov sizeof(struct ms_status_register)); 1166baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov memstick_new_req(card->host); 1167baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov wait_for_completion(&card->mrq_complete); 1168baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (card->current_mrq.error) 1169baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return card->current_mrq.error; 1170baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1171baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov dev_dbg(&card->dev, "card r/w status %d\n", msb->read_only ? 0 : 1); 1172baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1173baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->page_size = 512; 1174baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc = mspro_block_read_attributes(card); 1175baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (rc) 1176baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return rc; 1177baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1178baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov dev_dbg(&card->dev, "attributes loaded\n"); 1179baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return 0; 1180baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1181baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 1182baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1183baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstatic int mspro_block_init_disk(struct memstick_dev *card) 1184baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 1185baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_block_data *msb = memstick_get_drvdata(card); 1186baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct memstick_host *host = card->host; 1187baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_devinfo *dev_info = NULL; 1188baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_sys_info *sys_info = NULL; 1189baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_sys_attr *s_attr = NULL; 1190baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov int rc, disk_id; 1191baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov u64 limit = BLK_BOUNCE_HIGH; 1192baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned long capacity; 1193baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1194c4c66cf1787d408066fbfc69209185701f5df15fGreg Kroah-Hartman if (host->dev.dma_mask && *(host->dev.dma_mask)) 1195c4c66cf1787d408066fbfc69209185701f5df15fGreg Kroah-Hartman limit = *(host->dev.dma_mask); 1196baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1197baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov for (rc = 0; msb->attr_group.attrs[rc]; ++rc) { 1198baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov s_attr = mspro_from_sysfs_attr(msb->attr_group.attrs[rc]); 1199baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1200baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (s_attr->id == MSPRO_BLOCK_ID_DEVINFO) 1201baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov dev_info = s_attr->data; 1202baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov else if (s_attr->id == MSPRO_BLOCK_ID_SYSINFO) 1203baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov sys_info = s_attr->data; 1204baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 1205baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1206baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (!dev_info || !sys_info) 1207baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return -ENODEV; 1208baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1209baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->cylinders = be16_to_cpu(dev_info->cylinders); 1210baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->heads = be16_to_cpu(dev_info->heads); 1211baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->sectors_per_track = be16_to_cpu(dev_info->sectors_per_track); 1212baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1213baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->page_size = be16_to_cpu(sys_info->unit_size); 1214baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1215d8256d487840f9c2c372f8fc615a5d378bc133f1Alex Dubov mutex_lock(&mspro_block_disk_lock); 1216d8256d487840f9c2c372f8fc615a5d378bc133f1Alex Dubov if (!idr_pre_get(&mspro_block_disk_idr, GFP_KERNEL)) { 1217d8256d487840f9c2c372f8fc615a5d378bc133f1Alex Dubov mutex_unlock(&mspro_block_disk_lock); 1218baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return -ENOMEM; 1219d8256d487840f9c2c372f8fc615a5d378bc133f1Alex Dubov } 1220baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1221baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc = idr_get_new(&mspro_block_disk_idr, card, &disk_id); 1222baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov mutex_unlock(&mspro_block_disk_lock); 1223baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1224baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (rc) 1225baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return rc; 1226baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 12278e82f8c34b1759ae0d80fe96101746ec51fb1ba4Alex Dubov if ((disk_id << MSPRO_BLOCK_PART_SHIFT) > 255) { 1228baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc = -ENOSPC; 1229baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov goto out_release_id; 1230baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 1231baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 12328e82f8c34b1759ae0d80fe96101746ec51fb1ba4Alex Dubov msb->disk = alloc_disk(1 << MSPRO_BLOCK_PART_SHIFT); 1233baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (!msb->disk) { 1234baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc = -ENOMEM; 1235baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov goto out_release_id; 1236baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 1237baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1238f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov msb->queue = blk_init_queue(mspro_block_submit_req, &msb->q_lock); 1239baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (!msb->queue) { 1240baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc = -ENOMEM; 1241baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov goto out_put_disk; 1242baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 1243baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1244baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->queue->queuedata = card; 1245f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov blk_queue_prep_rq(msb->queue, mspro_block_prepare_req); 1246baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1247baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov blk_queue_bounce_limit(msb->queue, limit); 1248086fa5ff0854c676ec333760f4c0154b3b242616Martin K. Petersen blk_queue_max_hw_sectors(msb->queue, MSPRO_BLOCK_MAX_PAGES); 12498a78362c4eefc1deddbefe2c7f38aabbc2429d6bMartin K. Petersen blk_queue_max_segments(msb->queue, MSPRO_BLOCK_MAX_SEGS); 1250baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov blk_queue_max_segment_size(msb->queue, 1251baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov MSPRO_BLOCK_MAX_PAGES * msb->page_size); 1252baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1253baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->disk->major = major; 12548e82f8c34b1759ae0d80fe96101746ec51fb1ba4Alex Dubov msb->disk->first_minor = disk_id << MSPRO_BLOCK_PART_SHIFT; 1255baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->disk->fops = &ms_block_bdops; 1256baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->usage_count = 1; 1257baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->disk->private_data = msb; 1258baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->disk->queue = msb->queue; 1259baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->disk->driverfs_dev = &card->dev; 1260baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1261baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov sprintf(msb->disk->disk_name, "mspblk%d", disk_id); 1262baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1263e1defc4ff0cf57aca6c5e3ff99fa503f5943c1f1Martin K. Petersen blk_queue_logical_block_size(msb->queue, msb->page_size); 1264baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1265baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov capacity = be16_to_cpu(sys_info->user_block_count); 1266baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov capacity *= be16_to_cpu(sys_info->block_size); 1267baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov capacity *= msb->page_size >> 9; 1268baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov set_capacity(msb->disk, capacity); 1269baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov dev_dbg(&card->dev, "capacity set %ld\n", capacity); 1270baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1271baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov add_disk(msb->disk); 1272baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->active = 1; 1273baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return 0; 1274baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1275baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovout_put_disk: 1276baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov put_disk(msb->disk); 1277baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovout_release_id: 1278baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov mutex_lock(&mspro_block_disk_lock); 1279baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov idr_remove(&mspro_block_disk_idr, disk_id); 1280baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov mutex_unlock(&mspro_block_disk_lock); 1281baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return rc; 1282baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 1283baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1284baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstatic void mspro_block_data_clear(struct mspro_block_data *msb) 1285baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 1286baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov int cnt; 1287baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_sys_attr *s_attr; 1288baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1289baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (msb->attr_group.attrs) { 1290baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov for (cnt = 0; msb->attr_group.attrs[cnt]; ++cnt) { 1291baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov s_attr = mspro_from_sysfs_attr(msb->attr_group 1292baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov .attrs[cnt]); 1293baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov kfree(s_attr->data); 1294baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov kfree(s_attr); 1295baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 1296baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov kfree(msb->attr_group.attrs); 1297baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 1298baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1299baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->card = NULL; 1300baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 1301baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1302baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstatic int mspro_block_check_card(struct memstick_dev *card) 1303baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 1304baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_block_data *msb = memstick_get_drvdata(card); 1305baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1306baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return (msb->active == 1); 1307baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 1308baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1309baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstatic int mspro_block_probe(struct memstick_dev *card) 1310baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 1311baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_block_data *msb; 1312baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov int rc = 0; 1313baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1314baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb = kzalloc(sizeof(struct mspro_block_data), GFP_KERNEL); 1315baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (!msb) 1316baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return -ENOMEM; 1317baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov memstick_set_drvdata(card, msb); 1318baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov msb->card = card; 1319f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov spin_lock_init(&msb->q_lock); 1320baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1321baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc = mspro_block_init_card(card); 1322baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1323baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (rc) 1324baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov goto out_free; 1325baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1326baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc = sysfs_create_group(&card->dev.kobj, &msb->attr_group); 1327baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (rc) 1328baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov goto out_free; 1329baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1330baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc = mspro_block_init_disk(card); 1331baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (!rc) { 1332baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov card->check = mspro_block_check_card; 133317017d8d2c005734d7088d8281ce2daab8fcb097Alex Dubov card->stop = mspro_block_stop; 133417017d8d2c005734d7088d8281ce2daab8fcb097Alex Dubov card->start = mspro_block_start; 1335baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return 0; 1336baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 1337baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1338baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov sysfs_remove_group(&card->dev.kobj, &msb->attr_group); 1339baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovout_free: 1340baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov memstick_set_drvdata(card, NULL); 1341baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov mspro_block_data_clear(msb); 1342baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov kfree(msb); 1343baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return rc; 1344baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 1345baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1346baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstatic void mspro_block_remove(struct memstick_dev *card) 1347baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 1348baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_block_data *msb = memstick_get_drvdata(card); 1349baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned long flags; 1350baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1351baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov spin_lock_irqsave(&msb->q_lock, flags); 1352f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov msb->eject = 1; 1353f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov blk_start_queue(msb->queue); 1354baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov spin_unlock_irqrestore(&msb->q_lock, flags); 1355baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1356d862b13bc8cbab9692fbe0ef44c40d0488b81af1Maxim Levitsky del_gendisk(msb->disk); 1357d862b13bc8cbab9692fbe0ef44c40d0488b81af1Maxim Levitsky dev_dbg(&card->dev, "mspro block remove\n"); 1358d862b13bc8cbab9692fbe0ef44c40d0488b81af1Maxim Levitsky 1359baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov blk_cleanup_queue(msb->queue); 1360f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov msb->queue = NULL; 1361baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1362baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov sysfs_remove_group(&card->dev.kobj, &msb->attr_group); 1363baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1364baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov mutex_lock(&mspro_block_disk_lock); 1365baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov mspro_block_data_clear(msb); 1366baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov mutex_unlock(&mspro_block_disk_lock); 1367baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1368baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov mspro_block_disk_release(msb->disk); 1369baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov memstick_set_drvdata(card, NULL); 1370baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 1371baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1372baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov#ifdef CONFIG_PM 1373baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1374baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstatic int mspro_block_suspend(struct memstick_dev *card, pm_message_t state) 1375baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 1376baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_block_data *msb = memstick_get_drvdata(card); 1377baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned long flags; 1378baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1379baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov spin_lock_irqsave(&msb->q_lock, flags); 1380baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov blk_stop_queue(msb->queue); 1381f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov msb->active = 0; 1382baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov spin_unlock_irqrestore(&msb->q_lock, flags); 1383baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1384baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return 0; 1385baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 1386baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1387baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstatic int mspro_block_resume(struct memstick_dev *card) 1388baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 1389baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_block_data *msb = memstick_get_drvdata(card); 1390baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned long flags; 1391baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov int rc = 0; 1392baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1393baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov#ifdef CONFIG_MEMSTICK_UNSAFE_RESUME 1394baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1395baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_block_data *new_msb; 1396baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct memstick_host *host = card->host; 1397baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov struct mspro_sys_attr *s_attr, *r_attr; 1398baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unsigned char cnt; 1399baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1400baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov mutex_lock(&host->lock); 1401baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov new_msb = kzalloc(sizeof(struct mspro_block_data), GFP_KERNEL); 1402baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (!new_msb) { 1403baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc = -ENOMEM; 1404baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov goto out_unlock; 1405baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 1406baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1407baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov new_msb->card = card; 1408baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov memstick_set_drvdata(card, new_msb); 1409baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (mspro_block_init_card(card)) 1410baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov goto out_free; 1411baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1412baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov for (cnt = 0; new_msb->attr_group.attrs[cnt] 1413baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov && msb->attr_group.attrs[cnt]; ++cnt) { 1414baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov s_attr = mspro_from_sysfs_attr(new_msb->attr_group.attrs[cnt]); 1415baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov r_attr = mspro_from_sysfs_attr(msb->attr_group.attrs[cnt]); 1416baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1417baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (s_attr->id == MSPRO_BLOCK_ID_SYSINFO 1418baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov && r_attr->id == s_attr->id) { 1419baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (memcmp(s_attr->data, r_attr->data, s_attr->size)) 1420baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov break; 1421baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1422f1d82698029b92a88f5500b99f66514b6dee2bc3Alex Dubov msb->active = 1; 1423baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov break; 1424baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 1425baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 1426baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1427baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovout_free: 1428baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov memstick_set_drvdata(card, msb); 1429baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov mspro_block_data_clear(new_msb); 1430baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov kfree(new_msb); 1431baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovout_unlock: 1432baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov mutex_unlock(&host->lock); 1433baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1434baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov#endif /* CONFIG_MEMSTICK_UNSAFE_RESUME */ 1435baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1436baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov spin_lock_irqsave(&msb->q_lock, flags); 1437baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov blk_start_queue(msb->queue); 1438baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov spin_unlock_irqrestore(&msb->q_lock, flags); 1439baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return rc; 1440baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 1441baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1442baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov#else 1443baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1444baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov#define mspro_block_suspend NULL 1445baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov#define mspro_block_resume NULL 1446baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1447baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov#endif /* CONFIG_PM */ 1448baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1449baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstatic struct memstick_device_id mspro_block_id_tbl[] = { 1450baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov {MEMSTICK_MATCH_ALL, MEMSTICK_TYPE_PRO, MEMSTICK_CATEGORY_STORAGE_DUO, 14518e82f8c34b1759ae0d80fe96101746ec51fb1ba4Alex Dubov MEMSTICK_CLASS_DUO}, 1452baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov {} 1453baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov}; 1454baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1455baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1456baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstatic struct memstick_driver mspro_block_driver = { 1457baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov .driver = { 1458baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov .name = DRIVER_NAME, 1459baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov .owner = THIS_MODULE 1460baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov }, 1461baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov .id_table = mspro_block_id_tbl, 1462baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov .probe = mspro_block_probe, 1463baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov .remove = mspro_block_remove, 1464baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov .suspend = mspro_block_suspend, 1465baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov .resume = mspro_block_resume 1466baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov}; 1467baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1468baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstatic int __init mspro_block_init(void) 1469baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 1470baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov int rc = -ENOMEM; 1471baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1472baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc = register_blkdev(major, DRIVER_NAME); 1473baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (rc < 0) { 1474baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov printk(KERN_ERR DRIVER_NAME ": failed to register " 1475baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov "major %d, error %d\n", major, rc); 1476baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return rc; 1477baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov } 1478baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (!major) 1479baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov major = rc; 1480baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1481baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov rc = memstick_register_driver(&mspro_block_driver); 1482baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov if (rc) 1483baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unregister_blkdev(major, DRIVER_NAME); 1484baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov return rc; 1485baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 1486baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1487baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovstatic void __exit mspro_block_exit(void) 1488baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov{ 1489baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov memstick_unregister_driver(&mspro_block_driver); 1490baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov unregister_blkdev(major, DRIVER_NAME); 1491baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov idr_destroy(&mspro_block_disk_idr); 1492baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov} 1493baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1494baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovmodule_init(mspro_block_init); 1495baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubovmodule_exit(mspro_block_exit); 1496baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex Dubov 1497baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex DubovMODULE_LICENSE("GPL"); 1498baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex DubovMODULE_AUTHOR("Alex Dubov"); 1499baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex DubovMODULE_DESCRIPTION("Sony MemoryStickPro block device driver"); 1500baf8532a147d5b76681ce040e2c8f25a3f0e718dAlex DubovMODULE_DEVICE_TABLE(memstick, mspro_block_id_tbl); 1501