diff options
Diffstat (limited to 'drivers/usb/misc/ftdi-elan.c')
-rw-r--r-- | drivers/usb/misc/ftdi-elan.c | 592 |
1 files changed, 393 insertions, 199 deletions
diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c index 18b1925032a8..41c0161abdb9 100644 --- a/drivers/usb/misc/ftdi-elan.c +++ b/drivers/usb/misc/ftdi-elan.c | |||
@@ -40,6 +40,7 @@ | |||
40 | #include <linux/init.h> | 40 | #include <linux/init.h> |
41 | #include <linux/list.h> | 41 | #include <linux/list.h> |
42 | #include <linux/ioctl.h> | 42 | #include <linux/ioctl.h> |
43 | #include <linux/pci_ids.h> | ||
43 | #include <linux/slab.h> | 44 | #include <linux/slab.h> |
44 | #include <linux/module.h> | 45 | #include <linux/module.h> |
45 | #include <linux/kref.h> | 46 | #include <linux/kref.h> |
@@ -51,6 +52,10 @@ MODULE_AUTHOR("Tony Olech"); | |||
51 | MODULE_DESCRIPTION("FTDI ELAN driver"); | 52 | MODULE_DESCRIPTION("FTDI ELAN driver"); |
52 | MODULE_LICENSE("GPL"); | 53 | MODULE_LICENSE("GPL"); |
53 | #define INT_MODULE_PARM(n, v) static int n = v;module_param(n, int, 0444) | 54 | #define INT_MODULE_PARM(n, v) static int n = v;module_param(n, int, 0444) |
55 | static int distrust_firmware = 1; | ||
56 | module_param(distrust_firmware, bool, 0); | ||
57 | MODULE_PARM_DESC(distrust_firmware, "true to distrust firmware power/overcurren" | ||
58 | "t setup"); | ||
54 | extern struct platform_driver u132_platform_driver; | 59 | extern struct platform_driver u132_platform_driver; |
55 | static struct workqueue_struct *status_queue; | 60 | static struct workqueue_struct *status_queue; |
56 | static struct workqueue_struct *command_queue; | 61 | static struct workqueue_struct *command_queue; |
@@ -66,7 +71,9 @@ static struct list_head ftdi_static_list; | |||
66 | * end of the global variables protected by ftdi_module_lock | 71 | * end of the global variables protected by ftdi_module_lock |
67 | */ | 72 | */ |
68 | #include "usb_u132.h" | 73 | #include "usb_u132.h" |
69 | #define TD_DEVNOTRESP 5 | 74 | #include <asm/io.h> |
75 | #include "../core/hcd.h" | ||
76 | #include "../host/ohci.h" | ||
70 | /* Define these values to match your devices*/ | 77 | /* Define these values to match your devices*/ |
71 | #define USB_FTDI_ELAN_VENDOR_ID 0x0403 | 78 | #define USB_FTDI_ELAN_VENDOR_ID 0x0403 |
72 | #define USB_FTDI_ELAN_PRODUCT_ID 0xd6ea | 79 | #define USB_FTDI_ELAN_PRODUCT_ID 0xd6ea |
@@ -551,7 +558,7 @@ static void ftdi_elan_status_work(struct work_struct *work) | |||
551 | } else { | 558 | } else { |
552 | dev_err(&ftdi->udev->dev, "initialized failed - trying " | 559 | dev_err(&ftdi->udev->dev, "initialized failed - trying " |
553 | "again in 10 seconds\n"); | 560 | "again in 10 seconds\n"); |
554 | work_delay_in_msec = 10 *1000; | 561 | work_delay_in_msec = 1 *1000; |
555 | } | 562 | } |
556 | } else if (ftdi->registered == 0) { | 563 | } else if (ftdi->registered == 0) { |
557 | work_delay_in_msec = 10; | 564 | work_delay_in_msec = 10; |
@@ -2288,82 +2295,288 @@ static int ftdi_elan_checkingPCI(struct usb_ftdi *ftdi) | |||
2288 | } | 2295 | } |
2289 | } | 2296 | } |
2290 | 2297 | ||
2291 | static int ftdi_elan_enumeratePCI(struct usb_ftdi *ftdi) | 2298 | |
2299 | #define ftdi_read_pcimem(ftdi, member, data) ftdi_elan_read_pcimem(ftdi, \ | ||
2300 | offsetof(struct ohci_regs, member), 0, data); | ||
2301 | #define ftdi_write_pcimem(ftdi, member, data) ftdi_elan_write_pcimem(ftdi, \ | ||
2302 | offsetof(struct ohci_regs, member), 0, data); | ||
2303 | #define OHCI_QUIRK_AMD756 0x01 | ||
2304 | #define OHCI_QUIRK_SUPERIO 0x02 | ||
2305 | #define OHCI_QUIRK_INITRESET 0x04 | ||
2306 | #define OHCI_BIG_ENDIAN 0x08 | ||
2307 | #define OHCI_QUIRK_ZFMICRO 0x10 | ||
2308 | #define OHCI_CONTROL_INIT OHCI_CTRL_CBSR | ||
2309 | #define OHCI_INTR_INIT (OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_RD | \ | ||
2310 | OHCI_INTR_WDH) | ||
2311 | static int ftdi_elan_check_controller(struct usb_ftdi *ftdi, int quirk) | ||
2312 | { | ||
2313 | int devices = 0; | ||
2314 | int retval; | ||
2315 | u32 hc_control; | ||
2316 | int num_ports; | ||
2317 | u32 control; | ||
2318 | u32 rh_a = -1; | ||
2319 | u32 status; | ||
2320 | u32 fminterval; | ||
2321 | u32 hc_fminterval; | ||
2322 | u32 periodicstart; | ||
2323 | u32 cmdstatus; | ||
2324 | u32 roothub_a; | ||
2325 | int mask = OHCI_INTR_INIT; | ||
2326 | int sleep_time = 0; | ||
2327 | int reset_timeout = 30; /* ... allow extra time */ | ||
2328 | int temp; | ||
2329 | retval = ftdi_write_pcimem(ftdi, intrdisable, OHCI_INTR_MIE); | ||
2330 | if (retval) | ||
2331 | return retval; | ||
2332 | retval = ftdi_read_pcimem(ftdi, control, &control); | ||
2333 | if (retval) | ||
2334 | return retval; | ||
2335 | retval = ftdi_read_pcimem(ftdi, roothub.a, &rh_a); | ||
2336 | if (retval) | ||
2337 | return retval; | ||
2338 | num_ports = rh_a & RH_A_NDP; | ||
2339 | retval = ftdi_read_pcimem(ftdi, fminterval, &hc_fminterval); | ||
2340 | if (retval) | ||
2341 | return retval; | ||
2342 | hc_fminterval &= 0x3fff; | ||
2343 | if (hc_fminterval != FI) { | ||
2344 | } | ||
2345 | hc_fminterval |= FSMP(hc_fminterval) << 16; | ||
2346 | retval = ftdi_read_pcimem(ftdi, control, &hc_control); | ||
2347 | if (retval) | ||
2348 | return retval; | ||
2349 | switch (hc_control & OHCI_CTRL_HCFS) { | ||
2350 | case OHCI_USB_OPER: | ||
2351 | sleep_time = 0; | ||
2352 | break; | ||
2353 | case OHCI_USB_SUSPEND: | ||
2354 | case OHCI_USB_RESUME: | ||
2355 | hc_control &= OHCI_CTRL_RWC; | ||
2356 | hc_control |= OHCI_USB_RESUME; | ||
2357 | sleep_time = 10; | ||
2358 | break; | ||
2359 | default: | ||
2360 | hc_control &= OHCI_CTRL_RWC; | ||
2361 | hc_control |= OHCI_USB_RESET; | ||
2362 | sleep_time = 50; | ||
2363 | break; | ||
2364 | } | ||
2365 | retval = ftdi_write_pcimem(ftdi, control, hc_control); | ||
2366 | if (retval) | ||
2367 | return retval; | ||
2368 | retval = ftdi_read_pcimem(ftdi, control, &control); | ||
2369 | if (retval) | ||
2370 | return retval; | ||
2371 | msleep(sleep_time); | ||
2372 | retval = ftdi_read_pcimem(ftdi, roothub.a, &roothub_a); | ||
2373 | if (retval) | ||
2374 | return retval; | ||
2375 | if (!(roothub_a & RH_A_NPS)) { /* power down each port */ | ||
2376 | for (temp = 0; temp < num_ports; temp++) { | ||
2377 | retval = ftdi_write_pcimem(ftdi, | ||
2378 | roothub.portstatus[temp], RH_PS_LSDA); | ||
2379 | if (retval) | ||
2380 | return retval; | ||
2381 | } | ||
2382 | } | ||
2383 | retval = ftdi_read_pcimem(ftdi, control, &control); | ||
2384 | if (retval) | ||
2385 | return retval; | ||
2386 | retry:retval = ftdi_read_pcimem(ftdi, cmdstatus, &status); | ||
2387 | if (retval) | ||
2388 | return retval; | ||
2389 | retval = ftdi_write_pcimem(ftdi, cmdstatus, OHCI_HCR); | ||
2390 | if (retval) | ||
2391 | return retval; | ||
2392 | extra:{ | ||
2393 | retval = ftdi_read_pcimem(ftdi, cmdstatus, &status); | ||
2394 | if (retval) | ||
2395 | return retval; | ||
2396 | if (0 != (status & OHCI_HCR)) { | ||
2397 | if (--reset_timeout == 0) { | ||
2398 | dev_err(&ftdi->udev->dev, "USB HC reset timed o" | ||
2399 | "ut!\n"); | ||
2400 | return -ENODEV; | ||
2401 | } else { | ||
2402 | msleep(5); | ||
2403 | goto extra; | ||
2404 | } | ||
2405 | } | ||
2406 | } | ||
2407 | if (quirk & OHCI_QUIRK_INITRESET) { | ||
2408 | retval = ftdi_write_pcimem(ftdi, control, hc_control); | ||
2409 | if (retval) | ||
2410 | return retval; | ||
2411 | retval = ftdi_read_pcimem(ftdi, control, &control); | ||
2412 | if (retval) | ||
2413 | return retval; | ||
2414 | } | ||
2415 | retval = ftdi_write_pcimem(ftdi, ed_controlhead, 0x00000000); | ||
2416 | if (retval) | ||
2417 | return retval; | ||
2418 | retval = ftdi_write_pcimem(ftdi, ed_bulkhead, 0x11000000); | ||
2419 | if (retval) | ||
2420 | return retval; | ||
2421 | retval = ftdi_write_pcimem(ftdi, hcca, 0x00000000); | ||
2422 | if (retval) | ||
2423 | return retval; | ||
2424 | retval = ftdi_read_pcimem(ftdi, fminterval, &fminterval); | ||
2425 | if (retval) | ||
2426 | return retval; | ||
2427 | retval = ftdi_write_pcimem(ftdi, fminterval, | ||
2428 | ((fminterval & FIT) ^ FIT) | hc_fminterval); | ||
2429 | if (retval) | ||
2430 | return retval; | ||
2431 | retval = ftdi_write_pcimem(ftdi, periodicstart, | ||
2432 | ((9 *hc_fminterval) / 10) & 0x3fff); | ||
2433 | if (retval) | ||
2434 | return retval; | ||
2435 | retval = ftdi_read_pcimem(ftdi, fminterval, &fminterval); | ||
2436 | if (retval) | ||
2437 | return retval; | ||
2438 | retval = ftdi_read_pcimem(ftdi, periodicstart, &periodicstart); | ||
2439 | if (retval) | ||
2440 | return retval; | ||
2441 | if (0 == (fminterval & 0x3fff0000) || 0 == periodicstart) { | ||
2442 | if (!(quirk & OHCI_QUIRK_INITRESET)) { | ||
2443 | quirk |= OHCI_QUIRK_INITRESET; | ||
2444 | goto retry; | ||
2445 | } else | ||
2446 | dev_err(&ftdi->udev->dev, "init err(%08x %04x)\n", | ||
2447 | fminterval, periodicstart); | ||
2448 | } /* start controller operations */ | ||
2449 | hc_control &= OHCI_CTRL_RWC; | ||
2450 | hc_control |= OHCI_CONTROL_INIT | OHCI_CTRL_BLE | OHCI_USB_OPER; | ||
2451 | retval = ftdi_write_pcimem(ftdi, control, hc_control); | ||
2452 | if (retval) | ||
2453 | return retval; | ||
2454 | retval = ftdi_write_pcimem(ftdi, cmdstatus, OHCI_BLF); | ||
2455 | if (retval) | ||
2456 | return retval; | ||
2457 | retval = ftdi_read_pcimem(ftdi, cmdstatus, &cmdstatus); | ||
2458 | if (retval) | ||
2459 | return retval; | ||
2460 | retval = ftdi_read_pcimem(ftdi, control, &control); | ||
2461 | if (retval) | ||
2462 | return retval; | ||
2463 | retval = ftdi_write_pcimem(ftdi, roothub.status, RH_HS_DRWE); | ||
2464 | if (retval) | ||
2465 | return retval; | ||
2466 | retval = ftdi_write_pcimem(ftdi, intrstatus, mask); | ||
2467 | if (retval) | ||
2468 | return retval; | ||
2469 | retval = ftdi_write_pcimem(ftdi, intrdisable, | ||
2470 | OHCI_INTR_MIE | OHCI_INTR_OC | OHCI_INTR_RHSC | OHCI_INTR_FNO | | ||
2471 | OHCI_INTR_UE | OHCI_INTR_RD | OHCI_INTR_SF | OHCI_INTR_WDH | | ||
2472 | OHCI_INTR_SO); | ||
2473 | if (retval) | ||
2474 | return retval; /* handle root hub init quirks ... */ | ||
2475 | retval = ftdi_read_pcimem(ftdi, roothub.a, &roothub_a); | ||
2476 | if (retval) | ||
2477 | return retval; | ||
2478 | roothub_a &= ~(RH_A_PSM | RH_A_OCPM); | ||
2479 | if (quirk & OHCI_QUIRK_SUPERIO) { | ||
2480 | roothub_a |= RH_A_NOCP; | ||
2481 | roothub_a &= ~(RH_A_POTPGT | RH_A_NPS); | ||
2482 | retval = ftdi_write_pcimem(ftdi, roothub.a, roothub_a); | ||
2483 | if (retval) | ||
2484 | return retval; | ||
2485 | } else if ((quirk & OHCI_QUIRK_AMD756) || distrust_firmware) { | ||
2486 | roothub_a |= RH_A_NPS; | ||
2487 | retval = ftdi_write_pcimem(ftdi, roothub.a, roothub_a); | ||
2488 | if (retval) | ||
2489 | return retval; | ||
2490 | } | ||
2491 | retval = ftdi_write_pcimem(ftdi, roothub.status, RH_HS_LPSC); | ||
2492 | if (retval) | ||
2493 | return retval; | ||
2494 | retval = ftdi_write_pcimem(ftdi, roothub.b, | ||
2495 | (roothub_a & RH_A_NPS) ? 0 : RH_B_PPCM); | ||
2496 | if (retval) | ||
2497 | return retval; | ||
2498 | retval = ftdi_read_pcimem(ftdi, control, &control); | ||
2499 | if (retval) | ||
2500 | return retval; | ||
2501 | mdelay((roothub_a >> 23) & 0x1fe); | ||
2502 | for (temp = 0; temp < num_ports; temp++) { | ||
2503 | u32 portstatus; | ||
2504 | retval = ftdi_read_pcimem(ftdi, roothub.portstatus[temp], | ||
2505 | &portstatus); | ||
2506 | if (retval) | ||
2507 | return retval; | ||
2508 | if (1 & portstatus) | ||
2509 | devices += 1; | ||
2510 | } | ||
2511 | return devices; | ||
2512 | } | ||
2513 | |||
2514 | static int ftdi_elan_setup_controller(struct usb_ftdi *ftdi, int fn) | ||
2292 | { | 2515 | { |
2293 | u32 latence_timer; | 2516 | u32 latence_timer; |
2294 | u32 controlreg; | ||
2295 | int UxxxStatus; | 2517 | int UxxxStatus; |
2296 | u32 pcidata; | 2518 | u32 pcidata; |
2297 | int reg = 0; | 2519 | int reg = 0; |
2298 | int foundOHCI = 0; | 2520 | int activePCIfn = fn << 8; |
2299 | u8 fn; | 2521 | UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000025FL | 0x2800); |
2300 | int activePCIfn = 0; | ||
2301 | u32 pciVID = 0; | ||
2302 | u32 pciPID = 0; | ||
2303 | UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); | ||
2304 | if (UxxxStatus) | ||
2305 | return UxxxStatus; | ||
2306 | UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000000L); | ||
2307 | if (UxxxStatus) | ||
2308 | return UxxxStatus; | ||
2309 | msleep(750); | ||
2310 | UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000200L | 0x100); | ||
2311 | if (UxxxStatus) | 2522 | if (UxxxStatus) |
2312 | return UxxxStatus; | 2523 | return UxxxStatus; |
2313 | UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000200L | 0x500); | 2524 | reg = 16; |
2525 | UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0, | ||
2526 | 0xFFFFFFFF); | ||
2314 | if (UxxxStatus) | 2527 | if (UxxxStatus) |
2315 | return UxxxStatus; | 2528 | return UxxxStatus; |
2316 | UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); | 2529 | UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, |
2530 | &pcidata); | ||
2317 | if (UxxxStatus) | 2531 | if (UxxxStatus) |
2318 | return UxxxStatus; | 2532 | return UxxxStatus; |
2319 | UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020CL | 0x000); | 2533 | UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0, |
2534 | 0xF0000000); | ||
2320 | if (UxxxStatus) | 2535 | if (UxxxStatus) |
2321 | return UxxxStatus; | 2536 | return UxxxStatus; |
2322 | UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020DL | 0x000); | 2537 | UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, |
2538 | &pcidata); | ||
2323 | if (UxxxStatus) | 2539 | if (UxxxStatus) |
2324 | return UxxxStatus; | 2540 | return UxxxStatus; |
2325 | msleep(250); | 2541 | reg = 12; |
2326 | UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020FL | 0x000); | 2542 | UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, |
2543 | &latence_timer); | ||
2327 | if (UxxxStatus) | 2544 | if (UxxxStatus) |
2328 | return UxxxStatus; | 2545 | return UxxxStatus; |
2329 | UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); | 2546 | latence_timer &= 0xFFFF00FF; |
2547 | latence_timer |= 0x00001600; | ||
2548 | UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00, | ||
2549 | latence_timer); | ||
2330 | if (UxxxStatus) | 2550 | if (UxxxStatus) |
2331 | return UxxxStatus; | 2551 | return UxxxStatus; |
2332 | UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000025FL | 0x800); | 2552 | UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, |
2553 | &pcidata); | ||
2333 | if (UxxxStatus) | 2554 | if (UxxxStatus) |
2334 | return UxxxStatus; | 2555 | return UxxxStatus; |
2335 | UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); | 2556 | reg = 4; |
2557 | UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00, | ||
2558 | 0x06); | ||
2336 | if (UxxxStatus) | 2559 | if (UxxxStatus) |
2337 | return UxxxStatus; | 2560 | return UxxxStatus; |
2338 | UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); | 2561 | UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, |
2562 | &pcidata); | ||
2339 | if (UxxxStatus) | 2563 | if (UxxxStatus) |
2340 | return UxxxStatus; | 2564 | return UxxxStatus; |
2341 | msleep(1000); | 2565 | for (reg = 0; reg <= 0x54; reg += 4) { |
2342 | for (fn = 0; (fn < 4) && (!foundOHCI); fn++) { | 2566 | UxxxStatus = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); |
2343 | activePCIfn = fn << 8; | ||
2344 | ftdi->function = fn + 1; | ||
2345 | UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, | ||
2346 | &pcidata); | ||
2347 | if (UxxxStatus) | 2567 | if (UxxxStatus) |
2348 | return UxxxStatus; | 2568 | return UxxxStatus; |
2349 | pciVID = pcidata & 0xFFFF; | ||
2350 | pciPID = (pcidata >> 16) & 0xFFFF; | ||
2351 | if ((pciVID == 0x1045) && (pciPID == 0xc861)) { | ||
2352 | foundOHCI = 1; | ||
2353 | } else if ((pciVID == 0x1033) && (pciPID == 0x0035)) { | ||
2354 | foundOHCI = 1; | ||
2355 | } else if ((pciVID == 0x10b9) && (pciPID == 0x5237)) { | ||
2356 | foundOHCI = 1; | ||
2357 | } else if ((pciVID == 0x11c1) && (pciPID == 0x5802)) { | ||
2358 | foundOHCI = 1; | ||
2359 | } else if ((pciVID == 0x11AB) && (pciPID == 0x1FA6)) { | ||
2360 | } | ||
2361 | } | ||
2362 | if (foundOHCI == 0) { | ||
2363 | return -ENXIO; | ||
2364 | } | 2569 | } |
2365 | ftdi->platform_data.vendor = pciVID; | 2570 | return 0; |
2366 | ftdi->platform_data.device = pciPID; | 2571 | } |
2572 | |||
2573 | static int ftdi_elan_close_controller(struct usb_ftdi *ftdi, int fn) | ||
2574 | { | ||
2575 | u32 latence_timer; | ||
2576 | int UxxxStatus; | ||
2577 | u32 pcidata; | ||
2578 | int reg = 0; | ||
2579 | int activePCIfn = fn << 8; | ||
2367 | UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000025FL | 0x2800); | 2580 | UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000025FL | 0x2800); |
2368 | if (UxxxStatus) | 2581 | if (UxxxStatus) |
2369 | return UxxxStatus; | 2582 | return UxxxStatus; |
@@ -2377,7 +2590,7 @@ static int ftdi_elan_enumeratePCI(struct usb_ftdi *ftdi) | |||
2377 | if (UxxxStatus) | 2590 | if (UxxxStatus) |
2378 | return UxxxStatus; | 2591 | return UxxxStatus; |
2379 | UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0, | 2592 | UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0, |
2380 | 0xF0000000); | 2593 | 0x00000000); |
2381 | if (UxxxStatus) | 2594 | if (UxxxStatus) |
2382 | return UxxxStatus; | 2595 | return UxxxStatus; |
2383 | UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, | 2596 | UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, |
@@ -2401,7 +2614,7 @@ static int ftdi_elan_enumeratePCI(struct usb_ftdi *ftdi) | |||
2401 | return UxxxStatus; | 2614 | return UxxxStatus; |
2402 | reg = 4; | 2615 | reg = 4; |
2403 | UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00, | 2616 | UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00, |
2404 | 0x06); | 2617 | 0x00); |
2405 | if (UxxxStatus) | 2618 | if (UxxxStatus) |
2406 | return UxxxStatus; | 2619 | return UxxxStatus; |
2407 | UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, | 2620 | UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, |
@@ -2411,159 +2624,139 @@ static int ftdi_elan_enumeratePCI(struct usb_ftdi *ftdi) | |||
2411 | return 0; | 2624 | return 0; |
2412 | } | 2625 | } |
2413 | 2626 | ||
2627 | static int ftdi_elan_found_controller(struct usb_ftdi *ftdi, int fn, int quirk) | ||
2628 | { | ||
2629 | int result; | ||
2630 | int UxxxStatus; | ||
2631 | UxxxStatus = ftdi_elan_setup_controller(ftdi, fn); | ||
2632 | if (UxxxStatus) | ||
2633 | return UxxxStatus; | ||
2634 | result = ftdi_elan_check_controller(ftdi, quirk); | ||
2635 | UxxxStatus = ftdi_elan_close_controller(ftdi, fn); | ||
2636 | if (UxxxStatus) | ||
2637 | return UxxxStatus; | ||
2638 | return result; | ||
2639 | } | ||
2640 | |||
2641 | static int ftdi_elan_enumeratePCI(struct usb_ftdi *ftdi) | ||
2642 | { | ||
2643 | u32 controlreg; | ||
2644 | u8 sensebits; | ||
2645 | int UxxxStatus; | ||
2646 | UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); | ||
2647 | if (UxxxStatus) | ||
2648 | return UxxxStatus; | ||
2649 | UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000000L); | ||
2650 | if (UxxxStatus) | ||
2651 | return UxxxStatus; | ||
2652 | msleep(750); | ||
2653 | UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000200L | 0x100); | ||
2654 | if (UxxxStatus) | ||
2655 | return UxxxStatus; | ||
2656 | UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000200L | 0x500); | ||
2657 | if (UxxxStatus) | ||
2658 | return UxxxStatus; | ||
2659 | UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); | ||
2660 | if (UxxxStatus) | ||
2661 | return UxxxStatus; | ||
2662 | UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020CL | 0x000); | ||
2663 | if (UxxxStatus) | ||
2664 | return UxxxStatus; | ||
2665 | UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020DL | 0x000); | ||
2666 | if (UxxxStatus) | ||
2667 | return UxxxStatus; | ||
2668 | msleep(250); | ||
2669 | UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020FL | 0x000); | ||
2670 | if (UxxxStatus) | ||
2671 | return UxxxStatus; | ||
2672 | UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); | ||
2673 | if (UxxxStatus) | ||
2674 | return UxxxStatus; | ||
2675 | UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000025FL | 0x800); | ||
2676 | if (UxxxStatus) | ||
2677 | return UxxxStatus; | ||
2678 | UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); | ||
2679 | if (UxxxStatus) | ||
2680 | return UxxxStatus; | ||
2681 | UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); | ||
2682 | if (UxxxStatus) | ||
2683 | return UxxxStatus; | ||
2684 | msleep(1000); | ||
2685 | sensebits = (controlreg >> 16) & 0x000F; | ||
2686 | if (0x0D == sensebits) | ||
2687 | return 0; | ||
2688 | else | ||
2689 | return - ENXIO; | ||
2690 | } | ||
2691 | |||
2414 | static int ftdi_elan_setupOHCI(struct usb_ftdi *ftdi) | 2692 | static int ftdi_elan_setupOHCI(struct usb_ftdi *ftdi) |
2415 | { | 2693 | { |
2694 | int UxxxStatus; | ||
2416 | u32 pcidata; | 2695 | u32 pcidata; |
2417 | int U132Status; | 2696 | int reg = 0; |
2418 | int reg; | 2697 | u8 fn; |
2419 | int reset_repeat = 0; | 2698 | int activePCIfn = 0; |
2420 | do_reset:reg = 8; | 2699 | int max_devices = 0; |
2421 | U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x0e, 0x01); | 2700 | int controllers = 0; |
2422 | if (U132Status) | 2701 | int unrecognized = 0; |
2423 | return U132Status; | 2702 | ftdi->function = 0; |
2424 | reset_check:{ | 2703 | for (fn = 0; (fn < 4); fn++) { |
2425 | U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); | 2704 | u32 pciVID = 0; |
2426 | if (U132Status) | 2705 | u32 pciPID = 0; |
2427 | return U132Status; | 2706 | int devices = 0; |
2428 | if (pcidata & 1) { | 2707 | activePCIfn = fn << 8; |
2429 | msleep(500); | 2708 | UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, |
2430 | if (reset_repeat++ > 100) { | 2709 | &pcidata); |
2431 | reset_repeat = 0; | 2710 | if (UxxxStatus) |
2432 | goto do_reset; | 2711 | return UxxxStatus; |
2433 | } else | 2712 | pciVID = pcidata & 0xFFFF; |
2434 | goto reset_check; | 2713 | pciPID = (pcidata >> 16) & 0xFFFF; |
2714 | if ((pciVID == PCI_VENDOR_ID_OPTI) && (pciPID == 0xc861)) { | ||
2715 | devices = ftdi_elan_found_controller(ftdi, fn, 0); | ||
2716 | controllers += 1; | ||
2717 | } else if ((pciVID == PCI_VENDOR_ID_NEC) && (pciPID == 0x0035)) | ||
2718 | { | ||
2719 | devices = ftdi_elan_found_controller(ftdi, fn, 0); | ||
2720 | controllers += 1; | ||
2721 | } else if ((pciVID == PCI_VENDOR_ID_AL) && (pciPID == 0x5237)) { | ||
2722 | devices = ftdi_elan_found_controller(ftdi, fn, 0); | ||
2723 | controllers += 1; | ||
2724 | } else if ((pciVID == PCI_VENDOR_ID_ATT) && (pciPID == 0x5802)) | ||
2725 | { | ||
2726 | devices = ftdi_elan_found_controller(ftdi, fn, 0); | ||
2727 | controllers += 1; | ||
2728 | } else if (pciVID == PCI_VENDOR_ID_AMD && pciPID == 0x740c) { | ||
2729 | devices = ftdi_elan_found_controller(ftdi, fn, | ||
2730 | OHCI_QUIRK_AMD756); | ||
2731 | controllers += 1; | ||
2732 | } else if (pciVID == PCI_VENDOR_ID_COMPAQ && pciPID == 0xa0f8) { | ||
2733 | devices = ftdi_elan_found_controller(ftdi, fn, | ||
2734 | OHCI_QUIRK_ZFMICRO); | ||
2735 | controllers += 1; | ||
2736 | } else if (0 == pcidata) { | ||
2737 | } else | ||
2738 | unrecognized += 1; | ||
2739 | if (devices > max_devices) { | ||
2740 | max_devices = devices; | ||
2741 | ftdi->function = fn + 1; | ||
2742 | ftdi->platform_data.vendor = pciVID; | ||
2743 | ftdi->platform_data.device = pciPID; | ||
2435 | } | 2744 | } |
2436 | } | 2745 | } |
2437 | goto dump_regs; | 2746 | if (ftdi->function > 0) { |
2438 | msleep(500); | 2747 | UxxxStatus = ftdi_elan_setup_controller(ftdi, |
2439 | reg = 0x28; | 2748 | ftdi->function - 1); |
2440 | U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x11000000); | 2749 | if (UxxxStatus) |
2441 | if (U132Status) | 2750 | return UxxxStatus; |
2442 | return U132Status; | 2751 | return 0; |
2443 | U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); | 2752 | } else if (controllers > 0) { |
2444 | if (U132Status) | 2753 | return -ENXIO; |
2445 | return U132Status; | 2754 | } else if (unrecognized > 0) { |
2446 | reg = 0x40; | 2755 | return -ENXIO; |
2447 | U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x2edf); | 2756 | } else { |
2448 | if (U132Status) | 2757 | ftdi->enumerated = 0; |
2449 | return U132Status; | 2758 | return -ENXIO; |
2450 | U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); | ||
2451 | if (U132Status) | ||
2452 | return U132Status; | ||
2453 | reg = 0x34; | ||
2454 | U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x2edf2edf); | ||
2455 | if (U132Status) | ||
2456 | return U132Status; | ||
2457 | U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); | ||
2458 | if (U132Status) | ||
2459 | return U132Status; | ||
2460 | reg = 4; | ||
2461 | U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0xA0); | ||
2462 | if (U132Status) | ||
2463 | return U132Status; | ||
2464 | U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); | ||
2465 | if (U132Status) | ||
2466 | return U132Status; | ||
2467 | msleep(250); | ||
2468 | reg = 8; | ||
2469 | U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x0e, 0x04); | ||
2470 | if (U132Status) | ||
2471 | return U132Status; | ||
2472 | U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); | ||
2473 | if (U132Status) | ||
2474 | return U132Status; | ||
2475 | reg = 0x28; | ||
2476 | U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); | ||
2477 | if (U132Status) | ||
2478 | return U132Status; | ||
2479 | reg = 8; | ||
2480 | U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); | ||
2481 | if (U132Status) | ||
2482 | return U132Status; | ||
2483 | reg = 0x48; | ||
2484 | U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x00001200); | ||
2485 | if (U132Status) | ||
2486 | return U132Status; | ||
2487 | U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); | ||
2488 | if (U132Status) | ||
2489 | return U132Status; | ||
2490 | reg = 0x54; | ||
2491 | U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); | ||
2492 | if (U132Status) | ||
2493 | return U132Status; | ||
2494 | reg = 0x58; | ||
2495 | U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); | ||
2496 | if (U132Status) | ||
2497 | return U132Status; | ||
2498 | reg = 0x34; | ||
2499 | U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x28002edf); | ||
2500 | if (U132Status) | ||
2501 | return U132Status; | ||
2502 | U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); | ||
2503 | if (U132Status) | ||
2504 | return U132Status; | ||
2505 | msleep(100); | ||
2506 | reg = 0x50; | ||
2507 | U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x10000); | ||
2508 | if (U132Status) | ||
2509 | return U132Status; | ||
2510 | reg = 0x54; | ||
2511 | power_check:U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); | ||
2512 | if (U132Status) | ||
2513 | return U132Status; | ||
2514 | if (!(pcidata & 1)) { | ||
2515 | msleep(500); | ||
2516 | goto power_check; | ||
2517 | } | ||
2518 | msleep(3000); | ||
2519 | reg = 0x54; | ||
2520 | U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); | ||
2521 | if (U132Status) | ||
2522 | return U132Status; | ||
2523 | reg = 0x58; | ||
2524 | U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); | ||
2525 | if (U132Status) | ||
2526 | return U132Status; | ||
2527 | reg = 0x54; | ||
2528 | U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x02); | ||
2529 | if (U132Status) | ||
2530 | return U132Status; | ||
2531 | U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); | ||
2532 | if (U132Status) | ||
2533 | return U132Status; | ||
2534 | reg = 0x54; | ||
2535 | U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x10); | ||
2536 | if (U132Status) | ||
2537 | return U132Status; | ||
2538 | U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); | ||
2539 | if (U132Status) | ||
2540 | return U132Status; | ||
2541 | msleep(750); | ||
2542 | reg = 0x54; | ||
2543 | if (0) { | ||
2544 | U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x02); | ||
2545 | if (U132Status) | ||
2546 | return U132Status; | ||
2547 | } | ||
2548 | if (0) { | ||
2549 | U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); | ||
2550 | if (U132Status) | ||
2551 | return U132Status; | ||
2552 | } | ||
2553 | reg = 0x54; | ||
2554 | U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); | ||
2555 | if (U132Status) | ||
2556 | return U132Status; | ||
2557 | reg = 0x58; | ||
2558 | U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); | ||
2559 | if (U132Status) | ||
2560 | return U132Status; | ||
2561 | dump_regs:for (reg = 0; reg <= 0x54; reg += 4) { | ||
2562 | U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); | ||
2563 | if (U132Status) | ||
2564 | return U132Status; | ||
2565 | } | 2759 | } |
2566 | return 0; | ||
2567 | } | 2760 | } |
2568 | 2761 | ||
2569 | 2762 | ||
@@ -2688,6 +2881,7 @@ static void ftdi_elan_disconnect(struct usb_interface *interface) | |||
2688 | platform_device_unregister(&ftdi->platform_dev); | 2881 | platform_device_unregister(&ftdi->platform_dev); |
2689 | ftdi->synchronized = 0; | 2882 | ftdi->synchronized = 0; |
2690 | ftdi->enumerated = 0; | 2883 | ftdi->enumerated = 0; |
2884 | ftdi->initialized = 0; | ||
2691 | ftdi->registered = 0; | 2885 | ftdi->registered = 0; |
2692 | } | 2886 | } |
2693 | flush_workqueue(status_queue); | 2887 | flush_workqueue(status_queue); |