aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/host/sl811_cs.c140
1 files changed, 69 insertions, 71 deletions
diff --git a/drivers/usb/host/sl811_cs.c b/drivers/usb/host/sl811_cs.c
index 5da63f535005..9773601bf0bb 100644
--- a/drivers/usb/host/sl811_cs.c
+++ b/drivers/usb/host/sl811_cs.c
@@ -155,88 +155,84 @@ static void sl811_cs_release(struct pcmcia_device * link)
155 platform_device_unregister(&platform_dev); 155 platform_device_unregister(&platform_dev);
156} 156}
157 157
158struct sl811_css_cfg {
159 cistpl_cftable_entry_t dflt;
160 config_info_t conf;
161};
162
163static int sl811_cs_config_check(struct pcmcia_device *p_dev,
164 cistpl_cftable_entry_t *cfg,
165 void *priv_data)
166{
167 struct sl811_css_cfg *cfg_mem = priv_data;
168
169 if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
170 memcpy(&cfg_mem->dflt, cfg, sizeof(cistpl_cftable_entry_t));
171
172 if (cfg->index == 0)
173 return -ENODEV;
174
175 p_dev->conf.ConfigIndex = cfg->index;
176
177 /* Use power settings for Vcc and Vpp if present */
178 /* Note that the CIS values need to be rescaled */
179 if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) {
180 if (cfg->vcc.param[CISTPL_POWER_VNOM]/10000 !=
181 cfg_mem->conf.Vcc)
182 return -ENODEV;
183 } else if (cfg_mem->dflt.vcc.present & (1<<CISTPL_POWER_VNOM)) {
184 if (cfg_mem->dflt.vcc.param[CISTPL_POWER_VNOM]/10000
185 != cfg_mem->conf.Vcc)
186 return -ENODEV;
187 }
188
189 if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM))
190 p_dev->conf.Vpp =
191 cfg->vpp1.param[CISTPL_POWER_VNOM]/10000;
192 else if (cfg_mem->dflt.vpp1.present & (1<<CISTPL_POWER_VNOM))
193 p_dev->conf.Vpp =
194 cfg_mem->dflt.vpp1.param[CISTPL_POWER_VNOM]/10000;
195
196 /* we need an interrupt */
197 if (cfg->irq.IRQInfo1 || cfg_mem->dflt.irq.IRQInfo1)
198 p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
199
200 /* IO window settings */
201 p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0;
202 if ((cfg->io.nwin > 0) || (cfg_mem->dflt.io.nwin > 0)) {
203 cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &cfg_mem->dflt.io;
204
205 p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
206 p_dev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
207 p_dev->io.BasePort1 = io->win[0].base;
208 p_dev->io.NumPorts1 = io->win[0].len;
209
210 return pcmcia_request_io(p_dev, &p_dev->io);
211 }
212 pcmcia_disable_device(p_dev);
213 return -ENODEV;
214}
215
216
158static int sl811_cs_config(struct pcmcia_device *link) 217static int sl811_cs_config(struct pcmcia_device *link)
159{ 218{
160 struct device *parent = &handle_to_dev(link); 219 struct device *parent = &handle_to_dev(link);
161 local_info_t *dev = link->priv; 220 local_info_t *dev = link->priv;
162 tuple_t tuple;
163 cisparse_t parse;
164 int last_fn, last_ret; 221 int last_fn, last_ret;
165 u_char buf[64]; 222 struct sl811_css_cfg *cfg_mem;
166 config_info_t conf;
167 cistpl_cftable_entry_t dflt = { 0 };
168 223
169 DBG(0, "sl811_cs_config(0x%p)\n", link); 224 DBG(0, "sl811_cs_config(0x%p)\n", link);
170 225
226 cfg_mem = kzalloc(sizeof(struct sl811_css_cfg), GFP_KERNEL);
227 if (!cfg_mem)
228 return -ENOMEM;
229
171 /* Look up the current Vcc */ 230 /* Look up the current Vcc */
172 CS_CHECK(GetConfigurationInfo, 231 CS_CHECK(GetConfigurationInfo,
173 pcmcia_get_configuration_info(link, &conf)); 232 pcmcia_get_configuration_info(link, &cfg_mem->conf));
174
175 tuple.Attributes = 0;
176 tuple.TupleData = buf;
177 tuple.TupleDataMax = sizeof(buf);
178 tuple.TupleOffset = 0;
179 tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
180 CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
181 while (1) {
182 cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
183
184 if (pcmcia_get_tuple_data(link, &tuple) != 0
185 || pcmcia_parse_tuple(link, &tuple, &parse)
186 != 0)
187 goto next_entry;
188
189 if (cfg->flags & CISTPL_CFTABLE_DEFAULT) {
190 dflt = *cfg;
191 }
192 233
193 if (cfg->index == 0) 234 if (pcmcia_loop_config(link, sl811_cs_config_check, cfg_mem))
194 goto next_entry; 235 return -ENODEV;
195
196 link->conf.ConfigIndex = cfg->index;
197
198 /* Use power settings for Vcc and Vpp if present */
199 /* Note that the CIS values need to be rescaled */
200 if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) {
201 if (cfg->vcc.param[CISTPL_POWER_VNOM]/10000
202 != conf.Vcc)
203 goto next_entry;
204 } else if (dflt.vcc.present & (1<<CISTPL_POWER_VNOM)) {
205 if (dflt.vcc.param[CISTPL_POWER_VNOM]/10000
206 != conf.Vcc)
207 goto next_entry;
208 }
209
210 if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM))
211 link->conf.Vpp =
212 cfg->vpp1.param[CISTPL_POWER_VNOM]/10000;
213 else if (dflt.vpp1.present & (1<<CISTPL_POWER_VNOM))
214 link->conf.Vpp =
215 dflt.vpp1.param[CISTPL_POWER_VNOM]/10000;
216
217 /* we need an interrupt */
218 if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1)
219 link->conf.Attributes |= CONF_ENABLE_IRQ;
220
221 /* IO window settings */
222 link->io.NumPorts1 = link->io.NumPorts2 = 0;
223 if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
224 cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
225
226 link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
227 link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
228 link->io.BasePort1 = io->win[0].base;
229 link->io.NumPorts1 = io->win[0].len;
230
231 if (pcmcia_request_io(link, &link->io) != 0)
232 goto next_entry;
233 }
234 break;
235
236next_entry:
237 pcmcia_disable_device(link);
238 last_ret = pcmcia_get_next_tuple(link, &tuple);
239 }
240 236
241 /* require an IRQ and two registers */ 237 /* require an IRQ and two registers */
242 if (!link->io.NumPorts1 || link->io.NumPorts1 < 2) 238 if (!link->io.NumPorts1 || link->io.NumPorts1 < 2)
@@ -269,8 +265,10 @@ cs_failed:
269 printk("sl811_cs_config failed\n"); 265 printk("sl811_cs_config failed\n");
270 cs_error(link, last_fn, last_ret); 266 cs_error(link, last_fn, last_ret);
271 sl811_cs_release(link); 267 sl811_cs_release(link);
268 kfree(cfg_mem);
272 return -ENODEV; 269 return -ENODEV;
273 } 270 }
271 kfree(cfg_mem);
274 return 0; 272 return 0;
275} 273}
276 274