aboutsummaryrefslogtreecommitdiffstats
path: root/crypto/rmd160.c
blob: 472261fc913fb43918c0074fc72023190e31acff (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
/*
 * Cryptographic API.
 *
 * RIPEMD-160 - RACE Integrity Primitives Evaluation Message Digest.
 *
 * Based on the reference implementation by Antoon Bosselaers, ESAT-COSIC
 *
 * Copyright (c) 2008 Adrian-Ken Rueegsegger <rueegsegger (at) swiss-it.ch>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 */
#include <crypto/internal/hash.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/types.h>
#include <asm/byteorder.h>

#include "ripemd.h"

struct rmd160_ctx {
	u64 byte_count;
	u32 state[5];
	__le32 buffer[16];
};

#define K1  RMD_K1
#define K2  RMD_K2
#define K3  RMD_K3
#define K4  RMD_K4
#define K5  RMD_K5
#define KK1 RMD_K6
#define KK2 RMD_K7
#define KK3 RMD_K8
#define KK4 RMD_K9
#define KK5 RMD_K1

#define F1(x, y, z) (x ^ y ^ z)		/* XOR */
#define F2(x, y, z) (z ^ (x & (y ^ z)))	/* x ? y : z */
#define F3(x, y, z) ((x | ~y) ^ z)
#define F4(x, y, z) (y ^ (z & (x ^ y)))	/* z ? x : y */
#define F5(x, y, z) (x ^ (y | ~z))

#define ROUND(a, b, c, d, e, f, k, x, s)  { \
	(a) += f((b), (c), (d)) + le32_to_cpup(&(x)) + (k); \
	(a) = rol32((a), (s)) + (e); \
	(c) = rol32((c), 10); \
}

