]> rtime.felk.cvut.cz Git - socketcan-devel.git/blob - kernel/2.6/drivers/net/can/softing/softing_cs.c
Added two missing kernel version depencies.
[socketcan-devel.git] / kernel / 2.6 / drivers / net / can / softing / softing_cs.c
1 /*
2 * drivers/net/can/softing/softing_cs.c
3 *
4 * Copyright (C) 2008
5 *
6 * - Kurt Van Dijck, EIA Electronics
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the version 2 of the GNU General Public License
10 * as published by the Free Software Foundation
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22 #include <linux/module.h>
23 #include <linux/moduleparam.h>
24 #include <linux/version.h>
25 #include <linux/kernel.h>
26 #include <linux/init.h>
27 #include <linux/sched.h>
28 #include <linux/ptrace.h>
29 #include <linux/slab.h>
30 #include <linux/string.h>
31 #include <linux/timer.h>
32 #include <linux/major.h>
33 #include <linux/io.h>
34
35 #include <pcmcia/cs_types.h>
36 #include <pcmcia/cs.h>
37 #include <pcmcia/cistpl.h>
38 #include <pcmcia/ciscode.h>
39 #include <pcmcia/ds.h>
40 #include <pcmcia/cisreg.h>
41
42 #include <asm/system.h>
43
44 #include "softing.h"
45
46 struct softing_cs {
47         struct softing   softing;
48         win_req_t win;
49 };
50 #define softing2cs(x) container_of((x), struct softing_cs, softing)
51
52 /* card descriptions */
53 static const struct softing_desc carddescs[] = {
54 {
55         .name = "CANcard",
56         .manf = 0x0168, .prod = 0x001,
57         .generation = 1,
58         .freq = 16, .max_brp = 32, .max_sjw = 4,
59         .dpram_size = 0x0800,
60         .boot = {0x0000, 0x000000, fw_dir "bcard.bin",},
61         .load = {0x0120, 0x00f600, fw_dir "ldcard.bin",},
62         .app = {0x0010, 0x0d0000, fw_dir "cancard.bin",},
63 }, {
64         .name = "CANcard-NEC",
65         .manf = 0x0168, .prod = 0x002,
66         .generation = 1,
67         .freq = 16, .max_brp = 32, .max_sjw = 4,
68         .dpram_size = 0x0800,
69         .boot = {0x0000, 0x000000, fw_dir "bcard.bin",},
70         .load = {0x0120, 0x00f600, fw_dir "ldcard.bin",},
71         .app = {0x0010, 0x0d0000, fw_dir "cancard.bin",},
72 }, {
73         .name = "CANcard-SJA",
74         .manf = 0x0168, .prod = 0x004,
75         .generation = 1,
76         .freq = 20, .max_brp = 32, .max_sjw = 4,
77         .dpram_size = 0x0800,
78         .boot = {0x0000, 0x000000, fw_dir "bcard.bin",},
79         .load = {0x0120, 0x00f600, fw_dir "ldcard.bin",},
80         .app = {0x0010, 0x0d0000, fw_dir "cansja.bin",},
81 }, {
82         .name = "CANcard-2",
83         .manf = 0x0168, .prod = 0x005,
84         .generation = 2,
85         .freq = 24, .max_brp = 64, .max_sjw = 4,
86         .dpram_size = 0x0800,
87         .boot = {0x0000, 0x000000, fw_dir "bcard2.bin",},
88         .load = {0x0120, 0x00f600, fw_dir "ldcard2.bin",},
89         .app = {0x0010, 0x0d0000, fw_dir "cancrd2.bin",},
90 }, {
91         .name = "Vector-CANcard",
92         .manf = 0x0168, .prod = 0x081,
93         .generation = 1,
94         .freq = 16, .max_brp = 64, .max_sjw = 4,
95         .dpram_size = 0x0800,
96         .boot = {0x0000, 0x000000, fw_dir "bcard.bin",},
97         .load = {0x0120, 0x00f600, fw_dir "ldcard.bin",},
98         .app = {0x0010, 0x0d0000, fw_dir "cancard.bin",},
99 }, {
100         .name = "Vector-CANcard-SJA",
101         .manf = 0x0168, .prod = 0x084,
102         .generation = 1,
103         .freq = 20, .max_brp = 32, .max_sjw = 4,
104         .dpram_size = 0x0800,
105         .boot = {0x0000, 0x000000, fw_dir "bcard.bin",},
106         .load = {0x0120, 0x00f600, fw_dir "ldcard.bin",},
107         .app = {0x0010, 0x0d0000, fw_dir "cansja.bin",},
108 }, {
109         .name = "Vector-CANcard-2",
110         .manf = 0x0168, .prod = 0x085,
111         .generation = 2,
112         .freq = 24, .max_brp = 64, .max_sjw = 4,
113         .dpram_size = 0x0800,
114         .boot = {0x0000, 0x000000, fw_dir "bcard2.bin",},
115         .load = {0x0120, 0x00f600, fw_dir "ldcard2.bin",},
116         .app = {0x0010, 0x0d0000, fw_dir "cancrd2.bin",},
117 }, {
118         .name = "EDICcard-NEC",
119         .manf = 0x0168, .prod = 0x102,
120         .generation = 1,
121         .freq = 16, .max_brp = 64, .max_sjw = 4,
122         .dpram_size = 0x0800,
123         .boot = {0x0000, 0x000000, fw_dir "bcard.bin",},
124         .load = {0x0120, 0x00f600, fw_dir "ldcard.bin",},
125         .app = {0x0010, 0x0d0000, fw_dir "cancard.bin",},
126 }, {
127         .name = "EDICcard-2",
128         .manf = 0x0168, .prod = 0x105,
129         .generation = 2,
130         .freq = 24, .max_brp = 64, .max_sjw = 4,
131         .dpram_size = 0x0800,
132         .boot = {0x0000, 0x000000, fw_dir "bcard2.bin",},
133         .load = {0x0120, 0x00f600, fw_dir "ldcard2.bin",},
134         .app = {0x0010, 0x0d0000, fw_dir "cancrd2.bin",},
135         },
136 {0, 0,},
137 };
138
139 MODULE_FIRMWARE(fw_dir "bcard.bin");
140 MODULE_FIRMWARE(fw_dir "ldcard.bin");
141 MODULE_FIRMWARE(fw_dir "cancard.bin");
142 MODULE_FIRMWARE(fw_dir "cansja.bin");
143
144 MODULE_FIRMWARE(fw_dir "bcard2.bin");
145 MODULE_FIRMWARE(fw_dir "ldcard2.bin");
146 MODULE_FIRMWARE(fw_dir "cancrd2.bin");
147
148 static const struct softing_desc *softing_cs_lookup_desc
149                                         (unsigned int manf, unsigned int prod)
150 {
151         const struct softing_desc *lp = carddescs;
152         for (; lp->name; ++lp) {
153                 if ((lp->manf == manf) && (lp->prod == prod))
154                         return lp;
155         }
156         return 0;
157 }
158
159
160 struct lookup {
161         int i;
162         const char *a;
163 };
164
165 static const char __devinit *lookup_mask(const struct lookup *lp, int *i)
166 {
167         for (; lp->a; ++lp) {
168                 if (lp->i & *i) {
169                         *i &= ~lp->i;
170                         return lp->a;
171                 }
172         }
173         return 0;
174 }
175
176 static int card_reset_via_pcmcia(struct softing *sdev, int v)
177 {
178         struct pcmcia_device *pcmcia = to_pcmcia_dev(sdev->dev);
179         conf_reg_t reg;
180         reg.Function = 0; /* socket */
181         reg.Action       = CS_WRITE;
182         reg.Offset       = 2;
183         reg.Value        = v ? 0 : 0x20;
184         return pcmcia_access_configuration_register(pcmcia, &reg);
185 }
186
187 static int card_reset_via_dpram(struct softing *sdev, int v)
188 {
189         if (v) {
190                 spin_lock_bh(&sdev->spin);
191                 sdev->dpram.virt[0xe00] &= ~1;
192                 spin_unlock_bh(&sdev->spin);
193                 card_reset_via_pcmcia(sdev, v);
194         } else {
195                 card_reset_via_pcmcia(sdev, v);
196                 spin_lock_bh(&sdev->spin);
197                 sdev->dpram.virt[0xe00] |=  1;
198                 spin_unlock_bh(&sdev->spin);
199         }
200         return 0;
201 }
202
203 static int card_enable_irq_via_pcmcia(struct softing *sdev, int v)
204 {
205         int ret;
206         struct pcmcia_device *pcmcia = to_pcmcia_dev(sdev->dev);
207         conf_reg_t reg;
208         memset(&reg, 0, sizeof(reg));
209         reg.Function = 0; /* socket */
210         reg.Action       = CS_WRITE;
211         reg.Offset       = 0;
212         reg.Value        = v ? 0x60 : 0;
213         ret = pcmcia_access_configuration_register(pcmcia, &reg);
214         if (ret)
215                 dev_alert(&pcmcia->dev, "failed %u\n", ret);
216         return ret;
217 }
218
219 /* TODO: in 2.6.26, __devinitconst works*/
220 static const __devinitdata struct lookup pcmcia_io_attr[] = {
221         { IO_DATA_PATH_WIDTH_AUTO       , "[auto]"      , },
222         { IO_DATA_PATH_WIDTH_8          , "8bit"        , },
223         { IO_DATA_PATH_WIDTH_16         , "16bit"       , },
224         { 0, 0, },
225 };
226
227 static const __devinitdata struct lookup pcmcia_mem_attr[] = {
228         { WIN_ADDR_SPACE_IO     , "IO"          , },
229         { WIN_MEMORY_TYPE_AM    , "typeAM"      , },
230         { WIN_ENABLE            , "enable"      , },
231         { WIN_DATA_WIDTH_8      , "8bit"        , },
232         { WIN_DATA_WIDTH_16     , "16bit"       , },
233         { WIN_DATA_WIDTH_32     , "32bit"       , },
234         { WIN_PAGED             , "paged"       , },
235         { WIN_SHARED            , "shared"      , },
236         { WIN_FIRST_SHARED      , "first_shared", },
237         { WIN_USE_WAIT          , "wait"        , },
238         { WIN_STRICT_ALIGN      , "strict_align", },
239         { WIN_MAP_BELOW_1MB     , "below_1MB"   , },
240         { WIN_PREFETCH          , "prefetch"    , },
241         { WIN_CACHEABLE         , "cacheable"   , },
242         { 0, 0, },
243 };
244
245 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 28)
246 /* backported */
247 struct pcmcia_cfg_mem {
248         tuple_t tuple;
249         cisparse_t parse;
250         u8 buf[256];
251         cistpl_cftable_entry_t dflt;
252 };
253 static int pcmcia_loop_config(struct pcmcia_device *p_dev,
254                        int      (*conf_check)   (struct pcmcia_device *p_dev,
255                                                  cistpl_cftable_entry_t *cfg,
256                                                  cistpl_cftable_entry_t *dflt,
257                                                  unsigned int vcc,
258                                                  void *priv_data),
259                        void *priv_data)
260 {
261         struct pcmcia_cfg_mem *cfg_mem;
262
263         tuple_t *tuple;
264         int ret = -ENODEV;
265         unsigned int vcc;
266
267         cfg_mem = kzalloc(sizeof(*cfg_mem), GFP_KERNEL);
268         if (cfg_mem == NULL)
269                 return -ENOMEM;
270
271         /* get the current Vcc setting */
272         vcc = p_dev->socket->socket.Vcc;
273
274         tuple = &cfg_mem->tuple;
275         tuple->TupleData = cfg_mem->buf;
276         tuple->TupleDataMax = sizeof(cfg_mem->buf)-1;
277         tuple->TupleOffset = 0;
278         tuple->DesiredTuple = CISTPL_CFTABLE_ENTRY;
279         tuple->Attributes = 0;
280
281         ret = pcmcia_get_first_tuple(p_dev, tuple);
282         while (!ret) {
283                 cistpl_cftable_entry_t *cfg = &cfg_mem->parse.cftable_entry;
284
285                 if (pcmcia_get_tuple_data(p_dev, tuple))
286                         goto next_entry;
287
288                 if (pcmcia_parse_tuple(p_dev, tuple, &cfg_mem->parse))
289                         goto next_entry;
290
291                 /* default values */
292                 p_dev->conf.ConfigIndex = cfg->index;
293                 if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
294                         cfg_mem->dflt = *cfg;
295
296                 ret = conf_check(p_dev, cfg, &cfg_mem->dflt, vcc, priv_data);
297                 if (!ret)
298                         break;
299
300 next_entry:
301                 ret = pcmcia_get_next_tuple(p_dev, tuple);
302         }
303         kfree(cfg_mem);
304         return ret;
305 }
306 #endif
307
308 static int dev_conf_check(struct pcmcia_device *pdev,
309         cistpl_cftable_entry_t *cf, cistpl_cftable_entry_t *def_cf,
310         unsigned int vcc, void *priv_data)
311 {
312         struct softing_cs *csdev = priv_data;
313         struct softing *sdev = &csdev->softing;
314         int ret;
315
316         if (!cf->index)
317                 goto do_next;
318         /* power settings (Vcc & Vpp) */
319         if (cf->vcc.present & (1 << CISTPL_POWER_VNOM)) {
320                 if (vcc != cf->vcc.param[CISTPL_POWER_VNOM]/10000) {
321                         dev_alert(&pdev->dev, "cf->Vcc mismatch\n");
322                         goto do_next;
323                 }
324         } else if (def_cf->vcc.present & (1 << CISTPL_POWER_VNOM)) {
325                 if (vcc != def_cf->vcc.param[CISTPL_POWER_VNOM]/10000) {
326                         dev_alert(&pdev->dev, "cf->Vcc mismatch\n");
327                         goto do_next;
328                 }
329         }
330         if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM))
331                 pdev->conf.Vpp
332                         = cf->vpp1.param[CISTPL_POWER_VNOM] / 10000;
333
334         else if (def_cf->vpp1.present & (1 << CISTPL_POWER_VNOM))
335                 pdev->conf.Vpp
336                         = def_cf->vpp1.param[CISTPL_POWER_VNOM] / 10000;
337
338         /* interrupt ? */
339         if (cf->irq.IRQInfo1 || def_cf->irq.IRQInfo1)
340                 pdev->conf.Attributes |= CONF_ENABLE_IRQ;
341
342         /* IO window */
343         pdev->io.NumPorts1
344                 = pdev->io.NumPorts2
345                 = 0;
346         /* Memory window */
347         if ((cf->mem.nwin > 0) || (def_cf->mem.nwin > 0)) {
348                 memreq_t map;
349                 cistpl_mem_t *mem
350                         = (cf->mem.nwin) ? &cf->mem : &def_cf->mem;
351                 /* softing specific: choose 8 or 16bit access */
352                 csdev->win.Attributes = ((sdev->desc->generation >= 2)
353                                 ? WIN_DATA_WIDTH_16 : WIN_DATA_WIDTH_8)
354                         | WIN_MEMORY_TYPE_CM
355                         | WIN_ENABLE;
356                 csdev->win.Base = mem->win[0].host_addr;
357                 csdev->win.Size = mem->win[0].len;
358                 csdev->win.AccessSpeed = 0;
359                 /* softing specific: choose slower access for old cards */
360                 if (sdev->desc->generation < 2) {
361 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)
362                         pdev->win->ctl.flags
363                                 = MAP_ACTIVE | MAP_USE_WAIT;
364                         pdev->win->ctl.speed = 3;
365 #else
366                         csdev->win.Attributes |= WIN_USE_WAIT;
367                         csdev->win.AccessSpeed = 3;
368 #endif
369                 }
370 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)
371                 ret = pcmcia_request_window(&pdev, &csdev->win, &pdev->win);
372 #else
373                 ret = pcmcia_request_window(pdev, &csdev->win, &pdev->win);
374 #endif
375                 if (ret) {
376                         dev_alert(&pdev->dev,
377                                 "pcmcia_request_window() mismatch\n");
378                         goto do_next;
379                 }
380                 map.Page = 0;
381                 map.CardOffset = mem->win[0].card_addr;
382 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)
383                 if (pcmcia_map_mem_page(pdev->win, &map)) {
384 #else
385                 if (pcmcia_map_mem_page(pdev, pdev->win, &map)) {
386 #endif
387                         dev_alert(&pdev->dev,
388                                 "pcmcia_map_mem_page() mismatch\n");
389                         goto do_next_win;
390                 }
391         } else {
392                 dev_info(&pdev->dev, "no memory window in tuple %u\n",
393                         cf->index);
394                 goto do_next;
395         }
396         return 0;
397 do_next_win:
398 do_next:
399         pcmcia_disable_device(pdev);
400         return -ENODEV;
401 }
402
403 static void driver_remove(struct pcmcia_device *pcmcia)
404 {
405         struct softing *card = (struct softing *)pcmcia->priv;
406         struct softing_cs *cs = softing2cs(card);
407         dev_dbg(&pcmcia->dev, "%s, device '%s'\n"
408                 , card->id.name, pcmcia->devname);
409         rm_softing(card);
410         /* release pcmcia stuff */
411         pcmcia_disable_device(pcmcia);
412         /* free bits */
413         kfree(cs);
414 }
415
416 static int __devinit driver_probe(struct pcmcia_device *pcmcia)
417 {
418         struct softing_cs *cs;
419         struct softing *card;
420         char *str;
421         char line[1024]; /* possible memory corruption */
422
423         dev_dbg(&pcmcia->dev, "on %s\n", pcmcia->devname);
424
425         /* Create new softing device */
426         cs = kzalloc(sizeof(*cs), GFP_KERNEL);
427         if (!cs)
428                 goto no_mem;
429         /* setup links */
430         card = &cs->softing;
431         pcmcia->priv = card;
432         card->dev = &pcmcia->dev;
433         /* properties */
434         card->id.manf = pcmcia->manf_id;
435         card->id.prod = pcmcia->card_id;
436         card->desc = softing_cs_lookup_desc(card->id.manf, card->id.prod);
437         if (!card->desc) {
438                 dev_alert(&pcmcia->dev, "unknown card\n");
439                 goto description_failed;
440         }
441         if (card->desc->generation >= 2) {
442                 card->fn.reset = card_reset_via_dpram;
443         } else {
444                 card->fn.reset = card_reset_via_pcmcia;
445                 card->fn.enable_irq = card_enable_irq_via_pcmcia;
446         }
447
448         card->nbus = 2;
449         /* pcmcia presets */
450         pcmcia->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING;
451 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)
452         pcmcia->irq.IRQInfo1 = IRQ_LEVEL_ID;
453 #endif
454         pcmcia->irq.Handler     = 0;
455         pcmcia->conf.Attributes = 0;
456         pcmcia->conf.IntType = INT_MEMORY_AND_IO;
457
458         if (pcmcia_loop_config(pcmcia, dev_conf_check, cs))
459                 goto config_failed;
460
461         if (pcmcia_request_irq(pcmcia, &pcmcia->irq))
462                 goto config_failed;
463
464         if (pcmcia_request_configuration(pcmcia, &pcmcia->conf))
465                 goto config_failed;
466
467         card->dpram.phys = cs->win.Base;
468         card->dpram.size = cs->win.Size;
469
470         if (card->dpram.size != 0x1000) {
471                 dev_alert(&pcmcia->dev, "dpram size 0x%lx mismatch\n",
472                         card->dpram.size);
473                 goto wrong_dpram;
474         }
475
476         /* Finally, report what we've done */
477         str = line;
478         str += sprintf(str, "config index %u", pcmcia->conf.ConfigIndex);
479         if (pcmcia->conf.Vpp)
480                 str += sprintf(str, ", Vpp %d.%d",
481                         pcmcia->conf.Vpp/10, pcmcia->conf.Vpp%10);
482         if (pcmcia->conf.Attributes & CONF_ENABLE_IRQ) {
483                 str += sprintf(str, ", irq %d", pcmcia->irq.AssignedIRQ);
484                 card->irq.nr = pcmcia->irq.AssignedIRQ;
485         }
486
487         if (pcmcia->win) {
488                 int tmp;
489                 const char *p;
490                 str += sprintf(str, ", mem 0x%08lx-0x%08lx"
491                         , card->dpram.phys
492                         , card->dpram.phys + card->dpram.size-1);
493                 tmp = cs->win.Attributes;
494                 while (tmp) {
495                         p = lookup_mask(pcmcia_mem_attr, &tmp);
496                         if (!p)
497                                 continue;
498                         str += sprintf(str, " %s", p);
499                 }
500         }
501         dev_info(&pcmcia->dev, "%s\n", line);
502
503         if (mk_softing(card))
504                 goto softing_failed;
505         return 0;
506
507 softing_failed:
508 wrong_dpram:
509 config_failed:
510 description_failed:
511         kfree(cs);
512 no_mem:
513         pcmcia_disable_device(pcmcia);
514         return -ENODEV;
515 }
516
517 static struct pcmcia_device_id driver_ids[] = {
518         /* softing */
519         PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0001),
520         PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0002),
521         PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0004),
522         PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0005),
523         /* vector , manufacturer? */
524         PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0081),
525         PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0084),
526         PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0085),
527         /* EDIC */
528         PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0102),
529         PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0105),
530         PCMCIA_DEVICE_NULL,
531 };
532
533 MODULE_DEVICE_TABLE(pcmcia, driver_ids);
534
535 static struct pcmcia_driver softing_cs_driver = {
536         .owner          = THIS_MODULE,
537         .drv                    = {
538         .name           = "softing_cs",
539         },
540         .probe          = driver_probe,
541         .remove         = driver_remove,
542         .id_table       = driver_ids,
543 };
544
545 static int __init mod_start(void)
546 {
547         return pcmcia_register_driver(&softing_cs_driver);
548 }
549
550 static void __exit mod_stop(void)
551 {
552         pcmcia_unregister_driver(&softing_cs_driver);
553 }
554
555 module_init(mod_start);
556 module_exit(mod_stop);
557
558 MODULE_DESCRIPTION("softing CANcard driver"
559                 ", links PCMCIA card to softing driver");
560 MODULE_LICENSE("GPL");
561 MODULE_SUPPORTED_DEVICE("softing CANcard2");
562