162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Sony MemoryStick support 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2007 Alex Dubov <oakad@yahoo.com> 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Special thanks to Carlos Corbacho for providing various MemoryStick cards 862306a36Sopenharmony_ci * that made this driver possible. 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/memstick.h> 1262306a36Sopenharmony_ci#include <linux/idr.h> 1362306a36Sopenharmony_ci#include <linux/fs.h> 1462306a36Sopenharmony_ci#include <linux/delay.h> 1562306a36Sopenharmony_ci#include <linux/slab.h> 1662306a36Sopenharmony_ci#include <linux/module.h> 1762306a36Sopenharmony_ci#include <linux/pm_runtime.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#define DRIVER_NAME "memstick" 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistatic unsigned int cmd_retries = 3; 2262306a36Sopenharmony_cimodule_param(cmd_retries, uint, 0644); 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_cistatic struct workqueue_struct *workqueue; 2562306a36Sopenharmony_cistatic DEFINE_IDR(memstick_host_idr); 2662306a36Sopenharmony_cistatic DEFINE_SPINLOCK(memstick_host_lock); 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistatic int memstick_dev_match(struct memstick_dev *card, 2962306a36Sopenharmony_ci struct memstick_device_id *id) 3062306a36Sopenharmony_ci{ 3162306a36Sopenharmony_ci if (id->match_flags & MEMSTICK_MATCH_ALL) { 3262306a36Sopenharmony_ci if ((id->type == card->id.type) 3362306a36Sopenharmony_ci && (id->category == card->id.category) 3462306a36Sopenharmony_ci && (id->class == card->id.class)) 3562306a36Sopenharmony_ci return 1; 3662306a36Sopenharmony_ci } 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci return 0; 3962306a36Sopenharmony_ci} 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_cistatic int memstick_bus_match(struct device *dev, struct device_driver *drv) 4262306a36Sopenharmony_ci{ 4362306a36Sopenharmony_ci struct memstick_dev *card = container_of(dev, struct memstick_dev, 4462306a36Sopenharmony_ci dev); 4562306a36Sopenharmony_ci struct memstick_driver *ms_drv = container_of(drv, 4662306a36Sopenharmony_ci struct memstick_driver, 4762306a36Sopenharmony_ci driver); 4862306a36Sopenharmony_ci struct memstick_device_id *ids = ms_drv->id_table; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci if (ids) { 5162306a36Sopenharmony_ci while (ids->match_flags) { 5262306a36Sopenharmony_ci if (memstick_dev_match(card, ids)) 5362306a36Sopenharmony_ci return 1; 5462306a36Sopenharmony_ci ++ids; 5562306a36Sopenharmony_ci } 5662306a36Sopenharmony_ci } 5762306a36Sopenharmony_ci return 0; 5862306a36Sopenharmony_ci} 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_cistatic int memstick_uevent(const struct device *dev, struct kobj_uevent_env *env) 6162306a36Sopenharmony_ci{ 6262306a36Sopenharmony_ci const struct memstick_dev *card = container_of_const(dev, struct memstick_dev, 6362306a36Sopenharmony_ci dev); 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci if (add_uevent_var(env, "MEMSTICK_TYPE=%02X", card->id.type)) 6662306a36Sopenharmony_ci return -ENOMEM; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci if (add_uevent_var(env, "MEMSTICK_CATEGORY=%02X", card->id.category)) 6962306a36Sopenharmony_ci return -ENOMEM; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci if (add_uevent_var(env, "MEMSTICK_CLASS=%02X", card->id.class)) 7262306a36Sopenharmony_ci return -ENOMEM; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci return 0; 7562306a36Sopenharmony_ci} 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistatic int memstick_device_probe(struct device *dev) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci struct memstick_dev *card = container_of(dev, struct memstick_dev, 8062306a36Sopenharmony_ci dev); 8162306a36Sopenharmony_ci struct memstick_driver *drv = container_of(dev->driver, 8262306a36Sopenharmony_ci struct memstick_driver, 8362306a36Sopenharmony_ci driver); 8462306a36Sopenharmony_ci int rc = -ENODEV; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci if (dev->driver && drv->probe) { 8762306a36Sopenharmony_ci rc = drv->probe(card); 8862306a36Sopenharmony_ci if (!rc) 8962306a36Sopenharmony_ci get_device(dev); 9062306a36Sopenharmony_ci } 9162306a36Sopenharmony_ci return rc; 9262306a36Sopenharmony_ci} 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_cistatic void memstick_device_remove(struct device *dev) 9562306a36Sopenharmony_ci{ 9662306a36Sopenharmony_ci struct memstick_dev *card = container_of(dev, struct memstick_dev, 9762306a36Sopenharmony_ci dev); 9862306a36Sopenharmony_ci struct memstick_driver *drv = container_of(dev->driver, 9962306a36Sopenharmony_ci struct memstick_driver, 10062306a36Sopenharmony_ci driver); 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci if (dev->driver && drv->remove) { 10362306a36Sopenharmony_ci drv->remove(card); 10462306a36Sopenharmony_ci card->dev.driver = NULL; 10562306a36Sopenharmony_ci } 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci put_device(dev); 10862306a36Sopenharmony_ci} 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci#ifdef CONFIG_PM 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_cistatic int memstick_device_suspend(struct device *dev, pm_message_t state) 11362306a36Sopenharmony_ci{ 11462306a36Sopenharmony_ci struct memstick_dev *card = container_of(dev, struct memstick_dev, 11562306a36Sopenharmony_ci dev); 11662306a36Sopenharmony_ci struct memstick_driver *drv = container_of(dev->driver, 11762306a36Sopenharmony_ci struct memstick_driver, 11862306a36Sopenharmony_ci driver); 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci if (dev->driver && drv->suspend) 12162306a36Sopenharmony_ci return drv->suspend(card, state); 12262306a36Sopenharmony_ci return 0; 12362306a36Sopenharmony_ci} 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_cistatic int memstick_device_resume(struct device *dev) 12662306a36Sopenharmony_ci{ 12762306a36Sopenharmony_ci struct memstick_dev *card = container_of(dev, struct memstick_dev, 12862306a36Sopenharmony_ci dev); 12962306a36Sopenharmony_ci struct memstick_driver *drv = container_of(dev->driver, 13062306a36Sopenharmony_ci struct memstick_driver, 13162306a36Sopenharmony_ci driver); 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci if (dev->driver && drv->resume) 13462306a36Sopenharmony_ci return drv->resume(card); 13562306a36Sopenharmony_ci return 0; 13662306a36Sopenharmony_ci} 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci#else 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci#define memstick_device_suspend NULL 14162306a36Sopenharmony_ci#define memstick_device_resume NULL 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci#endif /* CONFIG_PM */ 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci#define MEMSTICK_ATTR(name, format) \ 14662306a36Sopenharmony_cistatic ssize_t name##_show(struct device *dev, struct device_attribute *attr, \ 14762306a36Sopenharmony_ci char *buf) \ 14862306a36Sopenharmony_ci{ \ 14962306a36Sopenharmony_ci struct memstick_dev *card = container_of(dev, struct memstick_dev, \ 15062306a36Sopenharmony_ci dev); \ 15162306a36Sopenharmony_ci return sprintf(buf, format, card->id.name); \ 15262306a36Sopenharmony_ci} \ 15362306a36Sopenharmony_cistatic DEVICE_ATTR_RO(name); 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ciMEMSTICK_ATTR(type, "%02X"); 15662306a36Sopenharmony_ciMEMSTICK_ATTR(category, "%02X"); 15762306a36Sopenharmony_ciMEMSTICK_ATTR(class, "%02X"); 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_cistatic struct attribute *memstick_dev_attrs[] = { 16062306a36Sopenharmony_ci &dev_attr_type.attr, 16162306a36Sopenharmony_ci &dev_attr_category.attr, 16262306a36Sopenharmony_ci &dev_attr_class.attr, 16362306a36Sopenharmony_ci NULL, 16462306a36Sopenharmony_ci}; 16562306a36Sopenharmony_ciATTRIBUTE_GROUPS(memstick_dev); 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_cistatic struct bus_type memstick_bus_type = { 16862306a36Sopenharmony_ci .name = "memstick", 16962306a36Sopenharmony_ci .dev_groups = memstick_dev_groups, 17062306a36Sopenharmony_ci .match = memstick_bus_match, 17162306a36Sopenharmony_ci .uevent = memstick_uevent, 17262306a36Sopenharmony_ci .probe = memstick_device_probe, 17362306a36Sopenharmony_ci .remove = memstick_device_remove, 17462306a36Sopenharmony_ci .suspend = memstick_device_suspend, 17562306a36Sopenharmony_ci .resume = memstick_device_resume 17662306a36Sopenharmony_ci}; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_cistatic void memstick_free(struct device *dev) 17962306a36Sopenharmony_ci{ 18062306a36Sopenharmony_ci struct memstick_host *host = container_of(dev, struct memstick_host, 18162306a36Sopenharmony_ci dev); 18262306a36Sopenharmony_ci kfree(host); 18362306a36Sopenharmony_ci} 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_cistatic struct class memstick_host_class = { 18662306a36Sopenharmony_ci .name = "memstick_host", 18762306a36Sopenharmony_ci .dev_release = memstick_free 18862306a36Sopenharmony_ci}; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_cistatic void memstick_free_card(struct device *dev) 19162306a36Sopenharmony_ci{ 19262306a36Sopenharmony_ci struct memstick_dev *card = container_of(dev, struct memstick_dev, 19362306a36Sopenharmony_ci dev); 19462306a36Sopenharmony_ci kfree(card); 19562306a36Sopenharmony_ci} 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_cistatic int memstick_dummy_check(struct memstick_dev *card) 19862306a36Sopenharmony_ci{ 19962306a36Sopenharmony_ci return 0; 20062306a36Sopenharmony_ci} 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci/** 20362306a36Sopenharmony_ci * memstick_detect_change - schedule media detection on memstick host 20462306a36Sopenharmony_ci * @host - host to use 20562306a36Sopenharmony_ci */ 20662306a36Sopenharmony_civoid memstick_detect_change(struct memstick_host *host) 20762306a36Sopenharmony_ci{ 20862306a36Sopenharmony_ci queue_work(workqueue, &host->media_checker); 20962306a36Sopenharmony_ci} 21062306a36Sopenharmony_ciEXPORT_SYMBOL(memstick_detect_change); 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci/** 21362306a36Sopenharmony_ci * memstick_next_req - called by host driver to obtain next request to process 21462306a36Sopenharmony_ci * @host - host to use 21562306a36Sopenharmony_ci * @mrq - pointer to stick the request to 21662306a36Sopenharmony_ci * 21762306a36Sopenharmony_ci * Host calls this function from idle state (*mrq == NULL) or after finishing 21862306a36Sopenharmony_ci * previous request (*mrq should point to it). If previous request was 21962306a36Sopenharmony_ci * unsuccessful, it is retried for predetermined number of times. Return value 22062306a36Sopenharmony_ci * of 0 means that new request was assigned to the host. 22162306a36Sopenharmony_ci */ 22262306a36Sopenharmony_ciint memstick_next_req(struct memstick_host *host, struct memstick_request **mrq) 22362306a36Sopenharmony_ci{ 22462306a36Sopenharmony_ci int rc = -ENXIO; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci if ((*mrq) && (*mrq)->error && host->retries) { 22762306a36Sopenharmony_ci (*mrq)->error = rc; 22862306a36Sopenharmony_ci host->retries--; 22962306a36Sopenharmony_ci return 0; 23062306a36Sopenharmony_ci } 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci if (host->card && host->card->next_request) 23362306a36Sopenharmony_ci rc = host->card->next_request(host->card, mrq); 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci if (!rc) 23662306a36Sopenharmony_ci host->retries = cmd_retries > 1 ? cmd_retries - 1 : 1; 23762306a36Sopenharmony_ci else 23862306a36Sopenharmony_ci *mrq = NULL; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci return rc; 24162306a36Sopenharmony_ci} 24262306a36Sopenharmony_ciEXPORT_SYMBOL(memstick_next_req); 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci/** 24562306a36Sopenharmony_ci * memstick_new_req - notify the host that some requests are pending 24662306a36Sopenharmony_ci * @host - host to use 24762306a36Sopenharmony_ci */ 24862306a36Sopenharmony_civoid memstick_new_req(struct memstick_host *host) 24962306a36Sopenharmony_ci{ 25062306a36Sopenharmony_ci if (host->card) { 25162306a36Sopenharmony_ci host->retries = cmd_retries; 25262306a36Sopenharmony_ci reinit_completion(&host->card->mrq_complete); 25362306a36Sopenharmony_ci host->request(host); 25462306a36Sopenharmony_ci } 25562306a36Sopenharmony_ci} 25662306a36Sopenharmony_ciEXPORT_SYMBOL(memstick_new_req); 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci/** 25962306a36Sopenharmony_ci * memstick_init_req_sg - set request fields needed for bulk data transfer 26062306a36Sopenharmony_ci * @mrq - request to use 26162306a36Sopenharmony_ci * @tpc - memstick Transport Protocol Command 26262306a36Sopenharmony_ci * @sg - TPC argument 26362306a36Sopenharmony_ci */ 26462306a36Sopenharmony_civoid memstick_init_req_sg(struct memstick_request *mrq, unsigned char tpc, 26562306a36Sopenharmony_ci const struct scatterlist *sg) 26662306a36Sopenharmony_ci{ 26762306a36Sopenharmony_ci mrq->tpc = tpc; 26862306a36Sopenharmony_ci if (tpc & 8) 26962306a36Sopenharmony_ci mrq->data_dir = WRITE; 27062306a36Sopenharmony_ci else 27162306a36Sopenharmony_ci mrq->data_dir = READ; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci mrq->sg = *sg; 27462306a36Sopenharmony_ci mrq->long_data = 1; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci if (tpc == MS_TPC_SET_CMD || tpc == MS_TPC_EX_SET_CMD) 27762306a36Sopenharmony_ci mrq->need_card_int = 1; 27862306a36Sopenharmony_ci else 27962306a36Sopenharmony_ci mrq->need_card_int = 0; 28062306a36Sopenharmony_ci} 28162306a36Sopenharmony_ciEXPORT_SYMBOL(memstick_init_req_sg); 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci/** 28462306a36Sopenharmony_ci * memstick_init_req - set request fields needed for short data transfer 28562306a36Sopenharmony_ci * @mrq - request to use 28662306a36Sopenharmony_ci * @tpc - memstick Transport Protocol Command 28762306a36Sopenharmony_ci * @buf - TPC argument buffer 28862306a36Sopenharmony_ci * @length - TPC argument size 28962306a36Sopenharmony_ci * 29062306a36Sopenharmony_ci * The intended use of this function (transfer of data items several bytes 29162306a36Sopenharmony_ci * in size) allows us to just copy the value between request structure and 29262306a36Sopenharmony_ci * user supplied buffer. 29362306a36Sopenharmony_ci */ 29462306a36Sopenharmony_civoid memstick_init_req(struct memstick_request *mrq, unsigned char tpc, 29562306a36Sopenharmony_ci const void *buf, size_t length) 29662306a36Sopenharmony_ci{ 29762306a36Sopenharmony_ci mrq->tpc = tpc; 29862306a36Sopenharmony_ci if (tpc & 8) 29962306a36Sopenharmony_ci mrq->data_dir = WRITE; 30062306a36Sopenharmony_ci else 30162306a36Sopenharmony_ci mrq->data_dir = READ; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci mrq->data_len = length > sizeof(mrq->data) ? sizeof(mrq->data) : length; 30462306a36Sopenharmony_ci if (mrq->data_dir == WRITE) 30562306a36Sopenharmony_ci memcpy(mrq->data, buf, mrq->data_len); 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci mrq->long_data = 0; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci if (tpc == MS_TPC_SET_CMD || tpc == MS_TPC_EX_SET_CMD) 31062306a36Sopenharmony_ci mrq->need_card_int = 1; 31162306a36Sopenharmony_ci else 31262306a36Sopenharmony_ci mrq->need_card_int = 0; 31362306a36Sopenharmony_ci} 31462306a36Sopenharmony_ciEXPORT_SYMBOL(memstick_init_req); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci/* 31762306a36Sopenharmony_ci * Functions prefixed with "h_" are protocol callbacks. They can be called from 31862306a36Sopenharmony_ci * interrupt context. Return value of 0 means that request processing is still 31962306a36Sopenharmony_ci * ongoing, while special error value of -EAGAIN means that current request is 32062306a36Sopenharmony_ci * finished (and request processor should come back some time later). 32162306a36Sopenharmony_ci */ 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_cistatic int h_memstick_read_dev_id(struct memstick_dev *card, 32462306a36Sopenharmony_ci struct memstick_request **mrq) 32562306a36Sopenharmony_ci{ 32662306a36Sopenharmony_ci struct ms_id_register id_reg; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci if (!(*mrq)) { 32962306a36Sopenharmony_ci memstick_init_req(&card->current_mrq, MS_TPC_READ_REG, &id_reg, 33062306a36Sopenharmony_ci sizeof(struct ms_id_register)); 33162306a36Sopenharmony_ci *mrq = &card->current_mrq; 33262306a36Sopenharmony_ci return 0; 33362306a36Sopenharmony_ci } 33462306a36Sopenharmony_ci if (!(*mrq)->error) { 33562306a36Sopenharmony_ci memcpy(&id_reg, (*mrq)->data, sizeof(id_reg)); 33662306a36Sopenharmony_ci card->id.match_flags = MEMSTICK_MATCH_ALL; 33762306a36Sopenharmony_ci card->id.type = id_reg.type; 33862306a36Sopenharmony_ci card->id.category = id_reg.category; 33962306a36Sopenharmony_ci card->id.class = id_reg.class; 34062306a36Sopenharmony_ci dev_dbg(&card->dev, "if_mode = %02x\n", id_reg.if_mode); 34162306a36Sopenharmony_ci } 34262306a36Sopenharmony_ci complete(&card->mrq_complete); 34362306a36Sopenharmony_ci return -EAGAIN; 34462306a36Sopenharmony_ci} 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_cistatic int h_memstick_set_rw_addr(struct memstick_dev *card, 34762306a36Sopenharmony_ci struct memstick_request **mrq) 34862306a36Sopenharmony_ci{ 34962306a36Sopenharmony_ci if (!(*mrq)) { 35062306a36Sopenharmony_ci memstick_init_req(&card->current_mrq, MS_TPC_SET_RW_REG_ADRS, 35162306a36Sopenharmony_ci (char *)&card->reg_addr, 35262306a36Sopenharmony_ci sizeof(card->reg_addr)); 35362306a36Sopenharmony_ci *mrq = &card->current_mrq; 35462306a36Sopenharmony_ci return 0; 35562306a36Sopenharmony_ci } else { 35662306a36Sopenharmony_ci complete(&card->mrq_complete); 35762306a36Sopenharmony_ci return -EAGAIN; 35862306a36Sopenharmony_ci } 35962306a36Sopenharmony_ci} 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci/** 36262306a36Sopenharmony_ci * memstick_set_rw_addr - issue SET_RW_REG_ADDR request and wait for it to 36362306a36Sopenharmony_ci * complete 36462306a36Sopenharmony_ci * @card - media device to use 36562306a36Sopenharmony_ci */ 36662306a36Sopenharmony_ciint memstick_set_rw_addr(struct memstick_dev *card) 36762306a36Sopenharmony_ci{ 36862306a36Sopenharmony_ci card->next_request = h_memstick_set_rw_addr; 36962306a36Sopenharmony_ci memstick_new_req(card->host); 37062306a36Sopenharmony_ci wait_for_completion(&card->mrq_complete); 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci return card->current_mrq.error; 37362306a36Sopenharmony_ci} 37462306a36Sopenharmony_ciEXPORT_SYMBOL(memstick_set_rw_addr); 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_cistatic struct memstick_dev *memstick_alloc_card(struct memstick_host *host) 37762306a36Sopenharmony_ci{ 37862306a36Sopenharmony_ci struct memstick_dev *card = kzalloc(sizeof(struct memstick_dev), 37962306a36Sopenharmony_ci GFP_KERNEL); 38062306a36Sopenharmony_ci struct memstick_dev *old_card = host->card; 38162306a36Sopenharmony_ci struct ms_id_register id_reg; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci if (card) { 38462306a36Sopenharmony_ci card->host = host; 38562306a36Sopenharmony_ci dev_set_name(&card->dev, "%s", dev_name(&host->dev)); 38662306a36Sopenharmony_ci card->dev.parent = &host->dev; 38762306a36Sopenharmony_ci card->dev.bus = &memstick_bus_type; 38862306a36Sopenharmony_ci card->dev.release = memstick_free_card; 38962306a36Sopenharmony_ci card->check = memstick_dummy_check; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci card->reg_addr.r_offset = offsetof(struct ms_register, id); 39262306a36Sopenharmony_ci card->reg_addr.r_length = sizeof(id_reg); 39362306a36Sopenharmony_ci card->reg_addr.w_offset = offsetof(struct ms_register, id); 39462306a36Sopenharmony_ci card->reg_addr.w_length = sizeof(id_reg); 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci init_completion(&card->mrq_complete); 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci host->card = card; 39962306a36Sopenharmony_ci if (memstick_set_rw_addr(card)) 40062306a36Sopenharmony_ci goto err_out; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci card->next_request = h_memstick_read_dev_id; 40362306a36Sopenharmony_ci memstick_new_req(host); 40462306a36Sopenharmony_ci wait_for_completion(&card->mrq_complete); 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci if (card->current_mrq.error) 40762306a36Sopenharmony_ci goto err_out; 40862306a36Sopenharmony_ci } 40962306a36Sopenharmony_ci host->card = old_card; 41062306a36Sopenharmony_ci return card; 41162306a36Sopenharmony_cierr_out: 41262306a36Sopenharmony_ci host->card = old_card; 41362306a36Sopenharmony_ci kfree_const(card->dev.kobj.name); 41462306a36Sopenharmony_ci kfree(card); 41562306a36Sopenharmony_ci return NULL; 41662306a36Sopenharmony_ci} 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_cistatic int memstick_power_on(struct memstick_host *host) 41962306a36Sopenharmony_ci{ 42062306a36Sopenharmony_ci int rc = host->set_param(host, MEMSTICK_POWER, MEMSTICK_POWER_ON); 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci if (!rc) 42362306a36Sopenharmony_ci rc = host->set_param(host, MEMSTICK_INTERFACE, MEMSTICK_SERIAL); 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci return rc; 42662306a36Sopenharmony_ci} 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_cistatic void memstick_check(struct work_struct *work) 42962306a36Sopenharmony_ci{ 43062306a36Sopenharmony_ci struct memstick_host *host = container_of(work, struct memstick_host, 43162306a36Sopenharmony_ci media_checker); 43262306a36Sopenharmony_ci struct memstick_dev *card; 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci dev_dbg(&host->dev, "memstick_check started\n"); 43562306a36Sopenharmony_ci pm_runtime_get_noresume(host->dev.parent); 43662306a36Sopenharmony_ci mutex_lock(&host->lock); 43762306a36Sopenharmony_ci if (!host->card) { 43862306a36Sopenharmony_ci if (memstick_power_on(host)) 43962306a36Sopenharmony_ci goto out_power_off; 44062306a36Sopenharmony_ci } else if (host->card->stop) 44162306a36Sopenharmony_ci host->card->stop(host->card); 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci if (host->removing) 44462306a36Sopenharmony_ci goto out_power_off; 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci card = memstick_alloc_card(host); 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci if (!card) { 44962306a36Sopenharmony_ci if (host->card) { 45062306a36Sopenharmony_ci device_unregister(&host->card->dev); 45162306a36Sopenharmony_ci host->card = NULL; 45262306a36Sopenharmony_ci } 45362306a36Sopenharmony_ci } else { 45462306a36Sopenharmony_ci dev_dbg(&host->dev, "new card %02x, %02x, %02x\n", 45562306a36Sopenharmony_ci card->id.type, card->id.category, card->id.class); 45662306a36Sopenharmony_ci if (host->card) { 45762306a36Sopenharmony_ci if (memstick_set_rw_addr(host->card) 45862306a36Sopenharmony_ci || !memstick_dev_match(host->card, &card->id) 45962306a36Sopenharmony_ci || !(host->card->check(host->card))) { 46062306a36Sopenharmony_ci device_unregister(&host->card->dev); 46162306a36Sopenharmony_ci host->card = NULL; 46262306a36Sopenharmony_ci } else if (host->card->start) 46362306a36Sopenharmony_ci host->card->start(host->card); 46462306a36Sopenharmony_ci } 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci if (!host->card) { 46762306a36Sopenharmony_ci host->card = card; 46862306a36Sopenharmony_ci if (device_register(&card->dev)) { 46962306a36Sopenharmony_ci put_device(&card->dev); 47062306a36Sopenharmony_ci host->card = NULL; 47162306a36Sopenharmony_ci } 47262306a36Sopenharmony_ci } else { 47362306a36Sopenharmony_ci kfree_const(card->dev.kobj.name); 47462306a36Sopenharmony_ci kfree(card); 47562306a36Sopenharmony_ci } 47662306a36Sopenharmony_ci } 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ciout_power_off: 47962306a36Sopenharmony_ci if (!host->card) 48062306a36Sopenharmony_ci host->set_param(host, MEMSTICK_POWER, MEMSTICK_POWER_OFF); 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci mutex_unlock(&host->lock); 48362306a36Sopenharmony_ci pm_runtime_put(host->dev.parent); 48462306a36Sopenharmony_ci dev_dbg(&host->dev, "memstick_check finished\n"); 48562306a36Sopenharmony_ci} 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci/** 48862306a36Sopenharmony_ci * memstick_alloc_host - allocate a memstick_host structure 48962306a36Sopenharmony_ci * @extra: size of the user private data to allocate 49062306a36Sopenharmony_ci * @dev: parent device of the host 49162306a36Sopenharmony_ci */ 49262306a36Sopenharmony_cistruct memstick_host *memstick_alloc_host(unsigned int extra, 49362306a36Sopenharmony_ci struct device *dev) 49462306a36Sopenharmony_ci{ 49562306a36Sopenharmony_ci struct memstick_host *host; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci host = kzalloc(sizeof(struct memstick_host) + extra, GFP_KERNEL); 49862306a36Sopenharmony_ci if (host) { 49962306a36Sopenharmony_ci mutex_init(&host->lock); 50062306a36Sopenharmony_ci INIT_WORK(&host->media_checker, memstick_check); 50162306a36Sopenharmony_ci host->dev.class = &memstick_host_class; 50262306a36Sopenharmony_ci host->dev.parent = dev; 50362306a36Sopenharmony_ci device_initialize(&host->dev); 50462306a36Sopenharmony_ci } 50562306a36Sopenharmony_ci return host; 50662306a36Sopenharmony_ci} 50762306a36Sopenharmony_ciEXPORT_SYMBOL(memstick_alloc_host); 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci/** 51062306a36Sopenharmony_ci * memstick_add_host - start request processing on memstick host 51162306a36Sopenharmony_ci * @host - host to use 51262306a36Sopenharmony_ci */ 51362306a36Sopenharmony_ciint memstick_add_host(struct memstick_host *host) 51462306a36Sopenharmony_ci{ 51562306a36Sopenharmony_ci int rc; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci idr_preload(GFP_KERNEL); 51862306a36Sopenharmony_ci spin_lock(&memstick_host_lock); 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci rc = idr_alloc(&memstick_host_idr, host, 0, 0, GFP_NOWAIT); 52162306a36Sopenharmony_ci if (rc >= 0) 52262306a36Sopenharmony_ci host->id = rc; 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci spin_unlock(&memstick_host_lock); 52562306a36Sopenharmony_ci idr_preload_end(); 52662306a36Sopenharmony_ci if (rc < 0) 52762306a36Sopenharmony_ci return rc; 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci dev_set_name(&host->dev, "memstick%u", host->id); 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci rc = device_add(&host->dev); 53262306a36Sopenharmony_ci if (rc) { 53362306a36Sopenharmony_ci spin_lock(&memstick_host_lock); 53462306a36Sopenharmony_ci idr_remove(&memstick_host_idr, host->id); 53562306a36Sopenharmony_ci spin_unlock(&memstick_host_lock); 53662306a36Sopenharmony_ci return rc; 53762306a36Sopenharmony_ci } 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci host->set_param(host, MEMSTICK_POWER, MEMSTICK_POWER_OFF); 54062306a36Sopenharmony_ci memstick_detect_change(host); 54162306a36Sopenharmony_ci return 0; 54262306a36Sopenharmony_ci} 54362306a36Sopenharmony_ciEXPORT_SYMBOL(memstick_add_host); 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci/** 54662306a36Sopenharmony_ci * memstick_remove_host - stop request processing on memstick host 54762306a36Sopenharmony_ci * @host - host to use 54862306a36Sopenharmony_ci */ 54962306a36Sopenharmony_civoid memstick_remove_host(struct memstick_host *host) 55062306a36Sopenharmony_ci{ 55162306a36Sopenharmony_ci host->removing = 1; 55262306a36Sopenharmony_ci flush_workqueue(workqueue); 55362306a36Sopenharmony_ci mutex_lock(&host->lock); 55462306a36Sopenharmony_ci if (host->card) 55562306a36Sopenharmony_ci device_unregister(&host->card->dev); 55662306a36Sopenharmony_ci host->card = NULL; 55762306a36Sopenharmony_ci host->set_param(host, MEMSTICK_POWER, MEMSTICK_POWER_OFF); 55862306a36Sopenharmony_ci mutex_unlock(&host->lock); 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci spin_lock(&memstick_host_lock); 56162306a36Sopenharmony_ci idr_remove(&memstick_host_idr, host->id); 56262306a36Sopenharmony_ci spin_unlock(&memstick_host_lock); 56362306a36Sopenharmony_ci device_del(&host->dev); 56462306a36Sopenharmony_ci} 56562306a36Sopenharmony_ciEXPORT_SYMBOL(memstick_remove_host); 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci/** 56862306a36Sopenharmony_ci * memstick_free_host - free memstick host 56962306a36Sopenharmony_ci * @host - host to use 57062306a36Sopenharmony_ci */ 57162306a36Sopenharmony_civoid memstick_free_host(struct memstick_host *host) 57262306a36Sopenharmony_ci{ 57362306a36Sopenharmony_ci mutex_destroy(&host->lock); 57462306a36Sopenharmony_ci put_device(&host->dev); 57562306a36Sopenharmony_ci} 57662306a36Sopenharmony_ciEXPORT_SYMBOL(memstick_free_host); 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci/** 57962306a36Sopenharmony_ci * memstick_suspend_host - notify bus driver of host suspension 58062306a36Sopenharmony_ci * @host - host to use 58162306a36Sopenharmony_ci */ 58262306a36Sopenharmony_civoid memstick_suspend_host(struct memstick_host *host) 58362306a36Sopenharmony_ci{ 58462306a36Sopenharmony_ci mutex_lock(&host->lock); 58562306a36Sopenharmony_ci host->set_param(host, MEMSTICK_POWER, MEMSTICK_POWER_OFF); 58662306a36Sopenharmony_ci mutex_unlock(&host->lock); 58762306a36Sopenharmony_ci} 58862306a36Sopenharmony_ciEXPORT_SYMBOL(memstick_suspend_host); 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci/** 59162306a36Sopenharmony_ci * memstick_resume_host - notify bus driver of host resumption 59262306a36Sopenharmony_ci * @host - host to use 59362306a36Sopenharmony_ci */ 59462306a36Sopenharmony_civoid memstick_resume_host(struct memstick_host *host) 59562306a36Sopenharmony_ci{ 59662306a36Sopenharmony_ci int rc = 0; 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci mutex_lock(&host->lock); 59962306a36Sopenharmony_ci if (host->card) 60062306a36Sopenharmony_ci rc = memstick_power_on(host); 60162306a36Sopenharmony_ci mutex_unlock(&host->lock); 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci if (!rc) 60462306a36Sopenharmony_ci memstick_detect_change(host); 60562306a36Sopenharmony_ci} 60662306a36Sopenharmony_ciEXPORT_SYMBOL(memstick_resume_host); 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ciint memstick_register_driver(struct memstick_driver *drv) 60962306a36Sopenharmony_ci{ 61062306a36Sopenharmony_ci drv->driver.bus = &memstick_bus_type; 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci return driver_register(&drv->driver); 61362306a36Sopenharmony_ci} 61462306a36Sopenharmony_ciEXPORT_SYMBOL(memstick_register_driver); 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_civoid memstick_unregister_driver(struct memstick_driver *drv) 61762306a36Sopenharmony_ci{ 61862306a36Sopenharmony_ci driver_unregister(&drv->driver); 61962306a36Sopenharmony_ci} 62062306a36Sopenharmony_ciEXPORT_SYMBOL(memstick_unregister_driver); 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_cistatic int __init memstick_init(void) 62462306a36Sopenharmony_ci{ 62562306a36Sopenharmony_ci int rc; 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci workqueue = create_freezable_workqueue("kmemstick"); 62862306a36Sopenharmony_ci if (!workqueue) 62962306a36Sopenharmony_ci return -ENOMEM; 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci rc = bus_register(&memstick_bus_type); 63262306a36Sopenharmony_ci if (rc) 63362306a36Sopenharmony_ci goto error_destroy_workqueue; 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci rc = class_register(&memstick_host_class); 63662306a36Sopenharmony_ci if (rc) 63762306a36Sopenharmony_ci goto error_bus_unregister; 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci return 0; 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_cierror_bus_unregister: 64262306a36Sopenharmony_ci bus_unregister(&memstick_bus_type); 64362306a36Sopenharmony_cierror_destroy_workqueue: 64462306a36Sopenharmony_ci destroy_workqueue(workqueue); 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci return rc; 64762306a36Sopenharmony_ci} 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_cistatic void __exit memstick_exit(void) 65062306a36Sopenharmony_ci{ 65162306a36Sopenharmony_ci class_unregister(&memstick_host_class); 65262306a36Sopenharmony_ci bus_unregister(&memstick_bus_type); 65362306a36Sopenharmony_ci destroy_workqueue(workqueue); 65462306a36Sopenharmony_ci idr_destroy(&memstick_host_idr); 65562306a36Sopenharmony_ci} 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_cimodule_init(memstick_init); 65862306a36Sopenharmony_cimodule_exit(memstick_exit); 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ciMODULE_AUTHOR("Alex Dubov"); 66162306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 66262306a36Sopenharmony_ciMODULE_DESCRIPTION("Sony MemoryStick core driver"); 663