static void rmd160_transform(u32 *state, const __le32 *in)
{
	u32 aa, bb, cc, dd, ee, aaa, bbb, ccc, ddd, eee;

	/* Initialize left lane */
	aa = state[0];
	bb = state[1];
	cc = state[2];
	dd = state[3];
	ee = state[4];

	/* Initialize right lane */
	aaa = state[0];
	bbb = state[1];
	ccc = state[2];
	ddd = state[3];
	eee = state[4];

	/* round 1: left lane */
	ROUND(aa, bb, cc, dd, ee, F1, K1, in[0],  11);
	ROUND(ee, aa, bb, cc, dd, F1, K1, in[1],  14);
	ROUND(dd, ee, aa, bb, cc, F1, K1, in[2],  15);
	ROUND(cc, dd, ee, aa, bb, F1, K1, in[3],  12);
	ROUND(bb, cc, dd, ee, aa, F1, K1, in[4],   5);
	ROUND(aa, bb, cc, dd, ee, F1, K1, in[5],   8);
	ROUND(ee, aa, bb, cc, dd, F1, K1, in[6],   7);
	ROUND(dd, ee, aa, bb, cc, F1, K1, in[7],   9);
	ROUND(cc, dd, ee, aa, bb, F1, K1, in[8],  11);
	ROUND(bb, cc, dd, ee, aa, F1, K1, in[9],  13);
	ROUND(aa, bb, cc, dd, ee, F1, K1, in[10], 14);
	ROUND(ee, aa, bb, cc, dd, F1, K1, in[11], 15);
	ROUND(dd, ee, aa, bb, cc, F1, K1, in[12],  6);
	ROUND(cc, dd, ee, aa, bb, F1, K1, in[13],  7);
	ROUND(bb, cc, dd, ee, aa, F1, K1, in[14],  9);
	ROUND(aa, bb, cc, dd, ee, F1, K1, in[15],  8);

	/* round 2: left lane" */
	ROUND(ee, aa, bb, cc, dd, F2, K2, in[7],   7);
	ROUND(dd, ee, aa, bb, cc, F2, K2, in[4],   6);
	ROUND(cc, dd, ee, aa, bb, F2, K2, in[13],  8);
	ROUND(bb, cc, dd, ee, aa, F2, K2, in[1],  13);
	ROUND(aa, bb, cc, dd, ee, F2, K2, in[10], 11);
	ROUND(ee, aa, bb, cc, dd, F2, K2, in[6],   9);
	ROUND(dd, ee, aa, bb, cc, F2, K2, in[15],  7);
	ROUND(cc, dd, ee, aa, bb, F2, K2, in[3],  15);
	ROUND(bb, cc, dd, ee, aa, F2, K2, in[12],  7);
	ROUND(aa, bb, cc, dd, ee, F2, K2, in[0],  12);
	ROUND(ee, aa, bb, cc, dd, F2, K2, in[9],  15);
	ROUND(dd, ee, aa, bb, cc, F2, K2, in[5],   9);
	ROUND(cc, dd, ee, aa, bb, F2, K2, in[2],  11);
	ROUND(bb, cc, dd, ee, aa, F2, K2, in[14],  7);
	ROUND(aa, bb, cc, dd, ee, F2, K2, in[11], 13);
	ROUND(ee, aa, bb, cc, dd, F2, K2, in[8],  12);

	/* round 3: left lane" */
	ROUND(dd, ee, aa, bb, cc, F3, K3, in[3],  11);
	ROUND(cc, dd, ee, aa, bb, F3, K3, in[10], 13);
	ROUND(bb, cc, dd, ee, aa, F3, K3, in[14],  6);
	ROUND(aa, bb, cc, dd, ee, F3, K3, in[4],   7);
	ROUND(ee, aa, bb, cc, dd, F3, K3, in[9],  14);
	ROUND(dd, ee, aa, bb, cc, F3, K3, in[15],  9);
	ROUND(cc, dd, ee, aa, bb, F3, K3, in[8],  13);
	ROUND(bb, cc, dd, ee, aa, F3, K3, in[1],  15);
	ROUND(aa, bb, cc, dd, ee, F3, K3, in[2],  14);
	ROUND(ee, aa, bb, cc, dd, F3, K3, in[7],   8);
	ROUND(dd, ee, aa, bb, cc, F3, K3, in[0],  13);
	ROUND(cc, dd, ee, aa, bb, F3, K3, in[6],   6);
	ROUND(bb, cc, dd, ee, aa, F3, K3, in[13],  5);
	ROUND(aa, bb, cc, dd, ee, F3, K3, in[11], 12);
	ROUND(ee, aa, bb, cc, dd, F3, K3, in[5],   7);
	ROUND(dd, ee, aa, bb, cc, F3, K3, in[12],  5);

	/* round 4: left lane" */
	ROUND(cc, dd, ee, aa, bb, F4, K4, in[1],  11);
	ROUND(bb, cc, dd, ee, aa, F4, K4, in[9],  12);
	ROUND(aa, bb, cc, dd, ee, F4, K4, in[11], 14);
	ROUND(ee, aa, bb, cc, dd, F4, K4, in[10], 15);
	ROUND(dd, ee, aa, bb, cc, F4, K4, in[0],  14);
	ROUND(cc, dd, ee, aa, bb, F4, K4, in[8],  15);
	ROUND(bb, cc, dd, ee, aa, F4, K4, in[12],  9);
	ROUND(aa, bb, cc, dd, ee, F4, K4, in[4],   8);
	ROUND(ee, aa, bb, cc, dd, F4, K4, in[13],  9);
	ROUND(dd, ee, aa, bb, cc, F4, K4, in[3],  14);
	ROUND(cc, dd, ee, aa, bb, F4, K4, in[7],   5);
	ROUND(bb, cc, dd, ee, aa, F4, K4, in[15],  6);
	ROUND(aa, bb, cc, dd, ee, F4, K4, in[14],  8);
	ROUND(ee, aa, bb, cc, dd, F4, K4, in[5],   6);
	ROUND(dd, ee, aa, bb, cc, F4, K4, in[6],   5);
	ROUND(cc, dd, ee, aa, bb, F4, K4, in[2],  12);

	/* round 5: left lane" */
	ROUND(bb, cc, dd, ee, aa, F5, K5, in[4],   9);
	ROUND(aa, bb, cc, dd, ee, F5, K5, in[0],  15);
	ROUND(ee, aa, bb, cc, dd, F5, K5, in[5],   5);
	ROUND(dd, ee, aa, bb, cc, F5, K5, in[9],  11);
	ROUND(cc, dd, ee, aa, bb, F5, K5, in[7],   6);
	ROUND(bb, cc, dd, ee, aa, F5, K5, in[12],  8);
	ROUND(aa, bb, cc, dd, ee, F5, K5, in[2],  13);
	ROUND(ee, aa, bb, cc, dd, F5, K5, in[10], 12);
	ROUND(dd, ee, aa, bb, cc, F5, K5, in[14],  5);
	ROUND(cc, dd, ee, aa, bb, F5, K5, in[1],  12);
	ROUND(bb, cc, dd, ee, aa, F5, K5, in[3],  13);
	ROUND(aa, bb, cc, dd, ee, F5, K5, in[8],  14);
	ROUND(ee, aa, bb, cc, dd, F5, K5, in[11], 11);
	ROUND(dd, ee, aa, bb, cc, F5, K5, in[6],   8);
	ROUND(cc, dd, ee, aa, bb, F5, K5, in[15],  5);
	ROUND(bb, cc, dd, ee, aa, F5, K5, in[13],  6);

	/* round 1: right lane */
	ROUND(aaa, bbb, ccc, ddd, eee, F5, KK1, in[5],   8);
	ROUND(eee, aaa, bbb, ccc, ddd, F5, KK1, in[14],  9);
	ROUND(ddd, eee, aaa, bbb, ccc, F5, KK1, in[7],   9);
	ROUND(ccc, ddd, eee, aaa, bbb, F5, KK1, in[0],  11);
	ROUND(bbb, ccc, ddd, eee, aaa, F5, KK1, in[9],  13);
	ROUND(aaa, bbb, ccc, ddd, eee, F5, KK1, in[2],  15);
	ROUND(eee, aaa, bbb, ccc, ddd, F5, KK1, in[11], 15);
	ROUND(ddd, eee, aaa, bbb, ccc, F5, KK1, in[4],   5);
	ROUND(ccc, ddd, eee, aaa, bbb, F5, KK1, in[13],  7);
	ROUND(bbb, ccc, ddd, eee, aaa, F5, KK1, in[6],   7);
	ROUND(aaa, bbb, ccc, ddd, eee, F5, KK1, in[15],  8);
	ROUND(eee, aaa, bbb, ccc, ddd, F5, KK1, in[8],  11);
	ROUND(ddd, eee, aaa, bbb, ccc, F5, KK1, in[1],  14);
	ROUND(ccc, ddd, eee, aaa, bbb, F5, KK1, in[10], 14);
	ROUND(bbb, ccc, ddd, eee, aaa, F5, KK1, in[3],  12);
	ROUND(aaa, bbb, ccc, ddd, eee, F5, KK1, in[12],  6);

	/* round 2: right lane */
	ROUND(eee, aaa, bbb, ccc, ddd, F4, KK2, in[6],   9);
	ROUND(ddd, eee, aaa, bbb, ccc, F4, KK2, in[11], 13);
	ROUND(ccc, ddd, eee, aaa, bbb, F4, KK2, in[3],  15);
	ROUND(bbb, ccc, ddd, eee, aaa, F4, KK2, in[7],   7);
	ROUND(aaa, bbb, ccc, ddd, eee, F4, KK2, in[0],  12);
	ROUND(eee, aaa, bbb, ccc, ddd, F4, KK2, in[13],  8);
	ROUND(ddd, eee, aaa, bbb, ccc, F4, KK2, in[5],   9);
	ROUND(ccc, ddd, eee, aaa, bbb, F4, KK2, in[10], 11);
	ROUND(bbb, ccc, ddd, eee, aaa, F4, KK2, in[14],  7);
	ROUND(aaa, bbb, ccc, ddd, eee, F4, KK2, in[15],  7);
	ROUND(eee, aaa, bbb, ccc, ddd, F4, KK2, in[8],  12);
	ROUND(ddd, eee, aaa, bbb, ccc, F4, KK2, in[12],  7);
	ROUND(ccc, ddd, eee, aaa, bbb, F4, KK2, in[4],   6);
	ROUND(bbb, ccc, ddd, eee, aaa, F4, KK2, in[9],  15);
	ROUND(aaa, bbb, ccc, ddd, eee, F4, KK2, in[1],  13);
	ROUND(eee, aaa, bbb, ccc, ddd, F4, KK2, in[2],  11);

	/* round 3: right lane */
	ROUND(ddd, eee, aaa, bbb, ccc, F3, KK3, in[15],  9);
	ROUND(ccc, ddd, eee, aaa, bbb, F3, KK3, in[5],   7);
	ROUND(bbb, ccc, ddd, eee, aaa, F3, KK3, in[1],  15);
	ROUND(aaa, bbb, ccc, ddd, eee, F3, KK3, in[3],  11);
	ROUND(eee, aaa, bbb, ccc, ddd, F3, KK3, in[7],   8);
	ROUND(ddd, eee, aaa, bbb, ccc, F3, KK3, in[14],  6);
	ROUND(ccc, ddd, eee, aaa, bbb, F3, KK3, in[6],   6);
	ROUND(bbb, ccc, ddd, eee, aaa, F3, KK3, in[9],  14);
	ROUND(aaa, bbb, ccc, ddd, eee, F3, KK3, in[11], 12);
	ROUND(eee, aaa, bbb, ccc, ddd, F3, KK3, in[8],  13);
	ROUND(ddd, eee, aaa, bbb, ccc, F3, KK3, in[12],  5);
	ROUND(ccc, ddd, eee, aaa, bbb, F3, KK3, in[2],  14);
	ROUND(bbb, ccc, ddd, eee, aaa, F3, KK3, in[10], 13);
	ROUND(aaa, bbb, ccc, ddd, eee, F3, KK3, in[0],  13);
	ROUND(eee, aaa, bbb, ccc, ddd, F3, KK3, in[4],   7);
	ROUND(ddd, eee, aaa, bbb, ccc, F3, KK3, in[13],  5);

	/* round 4: right lane */
	ROUND(ccc, ddd, eee, aaa, bbb, F2, KK4, in[8],  15);
	ROUND(bbb, ccc, ddd, eee, aaa, F2, KK4, in[6],   5);
	ROUND(aaa, bbb, ccc, ddd, eee, F2, KK4, in[4],   8);
	ROUND(eee, aaa, bbb, ccc, ddd, F2, KK4, in[1],  11);
	ROUND(ddd, eee, aaa, bbb, ccc, F2, KK4, in[3],  14);
	ROUND(ccc, ddd, eee, aaa, bbb, F2, KK4, in[11], 14);
	ROUND(bbb, ccc, ddd, eee, aaa, F2, KK4, in[15],  6);
	ROUND(aaa, bbb, ccc, ddd, eee, F2, KK4, in[0],  14);
	ROUND(eee, aaa, bbb, ccc, ddd, F2, KK4, in[5],   6);
	ROUND(ddd, eee, aaa, bbb, ccc, F2, KK4, in[12],  9);
	ROUND(ccc, ddd, eee, aaa, bbb, F2, KK4, in[2],  12);
	ROUND(bbb, ccc, ddd, eee, aaa, F2, KK4, in[13],  9);
	ROUND(aaa, bbb, ccc, ddd, eee, F2, KK4, in[9],  12);
	ROUND(eee, aaa, bbb, ccc, ddd, F2, KK4, in[7],   5);
	ROUND(ddd, eee, aaa, bbb, ccc, F2, KK4, in[10], 15);
	ROUND(ccc, ddd, eee, aaa, bbb, F2, KK4, in[14],  8);

	/* round 5: right lane */
	ROUND(bbb, ccc, ddd, eee, aaa, F1, KK5, in[12],  8);
	ROUND(aaa, bbb, ccc, ddd, eee, F1, KK5, in[15],  5);
	ROUND(eee, aaa, bbb, ccc, ddd, F1, KK5, in[10], 12);
	ROUND(ddd, eee, aaa, bbb, ccc, F1, KK5, in[4],   9);
	ROUND(ccc, ddd, eee, aaa, bbb, F1, KK5, in[1],  12);
	ROUND(bbb, ccc, ddd, eee, aaa, F1, KK5, in[5],   5);
	ROUND(aaa, bbb, ccc, ddd, eee, F1, KK5, in[8],  14);
	ROUND(eee, aaa, bbb, ccc, ddd, F1, KK5, in[7],   6);
	ROUND(ddd, eee, aaa, bbb, ccc, F1, KK5, in[6],   8);
	ROUND(ccc, ddd, eee, aaa, bbb, F1, KK5, in[2],  13);
	ROUND(bbb, ccc, ddd, eee, aaa, F1, KK5, in[13],  6);
	ROUND(aaa, bbb, ccc, ddd, eee, F1, KK5, in[14],  5);
	ROUND(eee, aaa, bbb, ccc, ddd, F1, KK5, in[0],  15);
	ROUND(ddd, eee, aaa, bbb, ccc, F1, KK5, in[3],  13);
	ROUND(ccc, ddd, eee, aaa, bbb, F1, KK5, in[9],  11);
	ROUND(bbb, ccc, ddd, eee, aaa, F1, KK5, in[11], 11);

	/* combine results */
	ddd += cc + state[1];		/* final result for state[0] */
	state[1] = state[2] + dd + eee;
	state[2] = state[3] + ee + aaa;
	state[3] = state[4] + aa + bbb;
	state[4] = state[0] + bb + ccc;
	state[0] = ddd;

	return;
}

