1#include "ixj-ver.h" 2 3#include <linux/module.h> 4 5#include <linux/init.h> 6#include <linux/kernel.h> /* printk() */ 7#include <linux/fs.h> /* everything... */ 8#include <linux/errno.h> /* error codes */ 9#include <linux/slab.h> 10 11#include <pcmcia/cs_types.h> 12#include <pcmcia/cs.h> 13#include <pcmcia/cistpl.h> 14#include <pcmcia/ds.h> 15 16#include "ixj.h" 17 18/* 19 * PCMCIA service support for Quicknet cards 20 */ 21 22#ifdef PCMCIA_DEBUG 23static int pc_debug = PCMCIA_DEBUG; 24module_param(pc_debug, int, 0644); 25#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) 26#else 27#define DEBUG(n, args...) 28#endif 29 30typedef struct ixj_info_t { 31 int ndev; 32 dev_node_t node; 33 struct ixj *port; 34} ixj_info_t; 35 36static void ixj_detach(struct pcmcia_device *p_dev); 37static int ixj_config(struct pcmcia_device * link); 38static void ixj_cs_release(struct pcmcia_device * link); 39 40static int ixj_probe(struct pcmcia_device *p_dev) 41{ 42 DEBUG(0, "ixj_attach()\n"); 43 /* Create new ixj device */ 44 p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8; 45 p_dev->io.Attributes2 = IO_DATA_PATH_WIDTH_8; 46 p_dev->io.IOAddrLines = 3; 47 p_dev->conf.IntType = INT_MEMORY_AND_IO; 48 p_dev->priv = kmalloc(sizeof(struct ixj_info_t), GFP_KERNEL); 49 if (!p_dev->priv) { 50 return -ENOMEM; 51 } 52 memset(p_dev->priv, 0, sizeof(struct ixj_info_t)); 53 54 return ixj_config(p_dev); 55} 56 57static void ixj_detach(struct pcmcia_device *link) 58{ 59 DEBUG(0, "ixj_detach(0x%p)\n", link); 60 61 ixj_cs_release(link); 62 63 kfree(link->priv); 64} 65 66#define CS_CHECK(fn, ret) \ 67do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) 68 69static void ixj_get_serial(struct pcmcia_device * link, IXJ * j) 70{ 71 char *str; 72 int i, place; 73 DEBUG(0, "ixj_get_serial(0x%p)\n", link); 74 75 str = link->prod_id[0]; 76 if (!str) 77 goto cs_failed; 78 printk("%s", str); 79 str = link->prod_id[1]; 80 if (!str) 81 goto cs_failed; 82 printk(" %s", str); 83 str = link->prod_id[2]; 84 if (!str) 85 goto cs_failed; 86 place = 1; 87 for (i = strlen(str) - 1; i >= 0; i--) { 88 switch (str[i]) { 89 case '0': 90 case '1': 91 case '2': 92 case '3': 93 case '4': 94 case '5': 95 case '6': 96 case '7': 97 case '8': 98 case '9': 99 j->serial += (str[i] - 48) * place; 100 break; 101 case 'A': 102 case 'B': 103 case 'C': 104 case 'D': 105 case 'E': 106 case 'F': 107 j->serial += (str[i] - 55) * place; 108 break; 109 case 'a': 110 case 'b': 111 case 'c': 112 case 'd': 113 case 'e': 114 case 'f': 115 j->serial += (str[i] - 87) * place; 116 break; 117 } 118 place = place * 0x10; 119 } 120 str = link->prod_id[3]; 121 if (!str) 122 goto cs_failed; 123 printk(" version %s\n", str); 124 cs_failed: 125 return; 126} 127 128static int ixj_config(struct pcmcia_device * link) 129{ 130 IXJ *j; 131 ixj_info_t *info; 132 tuple_t tuple; 133 u_short buf[128]; 134 cisparse_t parse; 135 cistpl_cftable_entry_t *cfg = &parse.cftable_entry; 136 cistpl_cftable_entry_t dflt = 137 { 138 0 139 }; 140 int last_ret, last_fn; 141 info = link->priv; 142 DEBUG(0, "ixj_config(0x%p)\n", link); 143 tuple.TupleData = (cisdata_t *) buf; 144 tuple.TupleOffset = 0; 145 tuple.TupleDataMax = 255; 146 tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; 147 tuple.Attributes = 0; 148 CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); 149 while (1) { 150 if (pcmcia_get_tuple_data(link, &tuple) != 0 || 151 pcmcia_parse_tuple(link, &tuple, &parse) != 0) 152 goto next_entry; 153 if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { 154 cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io; 155 link->conf.ConfigIndex = cfg->index; 156 link->io.BasePort1 = io->win[0].base; 157 link->io.NumPorts1 = io->win[0].len; 158 if (io->nwin == 2) { 159 link->io.BasePort2 = io->win[1].base; 160 link->io.NumPorts2 = io->win[1].len; 161 } 162 if (pcmcia_request_io(link, &link->io) != 0) 163 goto next_entry; 164 /* If we've got this far, we're done */ 165 break; 166 } 167 next_entry: 168 if (cfg->flags & CISTPL_CFTABLE_DEFAULT) 169 dflt = *cfg; 170 CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple)); 171 } 172 173 CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); 174 175 /* 176 * Register the card with the core. 177 */ 178 j=ixj_pcmcia_probe(link->io.BasePort1,link->io.BasePort1 + 0x10); 179 180 info->ndev = 1; 181 info->node.major = PHONE_MAJOR; 182 link->dev_node = &info->node; 183 ixj_get_serial(link, j); 184 return 0; 185 cs_failed: 186 cs_error(link, last_fn, last_ret); 187 ixj_cs_release(link); 188 return -ENODEV; 189} 190 191static void ixj_cs_release(struct pcmcia_device *link) 192{ 193 ixj_info_t *info = link->priv; 194 DEBUG(0, "ixj_cs_release(0x%p)\n", link); 195 info->ndev = 0; 196 pcmcia_disable_device(link); 197} 198 199static struct pcmcia_device_id ixj_ids[] = { 200 PCMCIA_DEVICE_MANF_CARD(0x0257, 0x0600), 201 PCMCIA_DEVICE_NULL 202}; 203MODULE_DEVICE_TABLE(pcmcia, ixj_ids); 204 205static struct pcmcia_driver ixj_driver = { 206 .owner = THIS_MODULE, 207 .drv = { 208 .name = "ixj_cs", 209 }, 210 .probe = ixj_probe, 211 .remove = ixj_detach, 212 .id_table = ixj_ids, 213}; 214 215static int __init ixj_pcmcia_init(void) 216{ 217 return pcmcia_register_driver(&ixj_driver); 218} 219 220static void ixj_pcmcia_exit(void) 221{ 222 pcmcia_unregister_driver(&ixj_driver); 223} 224 225module_init(ixj_pcmcia_init); 226module_exit(ixj_pcmcia_exit); 227 228MODULE_LICENSE("GPL"); 229