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