static int rmd160_init(struct shash_desc *desc)
{
	struct rmd160_ctx *rctx = shash_desc_ctx(desc);

	rctx->byte_count = 0;

	rctx->state[0] = RMD_H0;
	rctx->state[1] = RMD_H1;
	rctx->state[2] = RMD_H2;
	rctx->state[3] = RMD_H3;
	rctx->state[4] = RMD_H4;

	memset(rctx->buffer, 0, sizeof(rctx->buffer));

	return 0;
}

static int rmd160_update(struct shash_desc *desc, const u8 *data,
			 unsigned int len)
{
	struct rmd160_ctx *rctx = shash_desc_ctx(desc);
	const u32 avail = sizeof(rctx->buffer) - (rctx->byte_count & 0x3f);

	rctx->byte_count += len;

	/* Enough space in buffer? If so copy and we're done */
	if (avail > len) {
		memcpy((char *)rctx->buffer + (sizeof(rctx->buffer) - avail),
		       data, len);
		goto out;
	}

	memcpy((char *)rctx->buffer + (sizeof(rctx->buffer) - avail),
	       data, avail);

	rmd160_transform(rctx->state, rctx->buffer);
	data += avail;
	len -= avail;

	while (len >= sizeof(rctx->buffer)) {
		memcpy(rctx->buffer, data, sizeof(rctx->buffer));
		rmd160_transform(rctx->state, rctx->buffer);
		data += sizeof(rctx->buffer);
		len -= sizeof(rctx->buffer);
	}

	memcpy(rctx->buffer, data, len);

out:
	return 0;
}

