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