1e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel/* 2e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel * MTD driver for Alauda chips 3e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel * 4e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel * Copyright (C) 2007 Joern Engel <joern@logfs.org> 5e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel * 6e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel * Based on drivers/usb/usb-skeleton.c which is: 7e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com) 8e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel * and on drivers/usb/storage/alauda.c, which is: 9e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel * (c) 2005 Daniel Drake <dsd@gentoo.org> 10e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel * 11e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel * Idea and initial work by Arnd Bergmann <arnd@arndb.de> 12e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel */ 13e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel#include <linux/kernel.h> 14e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel#include <linux/errno.h> 15e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel#include <linux/init.h> 16e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel#include <linux/slab.h> 17e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel#include <linux/module.h> 18e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel#include <linux/kref.h> 19e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel#include <linux/usb.h> 20e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel#include <linux/mutex.h> 21e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel#include <linux/mtd/mtd.h> 22e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel#include <linux/mtd/nand_ecc.h> 23e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 24e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel/* Control commands */ 25e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel#define ALAUDA_GET_XD_MEDIA_STATUS 0x08 26e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel#define ALAUDA_ACK_XD_MEDIA_CHANGE 0x0a 27e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel#define ALAUDA_GET_XD_MEDIA_SIG 0x86 28e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 29e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel/* Common prefix */ 30e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel#define ALAUDA_BULK_CMD 0x40 31e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 32e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel/* The two ports */ 33e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel#define ALAUDA_PORT_XD 0x00 34e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel#define ALAUDA_PORT_SM 0x01 35e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 36e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel/* Bulk commands */ 37e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel#define ALAUDA_BULK_READ_PAGE 0x84 38e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel#define ALAUDA_BULK_READ_OOB 0x85 /* don't use, there's a chip bug */ 39e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel#define ALAUDA_BULK_READ_BLOCK 0x94 40e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel#define ALAUDA_BULK_ERASE_BLOCK 0xa3 41e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel#define ALAUDA_BULK_WRITE_PAGE 0xa4 42e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel#define ALAUDA_BULK_WRITE_BLOCK 0xb4 43e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel#define ALAUDA_BULK_RESET_MEDIA 0xe0 44e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 45e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel/* Address shifting */ 46e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel#define PBA_LO(pba) ((pba & 0xF) << 5) 47e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel#define PBA_HI(pba) (pba >> 3) 48e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel#define PBA_ZONE(pba) (pba >> 11) 49e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 50e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel#define TIMEOUT HZ 51e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 52b3acd638a2b8b9c3cd1b52b83e285c88d34ef7f3Márton Némethstatic const struct usb_device_id alauda_table[] = { 53e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel { USB_DEVICE(0x0584, 0x0008) }, /* Fujifilm DPC-R1 */ 54e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel { USB_DEVICE(0x07b4, 0x010a) }, /* Olympus MAUSB-10 */ 55e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel { } 56e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel}; 57e208520ed664db0f7584048ae09e5d2afda43714Jörn EngelMODULE_DEVICE_TABLE(usb, alauda_table); 58e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 59e208520ed664db0f7584048ae09e5d2afda43714Jörn Engelstruct alauda_card { 60e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel u8 id; /* id byte */ 61e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel u8 chipshift; /* 1<<chipshift total size */ 62e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel u8 pageshift; /* 1<<pageshift page size */ 63e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel u8 blockshift; /* 1<<blockshift block size */ 64e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel}; 65e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 66e208520ed664db0f7584048ae09e5d2afda43714Jörn Engelstruct alauda { 67e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel struct usb_device *dev; 68e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel struct usb_interface *interface; 69e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel struct mtd_info *mtd; 70e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel struct alauda_card *card; 71e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel struct mutex card_mutex; 72e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel u32 pagemask; 73e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel u32 bytemask; 74e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel u32 blockmask; 75e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel unsigned int write_out; 76e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel unsigned int bulk_in; 77e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel unsigned int bulk_out; 78e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel u8 port; 79e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel struct kref kref; 80e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel}; 81e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 82e208520ed664db0f7584048ae09e5d2afda43714Jörn Engelstatic struct alauda_card alauda_card_ids[] = { 83e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel /* NAND flash */ 84e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel { 0x6e, 20, 8, 12}, /* 1 MB */ 85e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel { 0xe8, 20, 8, 12}, /* 1 MB */ 86e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel { 0xec, 20, 8, 12}, /* 1 MB */ 87e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel { 0x64, 21, 8, 12}, /* 2 MB */ 88e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel { 0xea, 21, 8, 12}, /* 2 MB */ 89e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel { 0x6b, 22, 9, 13}, /* 4 MB */ 90e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel { 0xe3, 22, 9, 13}, /* 4 MB */ 91e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel { 0xe5, 22, 9, 13}, /* 4 MB */ 92e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel { 0xe6, 23, 9, 13}, /* 8 MB */ 93e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel { 0x73, 24, 9, 14}, /* 16 MB */ 94e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel { 0x75, 25, 9, 14}, /* 32 MB */ 95e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel { 0x76, 26, 9, 14}, /* 64 MB */ 96e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel { 0x79, 27, 9, 14}, /* 128 MB */ 97e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel { 0x71, 28, 9, 14}, /* 256 MB */ 98e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 99e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel /* MASK ROM */ 100e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel { 0x5d, 21, 9, 13}, /* 2 MB */ 101e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel { 0xd5, 22, 9, 13}, /* 4 MB */ 102e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel { 0xd6, 23, 9, 13}, /* 8 MB */ 103e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel { 0x57, 24, 9, 13}, /* 16 MB */ 104e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel { 0x58, 25, 9, 13}, /* 32 MB */ 105e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel { } 106e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel}; 107e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 108e208520ed664db0f7584048ae09e5d2afda43714Jörn Engelstatic struct alauda_card *get_card(u8 id) 109e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel{ 110e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel struct alauda_card *card; 111e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 112e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel for (card = alauda_card_ids; card->id; card++) 113e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel if (card->id == id) 114e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel return card; 115e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel return NULL; 116e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel} 117e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 118e208520ed664db0f7584048ae09e5d2afda43714Jörn Engelstatic void alauda_delete(struct kref *kref) 119e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel{ 120e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel struct alauda *al = container_of(kref, struct alauda, kref); 121e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 122e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel if (al->mtd) { 123ee0e87b174bb41f0310cf089262bf5dd8f95a212Jamie Iles mtd_device_unregister(al->mtd); 124e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel kfree(al->mtd); 125e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel } 126e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel usb_put_dev(al->dev); 127e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel kfree(al); 128e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel} 129e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 130e208520ed664db0f7584048ae09e5d2afda43714Jörn Engelstatic int alauda_get_media_status(struct alauda *al, void *buf) 131e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel{ 132e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel int ret; 133e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 134e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel mutex_lock(&al->card_mutex); 135e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel ret = usb_control_msg(al->dev, usb_rcvctrlpipe(al->dev, 0), 136e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel ALAUDA_GET_XD_MEDIA_STATUS, 0xc0, 0, 1, buf, 2, HZ); 137e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel mutex_unlock(&al->card_mutex); 138e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel return ret; 139e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel} 140e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 141e208520ed664db0f7584048ae09e5d2afda43714Jörn Engelstatic int alauda_ack_media(struct alauda *al) 142e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel{ 143e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel int ret; 144e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 145e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel mutex_lock(&al->card_mutex); 146e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel ret = usb_control_msg(al->dev, usb_sndctrlpipe(al->dev, 0), 147e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel ALAUDA_ACK_XD_MEDIA_CHANGE, 0x40, 0, 1, NULL, 0, HZ); 148e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel mutex_unlock(&al->card_mutex); 149e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel return ret; 150e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel} 151e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 152e208520ed664db0f7584048ae09e5d2afda43714Jörn Engelstatic int alauda_get_media_signatures(struct alauda *al, void *buf) 153e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel{ 154e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel int ret; 155e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 156e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel mutex_lock(&al->card_mutex); 157e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel ret = usb_control_msg(al->dev, usb_rcvctrlpipe(al->dev, 0), 158e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel ALAUDA_GET_XD_MEDIA_SIG, 0xc0, 0, 0, buf, 4, HZ); 159e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel mutex_unlock(&al->card_mutex); 160e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel return ret; 161e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel} 162e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 163e208520ed664db0f7584048ae09e5d2afda43714Jörn Engelstatic void alauda_reset(struct alauda *al) 164e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel{ 165e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel u8 command[] = { 166e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel ALAUDA_BULK_CMD, ALAUDA_BULK_RESET_MEDIA, 0, 0, 167e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 0, 0, 0, 0, al->port 168e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel }; 169e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel mutex_lock(&al->card_mutex); 170e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel usb_bulk_msg(al->dev, al->bulk_out, command, 9, NULL, HZ); 171e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel mutex_unlock(&al->card_mutex); 172e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel} 173e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 174e208520ed664db0f7584048ae09e5d2afda43714Jörn Engelstatic void correct_data(void *buf, void *read_ecc, 175e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel int *corrected, int *uncorrected) 176e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel{ 177e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel u8 calc_ecc[3]; 178e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel int err; 179e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 180e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel nand_calculate_ecc(NULL, buf, calc_ecc); 181e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel err = nand_correct_data(NULL, buf, read_ecc, calc_ecc); 182e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel if (err) { 183e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel if (err > 0) 184e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel (*corrected)++; 185e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel else 186e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel (*uncorrected)++; 187e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel } 188e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel} 189e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 190e208520ed664db0f7584048ae09e5d2afda43714Jörn Engelstruct alauda_sg_request { 191e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel struct urb *urb[3]; 192e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel struct completion comp; 193e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel}; 194e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 195e208520ed664db0f7584048ae09e5d2afda43714Jörn Engelstatic void alauda_complete(struct urb *urb) 196e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel{ 197e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel struct completion *comp = urb->context; 198e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 199e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel if (comp) 200e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel complete(comp); 201e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel} 202e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 203e208520ed664db0f7584048ae09e5d2afda43714Jörn Engelstatic int __alauda_read_page(struct mtd_info *mtd, loff_t from, void *buf, 204e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel void *oob) 205e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel{ 206e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel struct alauda_sg_request sg; 207e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel struct alauda *al = mtd->priv; 208e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel u32 pba = from >> al->card->blockshift; 209e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel u32 page = (from >> al->card->pageshift) & al->pagemask; 210e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel u8 command[] = { 211e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel ALAUDA_BULK_CMD, ALAUDA_BULK_READ_PAGE, PBA_HI(pba), 212e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel PBA_ZONE(pba), 0, PBA_LO(pba) + page, 1, 0, al->port 213e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel }; 214e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel int i, err; 215e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 216e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel for (i=0; i<3; i++) 217e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel sg.urb[i] = NULL; 218e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 219e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel err = -ENOMEM; 220e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel for (i=0; i<3; i++) { 221e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel sg.urb[i] = usb_alloc_urb(0, GFP_NOIO); 222e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel if (!sg.urb[i]) 223e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel goto out; 224e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel } 225e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel init_completion(&sg.comp); 226e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel usb_fill_bulk_urb(sg.urb[0], al->dev, al->bulk_out, command, 9, 227e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel alauda_complete, NULL); 228e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel usb_fill_bulk_urb(sg.urb[1], al->dev, al->bulk_in, buf, mtd->writesize, 229e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel alauda_complete, NULL); 230e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel usb_fill_bulk_urb(sg.urb[2], al->dev, al->bulk_in, oob, 16, 231e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel alauda_complete, &sg.comp); 232e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 233e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel mutex_lock(&al->card_mutex); 234e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel for (i=0; i<3; i++) { 235e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel err = usb_submit_urb(sg.urb[i], GFP_NOIO); 236e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel if (err) 237e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel goto cancel; 238e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel } 239e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel if (!wait_for_completion_timeout(&sg.comp, TIMEOUT)) { 240e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel err = -ETIMEDOUT; 241e208520ed664db0f7584048ae09e5d2afda43714Jörn Engelcancel: 242e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel for (i=0; i<3; i++) { 243e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel usb_kill_urb(sg.urb[i]); 244e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel } 245e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel } 246e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel mutex_unlock(&al->card_mutex); 247e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 248e208520ed664db0f7584048ae09e5d2afda43714Jörn Engelout: 249e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel usb_free_urb(sg.urb[0]); 250e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel usb_free_urb(sg.urb[1]); 251e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel usb_free_urb(sg.urb[2]); 252e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel return err; 253e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel} 254e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 255e208520ed664db0f7584048ae09e5d2afda43714Jörn Engelstatic int alauda_read_page(struct mtd_info *mtd, loff_t from, 256e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel void *buf, u8 *oob, int *corrected, int *uncorrected) 257e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel{ 258e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel int err; 259e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 260e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel err = __alauda_read_page(mtd, from, buf, oob); 261e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel if (err) 262e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel return err; 263e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel correct_data(buf, oob+13, corrected, uncorrected); 264e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel correct_data(buf+256, oob+8, corrected, uncorrected); 265e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel return 0; 266e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel} 267e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 268e208520ed664db0f7584048ae09e5d2afda43714Jörn Engelstatic int alauda_write_page(struct mtd_info *mtd, loff_t to, void *buf, 269e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel void *oob) 270e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel{ 271e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel struct alauda_sg_request sg; 272e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel struct alauda *al = mtd->priv; 273e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel u32 pba = to >> al->card->blockshift; 274e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel u32 page = (to >> al->card->pageshift) & al->pagemask; 275e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel u8 command[] = { 276e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel ALAUDA_BULK_CMD, ALAUDA_BULK_WRITE_PAGE, PBA_HI(pba), 277e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel PBA_ZONE(pba), 0, PBA_LO(pba) + page, 32, 0, al->port 278e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel }; 279e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel int i, err; 280e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 281e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel for (i=0; i<3; i++) 282e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel sg.urb[i] = NULL; 283e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 284e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel err = -ENOMEM; 285e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel for (i=0; i<3; i++) { 286e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel sg.urb[i] = usb_alloc_urb(0, GFP_NOIO); 287e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel if (!sg.urb[i]) 288e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel goto out; 289e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel } 290e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel init_completion(&sg.comp); 291e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel usb_fill_bulk_urb(sg.urb[0], al->dev, al->bulk_out, command, 9, 292e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel alauda_complete, NULL); 293e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel usb_fill_bulk_urb(sg.urb[1], al->dev, al->write_out, buf,mtd->writesize, 294e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel alauda_complete, NULL); 295e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel usb_fill_bulk_urb(sg.urb[2], al->dev, al->write_out, oob, 16, 296e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel alauda_complete, &sg.comp); 297e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 298e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel mutex_lock(&al->card_mutex); 299e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel for (i=0; i<3; i++) { 300e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel err = usb_submit_urb(sg.urb[i], GFP_NOIO); 301e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel if (err) 302e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel goto cancel; 303e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel } 304e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel if (!wait_for_completion_timeout(&sg.comp, TIMEOUT)) { 305e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel err = -ETIMEDOUT; 306e208520ed664db0f7584048ae09e5d2afda43714Jörn Engelcancel: 307e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel for (i=0; i<3; i++) { 308e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel usb_kill_urb(sg.urb[i]); 309e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel } 310e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel } 311e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel mutex_unlock(&al->card_mutex); 312e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 313e208520ed664db0f7584048ae09e5d2afda43714Jörn Engelout: 314e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel usb_free_urb(sg.urb[0]); 315e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel usb_free_urb(sg.urb[1]); 316e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel usb_free_urb(sg.urb[2]); 317e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel return err; 318e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel} 319e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 320e208520ed664db0f7584048ae09e5d2afda43714Jörn Engelstatic int alauda_erase_block(struct mtd_info *mtd, loff_t ofs) 321e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel{ 322e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel struct alauda_sg_request sg; 323e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel struct alauda *al = mtd->priv; 324e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel u32 pba = ofs >> al->card->blockshift; 325e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel u8 command[] = { 326e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel ALAUDA_BULK_CMD, ALAUDA_BULK_ERASE_BLOCK, PBA_HI(pba), 327e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel PBA_ZONE(pba), 0, PBA_LO(pba), 0x02, 0, al->port 328e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel }; 329e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel u8 buf[2]; 330e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel int i, err; 331e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 332e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel for (i=0; i<2; i++) 333e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel sg.urb[i] = NULL; 334e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 335e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel err = -ENOMEM; 336e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel for (i=0; i<2; i++) { 337e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel sg.urb[i] = usb_alloc_urb(0, GFP_NOIO); 338e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel if (!sg.urb[i]) 339e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel goto out; 340e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel } 341e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel init_completion(&sg.comp); 342e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel usb_fill_bulk_urb(sg.urb[0], al->dev, al->bulk_out, command, 9, 343e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel alauda_complete, NULL); 344e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel usb_fill_bulk_urb(sg.urb[1], al->dev, al->bulk_in, buf, 2, 345e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel alauda_complete, &sg.comp); 346e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 347e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel mutex_lock(&al->card_mutex); 348e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel for (i=0; i<2; i++) { 349e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel err = usb_submit_urb(sg.urb[i], GFP_NOIO); 350e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel if (err) 351e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel goto cancel; 352e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel } 353e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel if (!wait_for_completion_timeout(&sg.comp, TIMEOUT)) { 354e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel err = -ETIMEDOUT; 355e208520ed664db0f7584048ae09e5d2afda43714Jörn Engelcancel: 356e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel for (i=0; i<2; i++) { 357e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel usb_kill_urb(sg.urb[i]); 358e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel } 359e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel } 360e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel mutex_unlock(&al->card_mutex); 361e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 362e208520ed664db0f7584048ae09e5d2afda43714Jörn Engelout: 363e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel usb_free_urb(sg.urb[0]); 364e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel usb_free_urb(sg.urb[1]); 365e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel return err; 366e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel} 367e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 368e208520ed664db0f7584048ae09e5d2afda43714Jörn Engelstatic int alauda_read_oob(struct mtd_info *mtd, loff_t from, void *oob) 369e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel{ 370e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel static u8 ignore_buf[512]; /* write only */ 371e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 372e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel return __alauda_read_page(mtd, from, ignore_buf, oob); 373e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel} 374e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 375e208520ed664db0f7584048ae09e5d2afda43714Jörn Engelstatic int alauda_isbad(struct mtd_info *mtd, loff_t ofs) 376e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel{ 377e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel u8 oob[16]; 378e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel int err; 379e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 380e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel err = alauda_read_oob(mtd, ofs, oob); 381e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel if (err) 382e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel return err; 383e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 384e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel /* A block is marked bad if two or more bits are zero */ 38554c69cc25064c1d333a12b5883aaa3bfa3041deeAkinobu Mita return hweight8(oob[5]) >= 7 ? 0 : 1; 386e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel} 387e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 388e208520ed664db0f7584048ae09e5d2afda43714Jörn Engelstatic int alauda_bounce_read(struct mtd_info *mtd, loff_t from, size_t len, 389e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel size_t *retlen, u_char *buf) 390e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel{ 391e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel struct alauda *al = mtd->priv; 392e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel void *bounce_buf; 393e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel int err, corrected=0, uncorrected=0; 394e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 395e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel bounce_buf = kmalloc(mtd->writesize, GFP_KERNEL); 396e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel if (!bounce_buf) 397e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel return -ENOMEM; 398e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 399e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel *retlen = len; 400e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel while (len) { 401e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel u8 oob[16]; 402f96880d1e859e3937eb691da8293700b8eec17b3akpm@linux-foundation.org size_t byte = from & al->bytemask; 403e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel size_t cplen = min(len, mtd->writesize - byte); 404e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 405e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel err = alauda_read_page(mtd, from, bounce_buf, oob, 406e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel &corrected, &uncorrected); 407e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel if (err) 408e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel goto out; 409e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 410e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel memcpy(buf, bounce_buf + byte, cplen); 411e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel buf += cplen; 412e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel from += cplen; 413e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel len -= cplen; 414e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel } 415e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel err = 0; 416e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel if (corrected) 417e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel err = -EUCLEAN; 418e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel if (uncorrected) 419e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel err = -EBADMSG; 420e208520ed664db0f7584048ae09e5d2afda43714Jörn Engelout: 421e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel kfree(bounce_buf); 422e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel return err; 423e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel} 424e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 425e208520ed664db0f7584048ae09e5d2afda43714Jörn Engelstatic int alauda_read(struct mtd_info *mtd, loff_t from, size_t len, 426e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel size_t *retlen, u_char *buf) 427e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel{ 428e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel struct alauda *al = mtd->priv; 429e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel int err, corrected=0, uncorrected=0; 430e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 431e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel if ((from & al->bytemask) || (len & al->bytemask)) 432e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel return alauda_bounce_read(mtd, from, len, retlen, buf); 433e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 434e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel *retlen = len; 435e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel while (len) { 436e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel u8 oob[16]; 437e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 438e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel err = alauda_read_page(mtd, from, buf, oob, 439e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel &corrected, &uncorrected); 440e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel if (err) 441e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel return err; 442e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 443e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel buf += mtd->writesize; 444e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel from += mtd->writesize; 445e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel len -= mtd->writesize; 446e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel } 447e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel err = 0; 448e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel if (corrected) 449e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel err = -EUCLEAN; 450e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel if (uncorrected) 451e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel err = -EBADMSG; 452e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel return err; 453e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel} 454e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 455e208520ed664db0f7584048ae09e5d2afda43714Jörn Engelstatic int alauda_write(struct mtd_info *mtd, loff_t to, size_t len, 456e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel size_t *retlen, const u_char *buf) 457e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel{ 458e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel struct alauda *al = mtd->priv; 459e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel int err; 460e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 461e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel if ((to & al->bytemask) || (len & al->bytemask)) 462e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel return -EINVAL; 463e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 464e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel *retlen = len; 465e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel while (len) { 466e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel u32 page = (to >> al->card->pageshift) & al->pagemask; 467e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel u8 oob[16] = { 'h', 'e', 'l', 'l', 'o', 0xff, 0xff, 0xff, 468e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; 469e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 470e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel /* don't write to bad blocks */ 471e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel if (page == 0) { 472e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel err = alauda_isbad(mtd, to); 473e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel if (err) { 474e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel return -EIO; 475e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel } 476e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel } 477e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel nand_calculate_ecc(mtd, buf, &oob[13]); 478e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel nand_calculate_ecc(mtd, buf+256, &oob[8]); 479e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 480e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel err = alauda_write_page(mtd, to, (void*)buf, oob); 481e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel if (err) 482e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel return err; 483e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 484e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel buf += mtd->writesize; 485e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel to += mtd->writesize; 486e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel len -= mtd->writesize; 487e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel } 488e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel return 0; 489e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel} 490e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 491e208520ed664db0f7584048ae09e5d2afda43714Jörn Engelstatic int __alauda_erase(struct mtd_info *mtd, struct erase_info *instr) 492e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel{ 493e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel struct alauda *al = mtd->priv; 494e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel u32 ofs = instr->addr; 495e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel u32 len = instr->len; 496e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel int err; 497e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 498e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel if ((ofs & al->blockmask) || (len & al->blockmask)) 499e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel return -EINVAL; 500e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 501e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel while (len) { 502e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel /* don't erase bad blocks */ 503e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel err = alauda_isbad(mtd, ofs); 504e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel if (err > 0) 505e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel err = -EIO; 506e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel if (err < 0) 507e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel return err; 508e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 509e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel err = alauda_erase_block(mtd, ofs); 510e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel if (err < 0) 511e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel return err; 512e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 513e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel ofs += mtd->erasesize; 514e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel len -= mtd->erasesize; 515e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel } 516e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel return 0; 517e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel} 518e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 519e208520ed664db0f7584048ae09e5d2afda43714Jörn Engelstatic int alauda_erase(struct mtd_info *mtd, struct erase_info *instr) 520e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel{ 521e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel int err; 522e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 523e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel err = __alauda_erase(mtd, instr); 524e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel instr->state = err ? MTD_ERASE_FAILED : MTD_ERASE_DONE; 525e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel mtd_erase_callback(instr); 526e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel return err; 527e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel} 528e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 529e208520ed664db0f7584048ae09e5d2afda43714Jörn Engelstatic int alauda_init_media(struct alauda *al) 530e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel{ 531e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel u8 buf[4], *b0=buf, *b1=buf+1; 532e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel struct alauda_card *card; 533e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel struct mtd_info *mtd; 534e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel int err; 535e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 536e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel mtd = kzalloc(sizeof(*mtd), GFP_KERNEL); 537e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel if (!mtd) 538e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel return -ENOMEM; 539e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 540e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel for (;;) { 541e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel err = alauda_get_media_status(al, buf); 542e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel if (err < 0) 543e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel goto error; 544e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel if (*b0 & 0x10) 545e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel break; 546e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel msleep(20); 547e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel } 548e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 549e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel err = alauda_ack_media(al); 550e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel if (err) 551e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel goto error; 552e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 553e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel msleep(10); 554e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 555e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel err = alauda_get_media_status(al, buf); 556e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel if (err < 0) 557e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel goto error; 558e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 559e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel if (*b0 != 0x14) { 560e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel /* media not ready */ 561e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel err = -EIO; 562e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel goto error; 563e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel } 564e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel err = alauda_get_media_signatures(al, buf); 565e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel if (err < 0) 566e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel goto error; 567e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 568e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel card = get_card(*b1); 569e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel if (!card) { 570e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel printk(KERN_ERR"Alauda: unknown card id %02x\n", *b1); 571e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel err = -EIO; 572e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel goto error; 573e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel } 574e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel printk(KERN_INFO"pagesize=%x\nerasesize=%x\nsize=%xMiB\n", 575e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 1<<card->pageshift, 1<<card->blockshift, 576e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 1<<(card->chipshift-20)); 577e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel al->card = card; 578e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel al->pagemask = (1 << (card->blockshift - card->pageshift)) - 1; 579e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel al->bytemask = (1 << card->pageshift) - 1; 580e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel al->blockmask = (1 << card->blockshift) - 1; 581e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 582e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel mtd->name = "alauda"; 583e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel mtd->size = 1<<card->chipshift; 584e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel mtd->erasesize = 1<<card->blockshift; 585e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel mtd->writesize = 1<<card->pageshift; 586e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel mtd->type = MTD_NANDFLASH; 587e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel mtd->flags = MTD_CAP_NANDFLASH; 5883c3c10bba1e4ccb75b41442e45c1a072f6cded19Artem Bityutskiy mtd->_read = alauda_read; 5893c3c10bba1e4ccb75b41442e45c1a072f6cded19Artem Bityutskiy mtd->_write = alauda_write; 5903c3c10bba1e4ccb75b41442e45c1a072f6cded19Artem Bityutskiy mtd->_erase = alauda_erase; 5913c3c10bba1e4ccb75b41442e45c1a072f6cded19Artem Bityutskiy mtd->_block_isbad = alauda_isbad; 592e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel mtd->priv = al; 593e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel mtd->owner = THIS_MODULE; 5946a918bade9dab40aaef80559bd1169c69e8d69cbMike Dunn mtd->ecc_strength = 1; 595e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 596ee0e87b174bb41f0310cf089262bf5dd8f95a212Jamie Iles err = mtd_device_register(mtd, NULL, 0); 597e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel if (err) { 598e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel err = -ENFILE; 599e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel goto error; 600e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel } 601e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 602e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel al->mtd = mtd; 603e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel alauda_reset(al); /* no clue whether this is necessary */ 604e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel return 0; 605e208520ed664db0f7584048ae09e5d2afda43714Jörn Engelerror: 606e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel kfree(mtd); 607e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel return err; 608e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel} 609e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 610e208520ed664db0f7584048ae09e5d2afda43714Jörn Engelstatic int alauda_check_media(struct alauda *al) 611e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel{ 612e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel u8 buf[2], *b0 = buf, *b1 = buf+1; 613e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel int err; 614e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 615e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel err = alauda_get_media_status(al, buf); 616e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel if (err < 0) 617e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel return err; 618e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 619e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel if ((*b1 & 0x01) == 0) { 620e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel /* door open */ 621e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel return -EIO; 622e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel } 623e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel if ((*b0 & 0x80) || ((*b0 & 0x1F) == 0x10)) { 624e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel /* no media ? */ 625e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel return -EIO; 626e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel } 627e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel if (*b0 & 0x08) { 628e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel /* media change ? */ 629e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel return alauda_init_media(al); 630e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel } 631e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel return 0; 632e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel} 633e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 634e208520ed664db0f7584048ae09e5d2afda43714Jörn Engelstatic int alauda_probe(struct usb_interface *interface, 635e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel const struct usb_device_id *id) 636e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel{ 637e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel struct alauda *al; 638e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel struct usb_host_interface *iface; 639e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel struct usb_endpoint_descriptor *ep, 640e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel *ep_in=NULL, *ep_out=NULL, *ep_wr=NULL; 641e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel int i, err = -ENOMEM; 642e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 643e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel al = kzalloc(2*sizeof(*al), GFP_KERNEL); 644e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel if (!al) 645e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel goto error; 646e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 647e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel kref_init(&al->kref); 648e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel usb_set_intfdata(interface, al); 649e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 650e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel al->dev = usb_get_dev(interface_to_usbdev(interface)); 651e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel al->interface = interface; 652e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 653e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel iface = interface->cur_altsetting; 654e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel for (i = 0; i < iface->desc.bNumEndpoints; ++i) { 655e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel ep = &iface->endpoint[i].desc; 656e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 657e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel if (usb_endpoint_is_bulk_in(ep)) { 658e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel ep_in = ep; 659e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel } else if (usb_endpoint_is_bulk_out(ep)) { 660e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel if (i==0) 661e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel ep_wr = ep; 662e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel else 663e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel ep_out = ep; 664e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel } 665e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel } 666e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel err = -EIO; 667e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel if (!ep_wr || !ep_in || !ep_out) 668e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel goto error; 669e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 670e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel al->write_out = usb_sndbulkpipe(al->dev, 671232ed5e68a969b1717afdb1d4c49146e5beb5465Julia Lawall usb_endpoint_num(ep_wr)); 672e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel al->bulk_in = usb_rcvbulkpipe(al->dev, 673232ed5e68a969b1717afdb1d4c49146e5beb5465Julia Lawall usb_endpoint_num(ep_in)); 674e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel al->bulk_out = usb_sndbulkpipe(al->dev, 675232ed5e68a969b1717afdb1d4c49146e5beb5465Julia Lawall usb_endpoint_num(ep_out)); 676e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 677e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel /* second device is identical up to now */ 678e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel memcpy(al+1, al, sizeof(*al)); 679e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 680e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel mutex_init(&al[0].card_mutex); 681e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel mutex_init(&al[1].card_mutex); 682e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 683e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel al[0].port = ALAUDA_PORT_XD; 684e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel al[1].port = ALAUDA_PORT_SM; 685e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 686b887265c165f94917d0f565b1883a6e7b3c8388cGreg Kroah-Hartman dev_info(&interface->dev, "alauda probed\n"); 687e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel alauda_check_media(al); 688e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel alauda_check_media(al+1); 689e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 690e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel return 0; 691e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 692e208520ed664db0f7584048ae09e5d2afda43714Jörn Engelerror: 693e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel if (al) 694e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel kref_put(&al->kref, alauda_delete); 695e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel return err; 696e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel} 697e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 698e208520ed664db0f7584048ae09e5d2afda43714Jörn Engelstatic void alauda_disconnect(struct usb_interface *interface) 699e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel{ 700e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel struct alauda *al; 701e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 702e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel al = usb_get_intfdata(interface); 703e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel usb_set_intfdata(interface, NULL); 704e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 705e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel /* FIXME: prevent more I/O from starting */ 706e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 707e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel /* decrement our usage count */ 708e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel if (al) 709e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel kref_put(&al->kref, alauda_delete); 710e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 711b887265c165f94917d0f565b1883a6e7b3c8388cGreg Kroah-Hartman dev_info(&interface->dev, "alauda gone"); 712e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel} 713e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 714e208520ed664db0f7584048ae09e5d2afda43714Jörn Engelstatic struct usb_driver alauda_driver = { 715e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel .name = "alauda", 716e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel .probe = alauda_probe, 717e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel .disconnect = alauda_disconnect, 718e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel .id_table = alauda_table, 719e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel}; 720e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 721fe7484834bb614c2c205726647635171ce6cc070Greg Kroah-Hartmanmodule_usb_driver(alauda_driver); 722e208520ed664db0f7584048ae09e5d2afda43714Jörn Engel 723e208520ed664db0f7584048ae09e5d2afda43714Jörn EngelMODULE_LICENSE("GPL"); 724