/* Add padding and return the message digest. */
static int rmd160_final(struct shash_desc *desc, u8 *out)
{
	struct rmd160_ctx *rctx = shash_desc_ctx(desc);
	u32 i, index, padlen;
	__le64 bits;
	__le32 *dst = (__le32 *)out;
	static const u8 padding[64] = { 0x80, };

	bits = cpu_to_le64(rctx->byte_count << 3);

	/* Pad out to 56 mod 64 */
	index = rctx->byte_count & 0x3f;
	padlen = (index < 56) ? (56 - index) : ((64+56) - index);
	rmd160_update(desc, padding, padlen);

	/* Append length */
	rmd160_update(desc, (const u8 *)&bits, sizeof(bits));

	/* Store state in digest */
	for (i = 0; i < 5; i++)
		dst[i] = cpu_to_le32p(&rctx->state[i]);

	/* Wipe context */
	memset(rctx, 0, sizeof(*rctx));

	return 0;
}

static struct shash_alg alg = {
	.digestsize	=	RMD160_DIGEST_SIZE,
	.init		=	rmd160_init,
	.update		=	rmd160_update,
	.final		=	rmd160_final,
	.descsize	=	sizeof(struct rmd160_ctx),
	.base		=	{
		.cra_name	 =	"rmd160",
		.cra_flags	 =	CRYPTO_ALG_TYPE_SHASH,
		.cra_blocksize	 =	RMD160_BLOCK_SIZE,
		.cra_module	 =	THIS_MODULE,
	}
};

