File Index
Files and directories
Sign in
FILE

tifm_ms.c

File preview with syntax highlighting.

linux-6.19.14/drivers/memstick/host/tifm_ms.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 *  TI FlashMedia driver
  4 *
  5 *  Copyright (C) 2007 Alex Dubov <oakad@yahoo.com>
  6 *
  7 * Special thanks to Carlos Corbacho for providing various MemoryStick cards
  8 * that made this driver possible.
  9 */
 10
 11#include <linux/tifm.h>
 12#include <linux/memstick.h>
 13#include <linux/highmem.h>
 14#include <linux/scatterlist.h>
 15#include <linux/log2.h>
 16#include <linux/module.h>
 17#include <asm/io.h>
 18
 19#define DRIVER_NAME "tifm_ms"
 20
 21static bool no_dma;
 22module_param(no_dma, bool, 0644);
 23
 24/*
 25 * Some control bits of TIFM appear to conform to Sony's reference design,
 26 * so I'm just assuming they all are.
 27 */
 28
 29#define TIFM_MS_STAT_DRQ     0x04000
 30#define TIFM_MS_STAT_MSINT   0x02000
 31#define TIFM_MS_STAT_RDY     0x01000
 32#define TIFM_MS_STAT_CRC     0x00200
 33#define TIFM_MS_STAT_TOE     0x00100
 34#define TIFM_MS_STAT_EMP     0x00020
 35#define TIFM_MS_STAT_FUL     0x00010
 36#define TIFM_MS_STAT_CED     0x00008
 37#define TIFM_MS_STAT_ERR     0x00004
 38#define TIFM_MS_STAT_BRQ     0x00002
 39#define TIFM_MS_STAT_CNK     0x00001
 40
 41#define TIFM_MS_SYS_DMA      0x10000
 42#define TIFM_MS_SYS_RESET    0x08000
 43#define TIFM_MS_SYS_SRAC     0x04000
 44#define TIFM_MS_SYS_INTEN    0x02000
 45#define TIFM_MS_SYS_NOCRC    0x01000
 46#define TIFM_MS_SYS_INTCLR   0x00800
 47#define TIFM_MS_SYS_MSIEN    0x00400
 48#define TIFM_MS_SYS_FCLR     0x00200
 49#define TIFM_MS_SYS_FDIR     0x00100
 50#define TIFM_MS_SYS_DAM      0x00080
 51#define TIFM_MS_SYS_DRM      0x00040
 52#define TIFM_MS_SYS_DRQSL    0x00020
 53#define TIFM_MS_SYS_REI      0x00010
 54#define TIFM_MS_SYS_REO      0x00008
 55#define TIFM_MS_SYS_BSY_MASK 0x00007
 56
 57#define TIFM_MS_SYS_FIFO     (TIFM_MS_SYS_INTEN | TIFM_MS_SYS_MSIEN \
 58			      | TIFM_MS_SYS_FCLR | TIFM_MS_SYS_BSY_MASK)
 59
 60/* Hardware flags */
 61enum {
 62	CMD_READY  = 0x01,
 63	FIFO_READY = 0x02,
 64	CARD_INT   = 0x04
 65};
 66
 67struct tifm_ms {
 68	struct tifm_dev         *dev;
 69	struct timer_list       timer;
 70	struct memstick_request *req;
 71	struct tasklet_struct   notify;
 72	unsigned int            mode_mask;
 73	unsigned int            block_pos;
 74	unsigned long           timeout_jiffies;
 75	unsigned char           eject:1,
 76				use_dma:1;
 77	unsigned char           cmd_flags;
 78	unsigned char           io_pos;
 79	unsigned int            io_word;
 80};
 81
 82static unsigned int tifm_ms_read_data(struct tifm_ms *host,
 83				      unsigned char *buf, unsigned int length)
 84{
 85	struct tifm_dev *sock = host->dev;
 86	unsigned int off = 0;
 87
 88	while (host->io_pos && length) {
 89		buf[off++] = host->io_word & 0xff;
 90		host->io_word >>= 8;
 91		length--;
 92		host->io_pos--;
 93	}
 94
 95	if (!length)
 96		return off;
 97
 98	while (!(TIFM_MS_STAT_EMP & readl(sock->addr + SOCK_MS_STATUS))) {
 99		if (length < 4)
100			break;
101		*(unsigned int *)(buf + off) = __raw_readl(sock->addr
102							   + SOCK_MS_DATA);
103		length -= 4;
104		off += 4;
105	}
106
107	if (length
108	    && !(TIFM_MS_STAT_EMP & readl(sock->addr + SOCK_MS_STATUS))) {
109		host->io_word = readl(sock->addr + SOCK_MS_DATA);
110		for (host->io_pos = 4; host->io_pos; --host->io_pos) {
111			buf[off++] = host->io_word & 0xff;
112			host->io_word >>= 8;
113			length--;
114			if (!length)
115				break;
116		}
117	}
118
119	return off;
120}
121
122static unsigned int tifm_ms_write_data(struct tifm_ms *host,
123				       unsigned char *buf, unsigned int length)
124{
125	struct tifm_dev *sock = host->dev;
126	unsigned int off = 0;
127
128	if (host->io_pos) {
129		while (host->io_pos < 4 && length) {
130			host->io_word |=  buf[off++] << (host->io_pos * 8);
131			host->io_pos++;
132			length--;
133		}
134	}
135
136	if (host->io_pos == 4
137	    && !(TIFM_MS_STAT_FUL & readl(sock->addr + SOCK_MS_STATUS))) {
138		writel(TIFM_MS_SYS_FDIR | readl(sock->addr + SOCK_MS_SYSTEM),
139		       sock->addr + SOCK_MS_SYSTEM);
140		writel(host->io_word, sock->addr + SOCK_MS_DATA);
141		host->io_pos = 0;
142		host->io_word = 0;
143	} else if (host->io_pos) {
144		return off;
145	}
146
147	if (!length)
148		return off;
149
150	while (!(TIFM_MS_STAT_FUL & readl(sock->addr + SOCK_MS_STATUS))) {
151		if (length < 4)
152			break;
153		writel(TIFM_MS_SYS_FDIR | readl(sock->addr + SOCK_MS_SYSTEM),
154		       sock->addr + SOCK_MS_SYSTEM);
155		__raw_writel(*(unsigned int *)(buf + off),
156			     sock->addr + SOCK_MS_DATA);
157		length -= 4;
158		off += 4;
159	}
160
161	switch (length) {
162	case 3:
163		host->io_word |= buf[off + 2] << 16;
164		host->io_pos++;
165		fallthrough;
166	case 2:
167		host->io_word |= buf[off + 1] << 8;
168		host->io_pos++;
169		fallthrough;
170	case 1:
171		host->io_word |= buf[off];
172		host->io_pos++;
173	}
174
175	off += host->io_pos;
176
177	return off;
178}
179
180static unsigned int tifm_ms_transfer_data(struct tifm_ms *host)
181{
182	struct tifm_dev *sock = host->dev;
183	unsigned int length;
184	unsigned int off;
185	unsigned int t_size, p_cnt;
186	unsigned char *buf;
187	struct page *pg;
188	unsigned long flags = 0;
189
190	if (host->req->long_data) {
191		length = host->req->sg.length - host->block_pos;
192		off = host->req->sg.offset + host->block_pos;
193	} else {
194		length = host->req->data_len - host->block_pos;
195		off = 0;
196	}
197	dev_dbg(&sock->dev, "fifo data transfer, %d, %d\n", length,
198		host->block_pos);
199
200	while (length) {
201		unsigned int p_off;
202
203		if (host->req->long_data) {
204			pg = sg_page(&host->req->sg) + (off >> PAGE_SHIFT);
205			p_off = offset_in_page(off);
206			p_cnt = PAGE_SIZE - p_off;
207			p_cnt = min(p_cnt, length);
208
209			local_irq_save(flags);
210			buf = kmap_atomic(pg) + p_off;
211		} else {
212			buf = host->req->data + host->block_pos;
213			p_cnt = host->req->data_len - host->block_pos;
214		}
215
216		t_size = host->req->data_dir == WRITE
217			 ? tifm_ms_write_data(host, buf, p_cnt)
218			 : tifm_ms_read_data(host, buf, p_cnt);
219
220		if (host->req->long_data) {
221			kunmap_atomic(buf - p_off);
222			local_irq_restore(flags);
223		}
224
225		if (!t_size)
226			break;
227		host->block_pos += t_size;
228		length -= t_size;
229		off += t_size;
230	}
231
232	dev_dbg(&sock->dev, "fifo data transfer, %d remaining\n", length);
233	if (!length && (host->req->data_dir == WRITE)) {
234		if (host->io_pos) {
235			writel(TIFM_MS_SYS_FDIR
236			       | readl(sock->addr + SOCK_MS_SYSTEM),
237			       sock->addr + SOCK_MS_SYSTEM);
238			writel(host->io_word, sock->addr + SOCK_MS_DATA);
239		}
240		writel(TIFM_MS_SYS_FDIR
241		       | readl(sock->addr + SOCK_MS_SYSTEM),
242		       sock->addr + SOCK_MS_SYSTEM);
243		writel(0, sock->addr + SOCK_MS_DATA);
244	} else {
245		readl(sock->addr + SOCK_MS_DATA);
246	}
247
248	return length;
249}
250
251static int tifm_ms_issue_cmd(struct tifm_ms *host)
252{
253	struct tifm_dev *sock = host->dev;
254	unsigned int data_len, cmd, sys_param;
255
256	host->cmd_flags = 0;
257	host->block_pos = 0;
258	host->io_pos = 0;
259	host->io_word = 0;
260	host->cmd_flags = 0;
261
262	host->use_dma = !no_dma;
263
264	if (host->req->long_data) {
265		data_len = host->req->sg.length;
266		if (!is_power_of_2(data_len))
267			host->use_dma = 0;
268	} else {
269		data_len = host->req->data_len;
270		host->use_dma = 0;
271	}
272
273	writel(TIFM_FIFO_INT_SETALL,
274	       sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
275	writel(TIFM_FIFO_ENABLE,
276	       sock->addr + SOCK_FIFO_CONTROL);
277
278	if (host->use_dma) {
279		if (1 != tifm_map_sg(sock, &host->req->sg, 1,
280				     host->req->data_dir == READ
281				     ? DMA_FROM_DEVICE
282				     : DMA_TO_DEVICE)) {
283			host->req->error = -ENOMEM;
284			return host->req->error;
285		}
286		data_len = sg_dma_len(&host->req->sg);
287
288		writel(ilog2(data_len) - 2,
289		       sock->addr + SOCK_FIFO_PAGE_SIZE);
290		writel(TIFM_FIFO_INTMASK,
291		       sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET);
292		sys_param = TIFM_DMA_EN | (1 << 8);
293		if (host->req->data_dir == WRITE)
294			sys_param |= TIFM_DMA_TX;
295
296		writel(TIFM_FIFO_INTMASK,
297		       sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET);
298
299		writel(sg_dma_address(&host->req->sg),
300		       sock->addr + SOCK_DMA_ADDRESS);
301		writel(sys_param, sock->addr + SOCK_DMA_CONTROL);
302	} else {
303		writel(host->mode_mask | TIFM_MS_SYS_FIFO,
304		       sock->addr + SOCK_MS_SYSTEM);
305
306		writel(TIFM_FIFO_MORE,
307		       sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET);
308	}
309
310	mod_timer(&host->timer, jiffies + host->timeout_jiffies);
311	writel(TIFM_CTRL_LED | readl(sock->addr + SOCK_CONTROL),
312	       sock->addr + SOCK_CONTROL);
313	host->req->error = 0;
314
315	sys_param = readl(sock->addr + SOCK_MS_SYSTEM);
316	sys_param |= TIFM_MS_SYS_INTCLR;
317
318	if (host->use_dma)
319		sys_param |= TIFM_MS_SYS_DMA;
320	else
321		sys_param &= ~TIFM_MS_SYS_DMA;
322
323	writel(sys_param, sock->addr + SOCK_MS_SYSTEM);
324
325	cmd = (host->req->tpc & 0xf) << 12;
326	cmd |= data_len;
327	writel(cmd, sock->addr + SOCK_MS_COMMAND);
328
329	dev_dbg(&sock->dev, "executing TPC %x, %x\n", cmd, sys_param);
330	return 0;
331}
332
333static void tifm_ms_complete_cmd(struct tifm_ms *host)
334{
335	struct tifm_dev *sock = host->dev;
336	struct memstick_host *msh = tifm_get_drvdata(sock);
337	int rc;
338
339	timer_delete(&host->timer);
340
341	host->req->int_reg = readl(sock->addr + SOCK_MS_STATUS) & 0xff;
342	host->req->int_reg = (host->req->int_reg & 1)
343			     | ((host->req->int_reg << 4) & 0xe0);
344
345	writel(TIFM_FIFO_INT_SETALL,
346	       sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
347	writel(TIFM_DMA_RESET, sock->addr + SOCK_DMA_CONTROL);
348
349	if (host->use_dma) {
350		tifm_unmap_sg(sock, &host->req->sg, 1,
351			      host->req->data_dir == READ
352			      ? DMA_FROM_DEVICE
353			      : DMA_TO_DEVICE);
354	}
355
356	writel((~TIFM_CTRL_LED) & readl(sock->addr + SOCK_CONTROL),
357	       sock->addr + SOCK_CONTROL);
358
359	dev_dbg(&sock->dev, "TPC complete\n");
360	do {
361		rc = memstick_next_req(msh, &host->req);
362	} while (!rc && tifm_ms_issue_cmd(host));
363}
364
365static int tifm_ms_check_status(struct tifm_ms *host)
366{
367	if (!host->req->error) {
368		if (!(host->cmd_flags & CMD_READY))
369			return 1;
370		if (!(host->cmd_flags & FIFO_READY))
371			return 1;
372		if (host->req->need_card_int
373		    && !(host->cmd_flags & CARD_INT))
374			return 1;
375	}
376	return 0;
377}
378
379/* Called from interrupt handler */
380static void tifm_ms_data_event(struct tifm_dev *sock)
381{
382	struct tifm_ms *host;
383	unsigned int fifo_status = 0, host_status = 0;
384	int rc = 1;
385
386	spin_lock(&sock->lock);
387	host = memstick_priv((struct memstick_host *)tifm_get_drvdata(sock));
388	fifo_status = readl(sock->addr + SOCK_DMA_FIFO_STATUS);
389	host_status = readl(sock->addr + SOCK_MS_STATUS);
390	dev_dbg(&sock->dev,
391		"data event: fifo_status %x, host_status %x, flags %x\n",
392		fifo_status, host_status, host->cmd_flags);
393
394	if (host->req) {
395		if (host->use_dma && (fifo_status & 1)) {
396			host->cmd_flags |= FIFO_READY;
397			rc = tifm_ms_check_status(host);
398		}
399		if (!host->use_dma && (fifo_status & TIFM_FIFO_MORE)) {
400			if (!tifm_ms_transfer_data(host)) {
401				host->cmd_flags |= FIFO_READY;
402				rc = tifm_ms_check_status(host);
403			}
404		}
405	}
406
407	writel(fifo_status, sock->addr + SOCK_DMA_FIFO_STATUS);
408	if (!rc)
409		tifm_ms_complete_cmd(host);
410
411	spin_unlock(&sock->lock);
412}
413
414
415/* Called from interrupt handler */
416static void tifm_ms_card_event(struct tifm_dev *sock)
417{
418	struct tifm_ms *host;
419	unsigned int host_status = 0;
420	int rc = 1;
421
422	spin_lock(&sock->lock);
423	host = memstick_priv((struct memstick_host *)tifm_get_drvdata(sock));
424	host_status = readl(sock->addr + SOCK_MS_STATUS);
425	dev_dbg(&sock->dev, "host event: host_status %x, flags %x\n",
426		host_status, host->cmd_flags);
427
428	if (host->req) {
429		if (host_status & TIFM_MS_STAT_TOE)
430			host->req->error = -ETIME;
431		else if (host_status & TIFM_MS_STAT_CRC)
432			host->req->error = -EILSEQ;
433
434		if (host_status & TIFM_MS_STAT_RDY)
435			host->cmd_flags |= CMD_READY;
436
437		if (host_status & TIFM_MS_STAT_MSINT)
438			host->cmd_flags |= CARD_INT;
439
440		rc = tifm_ms_check_status(host);
441
442	}
443
444	writel(TIFM_MS_SYS_INTCLR | readl(sock->addr + SOCK_MS_SYSTEM),
445	       sock->addr + SOCK_MS_SYSTEM);
446
447	if (!rc)
448		tifm_ms_complete_cmd(host);
449
450	spin_unlock(&sock->lock);
451	return;
452}
453
454static void tifm_ms_req_tasklet(unsigned long data)
455{
456	struct memstick_host *msh = (struct memstick_host *)data;
457	struct tifm_ms *host = memstick_priv(msh);
458	struct tifm_dev *sock = host->dev;
459	unsigned long flags;
460	int rc;
461
462	spin_lock_irqsave(&sock->lock, flags);
463	if (!host->req) {
464		if (host->eject) {
465			do {
466				rc = memstick_next_req(msh, &host->req);
467				if (!rc)
468					host->req->error = -ETIME;
469			} while (!rc);
470			spin_unlock_irqrestore(&sock->lock, flags);
471			return;
472		}
473
474		do {
475			rc = memstick_next_req(msh, &host->req);
476		} while (!rc && tifm_ms_issue_cmd(host));
477	}
478	spin_unlock_irqrestore(&sock->lock, flags);
479}
480
481static void tifm_ms_dummy_submit(struct memstick_host *msh)
482{
483	return;
484}
485
486static void tifm_ms_submit_req(struct memstick_host *msh)
487{
488	struct tifm_ms *host = memstick_priv(msh);
489
490	tasklet_schedule(&host->notify);
491}
492
493static int tifm_ms_set_param(struct memstick_host *msh,
494			     enum memstick_param param,
495			     int value)
496{
497	struct tifm_ms *host = memstick_priv(msh);
498	struct tifm_dev *sock = host->dev;
499
500	switch (param) {
501	case MEMSTICK_POWER:
502		/* also affected by media detection mechanism */
503		if (value == MEMSTICK_POWER_ON) {
504			host->mode_mask = TIFM_MS_SYS_SRAC | TIFM_MS_SYS_REI;
505			writel(TIFM_MS_SYS_RESET, sock->addr + SOCK_MS_SYSTEM);
506			writel(TIFM_MS_SYS_FCLR | TIFM_MS_SYS_INTCLR,
507			       sock->addr + SOCK_MS_SYSTEM);
508			writel(0xffffffff, sock->addr + SOCK_MS_STATUS);
509		} else if (value == MEMSTICK_POWER_OFF) {
510			writel(TIFM_MS_SYS_FCLR | TIFM_MS_SYS_INTCLR,
511			       sock->addr + SOCK_MS_SYSTEM);
512			writel(0xffffffff, sock->addr + SOCK_MS_STATUS);
513		} else
514			return -EINVAL;
515		break;
516	case MEMSTICK_INTERFACE:
517		if (value == MEMSTICK_SERIAL) {
518			host->mode_mask = TIFM_MS_SYS_SRAC | TIFM_MS_SYS_REI;
519			writel((~TIFM_CTRL_FAST_CLK)
520			       & readl(sock->addr + SOCK_CONTROL),
521			       sock->addr + SOCK_CONTROL);
522		} else if (value == MEMSTICK_PAR4) {
523			host->mode_mask = 0;
524			writel(TIFM_CTRL_FAST_CLK
525			       | readl(sock->addr + SOCK_CONTROL),
526			       sock->addr + SOCK_CONTROL);
527		} else
528			return -EINVAL;
529		break;
530	}
531
532	return 0;
533}
534
535static void tifm_ms_abort(struct timer_list *t)
536{
537	struct tifm_ms *host = timer_container_of(host, t, timer);
538
539	dev_dbg(&host->dev->dev, "status %x\n",
540		readl(host->dev->addr + SOCK_MS_STATUS));
541	printk(KERN_ERR
542	       "%s : card failed to respond for a long period of time "
543	       "(%x, %x)\n",
544	       dev_name(&host->dev->dev), host->req ? host->req->tpc : 0,
545	       host->cmd_flags);
546
547	tifm_eject(host->dev);
548}
549
550static int tifm_ms_probe(struct tifm_dev *sock)
551{
552	struct memstick_host *msh;
553	struct tifm_ms *host;
554	int rc = -EIO;
555
556	if (!(TIFM_SOCK_STATE_OCCUPIED
557	      & readl(sock->addr + SOCK_PRESENT_STATE))) {
558		printk(KERN_WARNING "%s : card gone, unexpectedly\n",
559		       dev_name(&sock->dev));
560		return rc;
561	}
562
563	msh = memstick_alloc_host(sizeof(struct tifm_ms), &sock->dev);
564	if (!msh)
565		return -ENOMEM;
566
567	host = memstick_priv(msh);
568	tifm_set_drvdata(sock, msh);
569	host->dev = sock;
570	host->timeout_jiffies = msecs_to_jiffies(1000);
571
572	timer_setup(&host->timer, tifm_ms_abort, 0);
573	tasklet_init(&host->notify, tifm_ms_req_tasklet, (unsigned long)msh);
574
575	msh->request = tifm_ms_submit_req;
576	msh->set_param = tifm_ms_set_param;
577	sock->card_event = tifm_ms_card_event;
578	sock->data_event = tifm_ms_data_event;
579	if (tifm_has_ms_pif(sock))
580		msh->caps |= MEMSTICK_CAP_PAR4;
581
582	rc = memstick_add_host(msh);
583	if (!rc)
584		return 0;
585
586	memstick_free_host(msh);
587	return rc;
588}
589
590static void tifm_ms_remove(struct tifm_dev *sock)
591{
592	struct memstick_host *msh = tifm_get_drvdata(sock);
593	struct tifm_ms *host = memstick_priv(msh);
594	int rc = 0;
595	unsigned long flags;
596
597	msh->request = tifm_ms_dummy_submit;
598	tasklet_kill(&host->notify);
599	spin_lock_irqsave(&sock->lock, flags);
600	host->eject = 1;
601	if (host->req) {
602		timer_delete(&host->timer);
603		writel(TIFM_FIFO_INT_SETALL,
604		       sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
605		writel(TIFM_DMA_RESET, sock->addr + SOCK_DMA_CONTROL);
606		if (host->use_dma)
607			tifm_unmap_sg(sock, &host->req->sg, 1,
608				      host->req->data_dir == READ
609				      ? DMA_TO_DEVICE
610				      : DMA_FROM_DEVICE);
611		host->req->error = -ETIME;
612
613		do {
614			rc = memstick_next_req(msh, &host->req);
615			if (!rc)
616				host->req->error = -ETIME;
617		} while (!rc);
618	}
619	spin_unlock_irqrestore(&sock->lock, flags);
620
621	memstick_remove_host(msh);
622	memstick_free_host(msh);
623}
624
625#ifdef CONFIG_PM
626
627static int tifm_ms_suspend(struct tifm_dev *sock, pm_message_t state)
628{
629	struct memstick_host *msh = tifm_get_drvdata(sock);
630
631	memstick_suspend_host(msh);
632	return 0;
633}
634
635static int tifm_ms_resume(struct tifm_dev *sock)
636{
637	struct memstick_host *msh = tifm_get_drvdata(sock);
638
639	memstick_resume_host(msh);
640	return 0;
641}
642
643#else
644
645#define tifm_ms_suspend NULL
646#define tifm_ms_resume NULL
647
648#endif /* CONFIG_PM */
649
650static struct tifm_device_id tifm_ms_id_tbl[] = {
651	{ TIFM_TYPE_MS }, { 0 }
652};
653
654static struct tifm_driver tifm_ms_driver = {
655	.driver = {
656		.name  = DRIVER_NAME,
657		.owner = THIS_MODULE
658	},
659	.id_table = tifm_ms_id_tbl,
660	.probe    = tifm_ms_probe,
661	.remove   = tifm_ms_remove,
662	.suspend  = tifm_ms_suspend,
663	.resume   = tifm_ms_resume
664};
665
666static int __init tifm_ms_init(void)
667{
668	return tifm_register_driver(&tifm_ms_driver);
669}
670
671static void __exit tifm_ms_exit(void)
672{
673	tifm_unregister_driver(&tifm_ms_driver);
674}
675
676MODULE_AUTHOR("Alex Dubov");
677MODULE_DESCRIPTION("TI FlashMedia MemoryStick driver");
678MODULE_LICENSE("GPL");
679MODULE_DEVICE_TABLE(tifm, tifm_ms_id_tbl);
680
681module_init(tifm_ms_init);
682module_exit(tifm_ms_exit);
~/ Read-only file preview.