static int __init rmd160_mod_init(void)
{
	return crypto_register_shash(&alg);
}

static void __exit rmd160_mod_fini(void)
{
	crypto_unregister_shash(&alg);
}

module_init(rmd160_mod_init);
module_exit(rmd160_mod_fini);

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("RIPEMD-160 Message Digest");
m)->pdev->dev, fmt, ##arg); /* ---------------------------------------------------------------------*/ /* * Device register I/O */ static inline void cafe_reg_write(struct cafe_camera *cam, unsigned int reg, unsigned int val) { iowrite32(val, cam->regs + reg); } static inline unsigned int cafe_reg_read(struct cafe_camera *cam, unsigned int reg) { return ioread32(cam->regs + reg); } static inline void cafe_reg_write_mask(struct cafe_camera *cam, unsigned int reg, unsigned int val, unsigned int mask) { unsigned int v = cafe_reg_read(cam, reg); v = (v & ~mask) | (val & mask); cafe_reg_write(cam, reg, v); } static inline void cafe_reg_clear_bit(struct cafe_camera *cam, unsigned int reg, unsigned int val) { cafe_reg_write_mask(cam, reg, 0, val); } static inline void cafe_reg_set_bit(struct cafe_camera *cam, unsigned int reg, unsigned int val) { cafe_reg_write_mask(cam, reg, val, val); } /* -------------------------------------------------------------------- */ /* * The I2C/SMBUS interface to the camera itself starts here. The * controller handles SMBUS itself, presenting a relatively simple register * interface; all we have to do is to tell it where to route the data. */ #define CAFE_SMBUS_TIMEOUT (HZ) /* generous */ static int cafe_smbus_write_done(struct cafe_camera *cam) { unsigned long flags; int c1; /* * We must delay after the interrupt, or the controller gets confused * and never does give us good status. Fortunately, we don't do this * often. */ udelay(20); spin_lock_irqsave(&cam->dev_lock, flags); c1 = cafe_reg_read(cam, REG_TWSIC1); spin_unlock_irqrestore(&cam->dev_lock, flags); return (c1 & (TWSIC1_WSTAT|TWSIC1_ERROR)) != TWSIC1_WSTAT; } static int cafe_smbus_write_data(struct cafe_camera *cam, u16 addr, u8 command, u8 value) { unsigned int rval; unsigned long flags; DEFINE_WAIT(the_wait); spin_lock_irqsave(&cam->dev_lock, flags); rval = TWSIC0_EN | ((addr << TWSIC0_SID_SHIFT) & TWSIC0_SID); rval |= TWSIC0_OVMAGIC; /* Make OV sensors work */ /* * Marvell sez set clkdiv to all 1's for now. */ rval |= TWSIC0_CLKDIV; cafe_reg_write(cam, REG_TWSIC0, rval); (void) cafe_reg_read(cam, REG_TWSIC1); /* force write */ rval = value | ((command << TWSIC1_ADDR_SHIFT) & TWSIC1_ADDR); cafe_reg_write(cam, REG_TWSIC1, rval); spin_unlock_irqrestore(&cam->dev_lock, flags); /* * Time to wait for the write to complete. THIS IS A RACY * WAY TO DO IT, but the sad fact is that reading the TWSIC1 * register too quickly after starting the operation sends * the device into a place that may be kinder and better, but * which is absolutely useless for controlling the sensor. In * practice we have plenty of time to get into our sleep state * before the interrupt hits, and the worst case is that we * time out and then see that things completed, so this seems * the best way for now. */ do { prepare_to_wait(&cam->smbus_wait, &the_wait, TASK_UNINTERRUPTIBLE); schedule_timeout(1); /* even 1 jiffy is too long */ finish_wait(&cam->smbus_wait, &the_wait); } while (!cafe_smbus_write_done(cam)); #ifdef IF_THE_CAFE_HARDWARE_WORKED_RIGHT wait_event_timeout(cam->smbus_wait, cafe_smbus_write_done(cam), CAFE_SMBUS_TIMEOUT); #endif spin_lock_irqsave(&cam->dev_lock, flags); rval = cafe_reg_read(cam, REG_TWSIC1); spin_unlock_irqrestore(&cam->dev_lock, flags); if (rval & TWSIC1_WSTAT) { cam_err(cam, "SMBUS write (%02x/%02x/%02x) timed out\n", addr, command, value); return -EIO; } if (rval & TWSIC1_ERROR) { cam_err(cam, "SMBUS write (%02x/%02x/%02x) error\n", addr, command, value); return -EIO; } return 0; } static int cafe_smbus_read_done(struct cafe_camera *cam) { unsigned long flags; int c1; /* * We must delay after the interrupt, or the controller gets confused * and never does give us good status. Fortunately, we don't do this * often. */ udelay(20); spin_lock_irqsave(&cam->dev_lock, flags); c1 = cafe_reg_read(cam, REG_TWSIC1); spin_unlock_irqrestore(&cam->dev_lock, flags); return c1 & (TWSIC1_RVALID|TWSIC1_ERROR); } static int cafe_smbus_read_data(struct cafe_camera *cam, u16 addr, u8 command, u8 *value) { unsigned int rval; unsigned long flags; spin_lock_irqsave(&cam->dev_lock, flags); rval = TWSIC0_EN | ((addr << TWSIC0_SID_SHIFT) & TWSIC0_SID); rval |= TWSIC0_OVMAGIC; /* Make OV sensors work */ /* * Marvel sez set clkdiv to all 1's for now. */ rval |= TWSIC0_CLKDIV; cafe_reg_write(cam, REG_TWSIC0, rval); (void) cafe_reg_read(cam, REG_TWSIC1); /* force write */ rval = TWSIC1_READ | ((command << TWSIC1_ADDR_SHIFT) & TWSIC1_ADDR); cafe_reg_write(cam, REG_TWSIC1, rval); spin_unlock_irqrestore(&cam->dev_lock, flags); wait_event_timeout(cam->smbus_wait, cafe_smbus_read_done(cam), CAFE_SMBUS_TIMEOUT); spin_lock_irqsave(&cam->dev_lock, flags); rval = cafe_reg_read(cam, REG_TWSIC1); spin_unlock_irqrestore(&cam->dev_lock, flags); if (rval & TWSIC1_ERROR) { cam_err(cam, "SMBUS read (%02x/%02x) error\n", addr, command); return -EIO; } if (! (rval & TWSIC1_RVALID)) { cam_err(cam, "SMBUS read (%02x/%02x) timed out\n", addr, command); return -EIO; } *value = rval & 0xff; return 0; } /* * Perform a transfer over SMBUS. This thing is called under * the i2c bus lock, so we shouldn't race with ourselves... */ static int cafe_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags, char rw, u8 command, int size, union i2c_smbus_data *data) { struct v4l2_device *v4l2_dev = i2c_get_adapdata(adapter); struct cafe_camera *cam = to_cam(v4l2_dev); int ret = -EINVAL; /* * This interface would appear to only do byte data ops. OK * it can do word too, but the cam chip has no use for that. */ if (size != I2C_SMBUS_BYTE_DATA) { cam_err(cam, "funky xfer size %d\n", size); return -EINVAL; } if (rw == I2C_SMBUS_WRITE) ret = cafe_smbus_write_data(cam, addr, command, data->byte); else if (rw == I2C_SMBUS_READ) ret = cafe_smbus_read_data(cam, addr, command, &data->byte); return ret; } static void cafe_smbus_enable_irq(struct cafe_camera *cam) { unsigned long flags; spin_lock_irqsave(&cam->dev_lock, flags); cafe_reg_set_bit(cam, REG_IRQMASK, TWSIIRQS); spin_unlock_irqrestore(&cam->dev_lock, flags); } static u32 cafe_smbus_func(struct i2c_adapter *adapter) { return I2C_FUNC_SMBUS_READ_BYTE_DATA | I2C_FUNC_SMBUS_WRITE_BYTE_DATA; } static struct i2c_algorithm cafe_smbus_algo = { .smbus_xfer = cafe_smbus_xfer, .functionality = cafe_smbus_func }; /* Somebody is on the bus */ static void cafe_ctlr_stop_dma(struct cafe_camera *cam); static void cafe_ctlr_power_down(struct cafe_camera *cam); static int cafe_smbus_setup(struct cafe_camera *cam) { struct i2c_adapter *adap = &cam->i2c_adapter; int ret; cafe_smbus_enable_irq(cam); adap->owner = THIS_MODULE; adap->algo = &cafe_smbus_algo; strcpy(adap->name, "cafe_ccic"); adap->dev.parent = &cam->pdev->dev; i2c_set_adapdata(adap, &cam->v4l2_dev); ret = i2c_add_adapter(adap); if (ret) printk(KERN_ERR "Unable to register cafe i2c adapter\n"); return ret; } static void cafe_smbus_shutdown(struct cafe_camera *cam) { i2c_del_adapter(&cam->i2c_adapter); } /* ------------------------------------------------------------------- */ /* * Deal with the controller. */ /* * Do everything we think we need to have the interface operating * according to the desired format. */ static void cafe_ctlr_dma(struct cafe_camera *cam) { /* * Store the first two Y buffers (we aren't supporting * planar formats for now, so no UV bufs). Then either * set the third if it exists, or tell the controller * to just use two. */ cafe_reg_write(cam, REG_Y0BAR, cam->dma_handles[0]); cafe_reg_write(cam, REG_Y1BAR, cam->dma_handles[1]); if (cam->nbufs > 2) { cafe_reg_write(cam, REG_Y2BAR, cam->dma_handles[2]); cafe_reg_clear_bit(cam, REG_CTRL1, C1_TWOBUFS); } else cafe_reg_set_bit(cam, REG_CTRL1, C1_TWOBUFS); cafe_reg_write(cam, REG_UBAR, 0); /* 32 bits only for now */ } static void cafe_ctlr_image(struct cafe_camera *cam) { int imgsz; struct v4l2_pix_format *fmt = &cam->pix_format; imgsz = ((fmt->height << IMGSZ_V_SHIFT) & IMGSZ_V_MASK) | (fmt->bytesperline & IMGSZ_H_MASK); cafe_reg_write(cam, REG_IMGSIZE, imgsz); cafe_reg_write(cam, REG_IMGOFFSET, 0); /* YPITCH just drops the last two bits */ cafe_reg_write_mask(cam, REG_IMGPITCH, fmt->bytesperline, IMGP_YP_MASK); /* * Tell the controller about the image format we are using. */ switch (cam->pix_format.pixelformat) { case V4L2_PIX_FMT_YUYV: cafe_reg_write_mask(cam, REG_CTRL0, C0_DF_YUV|C0_YUV_PACKED|C0_YUVE_YUYV, C0_DF_MASK); break; case V4L2_PIX_FMT_RGB444: cafe_reg_write_mask(cam, REG_CTRL0, C0_DF_RGB|C0_RGBF_444|C0_RGB4_XRGB, C0_DF_MASK); /* Alpha value? */ break; case V4L2_PIX_FMT_RGB565: cafe_reg_write_mask(cam, REG_CTRL0, C0_DF_RGB|C0_RGBF_565|C0_RGB5_BGGR, C0_DF_MASK); break; default: cam_err(cam, "Unknown format %x\n", cam->pix_format.pixelformat); break; } /* * Make sure it knows we want to use hsync/vsync. */ cafe_reg_write_mask(cam, REG_CTRL0, C0_SIF_HVSYNC, C0_SIFM_MASK); } /* * Configure the controller for operation; caller holds the * device mutex. */ static int cafe_ctlr_configure(struct cafe_camera *cam) { unsigned long flags; spin_lock_irqsave(&cam->dev_lock, flags); cafe_ctlr_dma(cam); cafe_ctlr_image(cam); cafe_set_config_needed(cam, 0); spin_unlock_irqrestore(&cam->dev_lock, flags); return 0; } static void cafe_ctlr_irq_enable(struct cafe_camera *cam) { /* * Clear any pending interrupts, since we do not * expect to have I/O active prior to enabling. */ cafe_reg_write(cam, REG_IRQSTAT, FRAMEIRQS); cafe_reg_set_bit(cam, REG_IRQMASK, FRAMEIRQS); } static void cafe_ctlr_irq_disable(struct cafe_camera *cam) { cafe_reg_clear_bit(cam, REG_IRQMASK, FRAMEIRQS); } /* * Make the controller start grabbing images. Everything must * be set up before doing this. */ static void cafe_ctlr_start(struct cafe_camera *cam) { /* set_bit performs a read, so no other barrier should be needed here */ cafe_reg_set_bit(cam, REG_CTRL0, C0_ENABLE); } static void cafe_ctlr_stop(struct cafe_camera *cam) { cafe_reg_clear_bit(cam, REG_CTRL0, C0_ENABLE); } static void cafe_ctlr_init(struct cafe_camera *cam) { unsigned long flags; spin_lock_irqsave(&cam->dev_lock, flags); /* * Added magic to bring up the hardware on the B-Test board */ cafe_reg_write(cam, 0x3038, 0x8); cafe_reg_write(cam, 0x315c, 0x80008); /* * Go through the dance needed to wake the device up. * Note that these registers are global and shared * with the NAND and SD devices. Interaction between the * three still needs to be examined. */ cafe_reg_write(cam, REG_GL_CSR, GCSR_SRS|GCSR_MRS); /* Needed? */ cafe_reg_write(cam, REG_GL_CSR, GCSR_SRC|GCSR_MRC); cafe_reg_write(cam, REG_GL_CSR, GCSR_SRC|GCSR_MRS); /* * Here we must wait a bit for the controller to come around. */ spin_unlock_irqrestore(&cam->dev_lock, flags); msleep(5); spin_lock_irqsave(&cam->dev_lock, flags); cafe_reg_write(cam, REG_GL_CSR, GCSR_CCIC_EN|GCSR_SRC|GCSR_MRC); cafe_reg_set_bit(cam, REG_GL_IMASK, GIMSK_CCIC_EN); /* * Make sure it's not powered down. */ cafe_reg_clear_bit(cam, REG_CTRL1, C1_PWRDWN); /* * Turn off the enable bit. It sure should be off anyway, * but it's good to be sure. */ cafe_reg_clear_bit(cam, REG_CTRL0, C0_ENABLE); /* * Mask all interrupts. */ cafe_reg_write(cam, REG_IRQMASK, 0); /* * Clock the sensor appropriately. Controller clock should * be 48MHz, sensor "typical" value is half that. */ cafe_reg_write_mask(cam, REG_CLKCTRL, 2, CLK_DIV_MASK); spin_unlock_irqrestore(&cam->dev_lock, flags); } /* * Stop the controller, and don't return until we're really sure that no * further DMA is going on. */ static void cafe_ctlr_stop_dma(struct cafe_camera *cam) { unsigned long flags; /* * Theory: stop the camera controller (whether it is operating * or not). Delay briefly just in case we race with the SOF * interrupt, then wait until no DMA is active. */ spin_lock_irqsave(&cam->dev_lock, flags); cafe_ctlr_stop(cam); spin_unlock_irqrestore(&cam->dev_lock, flags); mdelay(1); wait_event_timeout(cam->iowait, !test_bit(CF_DMA_ACTIVE, &cam->flags), HZ); if (test_bit(CF_DMA_ACTIVE, &cam->flags)) cam_err(cam, "Timeout waiting for DMA to end\n"); /* This would be bad news - what now? */ spin_lock_irqsave(&cam->dev_lock, flags); cam->state = S_IDLE; cafe_ctlr_irq_disable(cam); spin_unlock_irqrestore(&cam->dev_lock, flags); } /* * Power up and down. */ static void cafe_ctlr_power_up(struct cafe_camera *cam) { unsigned long flags; spin_lock_irqsave(&cam->dev_lock, flags); cafe_reg_clear_bit(cam, REG_CTRL1, C1_PWRDWN); /* * Part one of the sensor dance: turn the global * GPIO signal on. */ cafe_reg_write(cam, REG_GL_FCR, GFCR_GPIO_ON); cafe_reg_write(cam, REG_GL_GPIOR, GGPIO_OUT|GGPIO_VAL); /* * Put the sensor into operational mode (assumes OLPC-style * wiring). Control 0 is reset - set to 1 to operate. * Control 1 is power down, set to 0 to operate. */ cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN); /* pwr up, reset */ /* mdelay(1); */ /* Marvell says 1ms will do it */ cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN|GPR_C0); /* mdelay(1); */ /* Enough? */ spin_unlock_irqrestore(&cam->dev_lock, flags); msleep(5); /* Just to be sure */ } static void cafe_ctlr_power_down(struct cafe_camera *cam) { unsigned long flags; spin_lock_irqsave(&cam->dev_lock, flags); cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN|GPR_C1); cafe_reg_write(cam, REG_GL_FCR, GFCR_GPIO_ON); cafe_reg_write(cam, REG_GL_GPIOR, GGPIO_OUT); cafe_reg_set_bit(cam, REG_CTRL1, C1_PWRDWN); spin_unlock_irqrestore(&cam->dev_lock, flags); } /* -------------------------------------------------------------------- */ /* * Communications with the sensor. */ static int __cafe_cam_reset(struct cafe_camera *cam) { return sensor_call(cam, core, reset, 0); } /* * We have found the sensor on the i2c. Let's try to have a * conversation. */ static int cafe_cam_init(struct cafe_camera *cam) { struct v4l2_dbg_chip_ident chip; int ret; mutex_lock(&cam->s_mutex); if (cam->state != S_NOTREADY) cam_warn(cam, "Cam init with device in funky state %d", cam->state); ret = __cafe_cam_reset(cam); if (ret) goto out; chip.ident = V4L2_IDENT_NONE; chip.match.type = V4L2_CHIP_MATCH_I2C_ADDR; chip.match.addr = cam->sensor_addr; ret = sensor_call(cam, core, g_chip_ident, &chip); if (ret) goto out; cam->sensor_type = chip.ident; if (cam->sensor_type != V4L2_IDENT_OV7670) { cam_err(cam, "Unsupported sensor type 0x%x", cam->sensor_type); ret = -EINVAL; goto out; } /* Get/set parameters? */ ret = 0; cam->state = S_IDLE; out: cafe_ctlr_power_down(cam); mutex_unlock(&cam->s_mutex); return ret; } /* * Configure the sensor to match the parameters we have. Caller should * hold s_mutex */ static int cafe_cam_set_flip(struct cafe_camera *cam) { struct v4l2_control ctrl; memset(&ctrl, 0, sizeof(ctrl)); ctrl.id = V4L2_CID_VFLIP; ctrl.value = flip; return sensor_call(cam, core, s_ctrl, &ctrl); } static int cafe_cam_configure(struct cafe_camera *cam) { struct v4l2_mbus_framefmt mbus_fmt; int ret; if (cam->state != S_IDLE) return -EINVAL; v4l2_fill_mbus_format(&mbus_fmt, &cam->pix_format, cam->mbus_code); ret = sensor_call(cam, core, init, 0); if (ret == 0) ret = sensor_call(cam, video, s_mbus_fmt, &mbus_fmt); /* * OV7670 does weird things if flip is set *before* format... */ ret += cafe_cam_set_flip(cam); return ret; } /* -------------------------------------------------------------------- */ /* * DMA buffer management. These functions need s_mutex held. */ /* FIXME: this is inefficient as hell, since dma_alloc_coherent just * does a get_free_pages() call, and we waste a good chunk of an orderN * allocation. Should try to allocate the whole set in one chunk. */ static int cafe_alloc_dma_bufs(struct cafe_camera *cam, int loadtime) { int i; cafe_set_config_needed(cam, 1); if (loadtime) cam->dma_buf_size = dma_buf_size; else cam->dma_buf_size = cam->pix_format.sizeimage; if (n_dma_bufs > 3) n_dma_bufs = 3; cam->nbufs = 0; for (i = 0; i < n_dma_bufs; i++) { cam->dma_bufs[i] = dma_alloc_coherent(&cam->pdev->dev, cam->dma_buf_size, cam->dma_handles + i, GFP_KERNEL); if (cam->dma_bufs[i] == NULL) { cam_warn(cam, "Failed to allocate DMA buffer\n"); break; } /* For debug, remove eventually */ memset(cam->dma_bufs[i], 0xcc, cam->dma_buf_size); (cam->nbufs)++; } switch (cam->nbufs) {